0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Free RTOS的計(jì)數(shù)型信號量

汽車電子技術(shù) ? 來源:玩轉(zhuǎn)單片機(jī) ? 作者:Julian ? 2023-02-10 15:29 ? 次閱讀

上篇講解了二值信號量,二值信號量只能判斷有無,而不能確定事件發(fā)生的次數(shù),因此我們?yōu)榱舜_定事件的次數(shù)引入了計(jì)數(shù)型信號量!

使用計(jì)數(shù)型信號量時,需要在FreeRTOSConfig.h中加入一行配置代碼

//為1時使用計(jì)數(shù)信號量
#define configUSE_COUNTING_SEMAPHORES    1

仔細(xì)閱讀源碼的同學(xué)就會發(fā)現(xiàn)有很多類似的代碼(如下圖),這些代碼讓FreeRTO可以實(shí)現(xiàn)不同需要的裁剪,以減少系統(tǒng)開銷

poYBAGPl8guAVafFAAA1Pwvf-tE762.png

創(chuàng)建計(jì)數(shù)型信號量

xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )

參數(shù)

uxMaxCount:計(jì)數(shù)信號量最大計(jì)數(shù)值,但信號量值等于此值的時候,釋放信號量就會失敗

uxInitialCount :計(jì)數(shù)信號量初始值

返回值:

NULL:計(jì)數(shù)信號量創(chuàng)建失敗

其他值:計(jì)數(shù)信號量創(chuàng)建成功,返回計(jì)數(shù)信號量句柄

釋放信號量

非中斷釋放

xSemaphoreGive( SemaphoreHandle_t xSemaphore )

參數(shù):

xSemaphore :要釋放的信號量句柄

返回值:

pdPASS: 釋放信號量成功

errQUEU_FULL:釋放信號量失敗

中斷釋放


BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
                                 BaseType_t* pxHigherPriorityTaskWoken)

參數(shù):

xSemaphore:要釋放的信號量句柄

pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)后是否需要進(jìn)行任務(wù)切換pxHigherPriorityTaskWoken是可選參數(shù),可以設(shè)置為NULL。當(dāng)該值為pdTRUE的時候在退出中斷服務(wù)函數(shù)之前一定要進(jìn)行一次任務(wù)切換。

返回值:

釋放成功返回pdPASS,失敗返回errQUEUE_FULL

獲取信號量

非中斷獲取

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
        TickType_t xBlockTime)

參數(shù):

xSemaphore:要釋放的信號量句柄

xBlockTime:阻塞時間

返回值:

獲取成功返回pdTRUE,失敗返回pdFALSE


中斷獲取

BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
BaseType_t* pxHigherPriorityTaskWoken)

參數(shù):

xSemaphore:要釋放的信號量句柄

pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)后是否需要進(jìn)行任務(wù)切換

返回值:

獲取成功返回pdTRUE,失敗返回pdFALSE

注意:不管是二值信號量、計(jì)數(shù)型信號量還是互斥信號量,它們都使用上面的釋放信號量和獲取信號量API函數(shù)

源碼例程

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

void LED_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;        //定義結(jié)構(gòu)體變量
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);  //開啟時鐘
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;            //選擇你要設(shè)置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;      //設(shè)置推挽輸出模式
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //設(shè)置傳輸速率
  GPIO_Init(GPIOC,&GPIO_InitStructure);                //初始化GPIO
  
  GPIO_SetBits(GPIOC,GPIO_Pin_0);             //將LED端口拉高,熄滅LED
}

void KEY_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; //定義結(jié)構(gòu)體變量  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;     //選擇你要設(shè)置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//下拉輸入  
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //設(shè)置傳輸速率
  GPIO_Init(GPIOA,&GPIO_InitStructure);      /* 初始化GPIO */
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_2|GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;  //上拉輸入
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(GPIOE,&GPIO_InitStructure);
}


void USART_init(uint32_t bound)
{
  GPIO_InitTypeDef GPIO_InitStruct;   //定義GPIO結(jié)構(gòu)體變量
  USART_InitTypeDef USART_InitStruct;   //定義串口結(jié)構(gòu)體變量
  
  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為復(fù)用推挽輸出
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //配置PA9速率
  GPIO_Init(GPIOA,&GPIO_InitStruct);   //GPIO初始化函數(shù)
  
  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初始化函數(shù)
  
  
  USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;   //發(fā)送接收模式
  USART_InitStruct.USART_Parity=USART_Parity_No;   //無奇偶校驗(yàn)
  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;   //無硬件數(shù)據(jù)流控制
  USART_Init(USART1,&USART_InitStruct);   //串口初始化函數(shù)
  
  USART_Cmd(USART1,ENABLE);   //使能USART1
}

int fputc(int ch,FILE *f)   //printf重定向函數(shù)
{
  USART_SendData(USART1,(uint8_t)ch);   //發(fā)送一字節(jié)數(shù)據(jù)
  while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);   //等待發(fā)送完成
  return ch;
}


#define START_TASK_PRIO 1      //任務(wù)優(yōu)先級
#define START_STK_SIZE 128      //任務(wù)堆棧大小
TaskHandle_t StartTask_Handler;   //任務(wù)句柄
void Start_Task(void *pvParameters);//任務(wù)函數(shù)

#define Send_TASK_PRIO 2       //任務(wù)優(yōu)先級
#define Send_STK_SIZE 50       //任務(wù)堆棧大小
TaskHandle_t SendTask_Handler;     //任務(wù)句柄
void Send_Task(void *p_arg);     //任務(wù)函數(shù)

#define Receive_TASK_PRIO 2     //任務(wù)優(yōu)先級
#define Receive_STK_SIZE 50     //任務(wù)堆棧大小
TaskHandle_t ReceiveTask_Handler;     //任務(wù)句柄
void Receive_Task(void *p_arg);   //任務(wù)函數(shù)

SemaphoreHandle_t CountSem_Handle =NULL;  //計(jì)數(shù)型信號量句柄

int main( void ) 
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設(shè)置系統(tǒng)中斷優(yōu)先級分組 4
  
  LED_Init(); //初始化 LED
  KEY_Init();
  USART_init(9600);
  
  //創(chuàng)建開始任務(wù)
  xTaskCreate(
    (TaskFunction_t )Start_Task,     //任務(wù)函數(shù)
    (const char* )"Start_Task",     //任務(wù)名稱
    (uint16_t )START_STK_SIZE,       //任務(wù)堆棧大小
    (void* )NULL,             //傳遞給任務(wù)函數(shù)的參數(shù)
    (UBaseType_t )START_TASK_PRIO,     //任務(wù)優(yōu)先級
    (TaskHandle_t* )&StartTask_Handler  //任務(wù)句柄 
  );
  vTaskStartScheduler();  //開啟調(diào)度
}

//開始任務(wù)函數(shù)
void Start_Task(void *pvParameters)
{
  taskENTER_CRITICAL();   //進(jìn)入臨界區(qū)
   /* 創(chuàng)建Test_Queue */
  CountSem_Handle = xSemaphoreCreateCounting(5,0);
  //創(chuàng)建 發(fā)送 任務(wù)
  xTaskCreate(
    (TaskFunction_t )Send_Task, 
    (const char* )"Send_Task", 
    (uint16_t )Send_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Send_TASK_PRIO,
    (TaskHandle_t* )&SendTask_Handler
  );
  //創(chuàng)建 接收 任務(wù)
  xTaskCreate(
    (TaskFunction_t )Receive_Task, 
    (const char* )"Receive_Task", 
    (uint16_t )Receive_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Receive_TASK_PRIO,
    (TaskHandle_t* )&ReceiveTask_Handler
  );
  vTaskDelete(StartTask_Handler); //刪除開始任務(wù)
  taskEXIT_CRITICAL();   //退出臨界區(qū)
}

//發(fā)送 任務(wù)函數(shù)
void Send_Task(void *pvParameters)
{
  BaseType_t xReturn = NULL;
  while(1)
  {
    if (CountSem_Handle != NULL)
    {
      xReturn = xSemaphoreGive(CountSem_Handle);
      if (xReturn == pdTRUE){
        printf("信號量釋放成功n");
      }
      else{
        printf("信號量釋放失敗n");
      }
    }
    vTaskDelay(1000);
  }
}

//接收 任務(wù)函數(shù)
void Receive_Task(void *pvParameters)
{
  BaseType_t xReturn = NULL;
  uint16_t count = 0;
  while(1)
  {
     // 等待獲取信號量
        xReturn = xSemaphoreTake(CountSem_Handle, portMAX_DELAY);
        if (xReturn == pdTRUE)
        {
      count = uxSemaphoreGetCount(CountSem_Handle);
      printf("%dn",count);
        }
        else
        {
      printf("獲取信號量失敗n");
        }
    vTaskDelay(2000);
  }
}

實(shí)驗(yàn)現(xiàn)象

poYBAGPl8diAbYRaAAD2RjtX1_0302.png

--END--

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    483

    瀏覽量

    61915
  • 信號量
    +關(guān)注

    關(guān)注

    0

    文章

    53

    瀏覽量

    8306
收藏 人收藏

    評論

    相關(guān)推薦

    韋東山freeRTOS系列教程之信號量(6)

    刪除 6.2.3 give/take 6.3 示例12: 使用二進(jìn)制信號量來同步 6.4 示例13: 防止數(shù)據(jù)丟失 6.5 示例14: 使用計(jì)數(shù)信號量 ? 需要獲取更好閱讀體驗(yàn)的同
    的頭像 發(fā)表于 12-13 14:35 ?5003次閱讀
    韋東山freeRTOS系列教程之<b class='flag-5'>信號量</b>(6)

    FreeRTOS信號量使用教程

    信號量是操作系統(tǒng)中重要的一部分,信號量一般用來進(jìn)行資源管理和任務(wù)同步, FreeRTOS中信號量又分為二值信號量、 計(jì)數(shù)
    的頭像 發(fā)表于 12-19 09:22 ?3044次閱讀
    FreeRTOS<b class='flag-5'>信號量</b>使用教程

    【MiCOKit試用體驗(yàn)】慶科MiCO系統(tǒng)篇(2)MiCO RTOS信號量

    本帖最后由 gjianw217 于 2015-10-25 15:41 編輯 在本帖子中,主要分析一下慶科MiCO RTOS信號量,具體包括: OS信號量MiCO 信號量關(guān)鍵AP
    發(fā)表于 10-24 17:01

    信號量是什么?信號量怎么運(yùn)作

    信號量信號量簡介二值信號量計(jì)數(shù)信號量應(yīng)用場景二值信號量怎么運(yùn)作計(jì)數(shù)
    發(fā)表于 01-05 08:09

    怎樣通過串口來顯示FreeRTOS計(jì)數(shù)信號量的數(shù)值呢

    計(jì)數(shù)信號量是指什么?怎樣通過串口來顯示FreeRTOS計(jì)數(shù)信號量的數(shù)值呢?
    發(fā)表于 02-28 09:11

    二值信號量計(jì)數(shù)信號量的區(qū)別是什么?系統(tǒng)怎么區(qū)分是二值還是計(jì)數(shù)

    二值信號量計(jì)數(shù)信號量的區(qū)別是什么?創(chuàng)建函數(shù)都是rt_sem_create,那么系統(tǒng)怎么區(qū)分我是二值還是計(jì)數(shù)?假設(shè)我創(chuàng)建了一個 信號量如下d
    發(fā)表于 10-09 14:16

    二值信號量計(jì)數(shù)信號量的區(qū)別是什么?

    二值信號量計(jì)數(shù)信號量的區(qū)別是什么?創(chuàng)建函數(shù)都是rt_sem_create,那么系統(tǒng)怎么區(qū)分我是二值還是計(jì)數(shù)?假設(shè)我創(chuàng)建了一個 信號量如下!
    發(fā)表于 11-11 14:42

    關(guān)于RTOS中的信號量問題

    信號量是操作系統(tǒng)里的一個基本概念 我現(xiàn)在了解信號量是做什么的,怎么做的。 限于工作經(jīng)驗(yàn),只能用到二值信號量。計(jì)數(shù)
    發(fā)表于 10-31 06:25

    你了解Linux 各類信號量

    內(nèi)核信號量與用戶信號量,用戶信號量分為POXIS信號量和SYSTEMV信號量,POXIS信號量
    發(fā)表于 05-04 17:19 ?2481次閱讀
    你了解Linux 各類<b class='flag-5'>信號量</b>?

    Linux信號量(2):POSIX 信號量

    上一章,講述了 SYSTEM V 信號量,主要運(yùn)行于進(jìn)程之間,本章主要介紹 POSIX 信號量:有名信號量、無名信號量。 POSIX 信號量
    的頭像 發(fā)表于 10-29 17:34 ?678次閱讀

    ThreadX(六)------信號量semaphore

    APItx_semaphore_createtx_semaphore_deletetx_semaphore_gettx_semaphore_puttx_semaphore_put_notifysemaphore_demo概述ThreadX提供32位計(jì)數(shù)信號量,范圍在0到4
    發(fā)表于 12-28 19:26 ?7次下載
    ThreadX(六)------<b class='flag-5'>信號量</b>semaphore

    FreeRTOS信號量計(jì)數(shù)示例分享

    信號量通常用來協(xié)調(diào)對資源的訪問,其中信號計(jì)數(shù)會初始化為可用資源的數(shù)目。
    的頭像 發(fā)表于 09-15 11:45 ?898次閱讀

    FreeRTOS的二值信號量

    FreeRTOS中的信號量是一種任務(wù)間通信的方式,信號量包括:二值信號量、互斥信號量、計(jì)數(shù)信號量
    的頭像 發(fā)表于 02-10 15:07 ?1423次閱讀

    Free RTOS的互斥信號量

    二進(jìn)制信號量和互斥非常相似,但確實(shí)有一些細(xì)微的區(qū)別?;コ怏w包含優(yōu)先級繼承機(jī)制,而二進(jìn)制信號量沒有。這使得二進(jìn)制信號量成為實(shí)現(xiàn)同步(任務(wù)之間或任務(wù)與中斷之間)的更好選擇,互斥體成為實(shí)現(xiàn)
    的頭像 發(fā)表于 02-10 15:36 ?1102次閱讀
    <b class='flag-5'>Free</b> <b class='flag-5'>RTOS</b>的互斥<b class='flag-5'>信號量</b>

    使用Linux信號量實(shí)現(xiàn)互斥點(diǎn)燈

    信號量常用于控制對共享資源的訪問,有計(jì)數(shù)信號量和二值信號量之分。初始化時信號量值大于1的,就是
    的頭像 發(fā)表于 04-13 15:12 ?772次閱讀
    使用Linux<b class='flag-5'>信號量</b>實(shí)現(xiàn)互斥點(diǎn)燈