ESP32S3——多线程

一、环境:

平台:arduino IDE 或 VS Code PlatformIO皆可。

我的是后者,具体为:

框架:VS + PlatformIO + Arduino

二、硬件准备:

一个esp32s3

本文用到的是U0RXD(GPIO44 )与U0TXD(GPIO43)引脚

一台电脑

一根数据线

三、代码功能:

一个LED一秒亮一次:

另一个LED两秒两一次。

注意:ESP32S3有两个type-C口,一个UART用来下载调试程序,一个USB用来供电。下载完程序后切换到USB,现象会更明显。

四、最简代码

cpp 复制代码
#include <Arduino.h>

#define LED_U0RXD 44
#define LED_U0TXD 43

// 创建两个任务,
// TaskBlink1任务:一个LED 1s亮一次,
// TaskBlink2任务:另一个LED 2s亮一次。
void TaskBlink1( void *pvParameters );
void TaskBlink2( void *pvParameters );

void setup() {
  Serial.begin(115200);
  uint32_t blink_delay1 = 1000; // Delay between changing state on LED pin
  uint32_t blink_delay2 = 2000; // Delay between changing state on LED pin

  xTaskCreate(
    TaskBlink1       // 这个任务运行的函数
    ,  "Task Blink1" //  给人看的名字
    ,  2048        // 任务栈的大小,用于存储任务运行时的上下文信息。简单来说,就是最多存这么多信息
    ,  (void*) &blink_delay1 // 任务参数。要么没有填NULL;要么必须为无类型指针
    ,  2  // 优先级
    ,  NULL // 任务的句柄,用于管理和控制任务,NULL相当于0,意味着此处不需要任务句柄
    );


  xTaskCreate(
    TaskBlink2       // 这个任务运行的函数
    ,  "Task Blink2" //  给人看的名字
    ,  2048        // 任务栈的大小,用于存储任务运行时的上下文信息。简单来说,就是最多存这么多信息
    ,  (void*) &blink_delay2 // 任务参数。要么没有填NULL;要么必须为无类型指针
    ,  2  // 优先级
    ,  NULL // 任务的句柄,用于管理和控制任务,NULL相当于0,意味着此处不需要任务句柄
    );

  Serial.printf("Basic Multi Threading Arduino Example\n");
  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}

void loop(){
// 这里什么都不用写
}

/*---------------------- Tasks ---------------------*/

void TaskBlink1(void *pvParameters){  // This is a task.
  uint32_t blink_delay = *((uint32_t*)pvParameters);

  // 初始化LED_U0RXD为output模式
  pinMode(LED_U0RXD, OUTPUT);
// for死循环
  for (;;){ // 多线程,每个任务必须是死循环
    digitalWrite(LED_U0RXD, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(blink_delay);
    digitalWrite(LED_U0RXD, LOW);    // turn the LED off by making the voltage LOW
    delay(blink_delay);
  }
}

void TaskBlink2(void *pvParameters){  // This is a task.
  uint32_t blink_delay = *((uint32_t*)pvParameters);

  // 初始化LED_U0RXD为output模式
  pinMode(LED_U0TXD, OUTPUT);

  for (;;){ // A Task shall never return or exit.
    digitalWrite(LED_U0TXD, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(blink_delay);
    digitalWrite(LED_U0TXD, LOW);    // turn the LED off by making the voltage LOW
    delay(blink_delay);
  }
}

主要代码解析

我们可以看到,多线程其实很简单。

主要就是函数 xTaskCreate( ) :创建一个线程,然后在线程内运行 TaskBlink1( ) 函数。

  • TaskBlink1 :这个任务运行的函数
  • "Task Blink1":给人看的名字
  • 2048 :任务栈的大小,用于存储任务运行时的上下文信息。简单来说,就是最多存这么多信息
  • (void*) &blink_delay1 :任务参数。要么没有填NULL;要么必须为无类型指针
  • 2 :优先级
  • NULL : 任务的句柄,用于管理和控制任务,NULL相当于0,意味着此处不需要任务句柄

五、多核下的多线程

有些板子有多个核,比如:ESP32S3有两个核,本身就可以就可以让两个核单独控制一个LED,实现上文双线程的效果。所以说,对于有两个核的ESP32S3,既可以指定某一个核运行俩线程,也可以指定俩核单独运行一个线程,而实现相同的效果。

这里介绍俩核各自运行一个线程,各自控制一个LED的闪烁。

话不多说,上代码:

cpp 复制代码
#include <Arduino.h>

// #if CONFIG_FREERTOS_UNICORE
// #define ARDUINO_RUNNING_CORE 0
// #else
// #define ARDUINO_RUNNING_CORE 1
// #endif

#define LED_U0RXD 44
#define LED_U0TXD 43

// 创建两个任务,
// TaskBlink1任务:一个LED 1s亮一次,
// TaskBlink2任务:另一个LED 2s亮一次。
void TaskBlink1(void *pvParameters);
void TaskBlink2(void *pvParameters);

void setup() {
  Serial.begin(115200);
  
  xTaskCreatePinnedToCore(
    TaskBlink1
    ,  "TaskBlink1"   // 任务名
    ,  1024  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的,0是最低的.
    ,  NULL 
    ,  0); // 第一个核

  xTaskCreatePinnedToCore(
    TaskBlink2
    ,  "TaskBlink2" //任务名
    ,  1024  // 栈大小
    ,  NULL
    ,  1  // 任务优先级
    ,  NULL 
    ,  1); // 第二个核

  //现在,接管单个任务调度控制的任务调度程序将自动启动。
}

void loop()
{
  // Empty. Things are done in Tasks.
}

/*---------------------- Tasks ---------------------*/

void TaskBlink1(void *pvParameters){  // This is a task.
  uint32_t blink_delay = 1000;

  // 初始化LED_U0RXD为output模式
  pinMode(LED_U0RXD, OUTPUT);
// for死循环
  for (;;){ // 多线程,每个任务必须是死循环
    digitalWrite(LED_U0RXD, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(blink_delay);
    digitalWrite(LED_U0RXD, LOW);    // turn the LED off by making the voltage LOW
    delay(blink_delay);
  }
}

void TaskBlink2(void *pvParameters){  // This is a task.
  uint32_t blink_delay = 2000;

  // 初始化LED_U0RXD为output模式
  pinMode(LED_U0TXD, OUTPUT);

  for (;;){ // A Task shall never return or exit.
    digitalWrite(LED_U0TXD, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(blink_delay);
    digitalWrite(LED_U0TXD, LOW);    // turn the LED off by making the voltage LOW
    delay(blink_delay);
  }
}

主要代码解析

我们可以看到,多核、多线程其实也很简单。

主要就是函数 xTaskCreatePinnedToCore ( ) :创建一个线程,并指定哪一个核运行线程,然后在线程内运行 TaskBlink1( ) 函数。与函数 xTaskCreate( ) 相比只多了指定运行的核,这一步。

  • TaskBlink1 :这个任务运行的函数
  • "Task Blink1":给人看的名字
  • 2048 :任务栈的大小,用于存储任务运行时的上下文信息。简单来说,就是最多存这么多信息
  • (void*) &blink_delay1 :任务参数。要么没有填NULL;要么必须为无类型指针
  • 2 :优先级
  • NULL : 任务的句柄,用于管理和控制任务,NULL相当于0,意味着此处不需要任务句柄
  • 0 :第一个核。只有俩核,只能填0或1

最后,我有话说:

如果文章对你有帮助,我很开心。有疑问,请留言,看到后,我会回复。

相关推荐
深圳市九鼎创展科技44 分钟前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
辰哥单片机设计1 小时前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
小龙报2 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机
范纹杉想快点毕业2 小时前
嵌入式与单片机开发核心学习指南——从思维转变到第一性原理的深度实践
单片机·嵌入式硬件
Industio_触觉智能2 小时前
瑞芯微RK3566开发板规格书,详细参数配置,型号EVB3566-V1,基于RK3566核心板SOM3566邮票孔封装
嵌入式硬件·开发板·rk3568·rk3566·核心板·瑞芯微
czwxkn3 小时前
4STM32(stdl)TIM定时器
stm32·单片机·嵌入式硬件
Love Song残响3 小时前
NVIDIA显卡终极优化指南
stm32·单片机·嵌入式硬件
qq_672592753 小时前
电源芯片为什么发热
单片机·嵌入式硬件
天天爱吃肉82183 小时前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
国科安芯4 小时前
抗辐照MCU在精密时频系统中的单粒子效应评估与可靠性验证
单片机·嵌入式硬件·架构·制造·安全性测试