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

    文章

    6801

    浏览量

    123283
  • STM32
    +关注

    关注

    2270

    文章

    10895

    浏览量

    355729
  • RTOS
    +关注

    关注

    22

    文章

    811

    浏览量

    119593
  • FreeRTOS
    +关注

    关注

    12

    文章

    484

    浏览量

    62139
  • 信号量
    +关注

    关注

    0

    文章

    53

    浏览量

    8331
收藏 人收藏

    评论

    相关推荐

    FreeRTOS嵌入式实时操作系统

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

    FreeRTOS信号量使用教程

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

    FreeRTOS信号量的使用与实例

    在嵌入式系统中,任务管理是一个重要的部分,它涉及到任务之间的通信和同步,信号量,队列,互斥锁和事件标志组等概念。本文将以 FreeRTOS 为例,详细讲解这些内容。
    的头像 发表于 12-12 15:25 2541次阅读

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

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

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

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

    FreeRTOS信号量介绍

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

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

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

    华为物联网操作系统 LiteOS内核教程04-信号量

    1. LiteOS内核的信号量 1.1.信号量 在多任务操作系统中,不同的任务之间需要同步运行,信号量功能可以为用户提供这方面的支持。信号量
    发表于 03-12 17:06 1699次阅读

    FreeRTOS信号量 & ESP32实战

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

    FreeRTOS 队列 信号量 互斥

    文章目录前言Queue 队列semaphore 信号量Mutex 互斥微信公众号前言FreeRTOS STM32CubeMX配置 内存管理 任务管理上节介绍了用STM32CubeMX生成带
    发表于 12-09 09:51 0次下载
    <b class='flag-5'>FreeRTOS</b> 队列 <b class='flag-5'>信号量</b> 互斥<b class='flag-5'>量</b>

    FreeRTOS高级篇6---FreeRTOS信号量分析

    FreeRTOS信号量包括二进制信号量、计数信号量、互斥信号量(以后简称互斥)和递归互斥
    发表于 01-26 17:39 7次下载
    <b class='flag-5'>FreeRTOS</b>高级篇6---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信号量</b>分析

    FreeRTOS系列第20篇---FreeRTOS信号量API函数

    FreeRTOS信号量包括二进制信号量、计数信号量、互斥信号量(以后简称互斥)和递归互斥
    发表于 01-26 17:44 4次下载
    <b class='flag-5'>FreeRTOS</b>系列第20篇---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信号量</b>API函数

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

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

    FreeRTOS的二值信号量

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

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

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