FreeRTOS的二值信号量

描述

信号量

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);
  }
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分