美文网首页
FreeRTOS内核应用开发手记

FreeRTOS内核应用开发手记

作者: 小锋学长 | 来源:发表于2020-07-04 09:32 被阅读0次

FreeRTOS内核应用开发学习手记

移植

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

 FreeRTOS\Source\*.c
 FreeRTOS\Source\include\*.h
 FreeRTOS\Source\portable\MemMang\heap_4.c
 FreeRTOS\Source\portable\RVDS\ARM_CM4F\*
 FreeRTOS\Demo\CORTEX_STM32F103_Keil\FreeRTOSConfig.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("创建成功\r\n"); // 创建成功
 }
 taskEXIT_CRITICAL(); // 退出临界区
 /*********************任务中发到队尾***********************/
 vQueueDelete(queueHandle); // 删除队列
 uint32_t sendData = 1; // 待发送内容
 xReturn = xQueueSend(queueHandle, // 队列句柄
                      &sendData, // 发送内容
                      0); // 等待时间
 if(pdPASS == xReturn){ // 发送成功
   printf("发送成功\r\n");
 }
 /*********************中断中发到队尾**********************/
 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("接收到:%d\r\n", 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("创建成功\r\n");
 }
 /********************计数信号量**********************/
 semaphoreHandle = xSemaphoreCreateCounting(5,   // 最大技术到5
                                            5);  // 初始当前计数值为5
 if(semaphoreHandle != NULL){ // 创建成功
   print("创建成功\r\n");
 }
 /********************互斥信号量**********************/
 semaphoreHandle = xSemaphoreCreateMutex(); // 创建单次互斥量
 if(semaphoreHandle != NULL){ // 创建成功
   print("创建成功\r\n");
 }
 semaphoreHandle = xSemaphoreCreateRecursiveMutex(); // 创建递归互斥量
 if(semaphoreHandle != NULL){  // 创建成功
   print("创建成功\r\n");
 }
 /********************删除信号量**********************/
 vSemaphoreDelete(semaphoreHandle);
 /******************任务中释放信号量*******************/
 xReturn = xSemaphoreGive(semaphoreHandle);  
 if(pdTRUE == xReturn){
   print("释放成功\r\n");
 }
 xSemaphoreGiveRecursive(...);   // 释放递归互斥量,其他一样
 /******************中断中释放信号量*******************/
 BaseType_t pxHigherPriorityTaskWoken;
 xSemaphoreGiveFromISR(semaphoreHandle, &pxHigherPriorityTaskWoken);
 portYIELD_FROM_ISR(pxHigherPriorityTaskWoken); // 上下文切换
 /*****************任务中获取信号量********************/
 xReturn = xSemaphoreTake(semaphoreHandle, // 信号量句柄
                         portMAX_DELAY) // 等待时间,一直等
 if(pdTRUE == xReturn){
   print("获取成功\r\n");
 }
 xSemaphoreTakeRecursive(...);   // 获取递归互斥量,其他一样
 /*****************中断中获取信号量********************/
 很少用到
 
   
   

事件

 configUSE_16_BIT_TICKS = 0
 /*****************任务中创建事件*********************/
 EventGroupHandle_t eventHandle = NULL; // 事件句柄
 eventHandle = xEventGroupCreate(); // 创建事件
 if(NULL != eventHandle){ // 创建成功
   print("创建成功\r\n");
 }
 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都到达\r\n");
 }
 /*****************任务中清除事件********************/
 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("启动成功\r\n");
 }
 if(xHigherPriorityTaskWoken){
   // 上下文切换
 }
 xReturn = vTimerStopFromISR(swtmrHandle, &xHigherPriorityTaskWoken);
 if(pdPASS == xReturn){
   print("停止成功\r\n");
 }
 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("\r\n");
 }
 vPortFree(ptr); // 释放内存

相关文章

网友评论

      本文标题:FreeRTOS内核应用开发手记

      本文链接:https://www.haomeiwen.com/subject/whgyqktx.html