前言:
先准备一个带有freertos的工程,没有的话可以参考我以前的博客------>点我跳转
测试的方法是
创建二值信号量 > 任务来获取信号量 > 按键释放信号量
按键释放有两种方法:查询点平法和外部中断法。
我们用的按键是GPIO_PIN_13
main函数
#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include#include "systick.h" #include "FreeRTOS.h" #include "task.h" #include "semphr.h" void CrateTask(void *pvParameters); void task_a(void *pvParameters); void task_b(void *pvParameters); TaskHandle_t StartTask_Handler; //任务句柄 xSemaphoreHandle xSemaphore = NULL; //二值信号量 int main(void) { gd_eval_key_init(KEY_TAMPER, KEY_MODE_GPIO); //KEY_MODE_GPIO 查询点平的模式 gd_eval_com_init(eval_COM0); //初始化串口 vSemaphoreCreateBinary(xSemaphore); //新建二值信号量 if(xSemaphore != NULL) //判断是否创建成功 printf("二值信号量创建成功!rn"); xTaskCreate(CrateTask ,"CrateTask" , 256, NULL, 1, &StartTask_Handler); //创建任务 vTaskStartScheduler(); //开启任务调度 } void CrateTask(void *pvParameters){ taskENTER_CRITICAL(); //打开临阶段 xTaskCreate(task_a , "task_a" ,128 ,NULL , 2 ,0); //创建任务A xTaskCreate(task_b , "task_b" ,128 ,NULL , 2 ,0); //创建任务B vTaskDelete(StartTask_Handler); //删除创建任务 taskEXIT_CRITICAL(); //关闭临界段 } void task_a(void *pvParameters) { while(1){ if(RESET == gd_eval_key_state_get(KEY_TAMPER)){ //消除按键抖动 vTaskDelay(50); if(RESET == gd_eval_key_state_get(KEY_TAMPER)){ vTaskDelay(50); if(RESET == gd_eval_key_state_get(KEY_TAMPER)){ xSemaphoreGive( xSemaphore); //释放二值信号量 } } } vTaskDelay(250); } } void task_b(void *pvParameters) { while(1){ if(pdTRUE == xSemaphoreTake( xSemaphore, 500 )) //获取信号量 { printf("获取成功!rn"); }else{ printf("等待take!rn"); } vTaskDelay(1000); } } int fputc(int ch, FILE *f) { usart_data_transmit(eval_COM0, (uint8_t)ch); while(RESET == usart_flag_get(eval_COM0, USART_FLAG_TBE)); return ch; }
这样我们在main函数里面直接创建了二值信号量,然后有一个任务每隔1s获取信号量,我们可以通过按键来释放信号量。
外部按键中断法main函数
#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include#include "systick.h" #include "FreeRTOS.h" #include "task.h" #include "semphr.h" void task(void *pvParameters); xSemaphoreHandle xSemaphore = NULL; portbase_TYPE xHigherPriorityTaskWoken = pdTRUE; //解除比当前中断优先级高的任务的阻塞态 int main(void) { gd_eval_key_init(KEY_TAMPER, KEY_MODE_EXTI); //KEY_MODE_EXTI 外部按键中断模式 gd_eval_com_init(eval_COM0); //初始化串口 vSemaphoreCreateBinary(xSemaphore); //创建二值信号量 if(xSemaphore != NULL) //判断信号量是否创建成功 printf("信号量创建成功!rn"); else printf("信号量创建失败!rn"); xTaskCreate(task , "task" ,128 ,NULL , 2 ,0); //创建任务 vTaskStartScheduler(); //开启任务调度 } void task(void *pvParameters) { while(1){ if(pdTRUE == xSemaphoreTake( xSemaphore, 500 )) //获取二值信号量 printf("获取成功!rn"); else printf("等待take!rn"); vTaskDelay(1000); } } int fputc(int ch, FILE *f) { usart_data_transmit(eval_COM0, (uint8_t)ch); while(RESET == usart_flag_get(eval_COM0, USART_FLAG_TBE)); return ch; }
gd32f4xx_it.c在最后添加下面的代码
extern xSemaphoreHandle xSemaphore;
extern portbase_TYPE xHigherPriorityTaskWoken;
void EXTI10_15_IRQHandler (void) //按键的中断函数
{
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken ); //释放二值信号量
exti_interrupt_flag_clear(EXTI_13); //清除中断标志位
}



