1、信号量的使用
首先介绍信号量与前面的队列的区别,队列传输的是信号和数据,信号量只是传输信号,在项目中不需要传输数据,只需要传输信号(比如唤醒信号)的时候,使用信号量是更简介、迅速的。下图是信号量和队列的区别的对比:
信号量有两种形式,一种是二进制信号量(数据中只有0和1),另一种是计数型信号量(数值可以一直累加的),这两中形式可以按情况配置使用,下图是两者的区别图:
这两者的创建函数分别为:
二进制信号量创建:xSemaphoreCreateBinary ()
计数型信号量创建:xSemaphoreCreateBinary ()
下面为静态创建去的函数:
xSemaphoreCreateBinaryStatic ()
xSemaphoreCreateCountingStatic ()
下面是信号量的删除函数:
/** xSemaphore: 信号量句柄,你要删除哪个信号量 */
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
下面是信号量的give(传递信号),take(获得信号)的函数:
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
xSemaphore 信号量句柄,释放哪个信号量
返回值
pdTRUE表示成功,
如果二进制信号量的计数值已经是1,再次调用此函数则返回失败;
如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );
xSemaphore 信号量句柄,释放哪个信号量pxHigherPriorityTaskWoken
如果释放信号量导致更高优先级的任务变为了就绪态,
则*pxHigherPriorityTaskWoken = pdTRUE
返回值
pdTRUE表示成功,
如果二进制信号量的计数值已经是1,再次调用此函数则返回失败;
如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
xSemaphore 信号量句柄,获取哪个信号量
xTicksToWait
如果无法马上获得信号量,阻塞一会:
0:不阻塞,马上返回
portMAX_DELAY: 一直阻塞直到成功
其他值: 阻塞的Tick个数,可以使用 pdMS_TO_TICKS() 来指定阻塞时间为若干
ms
返回值 pdTRUE表示成功
BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );
xSemaphore 信号量句柄,获取哪个信号量
pxHigherPriorityTaskWoken
如果获取信号量导致更高优先级的任务变为了就绪态,
则*pxHigherPriorityTaskWoken = pdTRUE
返回值 pdTRUE表示成功
2、信号量的使用demo
创建并使用了两个任务函数,task1和task2,task2的优先级大于task1的任务优先级,运行的顺序为:task2的任务优先级比较高,首先运行这个任务函数,运行到xSemaphoreTake(SemaphoreHandle,portMAX_DELAY);这个位置的时候,函数进入阻塞状态(因为等待的时间参数为portMAX_DELAY,死等),这时候task1开始运行,运行的过程中执行xSemaphoreGive(SemaphoreHandle);这行代码,就是向信号通道传输数据,会唤醒task2的任务函数的休眠阻塞状态,这时候task2就会开始运行,并且打断task1的运行。下面有debug的测试结果。
TaskHandle_t vCheckTask1_hander;
TaskHandle_t vCheckTask2_hander;
TaskHandle_t vCheckTask3_hander;
QueueHandle_t QueueUsart1;
QueueHandle_t QueueUsart2;
QueueSetHandle_t xQueueUsartHandle;
QueueHandle_t SemaphoreHandle;
static void vCheckTask1( void *pvParameters )
{
uint16_t data=1;
for( ;; )
{
// xQueueSend(QueueUsart1,&data,portMAX_DELAY);
printf("task1:%d\r\n",data);
xSemaphoreGive(SemaphoreHandle);
// vTaskDelay(10);
}
}
static void vCheckTask2( void *pvParameters )
{
uint16_t data=2;
for( ;; )
{
// xQueueSend(QueueUsart2,&data,portMAX_DELAY);
xSemaphoreTake(SemaphoreHandle,portMAX_DELAY);
printf("task2:%d\r\n",data);
// vTaskDelay(10);
}
}
//static void vCheckTask3( void *pvParameters )
//{
// uint16_t data;
// QueueSetMemberHandle_t hander;
// for( ;; )
// {
hander=xQueueSelectFromSet(xQueueUsartHandle,portMAX_DELAY);
xQueueReceive(hander,&data,portMAX_DELAY);
// printf("data:%d\r\n",data);
// vTaskDelay(10);
// }
//}
int main( void )
{
prvSetupHardware();
QueueUsart1=xQueueCreate(2,sizeof(uint16_t));
QueueUsart2=xQueueCreate(2,sizeof(uint16_t));
SemaphoreHandle=xSemaphoreCreateCounting(10,0);
xQueueUsartHandle=xQueueCreateSet(3);
xQueueAddToSet(QueueUsart1,xQueueUsartHandle);
xQueueAddToSet(QueueUsart2,xQueueUsartHandle);
xTaskCreate( vCheckTask1, "Check1", 100, NULL,1, &vCheckTask1_hander);
xTaskCreate( vCheckTask2, "Check2", 100, NULL,2, &vCheckTask2_hander);
// xTaskCreate( vCheckTask3, "Check3", 100, NULL,1, &vCheckTask3_hander);
vTaskStartScheduler();
return 0;
}