FreeRTOS学习笔记——(5)信号量

2023-05-16

系列文章目录

FreeRTOS学习笔记—— 系列文章目录


文章目录

  • 系列文章目录
  • 信号量
  • 一、信号量函数
    • 1、创建
    • 2、删除
    • 3、give 、 take 函数
  • 二、信号量的应用
    • 1、二进制信号量(防止数据丢失)
    • 2、计数型信号量


信号量

上一篇写的队列可以用来传输数据,但是有时我们只需要传递状态,并不需要传递具体的信息,比如:我用完串口了,通知你一下,你可以使用了。这时就可以使用信号量( semaphore ),只是记录状态或者记录数量,不传输数据,更节省内存。

信号: 起到通知的作用。
量: 可以用来表示资源的数量。

当量没有限制时,是计数型信号量。当量只有0、1 两个取值时,是二进制信号量
二进制信号量与计数型的唯一差别,就是二进制信号量计数值的最大值被限定为1。

一、信号量函数

1、创建

使用信号量之前先创建,得到信号量句柄。
信号量的创建有两种方法:动态创建、静态创建

创建二进制信号量 如下

/*  动态创建  二进制信号量,返回它的句柄。
* 此函数内部会分配信号量结构体
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateBinary( void );


/* 静态创建  二进制信号量,返回它的句柄。,需要事先定义 StaticSemaphore_t 结构体
* 传入 StaticSemaphore_t结构体指针
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t   *pxSemaphoreBuffer );

创建计数型信号量 如下

/* 动态创建  计数型信号量,返回它的句柄。
* 函数内部会分配信号量结构体
* uxMaxCount: 最大计数值
* uxInitialCount: 初始计数值
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);

/* 静态创建  计数型信号量,返回它的句柄。需要定义一个 StaticSemaphore_t 结构体
* uxMaxCount: 最大计数值
* uxInitialCount: 初始计数值
* pxSemaphoreBuffer: StaticSemaphore_t结构体指针
* 返回值: 返回句柄,非NULL表示成功
*/
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,
               									  UBaseType_t uxInitialCount,
                         						  StaticSemaphore_t  *pxSemaphoreBuffer );

2、删除

动态创建的信号量,不需要它们时,可以删除回收内存。

/*
* xSemaphore: 信号量句柄,要删除的信号量
*/
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )

3、give 、 take 函数

give 操作函数使信号量计数值加 1
take 操作函数使信号量计数值减 1

二进制信号量、计数型信号量的give、take操作函数是一样的。
与队列的操作函数类似都有两个版本:在任务中使用、在中断中使用(函数后缀为 ISR 的是在中断中使用)。

give 函数 如下:

/* 
 * 参数:xSemaphore :信号量句柄,释放哪个信号量
 * 参数:pxHigherPriorityTaskWoken  :  如果释放信号量导致更高优先级的任务变为了就绪态,则*pxHigherPriorityTaskWoken = pdTRUE
 * 
 * 返回值 : pdTRUE表示成功
 * 			如果二进制信号量的计数值已经是1,再次调用此函数则返回失败;
 * 			如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败
 */
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
BaseType_t xSemaphoreGiveFromISR(
          						  SemaphoreHandle_t xSemaphore,
          						  BaseType_t *pxHigherPriorityTaskWoken
      						    );

take 函数 如下:


/* 
 * 参数:xSemaphore :信号量句柄,获取哪个信号量
 * 参数:xTicksToWait : 如果无法马上获得信号量,阻塞一会:
 * 						0:不阻塞,马上返回
 * 						portMAX_DELAY: 一直阻塞直到成功
 * 						其他值: 阻塞的Tick个数,可以使用 pdMS_TO_TICKS() 来指定阻塞时间为若干ms
 * 参数:pxHigherPriorityTaskWoken  :  如果获取信号量导致更高优先级的任务变为了就绪态,则*pxHigherPriorityTaskWoken = pdTRUE
 * 
 * 返回值 : pdTRUE表示成功
 */
 
BaseType_t xSemaphoreTake(
        					 SemaphoreHandle_t xSemaphore,
         					 TickType_t xTicksToWait
      					 );
BaseType_t xSemaphoreTakeFromISR(
           							 SemaphoreHandle_t xSemaphore,
            						 BaseType_t *pxHigherPriorityTaskWoken
         						);

二、信号量的应用

1、二进制信号量(防止数据丢失)

要放置信号数据的丢失需要创建缓冲区来存储数据,这里创建环形缓冲区如下

//  创建环形缓冲区  txbuf[BUF_LEN];
#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);

	

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	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();
/* 创建计数型信号量   最大计数值为3,初始值计数值为0  */
xCountingSemaphore = xSemaphoreCreateCounting(3, 0);
if( xCountingSemaphore != NULL )
{
/* 创建1个任务用于释放信号量
* 优先级为2
*/
xTaskCreate( vSenderTask, "Sender", 1000, NULL, 2, NULL );
/* 创建1个任务用于获取信号量
* 优先级为1
*/
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(使用前将#替换为@)

FreeRTOS学习笔记——(5)信号量 的相关文章

  • TCP通信模型(C语言实现)

    大家好 xff0c 我是练习编程时长两年半的个人练习生昆工第一ikun xff0c 今天我们来分享TCP通信模型 xff0c 并且用C语言实现它 目录 一 我们将实现三个示例功能 xff1a 二 TCP服务器搭建流程 xff08 1 xff
  • 场景文本识别中的字符感知采样与校正(Character-Aware Sampling and Rectification for Scene Text Recognition)

    摘要 由于形状和纹理变化较大 xff0c 曲面场景文本识别在多媒体社会中是一项具有挑战性的任务 以前的方法通过等距离采样提取和校正文本行来解决这一问题 xff0c 这忽略了字符级别信息并导致字符失真 为了解决这个问题 xff0c 本文提出了
  • MyBatisPlus中的likeLeft和likeRight

    在使用MyBatisPlus来匹配身份证后6位时遇到了likeLeft和likeRight的问题 xff1a likeLeft时匹配最左边还是匹配最右边 xff1f 所以来一个简单的测试 xff08 通过打印 成功 失败 来判断 xff09
  • 计算机网络第一章总结

    目录 1 1计算机网络再信息时代中的作用 1 2互联网的概述 1 2 1网络 xff0c 互联网和因特网 1 2 2互联网基础结构的三个阶段 1 2 3互联网的标准化工作 1 3互联网的组成 1 3 1三种交换方式 1 4计算机网络的类别
  • Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column……报错的解决办法

    问题原因 xff1a 这个报错是执行有GROUP BY的语句时出现的 原因是MySQL启用了默认的only full group by SQL模式 导致GROUP BY语句报错 解决办法 xff1a 打开mysql的安装目录找到my ini
  • 【Linux安全管理】Firewalld详解

    目录 1 与iptables不同 2 配置防火墙 3 firewalld区域概念 4 filewalld 配置生效 5 firewalld服务 firewalld 端口映射 富规则 rich rule 1 与iptables不同 firew
  • C++之class和struct的区别

    在C语言中 xff0c struct是一个数据类型 xff0c 所以struct内不能定义函数 xff1b 在C 43 43 中保留了struct关键字 xff0c 并且进行了补充 xff0c struct类似于class xff0c 可以
  • QEMU使用virtio磁盘(Ubuntu/windows)

    环境 宿主环境 xff1a windows 10 pro QEMU版本 xff1a 3 1 客户机 xff1a windows2003 virtio是一种半虚拟化技术 xff0c window2003安装盘不带驱动程序 xff0c 所以首先
  • 创建一个ArrayList<String> 集合,通过反射向集合中添加Integer类型的数据

    1 思路 创建一个ArrayList lt String gt 集合 通过反射获取到ArrayList的Class对象通过Class类获取到ArrayList中的add方法 2 所需关键知识 获取Class类有三种方法 xff1a xff0
  • Git分支&标签

    目录 一 xff0c 分支 环境的的功能及特点 分支的策略 分支的相关指令 二 xff0c 标签 1 查看所有标签 2 创建tag 3 删除tag 4 分支与版本 一 xff0c 分支 1 分支的命名规范 dev test pre pro
  • java酒店管理系统小型项目

    前言 学习java这段时间以来 xff0c 给我的感觉是非常枯燥和乏味的 xff0c 因为学习编程这个过程就是这样 xff0c 除此之外我是自学 xff0c 所以遇到问题只能自己上网找资料 xff0c 或者看一些大佬的文章来解决问题 不过学
  • 基于智能优化算法的无人机路径规划(Matlab代码实现)

    目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 无人机作为一种现代航空设备 不仅作业速度快 成本低 还具有卓越的灵活性和时效性 常用于完成那些繁冗 危险 对灵活性要求较高 作业范围较大的任务 比如航空拍摄 农
  • 布谷鸟搜索算法的改进及其在优化问题中的应用(Matlab代码实现)

    x1f352 x1f352 x1f352 欢迎关注 x1f308 x1f308 x1f308 x1f4dd 个人主页 xff1a 我爱Matlab x1f44d 点赞 评论 收藏 61 61 养成习惯 xff08 一键三连 xff09 x1
  • 基于MATLAB中雷达和视觉合成数据的目标级传感器融合(Matlab)代码实现

    目录 x1f4a5 1 概述 x1f4da 2 运行结果 x1f389 3 参考文献 x1f468 x1f4bb 4 Matlab代码 x1f4a5 1 概述 本文使用MATLAB的场景生成器工具箱 xff0c 通过合成雷达和视觉观察创建一
  • Linux嵌入式开发——C编程

    文章目录 Linux嵌入式开发 C编程一 编写C程序1 1 设置vim编辑器1 2 编写C程序 二 编译C程序三 make工具和Makefile文件3 1 编写C程序C文件H文件 3 2 不使用make工具3 3 使用make工具和Make
  • C#中的接口

    一 什么是接口 含义 xff1a 接口是指定一组函数成员而不实现它们的引用类型 xff08 只能用类和结构实现接口 xff09 接口可以包含实例方法 属性 事件 索引器或这四种成员类型的任意组合 接口可以包含静态构造函数 xff08 不能创
  • VINS-MONO工程改造

    这篇是接着前文 主流VIO VSLAM系统改造与工程化落地 和 关于VIO零速更新 ZUPT 与控制三种约束的工程实践 的 xff0c 有时候想一出是一出 xff0c 导致写的东西还是太分散了 要做VINS改造首先要熟悉VSLAM和数学基础
  • DM-VIO简析

    今天主要是针对DMVIO DM VIO的简析 xff0c 中文网上有的东西都太少了 xff0c 只能靠看完论文和组员们一起改代码 Lukas组这个东西在中文网被称为有史以来最好的VIO xff0c 但是实际过程中我们还是发现了许多不完美的地
  • Hao to setup windbg on windows10 LTSC img

    Windows host Debugger install windbg https developer microsoft com en us windows downloads windows 10 sdk download the i
  • VINS/VIO的并行化与工程化(GPU篇)

    最近更新的这2篇应该是比较重的了 xff0c 先做GPU篇 xff0c 再做DSP篇 先友情提醒 xff0c 这篇文章很重很费时 xff0c 对各种软硬算的知识要求多多 主体知识来源于UZH和ETH的研究者Balazs Nagy组 xff0

随机推荐