简介
信号量可以是二进制信号量也可以是计数信号量。二进制信号量可以看作是计数信号量的一种特殊形式,一般用于对共享资源的访问,信号量的初始值设为1。在计数信号量的情况下,计数值通常被实现为一个简单的无符号整数。当发送一个计数信号量时,增加信号量的值。当获取一个信号量时,则计数值递减。在任务获取信号量时,如果该值为0,则任务被阻塞,直到有其他任务或中断服务程序发送该信号量,该任务才退出阻塞状态进入就绪状态,如果此时该任务是就绪表中优先级最该的任务则获得运行的机会。因此,可以使用信号量在任务之间发送信号,表示某事已准备就绪。例如,有一个CollectData任务从传感器读取数据,还有一个SendData任务将数据发送到云端。SendData任务使用“获取”信号量函数申请一个信号量,如果此时信号量的值为0,则任务阻塞,直到CollectData任务在新的数据可用时发送该信号量。
对于二进制信号量,无论发送信号量的函数被调用多少次,在清除信号量之前,只能有一个获取事件。使用计数信号量时,获取事件的数量可以与发送事件的数量相同。这两种方法在不同的情况下都很有用。使用信号量主要实现以下两个功能。
1)当共享资源为1时,实现两个任务之间或任务和中断服务程序之间的同步功能/
2)多个共享资源的管理。
语法:
SemaphoreHandle_t xHandler; 创建Handler
xHandler = xSemaphoreCreateBinary(); 创建一个二进制信号量 返回NULL,或者handler
xSemaphoreGive(xHandler); 生产者+1
xSemaphoreTake(xHanlder, timeout); 消费者-1 返回pdPASS, 或者pdFAIL
二进制信号量可以想成就是一个整数 0 或者 1
Give就是+1
Take就是-1
Take的时候如果这个整数是0的话,就等待一直到timeout
程序实现
首先,在setup()函数中创建一个二进制信号量
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
xSemaLED = xSemaphoreCreateBinary(); //创建二进制信号量
if (xSemaLED == NULL) {
printf("No Enough Ram, Unable to Create Semaphore.");
} else {
xTaskCreate(flashLED,
"Flash LED",
1024 * 4,
NULL,
1,
NULL);
xTaskCreate(readBtn,
"Read Button",
1024 * 4,
NULL,
1,
NULL);
}
}
void loop() {
}
通过按下按钮发送二进制信号量,使用小灯闪烁任务获取二进制信号量
SemaphoreHandle_t xSemaLED = NULL; //创建信号量Handler
TickType_t timeOut = 1000; //用于获取信号量的Timeout 1000 ticks
void flashLED(void *pvParam) {
pinMode(23, OUTPUT);
while (1) {
if (xSemaphoreTake( xSemaLED, timeOut) == pdTRUE )
{
digitalWrite(23, !digitalRead(23));
vTaskDelay(1000);
}
}
}
void readBtn(void *pvParam) {
pinMode(22, INPUT_PULLUP);
while (1) {
if (digitalRead(22) == LOW) {
xSemaphoreGive(xSemaLED);
vTaskDelay(120); //button debounce
}
}
}