19.8.1 模拟优先级翻转实验

模拟优先级翻转实验是在 FreeRTOS 中创建了三个任务与一个二值信号量, 任务分别是高优先级任务,中优先级任务,低优先级任务, 用于模拟产生优先级翻转。 低优先级任务在获取信号量的时候,被中优先级打断,中优先级的任务执行时间较长,因为低优先级还未释放信号量,那么高优先级任务就无法取得信号量继续运行,此时就发生了优先级翻转。

  1. /*
  2. *************************************************************************
  3. * 包含的头文件
  4. *************************************************************************
  5. */
  6. /* FreeRTOS头文件 */
  7. #include "FreeRTOS.h"
  8. #include "task.h"
  9. #include "queue.h"
  10. #include "semphr.h"
  11. /* 开发板硬件bsp头文件 */
  12. #include "bsp_led.h"
  13. #include "bsp_usart.h"
  14. #include "bsp_key.h"
  15. /**************************** 任务句柄 ********************************/
  16. /*
  17. * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
  18. * 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
  19. * 这个句柄可以为NULL。
  20. */
  21. static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */
  22. static TaskHandle_t LowPriority_Task_Handle = NULL;/* LowPriority_Task任务句柄 */
  23. static TaskHandle_t MidPriority_Task_Handle = NULL;/* MidPriority_Task任务句柄 */
  24. static TaskHandle_t HighPriority_Task_Handle = NULL;/* HighPriority_Task任务句柄 */
  25. /********************************** 内核对象句柄 *********************************/
  26. /*
  27. * 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核
  28. * 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我
  29. * 们就可以通过这个句柄操作这些内核对象。
  30. *
  31. * 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,
  32. * 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
  33. * 来完成的
  34. *
  35. */
  36. SemaphoreHandle_t BinarySem_Handle = NULL;
  37. /******************************* 全局变量声明 ************************************/
  38. /*
  39. * 当我们在写应用程序的时候,可能需要用到一些全局变量。
  40. */
  41. /******************************* 宏定义 ************************************/
  42. /*
  43. * 当我们在写应用程序的时候,可能需要用到一些宏定义。
  44. */
  45. /*
  46. *************************************************************************
  47. * 函数声明
  48. *************************************************************************
  49. */
  50. static void AppTaskCreate(void);/* 用于创建任务 */
  51. static void LowPriority_Task(void *pvParameters);/* LowPriority_Task任务实现 */
  52. static void MidPriority_Task(void *pvParameters);/* MidPriority_Task任务实现 */
  53. static void HighPriority_Task(void *pvParameters);/* MidPriority_Task任务实现 */
  54. static void BSP_Init(void);/* 用于初始化板载相关资源 */
  55. /*****************************************************************
  56. * @brief 主函数
  57. * @param 无
  58. * @retval 无
  59. * @note 第一步:开发板硬件初始化
  60. 第二步:创建APP应用任务
  61. 第三步:启动FreeRTOS,开始多任务调度
  62. ****************************************************************/
  63. int main(void)
  64. {
  65. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  66. /* 开发板硬件初始化 */
  67. BSP_Init();
  68. printf("这是一个[野火]-STM32全系列开发板-FreeRTOS优先级翻转实验!\n");
  69. /* 创建AppTaskCreate任务 */
  70. xReturn = xTaskCreate((TaskFunction_t)AppTaskCreate, /* 任务入口函数 */
  71. (const char *)"AppTaskCreate", /* 任务名字 */
  72. (uint16_t)512, /* 任务栈大小 */
  73. (void *)NULL, /* 任务入口函数参数 */
  74. (UBaseType_t)1, /* 任务的优先级 */
  75. (TaskHandle_t *)&AppTaskCreate_Handle); /* 任务控制块指针 */
  76. /* 启动任务调度 */
  77. if (pdPASS == xReturn)
  78. vTaskStartScheduler(); /* 启动任务,开启调度 */
  79. else
  80. return -1;
  81. while (1); /* 正常不会执行到这里 */
  82. }
  83. /***********************************************************************
  84. * @ 函数名 : AppTaskCreate
  85. * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
  86. * @ 参数 : 无
  87. * @ 返回值 : 无
  88. **********************************************************************/
  89. static void AppTaskCreate(void)
  90. {
  91. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  92. taskENTER_CRITICAL(); //进入临界区
  93. /* 创建Test_Queue */
  94. BinarySem_Handle = xSemaphoreCreateBinary();
  95. if (NULL != BinarySem_Handle)
  96. printf("BinarySem_Handle二值信号量创建成功!\r\n");
  97. xReturn = xSemaphoreGive(BinarySem_Handle); //给出二值信号量
  98. // if( xReturn == pdTRUE )
  99. // printf("释放信号量!\r\n");
  100. /* 创建LowPriority_Task任务 */
  101. xReturn = xTaskCreate((TaskFunction_t)LowPriority_Task, /* 任务入口函数 */
  102. (const char *)"LowPriority_Task", /* 任务名字 */
  103. (uint16_t)512, /* 任务栈大小 */
  104. (void *)NULL, /* 任务入口函数参数 */
  105. (UBaseType_t)2, /* 任务的优先级 */
  106. (TaskHandle_t *)&LowPriority_Task_Handle); /* 任务控制块指针 */
  107. if (pdPASS == xReturn)
  108. printf("创建LowPriority_Task任务成功!\r\n");
  109. /* 创建MidPriority_Task任务 */
  110. xReturn = xTaskCreate((TaskFunction_t)MidPriority_Task, /* 任务入口函数 */
  111. (const char *)"MidPriority_Task", /* 任务名字 */
  112. (uint16_t)512, /* 任务栈大小 */
  113. (void *)NULL, /* 任务入口函数参数 */
  114. (UBaseType_t)3, /* 任务的优先级 */
  115. (TaskHandle_t *)&MidPriority_Task_Handle); /* 任务控制块指针 */
  116. if (pdPASS == xReturn)
  117. printf("创建MidPriority_Task任务成功!\n");
  118. /* 创建HighPriority_Task任务 */
  119. xReturn = xTaskCreate((TaskFunction_t)HighPriority_Task, /* 任务入口函数 */
  120. (const char *)"HighPriority_Task", /* 任务名字 */
  121. (uint16_t)512, /* 任务栈大小 */
  122. (void *)NULL, /* 任务入口函数参数 */
  123. (UBaseType_t)4, /* 任务的优先级 */
  124. (TaskHandle_t *)&HighPriority_Task_Handle); /* 任务控制块指针 */
  125. if (pdPASS == xReturn)
  126. printf("创建HighPriority_Task任务成功!\n\n");
  127. vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
  128. taskEXIT_CRITICAL(); //退出临界区
  129. }
  130. /**********************************************************************
  131. * @ 函数名 : LowPriority_Task
  132. * @ 功能说明: LowPriority_Task任务主体
  133. * @ 参数 :
  134. * @ 返回值 : 无
  135. ********************************************************************/
  136. static void LowPriority_Task(void *parameter)
  137. {
  138. static uint32_t i;
  139. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  140. while (1)
  141. {
  142. printf("LowPriority_Task 获取信号量\n");
  143. //获取二值信号量 xSemaphore,没获取到则一直等待
  144. xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
  145. portMAX_DELAY); /* 等待时间 */
  146. if (xReturn == pdTRUE)
  147. printf("LowPriority_Task Runing\n\n");
  148. for (i = 0; i < 2000000; i++) //模拟低优先级任务占用信号量
  149. {
  150. taskYIELD();//发起任务调度
  151. }
  152. printf("LowPriority_Task 释放信号量!\r\n");
  153. xReturn = xSemaphoreGive(BinarySem_Handle); //给出二值信号量
  154. // if( xReturn == pdTRUE )
  155. // ; /* 什么都不做 */
  156. LED1_TOGGLE;
  157. vTaskDelay(500);
  158. }
  159. }
  160. /**********************************************************************
  161. * @ 函数名 : MidPriority_Task
  162. * @ 功能说明: MidPriority_Task任务主体
  163. * @ 参数 :
  164. * @ 返回值 : 无
  165. ********************************************************************/
  166. static void MidPriority_Task(void *parameter)
  167. {
  168. while (1)
  169. {
  170. printf("MidPriority_Task Runing\n");
  171. vTaskDelay(500);
  172. }
  173. }
  174. /**********************************************************************
  175. * @ 函数名 : HighPriority_Task
  176. * @ 功能说明: HighPriority_Task 任务主体
  177. * @ 参数 :
  178. * @ 返回值 : 无
  179. ********************************************************************/
  180. static void HighPriority_Task(void *parameter)
  181. {
  182. BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为pdPASS */
  183. while (1)
  184. {
  185. printf("HighPriority_Task 获取信号量\n");
  186. //获取二值信号量 xSemaphore,没获取到则一直等待
  187. xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
  188. portMAX_DELAY); /* 等待时间 */
  189. if (pdTRUE == xReturn)
  190. printf("HighPriority_Task Runing\n");
  191. LED1_TOGGLE;
  192. xReturn = xSemaphoreGive(BinarySem_Handle); //给出二值信号量
  193. // if( xReturn == pdTRUE )
  194. //printf("HighPriority_Task 释放信号量!\r\n");
  195. vTaskDelay(500);
  196. }
  197. }
  198. /***********************************************************************
  199. * @ 函数名 : BSP_Init
  200. * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
  201. * @ 参数 :
  202. * @ 返回值 : 无
  203. *********************************************************************/
  204. static void BSP_Init(void)
  205. {
  206. /*
  207. * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
  208. * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
  209. * 都统一用这个优先级分组,千万不要再分组,切忌。
  210. */
  211. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  212. /* LED 初始化 */
  213. LED_GPIO_Config();
  214. /* 串口初始化 */
  215. USART_Config();
  216. /* 按键初始化 */
  217. Key_GPIO_Config();
  218. }

19.8.2 互斥量实验

  1. /*
  2. *************************************************************************
  3. * 包含的头文件
  4. *************************************************************************
  5. */
  6. /* FreeRTOS头文件 */
  7. #include "FreeRTOS.h"
  8. #include "task.h"
  9. #include "queue.h"
  10. #include "semphr.h"
  11. /* 开发板硬件bsp头文件 */
  12. #include "bsp_led.h"
  13. #include "bsp_usart.h"
  14. #include "bsp_key.h"
  15. /**************************** 任务句柄 ********************************/
  16. /*
  17. * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
  18. * 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
  19. * 这个句柄可以为NULL。
  20. */
  21. static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */
  22. static TaskHandle_t LowPriority_Task_Handle = NULL;/* LowPriority_Task任务句柄 */
  23. static TaskHandle_t MidPriority_Task_Handle = NULL;/* MidPriority_Task任务句柄 */
  24. static TaskHandle_t HighPriority_Task_Handle = NULL;/* HighPriority_Task任务句柄 */
  25. /********************************** 内核对象句柄 *********************************/
  26. /*
  27. * 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核
  28. * 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我
  29. * 们就可以通过这个句柄操作这些内核对象。
  30. *
  31. * 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,
  32. * 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
  33. * 来完成的
  34. *
  35. */
  36. SemaphoreHandle_t MuxSem_Handle = NULL;
  37. /******************************* 全局变量声明 ************************************/
  38. /*
  39. * 当我们在写应用程序的时候,可能需要用到一些全局变量。
  40. */
  41. /******************************* 宏定义 ************************************/
  42. /*
  43. * 当我们在写应用程序的时候,可能需要用到一些宏定义。
  44. */
  45. /*
  46. *************************************************************************
  47. * 函数声明
  48. *************************************************************************
  49. */
  50. static void AppTaskCreate(void);/* 用于创建任务 */
  51. static void LowPriority_Task(void *pvParameters);/* LowPriority_Task任务实现 */
  52. static void MidPriority_Task(void *pvParameters);/* MidPriority_Task任务实现 */
  53. static void HighPriority_Task(void *pvParameters);/* MidPriority_Task任务实现 */
  54. static void BSP_Init(void);/* 用于初始化板载相关资源 */
  55. /*****************************************************************
  56. * @brief 主函数
  57. * @param 无
  58. * @retval 无
  59. * @note 第一步:开发板硬件初始化
  60. 第二步:创建APP应用任务
  61. 第三步:启动FreeRTOS,开始多任务调度
  62. ****************************************************************/
  63. int main(void)
  64. {
  65. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  66. /* 开发板硬件初始化 */
  67. BSP_Init();
  68. printf("这是一个[野火]-STM32全系列开发板-FreeRTOS互斥量实验!\n");
  69. /* 创建AppTaskCreate任务 */
  70. xReturn = xTaskCreate((TaskFunction_t)AppTaskCreate, /* 任务入口函数 */
  71. (const char *)"AppTaskCreate", /* 任务名字 */
  72. (uint16_t)512, /* 任务栈大小 */
  73. (void *)NULL, /* 任务入口函数参数 */
  74. (UBaseType_t)1, /* 任务的优先级 */
  75. (TaskHandle_t *)&AppTaskCreate_Handle); /* 任务控制块指针 */
  76. /* 启动任务调度 */
  77. if (pdPASS == xReturn)
  78. vTaskStartScheduler(); /* 启动任务,开启调度 */
  79. else
  80. return -1;
  81. while (1); /* 正常不会执行到这里 */
  82. }
  83. /***********************************************************************
  84. * @ 函数名 : AppTaskCreate
  85. * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
  86. * @ 参数 : 无
  87. * @ 返回值 : 无
  88. **********************************************************************/
  89. static void AppTaskCreate(void)
  90. {
  91. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  92. taskENTER_CRITICAL(); //进入临界区
  93. /* 创建MuxSem */
  94. MuxSem_Handle = xSemaphoreCreateMutex();
  95. if (NULL != MuxSem_Handle)
  96. printf("MuxSem_Handle互斥量创建成功!\r\n");
  97. xReturn = xSemaphoreGive(MuxSem_Handle); //给出互斥量
  98. // if( xReturn == pdTRUE )
  99. // printf("释放信号量!\r\n");
  100. /* 创建LowPriority_Task任务 */
  101. xReturn = xTaskCreate((TaskFunction_t)LowPriority_Task, /* 任务入口函数 */
  102. (const char *)"LowPriority_Task", /* 任务名字 */
  103. (uint16_t)512, /* 任务栈大小 */
  104. (void *)NULL, /* 任务入口函数参数 */
  105. (UBaseType_t)2, /* 任务的优先级 */
  106. (TaskHandle_t *)&LowPriority_Task_Handle); /* 任务控制块指针 */
  107. if (pdPASS == xReturn)
  108. printf("创建LowPriority_Task任务成功!\r\n");
  109. /* 创建MidPriority_Task任务 */
  110. xReturn = xTaskCreate((TaskFunction_t)MidPriority_Task, /* 任务入口函数 */
  111. (const char *)"MidPriority_Task", /* 任务名字 */
  112. (uint16_t)512, /* 任务栈大小 */
  113. (void *)NULL, /* 任务入口函数参数 */
  114. (UBaseType_t)3, /* 任务的优先级 */
  115. (TaskHandle_t *)&MidPriority_Task_Handle); /* 任务控制块指针 */
  116. if (pdPASS == xReturn)
  117. printf("创建MidPriority_Task任务成功!\n");
  118. /* 创建HighPriority_Task任务 */
  119. xReturn = xTaskCreate((TaskFunction_t)HighPriority_Task, /* 任务入口函数 */
  120. (const char *)"HighPriority_Task", /* 任务名字 */
  121. (uint16_t)512, /* 任务栈大小 */
  122. (void *)NULL, /* 任务入口函数参数 */
  123. (UBaseType_t)4, /* 任务的优先级 */
  124. (TaskHandle_t *)&HighPriority_Task_Handle); /* 任务控制块指针 */
  125. if (pdPASS == xReturn)
  126. printf("创建HighPriority_Task任务成功!\n\n");
  127. vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
  128. taskEXIT_CRITICAL(); //退出临界区
  129. }
  130. /**********************************************************************
  131. * @ 函数名 : LowPriority_Task
  132. * @ 功能说明: LowPriority_Task任务主体
  133. * @ 参数 :
  134. * @ 返回值 : 无
  135. ********************************************************************/
  136. static void LowPriority_Task(void *parameter)
  137. {
  138. static uint32_t i;
  139. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  140. while (1)
  141. {
  142. printf("LowPriority_Task 获取互斥量\n");
  143. //获取互斥量 MuxSem,没获取到则一直等待
  144. xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
  145. portMAX_DELAY); /* 等待时间 */
  146. if (pdTRUE == xReturn)
  147. printf("LowPriority_Task Runing\n\n");
  148. for (i = 0; i < 2000000; i++) //模拟低优先级任务占用互斥量
  149. {
  150. taskYIELD();//发起任务调度
  151. }
  152. printf("LowPriority_Task 释放互斥量!\r\n");
  153. xReturn = xSemaphoreGive(MuxSem_Handle); //给出互斥量
  154. LED1_TOGGLE;
  155. vTaskDelay(1000);
  156. }
  157. }
  158. /**********************************************************************
  159. * @ 函数名 : MidPriority_Task
  160. * @ 功能说明: MidPriority_Task任务主体
  161. * @ 参数 :
  162. * @ 返回值 : 无
  163. ********************************************************************/
  164. static void MidPriority_Task(void *parameter)
  165. {
  166. while (1)
  167. {
  168. printf("MidPriority_Task Runing\n");
  169. vTaskDelay(1000);
  170. }
  171. }
  172. /**********************************************************************
  173. * @ 函数名 : HighPriority_Task
  174. * @ 功能说明: HighPriority_Task 任务主体
  175. * @ 参数 :
  176. * @ 返回值 : 无
  177. ********************************************************************/
  178. static void HighPriority_Task(void *parameter)
  179. {
  180. BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为pdPASS */
  181. while (1)
  182. {
  183. printf("HighPriority_Task 获取互斥量\n");
  184. //获取互斥量 MuxSem,没获取到则一直等待
  185. xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
  186. portMAX_DELAY); /* 等待时间 */
  187. if (pdTRUE == xReturn)
  188. printf("HighPriority_Task Runing\n");
  189. LED1_TOGGLE;
  190. printf("HighPriority_Task 释放互斥量!\r\n");
  191. xReturn = xSemaphoreGive(MuxSem_Handle); //给出互斥量
  192. vTaskDelay(1000);
  193. }
  194. }
  195. /***********************************************************************
  196. * @ 函数名 : BSP_Init
  197. * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
  198. * @ 参数 :
  199. * @ 返回值 : 无
  200. *********************************************************************/
  201. static void BSP_Init(void)
  202. {
  203. /*
  204. * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
  205. * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
  206. * 都统一用这个优先级分组,千万不要再分组,切忌。
  207. */
  208. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  209. /* LED 初始化 */
  210. LED_GPIO_Config();
  211. /* 串口初始化 */
  212. USART_Config();
  213. /* 按键初始化 */
  214. Key_GPIO_Config();
  215. }