1.与队列一样任务每一次循环未得到信号量时就会进入阻塞态,以此来进行任务同步 ,当阻塞时间无限大时就会进入完全阻塞态(portMAX_DELAY)若不死等,则在阻塞时间过后就会执行该任务的下一步
二值信号量即为队列项为1的队列,不为空则可以使任务获得信号量,即可解除阻塞态和执行任务其余部分代码。
在使用前也需要创建二值信号量句柄
SemaphoreHandle_t my_Semaphorehandle;
并在开始任务中my_Semaphorehandle = xSemaphoreCreateBinary(); if(my_Semaphorehandle == NULL) printf("Semaphr creat faild!");
创建二值信号量
2.信号量用的时队列实现的
void task1_task(void *pvParameters)
{
u8 ui = 0;
u8 key = 0;
while(1)
{
key = KEY_Scan(0);
if(my_Semaphorehandle!=NULL && key)
{
if(xSemaphoreGive(my_Semaphorehandle))
{
printf("信号值释放成功!\r\n");
}
}
LED0 = !LED0;
// printf("task1 running");
vTaskDelay(7);
}
}
以上是发送,
以下是接收函数
```c
if(my_Semaphorehandle!=NULL)
{
xSemaphoreTake( my_Semaphorehandle, portMAX_DELAY );
放在另一个任务函数中。
3.也与队列一样,有中断释放信号量,释放完后得判断是否切换任务
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
BaseType_t pxHigherPriorityTaskWoken;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
//释放二值信号量
if((USART_RX_STA&0x8000)&&(my_Semaphorehandle!=NULL))//接收到数据,并且二值信号量有效
{
xSemaphoreGiveFromISR(my_Semaphorehandle,&pxHigherPriorityTaskWoken); //释放二值信号量
portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
}
}
#endif
中断中使用发送,任务中接收
4.计数信号量就是多个队列项的队列,和二值信号量一样只在乎有没有释放信号和多少个信号(二值信号量只有一个),不在乎信号内容
5.semphr这个h文件为什么可以定义函数,因为他都是用define和typedef来调用queue.c中的函数,来形成自己的函数,基于queue.c
6.与二值信号量一样
需要先定义
SemaphoreHandle_t counting_Semaphorehandle;
开始任务中初始化
```c
//counting_Semaphorehandle = xSemaphoreCreateCounting( 20, 0 ); inite vaule is 0
counting_Semaphorehandle = xSemaphoreCreateCounting( 20, 10 ); //init vaule is 10
if(counting_Semaphorehandle == NULL)
printf("Semaphr creat faild!");
7.释放信号量,则项数加一
void task1_task(void *pvParameters)
{
u8 key = 0;
while(1)
{
key = KEY_Scan(0);
if(counting_Semaphorehandle!=NULL && key)
{
if(xSemaphoreGive(counting_Semaphorehandle))
{
printf("信号值释放成功!\r\n");
}
}
LED0 = !LED0;
// printf("task1 running");
vTaskDelay(7);
}
}
8.获取信号量,则项数减一
void task2_task(void *pvParameters)
{
UBaseType_t a = 0;
while(1)
{
if(counting_Semaphorehandle!=NULL)
{
xSemaphoreTake( counting_Semaphorehandle, portMAX_DELAY );
{
a = uxSemaphoreGetCount(counting_Semaphorehandle);
printf("num = %d",a);
}
}
LED1 = !LED1;
printf("task2 running\r\n");
vTaskDelay(1000); //一秒获取一次,那在一秒内释放的信号量就得累积
}
}
9.优先级反转
这个现象是由于等待信号量造成的,比如:当一个低级任务获取到信号量并处于运行状态,此时高优先级也需要获取信号量才能运行,但是他会由于信号量被低级任务占用而处于阻塞态,此时如果有一个中级任务出现,则会打断低级任务的执行,这将导致效果:中级任务优先级高于高级任务,非常危险!!(以上针对二值信号量)
所以需要互斥信号量,在某些情况下代替二值信号量。可以避免中级任务优先于高级任务