ESP32 S3 基于开发框架(Arduino)使用FreeRTOS信号量

422 阅读5分钟

1 使用FreeRTOS二值信号量

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

#include <Arduino.h>
#define USE_MULTCORE 0
hw_timer_t * timer = NULL;

SemaphoreHandle_t Binary_Handler;

bool state = 0;

void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;
  bool ON = true;
  pinMode(45, OUTPUT);
  for (;;) // A Task shall never return or exit.
  {
    USBSerial.println("TaskBlink ask the semaphore\r\n");
    xSemaphoreTake(Binary_Handler,portMAX_DELAY);
    if (state == true)
    {
        digitalWrite(45, LOW);
        USBSerial.println("TaskBlink OFF\r\n");
    }
    else
    {
        USBSerial.println("TaskBlink ON\r\n");
        digitalWrite(45, HIGH);

    }
    state = !state;
  }
}


 //测试用的主函数
 void app_main(void)
 {
    int i;

    Binary_Handler = xSemaphoreCreateBinary();	
	
    if (Binary_Handler == NULL)
    {
        USBSerial.println("Semaphore Binary Creat Failed!!!\r\n");
    }

    xSemaphoreGive(Binary_Handler);

    // 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); 

    USBSerial.println("Tasks launched ...");
 }

// this function gets called by the interrupt at <sampleRate>Hertz
void TC4_Handler(void)
{
    BaseType_t err;
    err = xSemaphoreGive(Binary_Handler);//发送新信号量
    if (err != pdTRUE)//判断信号量是否发送成功
    {
        printf("信号量发送失败!\r\n");
    }

}

void ARDUINO_ISR_ATTR onTimer(){

  TC4_Handler();
}


void setup()
{
    USBSerial.begin(115200);
    // Use 1st timer of 4 (counted from zero).
    // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
    // info).
    timer = timerBegin(0, 80, true);
    // Attach onTimer function to our timer.
    timerAttachInterrupt(timer, &onTimer, true);
    // Set alarm to call onTimer function every second (value in microseconds).
    // Repeat the alarm (third parameter)
    timerAlarmWrite(timer, 5000000, true);
    // Start an alarm
    timerAlarmEnable(timer);

    delay(10);
    app_main();
}

void loop()
{

}

2 使用FreeRTOS计数信号量

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

#include <Arduino.h>
#define USE_MULTCORE 0
hw_timer_t * timer = NULL;

SemaphoreHandle_t semaphoreHandle;

bool state = 0;

void carInTask(void *pvParam) {
	int emptySpace = 0;
	BaseType_t iResult;
	while (1) {
		emptySpace = uxSemaphoreGetCount(semaphoreHandle);
		USBSerial.printf("emptySpace = %d\n", emptySpace);
		iResult = xSemaphoreTake(semaphoreHandle,0);
		if (iResult == pdPASS) {
			USBSerial.printf("one car in\n");
		} else {
			USBSerial.printf("No space\n");
		}
		vTaskDelay(pdMS_TO_TICKS(1000));
	}
}

void carOutTask(void *pvParam) {
	while (1) {
		vTaskDelay(pdMS_TO_TICKS(6000));
		xSemaphoreGive(semaphoreHandle);
		USBSerial.printf("one car out\n");
	}
}


void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;
  bool ON = true;
  pinMode(48, OUTPUT);
  for (;;) // A Task shall never return or exit.
  {
    if (state == true)
    {
        digitalWrite(48, LOW);
    }
    else
    {
        digitalWrite(48, HIGH);

    }
    state = !state;

    vTaskDelay(pdMS_TO_TICKS(6000));
  }
}

 //测试用的主函数
 void app_main(void)
 {
    int i;

    // 创建了一个计数型信号量,最大计数值为5,初始值计数值为5
    semaphoreHandle = xSemaphoreCreateCounting(5, 5);
	
    if (semaphoreHandle == NULL)
    {
        USBSerial.println("xSemaphoreCreateCounting Failed!!!\r\n");
    }

    // Now set up two tasks to run independently.
    /**
        pvTaskCode: 指向任务输入函数的指针。 任务必须实现永不返回(即连续循环),或者应该使用vTaskDelete函数终止。
        pcName 任务的描述性名称。 这主要是为了方便调试。 最大长度由configMAX_TASK_NAME_LEN定义 - 默认是16。
        usStackDepth: 任务栈的大小,以字节数表示。字节数。注意,这与vanilla FreeRTOS不同。
        pvParameters: 指针将被用作任务的参数。正在创建。
        uxPriority: 任务运行的优先级。 系统包括MPU支持的系统可以选择在特权(系统)下创建任务。通过设置优先级参数的位portPRIVILEGE_BIT来创建任务。 例如例如,要创建一个优先级为2的特权任务,uxPriority参数应该被设置为 ( 2 | portPRIVILEGE_BIT )。
        pvCreatedTask: 用于传回一个句柄,创建的任务可以通过它来引用。可以被引用。
        xCoreID: 如果该值为tskNO_AFFINITY,则创建的任务不被钉在任何CPU上。钉在任何CPU上,调度器可以在任何可用的核心上运行它。值为0或1时,表示该任务应该被钉在CPU上的索引号。被钉住。指定大于(portNUM_PROCESSORS - 1)的值将导致函数失败。导致该函数失败。
                  如果任务被成功创建并添加到准备好的列表中,返回pdPASS。列表中,否则会有一个错误代码,该代码在文件projdefs.h中定义。
    */
    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); 


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

	//xTaskCreate(carOutTask, "carOutTask", 1024 * 5, NULL, 1, NULL);
    USBSerial.println("Tasks launched ...");
 }

// this function gets called by the interrupt at <sampleRate>Hertz
void TC4_Handler(void)
{
    BaseType_t err;
    err = xSemaphoreGive(semaphoreHandle);
	USBSerial.printf("one car out sucess\n");
    if (err != pdTRUE)//判断信号量是否发送成功
    {
        USBSerial.printf("one car out Fail !\r\n");
    }
}

void ARDUINO_ISR_ATTR onTimer(){

  TC4_Handler();
}


void setup()
{
    USBSerial.begin(115200);
    // Use 1st timer of 4 (counted from zero).
    // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
    // info).
    timer = timerBegin(0, 80, true);
    // Attach onTimer function to our timer.
    timerAttachInterrupt(timer, &onTimer, true);
    // Set alarm to call onTimer function every second (value in microseconds).
    // Repeat the alarm (third parameter)
    timerAlarmWrite(timer, 5000000, true);
    // Start an alarm
    timerAlarmEnable(timer);

    delay(10);
    app_main();
}

void loop()
{

}

3 使用FreeRTOS互斥量

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

#include <Arduino.h>
#define USE_MULTCORE 0
hw_timer_t * timer = NULL;

#define LOW_TASK_PRIO  2
#define LOW_STACK_SIZE 4096
TaskHandle_t LowTask_Handler;
void low_task(void *pvParameters);

#define MIDDLE_TASK_PRIO  3
#define MIDDLE_STACK_SIZE 2048
TaskHandle_t MiddleTask_Handler;
void middle_task(void *pvParameters);

#define HIGH_TASK_PRIO  4
#define HIGH_STACK_SIZE 2048
TaskHandle_t HighTask_Handler;
void high_task(void *pvParameters);

SemaphoreHandle_t mutex_Handler;

bool state = 0;

void  low_task(void* pvParameters)
{
	long i;
	while(1)
	{
		USBSerial.printf("low task running\r\n");
		xSemaphoreTake(mutex_Handler,portMAX_DELAY);
		for (i=0; i<22222222; i++);
		xSemaphoreGive(mutex_Handler);
		USBSerial.printf("low task give semaphore\r\n");
		vTaskDelay(1000);
	}
}

void  middle_task(void* pvParameters)
{
	while(1)
	{
		USBSerial.printf("middle task running\r\n");
		vTaskDelay(1000);
	}
}

void  high_task(void* pvParameters)
{
	while(1)
	{
		USBSerial.printf("high task ask the semaphore\r\n");
		xSemaphoreTake(mutex_Handler,portMAX_DELAY);
		USBSerial.printf("high task running\r\n");
		xSemaphoreGive(mutex_Handler);
		vTaskDelay(1000);
	}
}


void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;
  bool ON = true;
  pinMode(48, OUTPUT);
  for (;;) // A Task shall never return or exit.
  {
    if (state == true)
    {
        digitalWrite(48, LOW);
    }
    else
    {
        digitalWrite(48, HIGH);

    }
    state = !state;

    vTaskDelay(pdMS_TO_TICKS(6000));
  }
}

 //测试用的主函数
 void app_main(void)
 {
    int i;

    // 创建了一个计数型信号量,最大计数值为5,初始值计数值为5
    mutex_Handler = xSemaphoreCreateMutex();
	//mutex_Handler = xSemaphoreCreateBinary();
    if (mutex_Handler == NULL)
    {
        USBSerial.println("xSemaphoreCreateCounting Failed!!!\r\n");
    }

    xSemaphoreGive(mutex_Handler);
    // Now set up two tasks to run independently.
    /**
        pvTaskCode: 指向任务输入函数的指针。 任务必须实现永不返回(即连续循环),或者应该使用vTaskDelete函数终止。
        pcName 任务的描述性名称。 这主要是为了方便调试。 最大长度由configMAX_TASK_NAME_LEN定义 - 默认是16。
        usStackDepth: 任务栈的大小,以字节数表示。字节数。注意,这与vanilla FreeRTOS不同。
        pvParameters: 指针将被用作任务的参数。正在创建。
        uxPriority: 任务运行的优先级。 系统包括MPU支持的系统可以选择在特权(系统)下创建任务。通过设置优先级参数的位portPRIVILEGE_BIT来创建任务。 例如例如,要创建一个优先级为2的特权任务,uxPriority参数应该被设置为 ( 2 | portPRIVILEGE_BIT )。
        pvCreatedTask: 用于传回一个句柄,创建的任务可以通过它来引用。可以被引用。
        xCoreID: 如果该值为tskNO_AFFINITY,则创建的任务不被钉在任何CPU上。钉在任何CPU上,调度器可以在任何可用的核心上运行它。值为0或1时,表示该任务应该被钉在CPU上的索引号。被钉住。指定大于(portNUM_PROCESSORS - 1)的值将导致函数失败。导致该函数失败。
                  如果任务被成功创建并添加到准备好的列表中,返回pdPASS。列表中,否则会有一个错误代码,该代码在文件projdefs.h中定义。
    */
    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 beinWg the lowest.
        ,  NULL 
        ,  ARDUINO_RUNNING_CORE); 


    xTaskCreate((TaskFunction_t )high_task,            //任务函数
                    (const char*    )"high_task",          //任务名称
                    (uint16_t       )HIGH_STACK_SIZE,        //任务堆栈大小
                    (void*          )NULL,                  //传递给任务函数的参数
                    (UBaseType_t    )HIGH_TASK_PRIO,       //任务优先级
                    (TaskHandle_t*  )&HighTask_Handler);   //任务句柄 
        
    xTaskCreate((TaskFunction_t )middle_task,            //任务函数
                    (const char*    )"middle_task",          //任务名称
                    (uint16_t       )MIDDLE_STACK_SIZE,        //任务堆栈大小
                    (void*          )NULL,                  //传递给任务函数的参数
                    (UBaseType_t    )MIDDLE_TASK_PRIO,       //任务优先级
                    (TaskHandle_t*  )&MiddleTask_Handler);   //任务句柄  
                                    
    xTaskCreate((TaskFunction_t )low_task,            //任务函数
                    (const char*    )"low_task",          //任务名称
                    (uint16_t       )LOW_STACK_SIZE,        //任务堆栈大小
                    (void*          )NULL,                  //传递给任务函数的参数
                    (UBaseType_t    )LOW_TASK_PRIO,       //任务优先级
                    (TaskHandle_t*  )&LowTask_Handler);   //任务句柄    	

    USBSerial.println("Tasks launched ...");
 }

// this function gets called by the interrupt at <sampleRate>Hertz
void TC4_Handler(void)
{
	//USBSerial.printf("TC4_Handler\n");
}

void ARDUINO_ISR_ATTR onTimer(){

   TC4_Handler();
}


void setup()
{
    USBSerial.begin(115200);
    // Use 1st timer of 4 (counted from zero).
    // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
    // info).
    timer = timerBegin(0, 80, true);
    // Attach onTimer function to our timer.
    timerAttachInterrupt(timer, &onTimer, true);
    // Set alarm to call onTimer function every second (value in microseconds).
    // Repeat the alarm (third parameter)
    timerAlarmWrite(timer, 5000000, true);
    // Start an alarm
    timerAlarmEnable(timer);

    delay(10);
    app_main();
}

void loop()
{

}