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

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

3天内不再提示

FreeRTOS的二值信号量

汽车电子技术 来源:玩转单片机 作者: Julian 2023-02-10 15:07 次阅读

信号

FreeRTOS中的信号量是一种任务间通信的方式,信号量包括:二值信号量、互斥信号量、计数信号量,本次实验只使用二值信号量。信号量用于任务间的同步,FreeRTOS是多任务系统,不同任务间可能需要某种同步关系

二值信号量

可以通俗理解为0或1标志位,比如串口中断接收完数据是一种状态,此时就需要进行串口数据处理又是一种状态,这时使用二值信号量就能很好达到任务同步效果

信号量的基本操作有获取信号量和释放信号量,例如:数据分析处理任务需要处理串口数据时,先尝试获取信号量,若获取不到,也就是信号量是0,则先进入阻塞等待,等待超时可先跳出,之后继续尝试获取信号量。串口空闲中断接受完一串数据后,可执行释放信号量操作,这时,数据分析处理任务就可以获取到信号量,进而可以处理串口数据了,实现了串口数据接收与数据处理的同步。

API函数

创建二值信号量

SemaphoreHandle_t xSemaphoreCreateBinary( void )

返回值:

NULL:创建信号量失败,因为FreeRTOS堆栈不足。

       其它值:信号量创建成功。这个返回值存储着信号量句柄。

非中断释放二值信号量

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore )

参数

xSemaphore:要释放的信号量句柄

返回值:

释放成功返回pdPASS,失败返回errQUEUE_FULL

中断释放二值信号量

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
                                 BaseType_t* pxHigherPriorityTaskWoken)

参数:

xSemaphore:要释放的信号量句柄

pxHigherPriorityTaskWoken:标记退出此函数后是否需要进行任务切换

返回值:

释放成功返回pdPASS,失败返回errQUEUE_FULL

获取信号量

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
                          TickType_t xBlockTime)

参数:

xSemaphore:要释放的信号量句柄

    xBlockTime:阻塞时间

返回值:

获取成功返回pdTRUE,失败返回pdFALSE

中断获取信号量

BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
                                 BaseType_t* pxHigherPriorityTaskWoken)

参数:

xSemaphore:要释放的信号量句柄

pxHigherPriorityTaskWoken:标记退出此函数后是否需要进行任务切换

返回值:

获取成功返回pdTRUE,失败返回pdFALSE

实现目的

通过按键触发二值信号量的释放,获取任务一直在等待信号量的到来,再执行相应的任务

上源码

#include "stm32f10x.h"


#include "stm32f10x.h"
#include 
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"


void LED_Init(void)
{

  GPIO_InitTypeDef  GPIO_InitStructure;


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);   //使能PE端口时钟


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_5;  //端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //IO口速度为50MHz
  GPIO_Init(GPIOC, &GPIO_InitStructure);            //推挽输出 ,IO口速度为50MHz
  GPIO_SetBits(GPIOC,GPIO_Pin_1|GPIO_Pin_5);         //输出高 

}


void KEY_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;       //定义结构体变量  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;     //选择你要设置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD; //下拉输入  
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;  //设置传输速率
  GPIO_Init(GPIOA,&GPIO_InitStructure);       //初始化GPIO
}




void USART_init(uint32_t bound)
{
  GPIO_InitTypeDef GPIO_InitStruct;   //定义GPIO结构体变量
  USART_InitTypeDef USART_InitStruct;   //定义串口结构体变量

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);   //使能GPIOC的时钟

  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;   //配置TX引脚
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;   //配置PA9为复用推挽输出
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //配置PA9速率
  GPIO_Init(GPIOA,&GPIO_InitStruct);   //GPIO初始化函数

  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;   //配置RX引脚
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //配置PA10为浮空输入
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //配置PA10速率
  GPIO_Init(GPIOA,&GPIO_InitStruct);   //GPIO初始化函数


  USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;   //发送接收模式
  USART_InitStruct.USART_Parity=USART_Parity_No;   //无奇偶校验
  USART_InitStruct.USART_BaudRate=bound;   //波特率
  USART_InitStruct.USART_StopBits=USART_StopBits_1;   //停止位1位
  USART_InitStruct.USART_WordLength=USART_WordLength_8b;   //字长8位
  USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;   //无硬件数据流控制
  USART_Init(USART1,&USART_InitStruct);   //串口初始化函数

  USART_Cmd(USART1,ENABLE);   //使能USART1
}


int fputc(int ch,FILE *f)   //printf重定向函数
{
  USART_SendData(USART1,(uint8_t)ch);   //发送一字节数据
  while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);   //等待发送完成
  return ch;
}


//创建开始任务
#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 128 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void Start_Task(void *pvParameters); //任务函数
//释放信号量
#define Release_TASK_PRIO 2 //任务优先级
#define Release_STK_SIZE 50 //任务堆栈大小
TaskHandle_t ReleaseTask_Handler; //任务句柄
void Release_Task(void *p_arg); //任务函数
//获取信号量
#define Gain_TASK_PRIO 3 //任务优先级
#define Gain_STK_SIZE 50 //任务堆栈大小
TaskHandle_t GainTask_Handler; //任务句柄
void Gain_Task(void *p_arg); //任务函数


SemaphoreHandle_t KeySemaphore;//串口接收二值信号量句柄


int main( void ) 
{ 
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
  LED_Init();     //初始化 LED
  KEY_Init();      //按键初始化
  USART_init(115200);  //初始化串口

  //创建开始任务
  xTaskCreate(
    (TaskFunction_t )Start_Task,     //任务函数
    (const char* )"Start_Task",     //任务名称
    (uint16_t )START_STK_SIZE,       //任务堆栈大小
    (void* )NULL,             //传递给任务函数的参数
    (UBaseType_t )START_TASK_PRIO,     //任务优先级
    (TaskHandle_t* )&StartTask_Handler  //任务句柄 
  );
  vTaskStartScheduler();  //开启调度
}


void Start_Task(void *pvParameters)
{
  taskENTER_CRITICAL();   //进入临界区
  //创建二值信号量
  KeySemaphore = xSemaphoreCreateBinary();
  //创建 释放信号量 任务
  xTaskCreate(
    (TaskFunction_t )Release_Task, 
    (const char* )"Release_Task", 
    (uint16_t )Release_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Release_TASK_PRIO,
    (TaskHandle_t* )&ReleaseTask_Handler
  ); 
  //创建 获取信号量 任务
  xTaskCreate(
    (TaskFunction_t )Gain_Task, 
    (const char* )"Gain_Task", 
    (uint16_t )Gain_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Gain_TASK_PRIO,
    (TaskHandle_t* )&GainTask_Handler
  ); 
  vTaskDelete(StartTask_Handler); //删除开始任务
  taskEXIT_CRITICAL();   //退出临界区
}
//释放信号量 任务函数
void Release_Task(void *pvParameters)
{
  BaseType_t xReturn = NULL;
  while(1)
  {
    if(GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_0))
    {
      vTaskDelay(10);
      if(GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_0))
      {
        xReturn = xSemaphoreGive(KeySemaphore);
        if(xReturn == pdPASS)
          printf("释放成功\\n");
      }
    }

    vTaskDelay(10);
  }
}


//获取信号量 任务函数
void Gain_Task(void *pvParameters)
{
  BaseType_t xReturn = NULL;
  while(1)
  {
    xReturn = xSemaphoreTake(KeySemaphore,portMAX_DELAY);//一直阻塞获取
    if(xReturn == pdPASS)
      printf("获取成功\\n");
    vTaskDelay(10);
  }
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FreeRTOS
    +关注

    关注

    12

    文章

    473

    浏览量

    61341
  • 任务系统
    +关注

    关注

    0

    文章

    4

    浏览量

    6101
  • 信号量
    +关注

    关注

    0

    文章

    53

    浏览量

    8257
收藏 人收藏

    评论

    相关推荐

    韦东山freeRTOS系列教程之信号量(6)

    文章目录 系列教程总目录 概述 6.1 信号量的特性 6.1.1 信号量的常规操作 6.1.2 信号量跟队列的对比 6.1.3 两种信号量的对比 6.2
    的头像 发表于 12-13 14:35 4692次阅读
    韦东山<b class='flag-5'>freeRTOS</b>系列教程之<b class='flag-5'>信号量</b>(6)

    转:第21章 FreeRTOS计数信号量

    信号量和计数信号量,其中信号量可以理解成计数信号量的一种特殊形式,即初始化为仅有一个资源可以
    发表于 09-05 09:36

    转:第22章 FreeRTOS信号量

    本章节讲解FreeRTOS任务间的同步和资源共享机制,信号量
    发表于 09-06 10:02

    转:第23章 FreeRTOS互斥信号量

    互斥信号量API函数23.3 实验例程说明23.4总结23.1 互斥信号量23.1.1互斥信号量的概念及其作用互斥信号量的主要作用是对资源实现互斥访问,使用
    发表于 09-06 14:58

    STM32CubeMX FreeRTOS学习[2] 信号量(Lu)

    STM32CubeMX FreeRTOS学习[2] 信号量(Lu)
    发表于 09-06 16:35

    转:第25章 FreeRTOS任务信号量

    本章节为大家讲解FreeRTOS信号量的另一种实现方式----基于任务通知(Task Notifications)的
    发表于 09-07 10:58

    FreeRTOS信号量卡住出不来怎么办?

    串口中断函数在调用xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken ),给出信号量时,卡在了
    发表于 06-10 09:25

    FreeRTOS任务通知模拟信号量怎么都获取不成功是怎么回事

    如图,所示,救助论坛的大神,元老? FreeRTOS 21080511 任务通知模拟信号量.rar (4.02 MB )
    发表于 06-15 04:32

    信号量简介

    一、信号量简介信号量通常用于互斥访问或同步,
    发表于 01-19 07:15

    FreeRTOS信号量介绍

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

    怎样去使用FreeRTOS信号量

    怎样去使用FreeRTOS信号量呢?怎样通过按键中断来控制LED灯的亮灭从而实现任务与中断之间的同步呢?
    发表于 02-28 07:23

    信号量和计数信号量的区别是什么?系统怎么区分是还是计数呢

    信号量和计数信号量的区别是什么?创建函数都是rt_sem_create,那么系统怎么区分我是
    发表于 10-09 14:16

    信号量和计数信号量的区别是什么?

    信号量和计数信号量的区别是什么?创建函数都是rt_sem_create,那么系统怎么区分我是
    发表于 11-11 14:42

    STM32WB55XX freertos 二值信号量+dma+idle 不定长串口接收 + dma传输完成中断

    2、开启全局中断低功耗串口1 : 添加 DMA时钟源选择1.2 freertos 配置添加串口任务创建信号量二、用户代码如果使用信号量同步,把使能空闲中断放在默认任务开头可以避免一种开机就死机的情况:开启中断后串口在
    发表于 12-24 19:13 5次下载
    STM32WB55XX  <b class='flag-5'>freertos</b> 二值<b class='flag-5'>信号量</b>+dma+idle 不定长串口接收 + dma传输完成中断

    使用Arduino在FreeRTOS中实现信号量和互斥量的方式

    信号量和互斥(互斥)是用于同步、资源管理和保护资源免受损坏的内核对象。在本教程的前半部分,我们将了解Semaphore背后的理念,以及如何以及在何处使用它。
    的头像 发表于 08-16 15:34 1901次阅读
    使用Arduino在<b class='flag-5'>FreeRTOS</b>中实现<b class='flag-5'>信号量</b>和互斥量的方式