精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Free RTOS的計數型信號量

汽車電子技術 ? 來源:玩轉單片機 ? 作者:Julian ? 2023-02-10 15:29 ? 次閱讀

上篇講解了二值信號量,二值信號量只能判斷有無,而不能確定事件發生的次數,因此我們為了確定事件的次數引入了計數型信號量!

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

//為1時使用計數信號量
#define configUSE_COUNTING_SEMAPHORES    1

仔細閱讀源碼的同學就會發現有很多類似的代碼(如下圖),這些代碼讓FreeRTO可以實現不同需要的裁剪,以減少系統開銷

poYBAGPl8guAVafFAAA1Pwvf-tE762.png

創建計數型信號量

xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )

參數

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

uxInitialCount :計數信號量初始值

返回值:

NULL:計數信號量創建失敗

其他值:計數信號量創建成功,返回計數信號量句柄

釋放信號量

非中斷釋放

xSemaphoreGive( SemaphoreHandle_t xSemaphore )

參數:

xSemaphore :要釋放的信號量句柄

返回值:

pdPASS: 釋放信號量成功

errQUEU_FULL:釋放信號量失敗

中斷釋放


BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
                                 BaseType_t* pxHigherPriorityTaskWoken)

參數:

xSemaphore:要釋放的信號量句柄

pxHigherPriorityTaskWoken:標記退出此函數后是否需要進行任務切換pxHigherPriorityTaskWoken是可選參數,可以設置為NULL。當該值為pdTRUE的時候在退出中斷服務函數之前一定要進行一次任務切換。

返回值:

釋放成功返回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

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

源碼例程

#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);  //開啟時鐘
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;            //選擇你要設置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;      //設置推挽輸出模式
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //設置傳輸速率
  GPIO_Init(GPIOC,&GPIO_InitStructure);                //初始化GPIO
  
  GPIO_SetBits(GPIOC,GPIO_Pin_0);             //將LED端口拉高,熄滅LED
}

void KEY_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; //定義結構體變量  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,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 */
  
  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結構體變量
  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 Send_TASK_PRIO 2       //任務優先級
#define Send_STK_SIZE 50       //任務堆棧大小
TaskHandle_t SendTask_Handler;     //任務句柄
void Send_Task(void *p_arg);     //任務函數

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

SemaphoreHandle_t CountSem_Handle =NULL;  //計數型信號量句柄

int main( void ) 
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//設置系統中斷優先級分組 4
  
  LED_Init(); //初始化 LED
  KEY_Init();
  USART_init(9600);
  
  //創建開始任務
  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();   //進入臨界區
   /* 創建Test_Queue */
  CountSem_Handle = xSemaphoreCreateCounting(5,0);
  //創建 發送 任務
  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
  );
  //創建 接收 任務
  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); //刪除開始任務
  taskEXIT_CRITICAL();   //退出臨界區
}

//發送 任務函數
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);
  }
}

//接收 任務函數
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);
  }
}

實驗現象

poYBAGPl8diAbYRaAAD2RjtX1_0302.png

--END--

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FreeRTOS
    +關注

    關注

    12

    文章

    483

    瀏覽量

    62001
  • 信號量
    +關注

    關注

    0

    文章

    53

    瀏覽量

    8314
收藏 人收藏

    評論

    相關推薦

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

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

    FreeRTOS信號量使用教程

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

    【MiCOKit試用體驗】慶科MiCO系統篇(2)MiCO RTOS信號量

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

    信號量是什么?信號量怎么運作

    信號量信號量簡介二值信號量計數信號量應用場景二值信號量怎么運作計數
    發表于 01-05 08:09

    怎樣通過串口來顯示FreeRTOS計數信號量的數值呢

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

    二值信號量計數信號量的區別是什么?系統怎么區分是二值還是計數

    二值信號量計數信號量的區別是什么?創建函數都是rt_sem_create,那么系統怎么區分我是二值還是計數?假設我創建了一個 信號量如下d
    發表于 10-09 14:16

    二值信號量計數信號量的區別是什么?

    二值信號量計數信號量的區別是什么?創建函數都是rt_sem_create,那么系統怎么區分我是二值還是計數?假設我創建了一個 信號量如下!
    發表于 11-11 14:42

    關于RTOS中的信號量問題

    信號量是操作系統里的一個基本概念 我現在了解信號量是做什么的,怎么做的。 限于工作經驗,只能用到二值信號量計數
    發表于 10-31 06:25

    你了解Linux 各類信號量

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

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

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

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

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

    FreeRTOS信號量計數示例分享

    信號量通常用來協調對資源的訪問,其中信號計數會初始化為可用資源的數目。
    的頭像 發表于 09-15 11:45 ?903次閱讀

    FreeRTOS的二值信號量

    FreeRTOS中的信號量是一種任務間通信的方式,信號量包括:二值信號量、互斥信號量計數信號量
    的頭像 發表于 02-10 15:07 ?1459次閱讀

    Free RTOS的互斥信號量

    二進制信號量和互斥非常相似,但確實有一些細微的區別。互斥體包含優先級繼承機制,而二進制信號量沒有。這使得二進制信號量成為實現同步(任務之間或任務與中斷之間)的更好選擇,互斥體成為實現
    的頭像 發表于 02-10 15:36 ?1123次閱讀
    <b class='flag-5'>Free</b> <b class='flag-5'>RTOS</b>的互斥<b class='flag-5'>信號量</b>

    使用Linux信號量實現互斥點燈

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