信号量的主要目的有两个:共享资源访问。 与任务同步。
FreeRTOS中信号量分为如下几种:
1、二值信号量
2、计数型信号量
3、互斥信号量
4、递归互斥信号量
-
二值信号量
二值信号量其实就是一个只有一个队列项的队列,二值信号量的使命就是同步,完成任务与任务或中断与任务之间的同步。
二值信号量创建函数
老版本常见函数vSemaphoreCreateBinary()创建之后就马上有效
释放信号量:
获取信号量:
实验
任务之间同步
task1_task任务通过按键释放信号量使之有效,Dataprocess任务获取信号量,没有获取到就阻塞无限等待
task1_task任务函数
void task1_task(void *pvParameters)
{
u8 key;
while(1)
{
key = KEY_Scan(0);
if(key == WKUP_PRES)//发送信号量
{
if(BinarySemaphore != NULL)
xSemaphoreGive(BinarySemaphore);
}
LED0 = ~LED0;
vTaskDelay(10);
}
}
Dataprocess任务函数
void Dataprocess_task(void *pvParameters)
{
u8 count = 0;
while(1)
{
count++;
if(BinarySemaphore != NULL)
{
xSemaphoreTake(BinarySemaphore, portMAX_DELAY);//获取信号量,死等
printf("Task2 Run Time = %d\r\n", count);
}
LED1 = !LED1;
vTaskDelay(10);
}
}
实现现象
按键没按下不能获取信号量,Dataprocess任务就一直阻塞,获取信号量之后才打印相关信息
中断与任务之间的同步:
串口接收到消息后就释放信号量,ISRDataprocess任务获取信号量,然后将串口缓冲区的数据读取出来打印到PC上
串口中断:
if((BinarySemaphore != NULL) && (USART_RX_STA & 0x8000))
{
xSemaphoreGiveFromISR(BinarySemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
USART_RX_STA = 0;
}
ISRDataprocess任务:
void ISRDataprocess_task(void *pvParameters)
{
BaseType_t err;
BaseType_t xHigherPriorityTaskWoken;
while(1)
{
if(BinarySemaphore != NULL)
{
err = xSemaphoreTakeFromISR(BinarySemaphore, &xHigherPriorityTaskWoken);//获取信号量,死等
if(err == pdTRUE)
{
printf("Reveive_data = %s\r\n", USART_RX_BUF);
memset(USART_RX_BUF, 0, USART_REC_LEN);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
vTaskDelay(1000);
}
}
实验现象