FreeRTOS 二值信号量

信号量(Semaphores)

 信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问

任务可以通过两种操作来访问信号量:

  1. 等待:如果信号量的值大于0,表示有可用资源,信号量的值减1,任务继续执行。如果信号量的值为0,表示没有可用资源,任务将被阻塞,直到信号量的值变为大于0。
  2. 释放:当任务完成对共享资源的访问后,它会释放信号量,即信号量的值加1。如果有任务因为等待该信号量而被阻塞,那么释放操作将唤醒(或称为解阻塞)其中一个等待的任务,使其能够继续执行。

信号量:用于传递状态 

 队列与信号量的对比

队列

信号量

可以容纳多个数据;

创建队列有两部分内存:队列结构体+队列项存储空间

仅存放计数值,无法存放其他数据;

创建信号量,只需分配信号量结构体

写入队列:当队列满时,可阻塞

释放信号量:不可阻塞,计数值++,

当计数值为最大值时,返回失败

   读取队列:当队列为空时,可阻塞

获取信号量:计数值--,

当没有资源时,可阻塞

二值信号量

        二值信号量的本质是一个队列长度为 1 的队列 ,该队列就只有空和满两种情况,这就是二值

        二值信号量通常用于互斥访问或任务同步, 与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题 ,所以二值信号量更适合用于同步

相关API函数

使用二值信号量的过程:创建二值信号量 \rightarrow 释放二值信号量  \rightarrow 获取二值信号量   

函数

描述

xSemaphoreCreateBinary ()

使用动态方式创建二值信号量

xSemaphoreCreateBinaryStatic ()

使用静态方式创建二值信号量

xSemaphoreGive ()

释放信号量

xSemaphoreGiveFromISR ()

在中断中释放信号量

xSemaphoreTake ()

获取信号量

xSemaphoreTakeFromISR ()

在中断中获取信号量

创建二值信号量函数:

SemaphoreHandle_t   xSemaphoreCreateBinary ( void )

#define   xSemaphoreCreateBinary( )                                   \
          QueueGenericCreate   ( 1, 
                                 semSEMAPHORE_QUEUE_ITEM_LENGTH ,                   
                                 queueQUEUE_TYPE_BINARY_SEMAPHORE )
#define  semSEMAPHORE_QUEUE_ITEM_LENGTH      ( ( uint8_t ) 0U )

返回值

描述

NULL

创建失败

其他值

创建成功返回二值信号量的句柄

        不同信号量创建的本质函数还是  QueueGenericCreate 只是不同信号量的第三个入口参数不同代表了不同信号量。

#define queueQUEUE_TYPE_BASE                  	( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                  	( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX                 	( ( uint8_t ) 1U )	/* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE    	( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE     	( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX       	( ( uint8_t ) 4U )	/* 递归互斥信号量 */

 释放二值信号量函数:

BaseType_t   xSemaphoreGive( xSemaphore )

#define   xSemaphoreGive   (   xSemaphore  )    	                    \					
          xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore )  ,  
                               NULL  ,   
                               semGIVE_BLOCK_TIME  , 
                               queueSEND_TO_BACK )
#define   semGIVE_BLOCK_TIME         ( ( TickType_t ) 0U 

形参

描述

xSemaphore

要释放的信号量句柄

返回值

描述

pdPASS

释放信号量成功

errQUEUE_FULL

释放信号量失败

#define queueSEND_TO_BACK                     ( ( BaseType_t ) 0 )
#define queueSEND_TO_FRONT                    ( ( BaseType_t ) 1 )
#define queueOVERWRITE                        ( ( BaseType_t ) 2 )

 获取二值信号量函数:

BaseType_t   xSemaphoreTake( xSemaphore, xBlockTime )

形参

描述

xSemaphore

要获取的信号量句柄

xBlockTime

阻塞时间

返回值

描述

pdTRUE

获取信号量成功

pdFALSE

超时,获取信号量失败

二值信号量实验 

实验目的:学习 FreeRTOS 的二值信号量相关API函数的使用

实验设计:将设计三个任务:start_task、task1、task2

三个任务的功能如下:

  • start_task:用来创建其他的2个任务
  • task1:用于按键扫描,当检测到按键KEY0被按下时,释放二值信号量
  • task2:获取二值信号量,当成功获取后打印提示信息
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /* 创建二值信号量 */
    BinarySemaphore = xSemaphoreCreateBinary();
	if (BinarySemaphore!= NULL)
	{
		printf("信号量创建成功\r\n");
	}
    /* 创建任务1 */
    xTaskCreate((TaskFunction_t )task1,
                (const char*    )"task1",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);
    /* 创建任务2 */
    xTaskCreate((TaskFunction_t )task2,
                (const char*    )"task2",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区 */
}


void task1(void *pvParameters)
{
    uint8_t key = 0;
    
    while (1)
    {
        key = key_scan(0);
		
		if (key == KEY0_PRES)
		{
			xSemaphoreGive(BinarySemaphore);                    /* 释放二值信号量 */
		}
           
        vTaskDelay(10);
    }
}


void task2(void *pvParameters)
{
    uint32_t task_num = 0;
	BaseType_t value;
    
    while (1)
    {
        value = xSemaphoreTake(BinarySemaphore, portMAX_DELAY);   /* 获取二值信号量 */
		if(value == pdTRUE)
		{
			task_num++;
			printf("成功获取信号量;获取次数:%u\r\n",task_num);
        }
    }
}

其他部分代码可自行查看之前博文;亦或者查看正点原子相关视频;代码部分相比源码有改编; 

实验结果 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值