FreeRTOS教程——任务(一)
FreeRTOS教程——定时器(二)
FreeRTOS教程——队列(三)
FreeRTOS教程——二值信号量(四)
信号量简介
目的:共享资源访问、与任务同步
信号量类型:二值信号量、计数型信号量、互斥信号量、递归互斥信号量
本质上是一种只包含一个项数的队列
二值信号量
0 和 1,一种内核机制。 内核同步,资源共享。
极简例子
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED0_TASK_PRIO 2
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 3
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
xSemaphoreHandle Sempore_Bin = NULL;
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
// 创建二值信号量
Sempore_Bin = xSemaphoreCreateBinary();
if(Sempore_Bin != NULL) printf("创建成功\r\n");
else printf("创建失败\r\n");
//创建LED0任务
xTaskCreate((TaskFunction_t )led0_task,
(const char* )"led0_task",
(uint16_t )LED0_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED0_TASK_PRIO,
(TaskHandle_t* )&LED0Task_Handler);
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED0任务函数
void led0_task(void *pvParameters)
{
u8 key= 0;
while(1){
printf("%d\r\n",key);
key++;
if(key == 10){
if(Sempore_Bin!=NULL&&key==10){
if (xSemaphoreGive(Sempore_Bin)==pdTRUE)
printf("释放成功\r\n");
else
printf("释放失败\r\n");
}
}
vTaskDelay(1000);
}
}
//LED1任务函数
void led1_task(void *pvParameters)
{
while(1){
if(xSemaphoreTake(Sempore_Bin, 10)== pdTRUE)
printf("获取成功\r\n");
else
printf("获取失败\r\n");
vTaskDelay(1000);
}
}
中断与二值信号量实验
主要函数
if (xSemaphoreGiveFromISR(Sempore_Bin, &xHigherPrioityTaskWoken)==pdTRUE)
if(xSemaphoreTake(Sempore_Bin, 10)== pdTRUE){}
delay_xms(10);//消抖
主要代码
// exit.c
void EXTIX_Init(void){
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
KEY_Init(); // 按键端口初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
//GPIOA.0 中断线以及中断初始化配置 上升沿触发 PA0 WK_UP
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键WK_UP所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x06; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
}
extern xSemaphoreHandle Sempore_Bin;
//外部中断0服务程序
void EXTI0_IRQHandler(void)
{
delay_xms(10);//消抖
BaseType_t xHigherPrioityTaskWoken;
if(WK_UP==1)
{
printf("按下按键\r\n");
if(Sempore_Bin!=NULL){
if (xSemaphoreGiveFromISR(Sempore_Bin, &xHigherPrioityTaskWoken)==pdTRUE)
printf("释放成功\r\n");
else
printf("释放失败\r\n");
}
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
}
//main.c
void led0_task(void *pvParameters)
{
u8 key_sum= 0;
while(1){
if(xSemaphoreTake(Sempore_Bin, 10)== pdTRUE){
printf("接受成功\r\n");
key_sum++;
printf("按键被按下%d次",key_sum);
}
else{
// printf("释放失败\r\n");
}
vTaskDelay(10);
}
}