系列文章目录
FreeRTOS学习笔记—— 系列文章目录
文章目录
- 系列文章目录
- 信号量
- 一、信号量函数
-
- 二、信号量的应用
-
信号量
上一篇写的队列可以用来传输数据,但是有时我们只需要传递状态,并不需要传递具体的信息,比如:我用完串口了,通知你一下,你可以使用了。这时就可以使用信号量( semaphore ),只是记录状态或者记录数量,不传输数据,更节省内存。
信号: 起到通知的作用。
量: 可以用来表示资源的数量。
当量没有限制时,是计数型信号量。当量只有0、1 两个取值时,是二进制信号量。
二进制信号量与计数型的唯一差别,就是二进制信号量计数值的最大值被限定为1。
一、信号量函数
1、创建
使用信号量之前先创建,得到信号量句柄。
信号量的创建有两种方法:动态创建、静态创建
创建二进制信号量 如下
SemaphoreHandle_t xSemaphoreCreateBinary( void );
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );
创建计数型信号量 如下
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount,
StaticSemaphore_t *pxSemaphoreBuffer );
2、删除
动态创建的信号量,不需要它们时,可以删除回收内存。
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )
3、give 、 take 函数
give 操作函数使信号量计数值加 1
take 操作函数使信号量计数值减 1
二进制信号量、计数型信号量的give、take操作函数是一样的。
与队列的操作函数类似都有两个版本:在任务中使用、在中断中使用(函数后缀为 ISR 的是在中断中使用)。
give 函数 如下:
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
BaseType_t xSemaphoreGiveFromISR(
SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken
);
take 函数 如下:
BaseType_t xSemaphoreTake(
SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait
);
BaseType_t xSemaphoreTakeFromISR(
SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken
);
二、信号量的应用
1、二进制信号量(防止数据丢失)
要放置信号数据的丢失需要创建缓冲区来存储数据,这里创建环形缓冲区如下
#define BUF_LEN 32
#define NEXT_PLACE(i) ((i+1)&0x1F)
uint8_t txbuf[BUF_LEN];
uint32_t tx_r = 0;
uint32_t tx_w = 0;
static int is_txbuf_empty(void)
{
return tx_r == tx_w;
}
static int is_txbuf_full(void)
{
return NEXT_PLACE(tx_w) == tx_r;
}
static int txbuf_put(unsigned char val)
{
if(is_txbuf_full())
return -1;
txbuf[tx_w] = val;
tx_w = NEXT_PLACE(tx_w);
return 0;
}
static int txbuf_get(unsigned char *pval)
{
if(is_txbuf_empty())
return -1;
*pval = txbuf[tx_r];
tx_r = NEXT_PLACE(tx_r);
return 0;
}
在main函数中创建信号量,创建任务,代码如下
SemaphoreHandle_t xBinarySemaphore;
int main( void )
{
prvSetupHardware();
xBinarySemaphore = xSemaphoreCreateBinary( );
if(xBinarySemaphore == NULL)
{
printf("can not create Semaphore\r\n");
}
xTaskCreate(vSenderTask, "Sender", 1000, NULL, 2, NULL);
xTaskCreate(vReceiverTask, "Receiver", 1000, NULL, 1, NULL);
vTaskStartScheduler();
return 0;
}
发送任务:
static void vSenderTask(void * param)
{
int i;
int cnt_tx = 0;
int cnt_ok = 0;
int cnt_err = 0;
const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );
while (1)
{
for(i = 0; i < 3; i++)
{
txbuf_put('a' + cnt_tx);
cnt_tx++;
if(xSemaphoreGive(xBinarySemaphore) == pdTRUE)
printf("Give BinarySemaphore %d time: OK\r\n", cnt_ok++);
else
printf("Give BinarySemaphore %d time: ERR\r\n", cnt_err++);
}
vTaskDelay(xTicksToWait);
}
}
接收任务;
static void vReceiverTask(void * param)
{
int cnt_ok = 0;
int cnt_err = 0;
uint8_t c;
while(1)
{
if(xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE)
{
printf("Get BinarySemaphore OK: %d, data: ", cnt_ok++);
while (txbuf_get(&c) == 0)
{
printf("%c", c);
}
printf("\r\n");
}
else
{
printf("Get BinarySemaphore ERR: %d\r\n", cnt_err++);
}
}
}
运行结果;
2、计数型信号量
使用计数型信号量时,可以多次释放信号量;当信号量的计数值达到最大时,再次释放信号量就会出错。如果信号量计数值为n,就可以连续n次获取信号量,第(n+1)次获取信号量就会阻塞或失败。
SemaphoreHandle_t xCountingSemaphore;
int main( void )
{
prvSetupHardware();
xCountingSemaphore = xSemaphoreCreateCounting(3, 0);
if( xCountingSemaphore != NULL )
{
xTaskCreate( vSenderTask, "Sender", 1000, NULL, 2, NULL );
xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );
vTaskStartScheduler();
}
else
{
}
return 0;
}
static void vSenderTask( void *pvParameters )
{
int i;
int cnt_ok = 0;
int cnt_err = 0;
const TickType_t xTicksToWait = pdMS_TO_TICKS( 20UL );
for( ;; )
{
for (i = 0; i < 4; i++)
{
if (xSemaphoreGive(xCountingSemaphore) == pdTRUE)
printf("Give CountingSemaphore %d time: OK\r\n", cnt_ok++);
else
printf("Give CountingSemaphore %d time: ERR\r\n", cnt_err++);
}
vTaskDelay(xTicksToWait);
}
}
static void vReceiverTask( void *pvParameters )
{
int cnt_ok = 0;
int cnt_err = 0;
for( ;; )
{
if( xSemaphoreTake(xCountingSemaphore, portMAX_DELAY) == pdTRUE )
{
printf("Get CountingSemaphore OK: %d\r\n", cnt_ok++);
}
else
{
printf("Get BinarySemaphore ERR: %d\r\n", cnt_err++);
}
}
}
在此程序中 发送任务优先级高,先执行。连续释放4个信号量,只有前面3次成功,第4次失败;然后发送任务进入阻塞态;接收任务开始执行,得到3个信号量,执行3次,在试图获得第4个信号量时进入阻塞状态;在发送任务的vTaskDelay退出之前,运行的是空闲任务:现在发送任务、接收任务都阻塞了。然后发送任务在此运行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)