esp32-s3多任务处理

esp32_S3多任务处理

多任务介绍

  • 多任务的概念:同一时间内执行多个任务,它充分利用CPU资源,提高程序的执行效率。
  • 对于单核CPU处理多任务,操作系统会给每个运行的任务一小段运行的时间,时间一到,然后立马切换任务,由于交替切换的速度过快,以人的眼光去看感觉每个程序都是同时执行的错觉。
  • 相对于多核CPU,操作系统会给每个内核安排一个执行的软件同时运行,从而达到同一个时间内执行多任务的效果。
  • ESP32的任务和操作系统的进程的概念是一样的

在这里插入图片描述

  • ESP32有两颗CPU,包含ProtocolcPU(称为CPUO或PRO_CPU)和ApplicationcPu(称为CPU1或APP_CPU)。这两个核实际上是相同的,并且共享相同的内存
  • 我们之前用的setup和loop方法都是在CPU1上执行的CPUO一直不干活,我们要使用多任务让它动起来。
  • 保证所有的任务都以合理正确的速率推进,不被其它任务所阻塞。
void1oop(){
task1()//这个需要较长的操作,比如59oms
task2();//这个需要50ms执行一次
}

有如上代码,任务一的时间较长,但任务二时间较短,就会有一定冲突。此时就适合双线程来完成任务。

时间片轮转调度

参考:(8条消息) UCOS学习笔记(四)时间片轮转调度_ucosii时间片轮转调度_爱吃肉的大高个的博客-CSDN博客

在这里插入图片描述

多任务处理相关函数

头文件
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
创建任务
BaseType_t tXTaskCreatePinnedToCore(TaskFunctiont_t pvTaskcode,
const char * const pcName,const uint32_t usstackDepth,
void* const pvParameters,UBaseType_t uxPriority,TaskHandle_t const pvCreatedTask,const BaseType_t xCoreID)
  • pvTaskCode:指向任务输入函数的指针。任务必须被实现为永不Return(如:死循环),或者应该使用
  • vtTaskDelete:函数终止
  • pcName:该任务的描述性名称,最大长度16字节
  • usStackDepth:指定为字节数的任务堆栈的大小
  • pvParameters:将用作所创建的任务的参数的指针,在创建任务的时候可以向任务传递参数。
  • uxPriority:任务运行的优先级。目前ESP32的优先级有25级,0-24,数字越大优先级越高,Idle为0,loop任务的优先级是1
  • pvCreatedTask:用于传递回所创建任务的句柄
  • xCoreID:如果值为tskNOAFFINITY,则创建的任务不会固定到任何CPU,调度程序可以在任何可用的核心上运行。值0或1表示任务应固定到的CPU的索引编号。指定大于(portNUMPROCESSORS-1)的值将导致函数失败
  • 函数成功返回pdPASS,其它值都是失败。
任务函数原型
void task(void* param);
获取任务的优先级

如果在任务函数里获取本任务的优先级可以使用uxTaskPriorityGet(NULL)

UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask);
获取本任务在哪个CPU上运行
BaseType_t IRAM_ATTR xPortGetcoreID(void);
删除任务

如果在任务函数体内使用vTaskDelete(NULL)来结束本任务

void vTaskDelete(TaskHandle_t xTaskToDelete)

 

 

互斤量(xSemaphoreHandle)

互压量又称互床信号量(本质是信号量),是一种特殊的二值信号量,它用于实现对临界资源的独占式处理(它不会屏蔽CPU的中断处理)任意时刻互压量的状态只有两种,开锁或闭锁。当互斤量被任务持有时,该互压量处于闭锁状态,这个任务获得互压量的所有权。

xSemaphoreHandle//互斤锁,也算是一种信号量

创建一个互斤锁

xSemaphoreHandle xMutex = xSemaphoreCreateMutex()

获取互斤锁

xSemaphoreTake (xSemaphore,xBlockTime)

功能:在普通任务中获取信号量
参数:xSemaphore信号量句柄
xBlockTime等待的节拍数,立即返回,portMAX_DELAY等待到信号到来
ESP32默认的一节拍是1ms
返回值:pdTRUE:获取成功1pdFALSE:获取失败

释放互压锁

xSemaphoreGive(xSemaphore)

功能:在普通任务中释放信号量,也就是将信号量设为有信号的状态返回值:pdTRUE:设置成功 ,pdFALSE:设置失败

 

使用方法

if (xSemaphoreTake(xMutex,portMAX_DELAY))
//临界资源处理
xSemaphoreGive(xMutex);
}

 

综合例子

#include <FreeRTOSConfig.h>
xSemaphoreHandle xMutex; //互斥量
int number = 0;          //互斥资源

void task1(void* param)
{
  static int count = 0;
  int p = *((int*)param);

  while(count++ < 200)
  {
    int core = xPortGetCoreID();  //获取当前核
    Serial.printf("Core %d -> ", core);
    Serial.print("I am task1, Param: ");
    Serial.print(p);
    if(xSemaphoreTake(xMutex, portMAX_DELAY))
    {
      Serial.printf(" number: %d", number);
      xSemaphoreGive(xMutex);
    }
    Serial.println();
    delay(2000);
  }
  vTaskDelete(NULL);  //结束任务
}

void task2(void* param)
{
  static int count = 0;
  while(count++ < 200)
  {
    int core = xPortGetCoreID();  //获取当前核
    Serial.printf("Core %d -> ", core);
    Serial.println("I am task2");
    if(xSemaphoreTake(xMutex, portMAX_DELAY))
    {
      number++;
      xSemaphoreGive(xMutex);
    }
    delay(2000);
  }
  vTaskDelete(NULL);  //结束任务
}

void setup() {
  Serial.begin(115200);
  
  TaskHandle_t handle1;
  int param = 30;
  xMutex = xSemaphoreCreateMutex();
  xTaskCreatePinnedToCore(task1, "task1", 2048, (void*)&param, 15, &handle1, 0);
  xTaskCreatePinnedToCore(task2, "task2", 2048, NULL, 15, NULL, 1);  
}

void loop() {
  int core = xPortGetCoreID();  //获取当前核
  Serial.printf("Core %d -> I am loop ", core);
  auto pri = uxTaskPriorityGet(NULL);
  Serial.printf(" priority: %d", pri);
  Serial.println();
  delay(2000);
  //一个任务的delay不会影响到其它任务的运行
}

使用方法

if (xSemaphoreTake(xMutex, portMAX_DELAY)){ 
//临界资源处理
xSemaphoreGive(xMutex);
}

多并行任务创建

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

/*
FreeRTOS任务优先级:任务优先级数值越小,任务优先级越低。
一、 FreeRTOS 中任务的最高优先级是通过 FreeRTOSConfig.h 文件中的 configMAX_PRIORITIES 进行
配置的,用户实际可以使用的优先级范围是 0 到 configMAX_PRIORITIES – 1。比如我们配置此宏定
义为 5,那么用户可以使用的优先级号是 0,1,2,3,4,不包含 5。
二、用户配置任务的优先级数值越小,那么此任务的优先级越低,空闲任务的优先级是 0。
三、用户配置宏定义 configMAX_PRIORITIES 的最大值不要超过 32,即用户任务可以使用的优先级
范围是0到31
*/
// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogReadA3( void *pvParameters );

// the setup function runs once when you press reset or power the board
void setup() {
  
  // initialize serial communication at 115200 bits per second:
  USBSerial.begin(115200); 
  
  // Now set up two tasks to run independently.
  xTaskCreatePinnedToCore(
    TaskBlink
    ,  "TaskBlink"   // A name just for humans
    ,  1024  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE);

  xTaskCreatePinnedToCore(
    TaskAnalogReadA3
    ,  "AnalogReadA3"
    ,  1024  // Stack size
    ,  NULL
    ,  1  // Priority
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE);

  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}

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

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

void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.
    
  If you want to know what pin the on-board LED is connected to on your ESP32 model, check
  the Technical Specs of your board.
*/

  // initialize digital LED_BUILTIN on pin 13 as an output.
  pinMode(45, OUTPUT);

  for (;;) // A Task shall never return or exit.
  {
    digitalWrite(45, HIGH);   // turn the LED on (HIGH is the voltage level)
    vTaskDelay(100);  // one tick delay (15ms) in between reads for stability
    digitalWrite(45, LOW);    // turn the LED off by making the voltage LOW
    vTaskDelay(100);  // one tick delay (15ms) in between reads for stability
  }
}

void TaskAnalogReadA3(void *pvParameters)  // This is a task.
{
  (void) pvParameters;
  
/*
  AnalogReadSerial
  Reads an analog input on pin A3, prints the result to the serial monitor.
  Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
  Attach the center pin of a potentiometer to pin A3, and the outside pins to +5V and ground.

  This example code is in the public domain.
*/

  for (;;)
  {
    // read the input on analog pin A3:
    int sensorValueA3 = analogRead(A3);
    // print out the value you read:
    USBSerial.print("A3->");
    USBSerial.println(sensorValueA3);
    vTaskDelay(100);  // one tick delay (15ms) in between reads for stability
  }
}

 

基于多核并行任务创建

/*
//  多线程基于FreeRTOS,可以多个任务并行处理;
//  ESP32具有两个32位Tensilica Xtensa LX6微处理器;
//  实际上我们用Arduino进行编程时只使用到了第一个核(大核),第0核并没有使用
//  多线程可以指定在那个核运行;
 */

#include <Arduino.h>
#define USE_MULTCORE 1

void xTaskOne(void *xTask1)
{
    while (1)
    {
        USBSerial.printf("Task1 \r\n");
        delay(500);
    }
}

void xTaskTwo(void *xTask2)
{
    while (1)
    {
        USBSerial.printf("Task2 \r\n");
        delay(1000);
    }
}

void setup()
{
    USBSerial.begin(115200);
    delay(10);

}

void loop()
{

#if !USE_MULTCORE

    xTaskCreate(
        xTaskOne,  /* Task function. */
        "TaskOne", /* String with name of task. */
        4096,      /* Stack size in bytes. */
        NULL,      /* Parameter passed as input of the task */
        1,         /* Priority of the task.(configMAX_PRIORITIES - 1 being the highest, and 0 being the lowest.) */
        NULL);     /* Task handle. */

    xTaskCreate(
        xTaskTwo,  /* Task function. */
        "TaskTwo", /* String with name of task. */
        4096,      /* Stack size in bytes. */
        NULL,      /* Parameter passed as input of the task */
        2,         /* Priority of the task.(configMAX_PRIORITIES - 1 being the highest, and 0 being the lowest.) */
        NULL);     /* Task handle. */

#else

    //最后一个参数至关重要,决定这个任务创建在哪个核上.PRO_CPU 为 0, APP_CPU 为 1,或者 tskNO_AFFINITY 允许任务在两者上运行.
    xTaskCreatePinnedToCore(xTaskOne, "TaskOne", 4096, NULL, 1, NULL, 0);
    xTaskCreatePinnedToCore(xTaskTwo, "TaskTwo", 4096, NULL, 2, NULL, 1);

#endif

    while (1)
    {
        Serial.printf("XTask is running\r\n");
        delay(1000);
    }
}

<think>嗯,用户想了解ESP32-S3的技术文档和使用教程。首先,我需要确认现有的参考信息中有哪些相关资料。根据引用[1],ESP32-S3-WROOM-1的数据手册可以在提供的项目地址下载,这个应该是基础的技术文档。用户可能需要数据手册中的硬件规格、引脚定义、电气特性等信息。 然后,引用[2]提到了一个基于ESP32-S3的三模键盘项目,这可能涉及到实际应用的例子,比如GPIO的使用、启动模式切换等。用户可能对具体的硬件设计或固件开发感兴趣,需要结合这些案例来讲解使用方法。 接下来,用户可能还需要官方资源,比如乐鑫的官网,那里有最新的技术参考手册和开发指南。需要确认是否有中文版本,或者是否需要用户自行查找英文资料。此外,开发环境搭建也是关键,比如ESP-IDF的安装和配置,Arduino的支持,这些都能帮助用户快速上手。 还要考虑用户可能的项目类型,比如物联网设备、传感器应用或者人机交互设备(如键盘),不同的应用场景需要不同的外设配置和开发重点。比如,GPIO、ADC、Wi-Fi/蓝牙的使用都是常见需求,需要提供相应的代码示例和配置说明。 另外,常见问题部分需要涵盖固件下载方法、低功耗配置、多任务处理等,这些都是开发中容易遇到的难点。可能还需要推荐社区和论坛,方便用户获取更多支持和资源。 最后,生成的相关问题需要覆盖技术文档获取、硬件设计、开发环境搭建、应用场景和问题排查,这样用户可以根据自己的需求进一步探索。需要确保每个回答都有据可依,引用现有的资料,比如数据手册和示例项目,保证信息的准确性。</think>### ESP32-S3 技术文档与使用教程说明 #### 一、技术文档资源 1. **ESP32-S3-WROOM-1 数据手册** - 包含模块的硬件规格、引脚定义、电气特性、射频性能等核心参数[^1]。 - **下载地址**:[ESP32-S3-WROOM-1 数据手册](https://gitcode.com/Open-source-documentation-tutorial/8473e) 2. **官方技术参考手册** - 乐鑫官方提供详细的《ESP32-S3 技术参考手册》,涵盖芯片架构、外设功能、寄存器映射等内容。 - 访问 [乐鑫官网](https://www.espressif.com) 搜索 "ESP32-S3 Technical Reference Manual"。 3. **应用案例参考** - 如基于 ESP32-S3 的键盘项目(ESP-KeyBoard),展示了 GPIO 控制、启动模式切换等硬件设计方法[^2]。 --- #### 二、开发环境与工具 1. **ESP-IDF 开发框架** - 乐鑫官方推荐使用 **ESP-IDF**(IoT Development Framework)进行开发,支持 FreeRTOS 和多任务处理- 安装教程:[ESP-IDF 编程指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/get-started/index.html) 2. **Arduino 支持** - ESP32-S3 兼容 Arduino 生态,可通过 Arduino IDE 快速开发。 - 配置步骤:安装 ESP32 开发板包,选择 `ESP32S3 Dev Module` 板型。 --- #### 三、核心功能与代码示例 1. **GPIO 控制** - 示例:按钮电路与启动模式切换(参考 ESP-KeyBoard 项目): ```c // 初始化 GPIO0 输入模式 gpio_reset_pin(GPIO_NUM_0); gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT); ``` 2. **Wi-Fi/蓝牙配置** ```c // 初始化 Wi-Fi esp_netif_init(); esp_event_loop_create_default(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(&cfg); ``` 3. **低功耗模式** - 使用 `light sleep` 或 `deep sleep` 模式,通过 `esp_sleep_enable_timer_wakeup()` 设置唤醒条件。 --- #### 四、常见问题与调试 1. **固件下载失败** - 检查 `Download Boot` 模式:按住 `BOOT` 键后复位。 2. **外设驱动异常** - 确认引脚复用配置,避免冲突(参考数据手册的 IO_MUX 表)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

y江江江江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值