FreeRTOS二值信号量使用

基本特性

二值信号量常用于互斥和同步。

二值信号量和互斥量非常相似,但是又有区别。互斥量有优先级继承机制,二值信号量没有。

二值信号量更适合用于同步(任务与任务之间,任务与中断之间)。

互斥量更适合用于简单的互斥访问。

 阻塞任务

当一个任务尝试读取信号量的时候,如果信号量无效,那么可以制定一个阻塞时间,在这个时间内任务进入阻塞状态。如果有多个任务阻塞在同一个信号量,当信号量有效时,最高优先级的任务先解除阻塞状态。

本质特性 

二值信号量可以被认为是只有一个项的队列,这个队列只有“空”或“满”两种状态(因此叫做二值)。任务和中断使用的时候不需要关心队列里面是什么,只需要关心这个队列是空还是满,这种机制被用于任务和中断之间的同步。

 典型应用

一个很典型的应用,串口中断接收数据,接收完成后,接收完成标志置1,然后再主循环里面轮询判断这个标志,然后处理接收到的数据。使用系统后,我们只需设置二值信号量,然后在任务里面阻塞判断这个二值信号量。相比不用系统,省去了轮询判断标志的过程,这个时间cpu可以去干其他事情了。

另一个典型应用:按键动作(外部中断)发生后,设置设置信号量,然后在任务里面获取这个信号量,阻塞任务。省去了轮询判断标志的过程,这个时间cpu可以去干其他事情了。

部分API

typedef void * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;//信号量句柄,从这里也可以看到源码实现还是用的队列

SemaphoreHandle_t xSemaphoreCreateBinary( void )//创建二值信号量
xSemaphoreGive( SemaphoreHandle_t xSemaphore )  //给一个信号量
xSemaphoreTake( SemaphoreHandle_t xSemaphore,TickType_t xBlockTime)//获取信号量
xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken)
//给一个信号量,用于中断函数里面

测试程序

总体设计:3个任务,2个信号量

lcdtask:lcd显示当前计数并串口打印,当计数到50的时候,给TaskToTaskSemaphore一个信号量;

totalcounttask:获取TaskToTaskSemaphore信号量,如果获取到了,计数一次,并打印总共获取到的次数;

serialtask:获取TaskToIrqSemaphore信号量,当串口空闲中断产生的时候,这个信号量会在串口中断中给一个信号量。

创建任务和信号量

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

#define LCD_TASK_PRIO		           1	   //任务优先级
#define LCD_TASK_STK_SIZE                  80      //任务堆栈大小
TaskHandle_t LCDTaskHandler;                       //任务句柄
void LCDTaskFunc(void *pvParameters);              //任务函数

#define TOTAL_COUNT_TASK_PRIO		   2	   //任务优先级
#define TOTAL_COUNT_TASK_STK_SIZE 	   50      //任务堆栈大小
TaskHandle_t TotalCountTaskHandler;                //任务句柄
void TotalCountTaskFunc(void *pvParameters);       //任务函数

#define SERIAL_TASK_PRIO		   4	   //任务优先级
#define SERIAL_TASK_STK_SIZE 		   80      //任务堆栈大小
TaskHandle_t SerialTaskHandler;                    //任务句柄
void SerialTaskFunc(void *pvParameters);           //任务函数

SemaphoreHandle_t TaskToIrqSemaphore;
SemaphoreHandle_t TaskToTaskSemaphore;

void OtherTest(void )
{
    BaseType_t ret;
	
    BoardInitMcu();
    BoardInitPeriph();
	
    TaskToIrqSemaphore=xSemaphoreCreateBinary();//创建一个二值信号量
    TaskToTaskSemaphore=xSemaphoreCreateBinary();

    ret=xTaskCreate((TaskFunction_t )LCDTaskFunc,     	
		    (const char*    )"lcdtask",   	
		    (uint16_t       )LCD_TASK_STK_SIZE, 
		    (void*          )NULL,				
		    (UBaseType_t    )LCD_TASK_PRIO,	
		    (TaskHandle_t*  )&LCDTaskHandler); 
	
    ret=xTaskCreate((TaskFunction_t )TotalCountTaskFunc,     	
		    (const char*    )"totalcount",   	
		    (uint16_t       )TOTAL_COUNT_TASK_STK_SIZE, 
		    (void*          )NULL,				
		    (UBaseType_t    )TOTAL_COUNT_TASK_PRIO,	
		    (TaskHandle_t*  )&TotalCountTaskHandler);   

    ret=xTaskCreate((TaskFunction_t )SerialTaskFunc,     
		    (const char*    )"serialtask",   
		    (uint16_t       )SERIAL_TASK_STK_SIZE, 
		    (void*          )NULL,
		    (UBaseType_t    )SERIAL_TASK_PRIO,
		    (TaskHandle_t*  )&SerialTaskHandler); 
				
    vTaskStartScheduler(); 
}

各个任务函数:

void  LCDTaskFunc(void *pvParameters)
{
    char  string[21] = {0};
    static uint8_t i=0;

    for(;;)
    {
        i++;
		
        sprintf(string, "%03d ", i);
        printf("current count :%d\r\n",i);
		
        dis_string(1,0,(uint8_t *)string,1);
		
        if(i==50)
        {
            xSemaphoreGive(TaskToTaskSemaphore);
            i=0;
        }
						
        vTaskDelay(500);               
    }
}

void TotalCountTaskFunc(void *pvParameters)
{
    static uint16_t i=0;
	
    for(;;)
    {	
	if(xSemaphoreTake(TaskToTaskSemaphore,portMAX_DELAY))
	{
	    i++;
            printf(" total count:%d\r\n",i);
	}
	else
	{
	    vTaskDelay(10);
	}
    }
}   

void SerialTaskFunc(void *pvParameters)
{
    for(;;)
    {
	if(xSemaphoreTake(TaskToIrqSemaphore,portMAX_DELAY))
	{
	    printf("serial:%s\r\n",SerialFrame.Buff);
			
	    SerialFrame.Len=0;
	    memset(SerialFrame.Buff,255,0);
	}
	else
	{
	    vTaskDelay(10);
	}
    }
}

 运行结果:

发布了35 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/freemote/article/details/104315222