1. /**
    2. *********************************************************************
    3. * @file main.c
    4. * @author fire
    5. * @version V1.0
    6. * @date 2018-xx-xx
    7. * @brief FreeRTOS V9.0.0 + STM32 事件
    8. *********************************************************************
    9. * @attention
    10. *
    11. * 实验平台:野火 STM32全系列开发板
    12. * 论坛 :http://www.firebbs.cn
    13. * 淘宝 :https://fire-stm32.taobao.com
    14. *
    15. **********************************************************************
    16. */
    17. /*
    18. *************************************************************************
    19. * 包含的头文件
    20. *************************************************************************
    21. */
    22. /* FreeRTOS头文件 */
    23. #include "FreeRTOS.h"
    24. #include "task.h"
    25. #include "event_groups.h"
    26. /* 开发板硬件bsp头文件 */
    27. #include "bsp_led.h"
    28. #include "bsp_usart.h"
    29. #include "bsp_key.h"
    30. /**************************** 任务句柄 ********************************/
    31. /*
    32. * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
    33. * 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
    34. * 这个句柄可以为NULL。
    35. */
    36. static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */
    37. static TaskHandle_t LED_Task_Handle = NULL;/* LED_Task任务句柄 */
    38. static TaskHandle_t KEY_Task_Handle = NULL;/* KEY_Task任务句柄 */
    39. /********************************** 内核对象句柄 *********************************/
    40. /*
    41. * 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核
    42. * 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我
    43. * 们就可以通过这个句柄操作这些内核对象。
    44. *
    45. * 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,
    46. * 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
    47. * 来完成的
    48. *
    49. */
    50. static EventGroupHandle_t Event_Handle =NULL;
    51. /******************************* 全局变量声明 ************************************/
    52. /*
    53. * 当我们在写应用程序的时候,可能需要用到一些全局变量。
    54. */
    55. /******************************* 宏定义 ************************************/
    56. /*
    57. * 当我们在写应用程序的时候,可能需要用到一些宏定义。
    58. */
    59. #define KEY1_EVENT (0x01 << 0)//设置事件掩码的位0
    60. #define KEY2_EVENT (0x01 << 1)//设置事件掩码的位1
    61. /*
    62. *************************************************************************
    63. * 函数声明
    64. *************************************************************************
    65. */
    66. static void AppTaskCreate(void);/* 用于创建任务 */
    67. static void LED_Task(void* pvParameters);/* LED_Task 任务实现 */
    68. static void KEY_Task(void* pvParameters);/* KEY_Task 任务实现 */
    69. static void BSP_Init(void);/* 用于初始化板载相关资源 */
    70. /*****************************************************************
    71. * @brief 主函数
    72. * @param 无
    73. * @retval 无
    74. * @note 第一步:开发板硬件初始化
    75. 第二步:创建APP应用任务
    76. 第三步:启动FreeRTOS,开始多任务调度
    77. ****************************************************************/
    78. int main(void)
    79. {
    80. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
    81. /* 开发板硬件初始化 */
    82. BSP_Init();
    83. printf("这是一个[野火]-STM32全系列开发板-FreeRTOS事件标志组实验!\n");
    84. /* 创建AppTaskCreate任务 */
    85. xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */
    86. (const char* )"AppTaskCreate",/* 任务名字 */
    87. (uint16_t )512, /* 任务栈大小 */
    88. (void* )NULL,/* 任务入口函数参数 */
    89. (UBaseType_t )1, /* 任务的优先级 */
    90. (TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */
    91. /* 启动任务调度 */
    92. if(pdPASS == xReturn)
    93. vTaskStartScheduler(); /* 启动任务,开启调度 */
    94. else
    95. return -1;
    96. while(1); /* 正常不会执行到这里 */
    97. }
    98. /***********************************************************************
    99. * @ 函数名 : AppTaskCreate
    100. * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
    101. * @ 参数 : 无
    102. * @ 返回值 : 无
    103. **********************************************************************/
    104. static void AppTaskCreate(void)
    105. {
    106. BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
    107. taskENTER_CRITICAL(); //进入临界区
    108. /* 创建 Event_Handle */
    109. Event_Handle = xEventGroupCreate();
    110. if(NULL != Event_Handle)
    111. printf("Event_Handle 事件创建成功!\r\n");
    112. /* 创建LED_Task任务 */
    113. xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任务入口函数 */
    114. (const char* )"LED_Task",/* 任务名字 */
    115. (uint16_t )512, /* 任务栈大小 */
    116. (void* )NULL, /* 任务入口函数参数 */
    117. (UBaseType_t )2, /* 任务的优先级 */
    118. (TaskHandle_t* )&LED_Task_Handle);/* 任务控制块指针 */
    119. if(pdPASS == xReturn)
    120. printf("创建LED_Task任务成功!\r\n");
    121. /* 创建KEY_Task任务 */
    122. xReturn = xTaskCreate((TaskFunction_t )KEY_Task, /* 任务入口函数 */
    123. (const char* )"KEY_Task",/* 任务名字 */
    124. (uint16_t )512, /* 任务栈大小 */
    125. (void* )NULL,/* 任务入口函数参数 */
    126. (UBaseType_t )3, /* 任务的优先级 */
    127. (TaskHandle_t* )&KEY_Task_Handle);/* 任务控制块指针 */
    128. if(pdPASS == xReturn)
    129. printf("创建KEY_Task任务成功!\n");
    130. vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
    131. taskEXIT_CRITICAL(); //退出临界区
    132. }
    133. /**********************************************************************
    134. * @ 函数名 : LED_Task
    135. * @ 功能说明: LED_Task任务主体
    136. * @ 参数 :
    137. * @ 返回值 : 无
    138. ********************************************************************/
    139. static void LED_Task(void* parameter)
    140. {
    141. EventBits_t r_event; /* 定义一个事件接收变量 */
    142. /* 任务都是一个无限循环,不能返回 */
    143. while (1)
    144. {
    145. /*******************************************************************
    146. * 等待接收事件标志
    147. *
    148. * 如果xClearOnExit设置为pdTRUE,那么在xEventGroupWaitBits()返回之前,
    149. * 如果满足等待条件(如果函数返回的原因不是超时),那么在事件组中设置
    150. * 的uxBitsToWaitFor中的任何位都将被清除。
    151. * 如果xClearOnExit设置为pdFALSE,
    152. * 则在调用xEventGroupWaitBits()时,不会更改事件组中设置的位。
    153. *
    154. * xWaitForAllBits如果xWaitForAllBits设置为pdTRUE,则当uxBitsToWaitFor中
    155. * 的所有位都设置或指定的块时间到期时,xEventGroupWaitBits()才返回。
    156. * 如果xWaitForAllBits设置为pdFALSE,则当设置uxBitsToWaitFor中设置的任何
    157. * 一个位置1 或指定的块时间到期时,xEventGroupWaitBits()都会返回。
    158. * 阻塞时间由xTicksToWait参数指定。
    159. *********************************************************/
    160. r_event = xEventGroupWaitBits(Event_Handle, /* 事件对象句柄 */
    161. KEY1_EVENT|KEY2_EVENT,/* 接收线程感兴趣的事件 */
    162. pdTRUE, /* 退出时清除事件位 */
    163. pdTRUE, /* 满足感兴趣的所有事件 */
    164. portMAX_DELAY);/* 指定超时事件,一直等 */
    165. if((r_event & (KEY1_EVENT|KEY2_EVENT)) == (KEY1_EVENT|KEY2_EVENT))
    166. {
    167. /* 如果接收完成并且正确 */
    168. printf ( "KEY1与KEY2都按下\n");
    169. LED1_TOGGLE; //LED1 反转
    170. }
    171. else
    172. printf ( "事件错误!\n");
    173. }
    174. }
    175. /**********************************************************************
    176. * @ 函数名 : KEY_Task
    177. * @ 功能说明: KEY_Task任务主体
    178. * @ 参数 :
    179. * @ 返回值 : 无
    180. ********************************************************************/
    181. static void KEY_Task(void* parameter)
    182. {
    183. /* 任务都是一个无限循环,不能返回 */
    184. while (1)
    185. {
    186. if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ) //如果KEY2被单击
    187. {
    188. printf ( "KEY1被按下\n" );
    189. /* 触发一个事件1 */
    190. xEventGroupSetBits(Event_Handle,KEY1_EVENT);
    191. }
    192. if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON ) //如果KEY2被单击
    193. {
    194. printf ( "KEY2被按下\n" );
    195. /* 触发一个事件2 */
    196. xEventGroupSetBits(Event_Handle,KEY2_EVENT);
    197. }
    198. vTaskDelay(20); //每20ms扫描一次
    199. }
    200. }
    201. /***********************************************************************
    202. * @ 函数名 : BSP_Init
    203. * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
    204. * @ 参数 :
    205. * @ 返回值 : 无
    206. *********************************************************************/
    207. static void BSP_Init(void)
    208. {
    209. /*
    210. * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
    211. * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
    212. * 都统一用这个优先级分组,千万不要再分组,切忌。
    213. */
    214. NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
    215. /* LED 初始化 */
    216. LED_GPIO_Config();
    217. /* 串口初始化 */
    218. USART_Config();
    219. /* 按键初始化 */
    220. Key_GPIO_Config();
    221. }
    222. /********************************END OF FILE****************************/