FreeRTOS内核应用开发手记

时间:2022-07-23
本文章向大家介绍FreeRTOS内核应用开发手记,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

FreeRTOS内核应用开发学习手记移植任务状态迁移任务创建与删除任务挂起与恢复任务延时消息队列信号量事件软件定时器任务通知内存管理

FreeRTOS内核应用开发学习手记

移植

1、解压并添加官方源码到工程中,包括:

 FreeRTOSSource*.c
 FreeRTOSSourceinclude*.h
 FreeRTOSSourceportableMemMangheap_4.c
 FreeRTOSSourceportableRVDSARM_CM4F*
 FreeRTOSDemoCORTEX_STM32F103_KeilFreeRTOSConfig.h

2、修改FreeRTOSConfig.h:

 #include "stm32f103.h"
 改为你的,如
 #include "stm32f4xx.h"

3、注释原工程中:

 void SVC_Handler(void) {}
 void PendSV_Handler(void) {}

4、修改SysTick中断服务函数

 extern void xPortSysTickHandler(void);
 //systick中断服务函数
 void SysTick_Handler(void)
 {
     TimingDelay_Decrement();
     #if (INCLUDE_xTaskGetSchedulerState  == 1 )
       if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
       {
     #endif  /* INCLUDE_xTaskGetSchedulerState */  
         xPortSysTickHandler();
     #if (INCLUDE_xTaskGetSchedulerState  == 1 )
       }
     #endif  /* INCLUDE_xTaskGetSchedulerState */
 }

5、完成

任务状态迁移

任务创建与删除

 BaseType_t xReturn = pdPASS;                       // 返回值
 TaskHandle_t testHandle = NULL;                    // 任务句柄
 xReturn = xTaskCreate((TaskFunction_t) TaskTest,   // 任务入口函数
                       (const char*) "TaskTest"),   // 任务名字
                       (uint16_t) 512,              // 任务栈大小
                       (void*) NULL,                // 任务入口函数参数
                       (UBaseType_t)3,              // 任务优先级
                       (TaskHandle_t*)&testHandle); // 控制块指针
 if(xReturn == pdPASS){
   vTaskStartScheduler();                           // 启动任务调度
 }
 vTaskDelete(testHandle);                           // 删除指定任务
 vTaskDelete(NULL);                                 // 删除任务自身

任务挂起与恢复

 // 挂起任务
 vTaskSuspend(taskHandle);
 // 挂起全部任务
 vTaskSuspendAll();
 // 恢复任务
 vTaskResume(taskHandle);
 // 恢复全部任务
 vTaskResumeAll();
 // 从中断恢复任务
 BaseType_t xYieldRequired = xTaskResumeFromISR(taskHandle);
 if(xYieldRequired == pdTRUE){
   portYIELD_FROM_ISR(); // 执行上下文切换
 }

任务延时

 /***********************相对延时**************************/
 // 相对延时,延时100个tick,不排除调用前后任务被抢占
 vTaskDelay(100);
 /* ...code... */
 /***********************绝对延时*************************/
 // 绝对延时,固定频率运行
 static portTickType previousWakeTime;   // 保存上一次时间,系统自动更新
 const portTickType timeIncrement = pdMS_TO_TICKS(100); // 延时时间
 previousWakeTime = xTaskGetTickCount(); // 当前系统时间
 while(1){
   vTaskDelayUntil(&previousWakeTime, timeIncrement); // 间隔100个tick
   /* ...code... */
 }

消息队列

 configSUPPORT_DYNAMIC_ALLOCATION = 1
 /************************创建队列***********************/
 #define QUEUE_LEN  4                        // 队列长度,最大消息数
 #define QUEUE_SIZE 4                        // 每个消息的大小(字节)
 BaseType_t xReturn = pdPASS;                // 返回值
 QueueHandle_t queueHandle = NULL;           // 队列句柄
 taskENTER_CRITICAL();                       // 进入临界区
 queueHandle = xQueueCreate((UBaseType_t) QUEUE_LEN,   // 长度
                            (UBaseType_t) QUEUE_SIZE); // 大小
 if(NULL != queueHandle){
   printf("创建成功rn");                    // 创建成功
 }
 taskEXIT_CRITICAL();                        // 退出临界区
 /*********************任务中发到队尾***********************/
 vQueueDelete(queueHandle);                  // 删除队列
 uint32_t sendData = 1;                      // 待发送内容
 xReturn = xQueueSend(queueHandle,           // 队列句柄
                      &sendData,             // 发送内容
                      0);                    // 等待时间
 if(pdPASS == xReturn){                      // 发送成功
   printf("发送成功rn"); 
 }
 /*********************中断中发到队尾**********************/
 BaseType_t xHigherPriorityTaskWoken = pdFALSE; // 从中断发送队列消息
 xQueueSendFromISR(queueHandle,&sendData,&xHigherPriorityTaskWoken);
 if(xHigherPriorityTaskWoken){
   taskYIELD_FROM_ISR();                     // 上下文切换
 }
 /**********************其他发到队首***********************/
 xQueueSendToFront(...);                     // 发到队首
 xQueueSendToFrontFromISR(...);              // 中断中发到队首
 /*********************任务中接收消息**********************/
 uint32_t getData;                           // 待接收内容
 xReturn = xQueueRecevie(queueHandle,        // 队列句柄(会删除队列消息)
                         &getData,           // 接收内容
                         portMAX_DELAY);     // 等待时间,一直等
 if(pdTRUE == xReturn){                      // 获取成功
   print("接收到:%drn", getData);
 }
 xQueuePeek(...)       // 获取队列消息,但不删除队列中的内容,用法一样
 /********************中断中接收消息**********************/
 BaseType_t xTaskWokenByReceive = pdFALSE;
 xQueueReceiveFromISR(queueHandle, &getData, xTaskWokenByReceive);
 if(xTaskWokenByReceive != pdFALSE){
   taskYIELD();                              // 上下文切换
 }

信号量

 信号量可以由其他任务删除,互斥量只能由当前任务删除。
 互斥量可减小“优先级翻转”现象的影响。
 configUSE_MUTEXES = 1
 configUSE_RECURSIVE_MUTEXES = 1
 configQUEUE_REGISTRY_SIZE = 10
 /********************二值信号量**********************/
 SemaphoreHandle_t semaphoreHandle = NULL;       // 信号量句柄
 semaphoreHandle = xSemaphoreCreateBinary();     // 创建二值信号量
 if(semaphoreHandle != NULL){                    // 创建成功
   print("创建成功rn");
 }
 /********************计数信号量**********************/
 semaphoreHandle = xSemaphoreCreateCounting(5,   // 最大技术到5
                                            5);  // 初始当前计数值为5
 if(semaphoreHandle != NULL){                    // 创建成功
   print("创建成功rn");
 }
 /********************互斥信号量**********************/
 semaphoreHandle = xSemaphoreCreateMutex();      // 创建单次互斥量
 if(semaphoreHandle != NULL){                    // 创建成功
   print("创建成功rn");
 }
 semaphoreHandle = xSemaphoreCreateRecursiveMutex(); // 创建递归互斥量
 if(semaphoreHandle != NULL){                        // 创建成功
   print("创建成功rn");
 }
 /********************删除信号量**********************/
 vSemaphoreDelete(semaphoreHandle);
 /******************任务中释放信号量*******************/
 xReturn = xSemaphoreGive(semaphoreHandle);  
 if(pdTRUE == xReturn){
   print("释放成功rn");
 }
 xSemaphoreGiveRecursive(...);   // 释放递归互斥量,其他一样
 /******************中断中释放信号量*******************/
 BaseType_t pxHigherPriorityTaskWoken;
 xSemaphoreGiveFromISR(semaphoreHandle, &pxHigherPriorityTaskWoken);
 portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);  // 上下文切换
 /*****************任务中获取信号量********************/
 xReturn = xSemaphoreTake(semaphoreHandle,       // 信号量句柄
                         portMAX_DELAY)          // 等待时间,一直等
 if(pdTRUE == xReturn){
   print("获取成功rn");
 }
 xSemaphoreTakeRecursive(...);   // 获取递归互斥量,其他一样
 /*****************中断中获取信号量********************/
 很少用到

事件

 configUSE_16_BIT_TICKS = 0
 /*****************任务中创建事件*********************/
 EventGroupHandle_t eventHandle = NULL;          // 事件句柄
 eventHandle = xEventGroupCreate();              // 创建事件
 if(NULL != eventHandle){                        // 创建成功
   print("创建成功rn");
 }
 xEventGroupDelete(eventHandle);                 // 删除事件
 #define BIT0 (0x01 << 0) //
 #define BIT1 (0x01 << 1) //
 /*****************任务中设置事件********************/
 EventBits_t rReturn;                       // 返回值,返回的置位前的值
 rReturn = xEventGroupSetBits(eventHandle,  // 事件句柄
                              BIT0 | BIT1); // 置位事件组
 /*****************中断中设置事件********************/
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 BaseType_t xResult;
 xResult = xEventGroupSetBitsFromISR(eventHandle,
                                     BIT0 | BIT1,
                                     &xHigherPriorityTaskWoken);
 if(pdFAIL != xResult){
   portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
 }
 /*****************任务中等待事件********************/
 EventBits_t rReturn;
 rReturn = xEventGroupWaitBits(eventHandle,    // 事件句柄
                               BIT0|BIT1,      // 事件组
                               pdTRUE,         // 退出时清除事件
                               pdTRUE,         // 等待所有事件
                               portMAX_DELAY)  // 超时等待时间
 if((rReturn&(BIT0|BIT1)) == (BIT0|BIT1)){     // 两个事件都到达
   print("BIT0和BIT1都到达rn");
 }
 /*****************任务中清除事件********************/
 EventBits_t uxBits;                       // 返回值,返回的清除前的值
 uxBits = xEventGroupClearBits(eventHandle, BITO|BIT1);

软件定时器

 configUSE_TIMERS = 1
 configTIMER_TASK_PRIORITY = (configMAX_PRIORITIES-1)
 configTIMER_QUEUE_LENGTH = 10
 /*****************任务中创建定时器********************/
 TimerHandle_t swtmrHandle = NULL;                    // 定时器句柄
 BaseType_t xReturn;
 void SwtFun(void* parameter){}                       // 自定义回调函数
 swtmrHandle = xTimerCreate((const char*)"time1",     // 定时器名字
                           (TickType_t)1000,          // 周期1000tick
                           (UBaseType_t)pdTRUE,       // 循环模式
                           (void*)1,                  // 唯一ID
                           (TimerCallbackFunction_t)SwtFun);//回调函数
 /*****************任务中启动定时器********************/
 if(NULL != swtmrHandle){                    // 创建成功
   xTimerStart(swtmrHandle,                  // 启动定时器
               0);                           // 等待时间0
 }
 xReturn = vTimerStop(swtmrHandle, 0);       // 停止软件定时器
 xReturn = xTimerDelete(swtmrHandle, 0);     // 删除软件定时器
 /*****************中断中启动定时器********************/
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 xReturn = xTimerStartFromISR(swtmrHandle,&xHigherPriorityTaskWoken);
 if(pdPASS == xReturn){
   print("启动成功rn");
 }
 if(xHigherPriorityTaskWoken){
   // 上下文切换
 }
 xReturn = vTimerStopFromISR(swtmrHandle, &xHigherPriorityTaskWoken);
 if(pdPASS == xReturn){
   print("停止成功rn");
 }
 if(xHigherPriorityTaskWoken){
   // 上下文切换
 }

任务通知

 configUSE_TASK_NOTIFICATIONS = 1
 // 发送通知部分
 /*****************xTaskNotifyGive()********************/
 TaskHandle_t taskHandle;
 xTaskNotifyGive(taskHandle);              // 向taskHandle发送通知
 ulTaskNotifyTake(pdTRUE,                  // 退出时清空任务计数
                  portMAX_DELAY);          // 阻塞等待通知
 /*************vTaskNotifyGiveFromISR()*****************/
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 vTaskNotifyGiveFromISR(taskHandle, &xHigherPriorityTaskWoken);
 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 上下文切换
 /******************xTaskNotify()***********************/
 xTaskNotify(taskHandle, 0, eNoAction);
 “eAction取值:eNoAction、eSetBits、eIncrement、eSetValueWithOverwrite、eSetValueWithoutOverwrite”
 /***************xTaskNotifyFromISR()*******************/
 xTaskNotifyFromISR(taskHandle, 0, eNoAction, &xHigherPriTaskWoken);
 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 上下文切换
 /***************xTaskNotifyAndQuery()******************/
 uint32_t ulPreviousValue; // 存对象任务的上一个任务通知值,为NULL则不用回传
 xTaskNotifyAndQuery(taskHandle, 0, eSetBits, &ulPreviousValue)
 /************xTaskNotifyAndQueryFromISR()**************/
 xTaskNotifyAndQueryFromISR(taskHandle,
                            0,
                            eSetBits,
                            &ulPreviousValue,
                            &xHigherPriorityTaskWoken);
 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 上下文切换
 
 // 获取通知部分
 /****************ulTaskNotifyTake()*******************/
 uint32_t res;  // 返回任务的当前通知值(减1或清0之前的值)
 res = ulTaskNotifyTake(pdTRUE,         // 退出时清零(pdFALSE则减一)
                        portMAX_DELAY); // 等待时间
 /****************xTaskNotifyWait()********************/
 uint32_t ulNotifiedValue;   // 存接收到的任务通知值,为NULL则不需要
 BaseType_t res;
 res = xTaskNotifyWait(0x00,    // 使用通知前,任务通知值的哪些位清0
                 ULONG_MAX,     // 结束本函数前,接收到的通知值的哪些位清0
                 &ulNotifiedValue, // 保存接收到的任务通知值
                 portMAX_DELAY);   // 等待时间
 if((ulNotifiedValue & 0x01) != 0){
   /* 位0被置1 */
 }

内存管理

 /****************heap_4.c*******************/
 //系统所有总的堆大小
 #define configTOTAL_HEAP_SIZE         ((size_t)(36*1024))    
 uint32_t g_memsize = xPortGetFreeHeapSize();  // 获取剩余内存
 uint8_t* ptr = pvPortMalloc(1024);            // 申请1024字节内存
 if(NULL != ptr) {                             // 获取成功
   printf("rn");
 }
 vPortFree(ptr);                               // 释放内存