文章目录
- 前言
- 一、任务调度
- 二、Freertos任务与中断
- 三、消息队列
- 四、二值信号量
- 五、互斥量
- 六、事件组
- 七、任务通知
- 八、流缓冲区 ==(待填)==
- 九、消息缓冲区 ==(待填)==
- 十、软件定时器
- 十一、空闲任务与低功耗 ==(待填)==
- 总结
前言
cubemx_freertos
一、任务调度
文件
1.1 延时
1.1.1 相对延时
vTaskDelay(ticks1);
void appTask_led1(void *argument)
{
/* USER CODE BEGIN appTask_led1 */
TickType_t ticks1=pdMS_TO_TICKS(1000);
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
vTaskDelay(ticks1);
}
/* USER CODE END appTask_led1 */
}
osDelay();
void appTask_led1(void *argument)
{
/* USER CODE BEGIN appTask_led1 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
osDelay(1000);
}
/* USER CODE END appTask_led1 */
}
1.1.2 绝对延时
vTaskDelayUntil(&wake_time,ticks2);
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
TickType_t ticks2=pdMS_TO_TICKS(2000);
TickType_t wake_time=xTaskGetTickCount();
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
vTaskDelayUntil(&wake_time,ticks2);
}
/* USER CODE END appTask_led2 */
}
1.2 挂起和恢复
1.2.1 cmsis的挂起和恢复函数
osThreadSuspend
osThreadResume
void appTask_key1(void *argument)
{
/* USER CODE BEGIN appTask_key1 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(key0_GPIO_Port,key0_Pin)==GPIO_PIN_RESET)
{
osThreadSuspend(Task_led1Handle);
}
osDelay(20);
}
/* USER CODE END appTask_key1 */
}
void appTask_key2(void *argument)
{
/* USER CODE BEGIN appTask_key2 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(key1_GPIO_Port,key1_Pin)==GPIO_PIN_RESET)
{
osThreadResume(Task_led1Handle);
}
osDelay(20);
}
/* USER CODE END appTask_key2 */
}
1.2.2 freertos的挂起和恢复函数
vTaskSuspend
vTaskResume
void appTask_key1(void *argument)
{
/* USER CODE BEGIN appTask_key1 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(key0_GPIO_Port,key0_Pin)==GPIO_PIN_RESET)
{
vTaskSuspend((TaskHandle_t)Task_led1Handle);
}
osDelay(20);
}
/* USER CODE END appTask_key1 */
}
void appTask_key2(void *argument)
{
/* USER CODE BEGIN appTask_key2 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(key1_GPIO_Port,key1_Pin)==GPIO_PIN_RESET)
{
vTaskResume((TaskHandle_t)Task_led1Handle);
}
osDelay(20);
}
/* USER CODE END appTask_key2 */
}
1.3 删除
1.3.1 cmsis的删除任务函数
osThreadTerminate
void appTask_key1(void *argument)
{
/* USER CODE BEGIN appTask_key1 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(key0_GPIO_Port,key0_Pin)==GPIO_PIN_RESET)
{
osThreadTerminate(Task_led1Handle);
}
osDelay(20);
}
/* USER CODE END appTask_key1 */
}
1.3.2 freertos的删除任务函数
直接使用vTaskDelete
会导致程序卡死,进入HardFault_Handler函数
二、Freertos任务与中断
三、消息队列
文件
3.1 写入和读取一个数据
osMessageQueuePut 将一个新的项目发送到队列的末尾
osMessageQueueGet 从队列的前面读取一个(读取以后会自动删除那个)
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
uint32_t data = 0;
/* Infinite loop */
for(;;)
{
data++;
osMessageQueuePut(myQueue01Handle,&data,0,0);
osDelay(1000);
}
/* USER CODE END appTask_led2 */
}
void appTask_key1(void *argument)
{
/* USER CODE BEGIN appTask_key1 */
uint32_t receivedData = 0;
/* Infinite loop */
for(;;)
{
osMessageQueueGet(myQueue01Handle, &receivedData, 0, osWaitForever);
/* 处理数据,这里我们只是简单地打印出来 */
printf("Received data: %d\n", receivedData);
}
/* USER CODE END appTask_key1 */
}
3.2 写入和读取一个段数据 (指针) (分配内存法)
osMessageQueuePut
osMessageQueueGet
pvPortMalloc
vPortFree
#define ARRAY_SIZE 20
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
/* Infinite loop */
for(;;)
{
uint32_t* array = (uint32_t*)pvPortMalloc(ARRAY_SIZE * sizeof(uint32_t));
for (int i = 0; i < ARRAY_SIZE; i++)
{
array[i] = i;
}
osMessageQueuePut(myQueue01Handle, &array, 0, 0);
osDelay(1000);
}
/* USER CODE END appTask_led2 */
}
void appTask_key1(void *argument)
{
/* USER CODE BEGIN appTask_key1 */
/* Infinite loop */
for(;;)
{
uint32_t* receivedArray;
osMessageQueueGet(myQueue01Handle, &receivedArray, 0, osWaitForever);
// Process the array
for (int i = 0; i < ARRAY_SIZE; i++) {
printf("Received: %d\n", receivedArray[i]);
HAL_Delay(10);
}
vPortFree(receivedArray);
}
/* USER CODE END appTask_key1 */
}
四、二值信号量
文件
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
/* Infinite loop */
for(;;)
{
osSemaphoreAcquire(Bin_key0_readyHandle,osWaitForever);
printf("hello world\n");
}
/* USER CODE END appTask_led2 */
}
void appTask_key1(void *argument)
{
/* USER CODE BEGIN appTask_key1 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(key0_GPIO_Port,key0_Pin)==GPIO_PIN_RESET)
{
osSemaphoreRelease(Bin_key0_readyHandle);
}
}
/* USER CODE END appTask_key1 */
}
但是
有效方案是:
在使用那个二值信号量的任务主循环之前先调用一次, osSemaphoreAcquire(Bin_key0_readyHandle,0);
要注意位置!!
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
/* Infinite loop */
osSemaphoreAcquire(Bin_key0_readyHandle,0);
for(;;)
{
osSemaphoreAcquire(Bin_key0_readyHandle,osWaitForever);
printf("hello world\n");
}
/* USER CODE END appTask_led2 */
}
五、互斥量
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
/* Infinite loop */
for(;;)
{
osMutexAcquire(usart_MutexHandle, osWaitForever);
// Use the UART here...
printf("hello world user cc\n");
osMutexRelease(usart_MutexHandle);
osDelay(20);
}
/* USER CODE END appTask_led2 */
}
void appTask_key1(void *argument)
{
/* USER CODE BEGIN appTask_key1 */
/* Infinite loop */
for(;;)
{
osMutexAcquire(usart_MutexHandle, osWaitForever);
printf("hello\n");
osMutexRelease(usart_MutexHandle);
osDelay(5);
}
/* USER CODE END appTask_key1 */
}
六、事件组
文件
6.1 设置位
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance == USART1)
{
memcpy(MainBuf_1, RxBuf_1, Size); //将接收缓冲区的数据复制到主缓冲区
/* 再次启动 DMA */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *) RxBuf_1, RxBuf_SIZE_1);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
if(MainBuf_1[0]==1)
{
osEventFlagsSet(myEvent01Handle,EVENT_0_BIT);
}
if(MainBuf_1[0]==2)
{
osEventFlagsSet(myEvent01Handle,EVENT_1_BIT);
}
}
}
6.2 等待位
当两个标志位都被置为的时候才能进行任务。
flags 得到的值是EVENT_0_BIT和EVENT_1_BIT
相与的值。
所以
#define EVENT_0_BIT (1 << 0) // Event bit 0, which corresponds to event 1
#define EVENT_1_BIT (1 << 1) // Event bit 1, which corresponds to event 2
其他的就应该 (1<<?)
for(;;)
{
uint32_t flags = osEventFlagsWait(myEvent01Handle,EVENT_0_BIT|EVENT_1_BIT,osFlagsWaitAll,osWaitForever);
if (flags & EVENT_0_BIT)
{
// Event 1 has occurred
printf("over 1\n");
}
if (flags & EVENT_1_BIT) {
// Event 2 has occurred
printf("over 2\n");
}
printf("over 5\n");
}
七、任务通知
7.1 CMSIS-RTOS API 线程标志
无需配置cubemx
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#define Thread_0_BIT (1 << 0) // Event bit 0, which corresponds to event 1
#define Thread_1_BIT (1 << 1) // Event bit 1, which corresponds to event 2
extern osThreadId_t Task_led2Handle;
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance == USART1)
{
memcpy(MainBuf_1, RxBuf_1, Size); //将接收缓冲区的数据复制到主缓冲区
/* 再次启动 DMA */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *) RxBuf_1, RxBuf_SIZE_1);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
if(MainBuf_1[0]==1)
{
osThreadFlagsSet(Task_led2Handle,Thread_0_BIT);
//xTaskNotifyFromISR()
}
if(MainBuf_1[0]==2)
{
osThreadFlagsSet(Task_led2Handle,Thread_1_BIT);
}
}
}
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
/* Infinite loop */
#define Thread_0_BIT (1 << 0) // Event bit 0, which corresponds to event 1
#define Thread_1_BIT (1 << 1) // Event bit 1, which corresponds to event 2
for(;;)
{
uint32_t flags = osThreadFlagsWait(Thread_0_BIT|Thread_1_BIT,osFlagsWaitAny,osWaitForever);
if (flags & Thread_0_BIT)
{
// Event 1 has occurred
printf("over 1\n");
}
if (flags & Thread_1_BIT) {
// Event 2 has occurred
printf("over 2\n");
}
printf("over 5\n");
}
/* USER CODE END appTask_led2 */
}
任务通知(线程标志)和事件组在功能上确实有很多相似之处,都可以用于通知线程某种状态的发生。然而,它们之间还是有一些关键的区别:
7.2 Free-RTOS API 任务通知 (待填)
八、流缓冲区 (待填)
九、消息缓冲区 (待填)
十、软件定时器
10.1 任务中开启定时器
10.1.1 周期定时器
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#define Thread_0_BIT (1 << 0) // Event bit 0, which corresponds to event 1
#define Thread_1_BIT (1 << 1) // Event bit 1, which corresponds to event 2
extern osThreadId_t Task_led2Handle;
extern osTimerId_t myTimer01Handle;
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance == USART1)
{
memcpy(MainBuf_1, RxBuf_1, Size); //将接收缓冲区的数据复制到主缓冲区
/* 再次启动 DMA */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *) RxBuf_1, RxBuf_SIZE_1);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
if(MainBuf_1[0]==1)
{
osThreadFlagsSet(Task_led2Handle,Thread_0_BIT);
}
if(MainBuf_1[0]==2)
{
osThreadFlagsSet(Task_led2Handle,Thread_1_BIT);
}
}
}
void appTask_led2(void *argument)
{
/* USER CODE BEGIN appTask_led2 */
/* Infinite loop */
#define Thread_0_BIT (1 << 0) // Event bit 0, which corresponds to event 1
#define Thread_1_BIT (1 << 1) // Event bit 1, which corresponds to event 2
for(;;)
{
uint32_t flags = osThreadFlagsWait(Thread_0_BIT,osFlagsWaitAny,osWaitForever);
osTimerStart(myTimer01Handle,1000);
}
/* USER CODE END appTask_led2 */
}
void Callback01(void *argument)
{
/* USER CODE BEGIN Callback01 */
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
/* USER CODE END Callback01 */
}