0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

实时操作系统FreeRTOS信号量应用

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-06-08 09:24 次阅读

1.信号量简介

信号量常用于控制对共享资源的访问与任务同步。资源共享例如火车票售卖,所有用户都可以进行买票和退票操作,对于所用用户来说火车票就是共享资源,当卖出一张票信号量减一、有人退一张票信号量加一,这种案例就属于计数型信号量。常用的信号量还有二值信号量。例如使用公共电话,同一时间只能一个人使用,此时电话就只有两种状态:使用或者未使用,若将电话这两个状态作为信号量的话则就是二值信号量。
信号量的另一应用场合就是任务同步。用于任务与任务间或任务与中断间同步。在执行中断服务函数时可以向任务发送信号量通知任务该事件发生了,在退出中断服务函数以后任务调度器的调度下同步的任务就会执行。因为中断服务函数需要快进快出,代码简洁,一般在中断服务函数中设置标志位,然后在其它地方根据标志位来实现具体功能,在FreeRTOS中就可使用信号量来完成此功能。

2.二值信号量

二值信号量通常用于互斥访问或同步,二值信号量和互斥信号量非常相似,但还是有细微差别,互斥信号量拥有优先级继承机制,二值信号没有。因此二值信量适合于同步(任务与任务、任务与中断同步),而互斥信号量适合于简单的互斥访问。
二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空的。使用二值信号量必须包含semphr.h头文件。

函数名 功能
vSemaphoreCreateBinary() 动态创建二值信号量,老版FreeRTOS创建二值信号量函数
xSemaphoreCreateBinary() 动态创建二值信号量,新版FreeRTOS创建二值信号量函数
xSemaphoreCreateBinaryStatic() 静态创建二值信号量

3.二值信号量应用示例

此示例通过创建3个任务,start_task、LED0_task、Semaphore_task。通过任务start_task创建另外两个任务。

#include "freeRTOS.h"
#include "task.h"//创建相关头文件
#include "queue.h"//消息队列相关头文件
#include "semphr.h"//信号量相关头文件

#define START_TASK_PRIO 1        //任务优先级
#define START_STK_SIZE 128       //任务堆栈大小
TaskHandle_t StartTask_Handler;   //任务句柄
void start_task(void *pvParameters);//任务函数

#define LED0_TASK_PRIO 2     //任务优先级,数字越大优先级越高
#define LED0_STK_SIZE 128     //任务堆栈大小
TaskHandle_t LED0Task_Handler; //任务句柄
void LED0_task(void);         //任务函数

#define Semaphore_TASK_PRIO 2     //任务优先级
#define Semaphore_STK_SIZE 128      //任务堆栈大小
TaskHandle_t SemaphoreTask_Handler; //任务句柄
void Semaphore_task(void);          //任务函数

主函数

int main()
{
	Beep_Init();//蜂鸣器初始化
	LED_Init();//LED初始化
	KEY_Init();
	Usart1_Init(115200);//串口1初始化
	TIMx_Init(TIM2,72,20000);//20ms
	TIMx_Init(TIM3,7200,5000);//500ms
	TIM3->CR1|=1<<0;
	/*创建任务*/
	xTaskCreate((TaskFunction_t)start_task,//任务函数
							(const char *)"start_task",//任务名称	
							(uint16_t)START_STK_SIZE,//堆栈大小
							NULL,           //传递给任务函数的参数
							(UBaseType_t)START_TASK_PRIO,//任务优先级
							(TaskHandle_t *)&StartTask_Handler//任务句柄
							);
	vTaskStartScheduler();     //开启任务调度		
}	

开始任务

SemaphoreHandle_t BinarySemaphore;	//二值信号量句柄
/*开始任务函数*/
void start_task(void *pvParameters)
{
	taskENTER_CRITICAL();  //进入临界区
	/*创建二值信号量*/
	BinarySemaphore=xSemaphoreCreateBinary();//创建二值信号量
	//创建LED0任务
	xTaskCreate( (TaskFunction_t  )LED0_task,//任务函数
							(const char    *)"LED0_task",//任务名称
							 (uint16_t)LED0_STK_SIZE,//堆栈大小
								NULL,           //传递给任务函数的参数
							 (UBaseType_t   )LED0_TASK_PRIO,//任务优先级
							 (TaskHandle_t *)&LED0Task_Handler);//任务句柄

	xTaskCreate(  (TaskFunction_t )Semaphore_task,//任务函数
							(const char    *)"Semaphore_task",//任务名称
							(uint16_t )Semaphore_STK_SIZE,//堆栈大小
								NULL,           //传递给任务函数的参数
							(UBaseType_t    )Semaphore_TASK_PRIO,//任务优先级
		                   (TaskHandle_t  *)&SemaphoreTask_Handler);//任务句柄

	vTaskDelete(StartTask_Handler); //删除开始任务	
	taskEXIT_CRITICAL();    //退出临界区					
}

LED0任务,此任务1000ms进行LED翻转

void LED0_task(void)
{
	while(1)
	{
		LED1=!LED1;
		Delay_Ms(1000);	
	}
}

Semaphore函数,此任务函数获取信号量,处理串口1中断接收数据。

void Semaphore_task(void)//任务函数
{
	BaseType_t err=pdFALSE;
	while(1)
	{
		if(BinarySemaphore!=NULL)
		{
			err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY);	//获取信号量
			if(err==pdTRUE)
			{
				usart1_rx_buff[usart1_cnt]='\0';
				printf("rx=%s\r\n",usart1_rx_buff);
				usart1_cnt=0;
			}
		}
	}
}

串口中断服务函数

#include "FreeRTOS.h"					//FreeRTOS使用
#include "task.h" 
#include "queue.h"	 //消息队列
#include "semphr.h"//信号量
u8 usart1_rx_buff[1024];//串口1接收数据缓冲区
u16 usart1_cnt=0;//保存数组下班
u8 usart1_flag;//接收完成标志符
extern SemaphoreHandle_t BinarySemaphore;	//二值信号量句柄
void USART1_IRQHandler(void)
{
	u8 c;
	BaseType_t pxHigherPriorityTaskWoken;//保存任务是否需要切换的值
	if(USART1->SR&1<<5)
	{
		c=USART1->DR;
		if(usart1_flag==0)//判断上一次数据是否处理完成
		{
			if(usart1_cnt<1024)	
			{
				usart1_rx_buff[usart1_cnt++]=c;
				TIM2->CNT=0;//清空计数器值
				TIM2->CR1|=1<<0;//开启定时
			}
			else usart1_flag=1;
		}
	}
	if( usart1_flag && (BinarySemaphore!=NULL))
	{
//释放信号量
	xSemaphoreGiveFromISR(BinarySemaphore,&pxHigherPriorityTaskWoken);	
//如果需要的话,进行一次上下文切换
	portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
		usart1_flag=0;
	}
}

定时器中断服务函数

#include "FreeRTOS.h"					//FreeRTOS使用
#include "semphr.h"
extern SemaphoreHandle_t BinarySemaphore;	//二值信号量句柄//消息队列句柄
void TIM2_IRQHandler(void)
{
	BaseType_t pxHigherPriorityTaskWoken;//保存任务是否需要切换的值
	if(TIM2->SR&1<<0)//判断是否为更新中断
	{
		TIM2->CR1&=~(1<<0);//关闭定时器2
		usart1_flag=1;
		if( usart1_flag && (BinarySemaphore!=NULL))
		{
             //释放信号量
			xSemaphoreGiveFromISR(BinarySemaphore,&pxHigherPriorityTaskWoken);
            //如果需要的话,进行一次上下文切换
			portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);		
	usart1_flag=0;
		}
	}
	TIM2->SR=0;//清除标志位
}

实现效果

poYBAGKXEqmAaxw_AABsyvIK1BQ061.png
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 操作系统
    +关注

    关注

    37

    文章

    6284

    浏览量

    121874
  • STM32
    +关注

    关注

    2239

    文章

    10671

    浏览量

    348735
  • RTOS
    +关注

    关注

    20

    文章

    776

    浏览量

    118790
  • FreeRTOS
    +关注

    关注

    12

    文章

    473

    浏览量

    61347
  • 信号量
    +关注

    关注

    0

    文章

    53

    浏览量

    8257
收藏 人收藏

    评论

    相关推荐

    FreeRTOS嵌入式实时操作系统

      1 FreeRTOS操作系统功能   作为一个轻量级的操作系统FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、
    发表于 07-06 11:07 6421次阅读
    <b class='flag-5'>FreeRTOS</b>嵌入式<b class='flag-5'>实时</b><b class='flag-5'>操作系统</b>

    FreeRTOS信号量使用教程

    信号量操作系统中重要的一部分,信号量一般用来进行资源管理和任务同步, FreeRTOS信号量又分为二值
    的头像 发表于 12-19 09:22 2429次阅读
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>信号量</b>使用教程

    Mindows操作系统更新到4.8节,增加计数信号量功能

    。/***************************************************************************/Wanlix是一个内核非常小的嵌入式操作系统,只有几百个字节,但功能少,只提供任务切换功能,非常适合资源特别少但又需要任务切换的小项目。Mindows可提供多种
    发表于 12-07 16:55

    Mindows操作系统更新到4.9节,增加互斥信号量功能

    Mindows操作系统更新到4.9节,增加互斥信号量功能,更多资料请登陆www.ifreecoding.com下载。前面2节我们实现了二进制信号量和计数信号量,本节我们将实现最后一种
    发表于 12-12 17:21

    硬件实时操作系统信号量管理的工作原理是什么?

    随着嵌入式技术的发展,实时操作系统RTOS(Real Time Operating System)被越来越多地应用在嵌入式系统中,但是对现有基于软件实现的RTOS,单纯依靠改进调度算法已经不能使
    发表于 10-30 06:35

    请问freertos是硬实时操作系统吗?

    freertos是硬实时操作系统吗?都有哪些硬实时操作系统啊?
    发表于 06-13 09:00

    FreeRTOS队列和信号量是干什么用的?

    1.最近在学习FreeRTOS(stm32下),虽然好像知道了队列和信号量是用来做任务之间的通信的,但是不太理解为什么要用这些东西,我觉得好像用rtos的队列和信号量要实现的功能,我定义一个全局变量
    发表于 08-05 02:57

    实时操作系统的行为同步是什么意思

    实时操作系统的支持下,系统的整体功能是通过各个任务(包括ISR)的协同运行来实现的,这种协同关系包括运行步骤的协同,这种协同操作就是“行为同步”。本章笔记清单1. 二值
    发表于 12-22 06:16

    嵌入式实时操作系统的相关资料分享

    实时操作系统内核。属于轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统
    发表于 01-24 06:44

    FreeRTOS信号量介绍

    FreeRTOS信号量 & ESP32实战阅读建议:有一定操作系统基础知识。FreeRTOS信号量1. 二值
    发表于 01-27 07:28

    Linux操作系统信号量机制的实时化改造

    为了提高Linux操作系统实时性,研究了Linux操作系统System V信号量机制在内核中的实现,发现其在实时应用中存在的不足,提出并实
    发表于 06-25 16:41 18次下载

    FreeRTOS信号量 & ESP32实战

    FreeRTOS信号量 & ESP32实战阅读建议:有一定操作系统基础知识。FreeRTOS信号量1. 二值
    发表于 12-03 18:06 1次下载
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>信号量</b> & ESP32实战

    freeRTOS中最常用到的信号量有哪些

    操作系统系统中,信号量通常用于控制对共享资源的访问和任务之间进行同步,信号量操作系统中是很常用的,也是学习
    的头像 发表于 02-10 11:04 1132次阅读
    <b class='flag-5'>freeRTOS</b>中最常用到的<b class='flag-5'>信号量</b>有哪些

    FreeRTOS的二值信号量

    FreeRTOS中的信号量是一种任务间通信的方式,信号量包括:二值信号量、互斥信号量、计数信号量
    的头像 发表于 02-10 15:07 936次阅读

    FreeRTOS:一个迷你的实时操作系统内核

    ** 1、FreeRTOS** FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、
    的头像 发表于 06-29 17:15 517次阅读
    <b class='flag-5'>FreeRTOS</b>:一个迷你的<b class='flag-5'>实时</b><b class='flag-5'>操作系统</b>内核