freeRTOS使用方法 freertos从入门到精通( 三 )


(2)获取互斥信号量
函数原型:
xSemaphoreTake( SemaphoreHandle_t xSemaphore, /* 信号量句柄 */ TickType_t xTicksToWait ); /* 等待信号量可用的最大等待时间 */函数描述:函数 xSemaphoreTake 用于在任务代码中获取信号量 。
xSemaphore:是信号量句柄 。xTicksToWait:是没有信号量可用时,等待信号量可用的最大等待时间,单位系统时钟节拍 。返回值:如果创建成功会获取信号量返回 pdTRUE,否则返回 pdFALSE 。
(3)释放互斥信号量
函数原型:
xSemaphoreGive( SemaphoreHandle_t xSemaphore ); /* 信号量句柄 */函数描述:函数 xSemaphoreGive 用于在任务代码中释放信号量 。
xSemaphore:是信号量句柄 。返回值:如果信号量释放成功返回 pdTRUE,否则返回 pdFALSE,因为信号量的实现是基于消息队列,返回失败的主要原因是消息队列已经满了 。
4、二值信号量和计数信号量的使用示例二值信号量和计数信号量的使用思路如下:
1)通过任务start_task创建两个任务led0_task、led2_task,一个二值信号量binary_sem,一个计数信号量count_sem 。
2)信号量创建成功之后,在led0_task任务中等到信号量,如果能获取到就翻转LED2的状态 。
3)在led2_task任务中定时翻转LED3的状态,表明系统正在运行中 。
4)通过外部中断获取按键的按下,更新信号量的值 。
注意:本例程使用的是GD32E103进行演示,通过按键更新信号量,从而改变LED灯的状态 。
(1)创建任务和二值信号量、计数信号量
/*MCU:GD32E103Vx* RTOS:freeRTOS*/void start_task(void *pvParameters){pvParameters =pvParameters;taskENTER_CRITICAL();//进入临界区binary_sem = xSemaphoreCreateBinary();//创建二值信号量count_sem= xSemaphoreCreateCounting(10,10);//创建计数信号量xTaskCreate((TaskFunction_t)led0_task,(const char*)\"led0_task\",(uint16_t)TASK_STK_LED0_SIZE,(void*)NULL,(UBaseType_t)TASK_LED0_PRIO,NULL );xTaskCreate((TaskFunction_t)led2_task,(const char*)\"led2_task\",(uint16_t)TASK_STK_LED2_SIZE,(void*)NULL,(UBaseType_t)TASK_LED2_PRIO,NULL );vTaskDelete(StartTask_Handler);//删除开始任务taskEXIT_CRITICAL();//退出临界区}
(2)任务函数
void led0_task(void *pvParameters){//pvParameters =pvParameters;BaseType_t err = pdFALSE;for(;;){/* 二值信号量if(binary_sem != NULL){err =xSemaphoreTake(binary_sem,portMAX_DELAY);if(err == pdTRUE){gd_eval_led_toggle(LED2);}}*/if(count_sem != NULL){err = xSemaphoreTake(count_sem,portMAX_DELAY);if(err == pdTRUE){gd_eval_led_toggle(LED2);}}vTaskDelay(100);}}void led2_task(void *pvParameters){pvParameters = pvParameters;for(;;){gd_eval_led_toggle(LED3);vTaskDelay(500);}}
(3)中断处理函数
【freeRTOS使用方法 freertos从入门到精通】void EXTI10_15_IRQHandler(void){BaseType_t xHigherPriorityTaskWoken;if(exti_interrupt_flag_get(EXTI_13) != RESET){exti_interrupt_flag_clear(EXTI_13); //清除中断标志位/*if(binary_sem != NULL){//释放二值信号量xSemaphoreGiveFromISR(binary_sem,&xHigherPriorityTaskWoken);//必要时进行任务切换portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}*/if(count_sem != NULL){xSemaphoreGiveFromISR(count_sem,&xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}}}