娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

STM32 系統級開發之 ucosIII 或 freeRTOS 事件標志組詳解

發布者:VS821001最新更新時間:2021-02-07 來源: eefocus關鍵字:STM32  ucosIII  freeRTOS  事件標志組 手機看文章 掃描二維碼
隨時隨地手機看文章

1、輕型操作系統同步的方案詳解


1)信號量

假設有兩個任務 Task1 和 Task2,第一個任務進行按鍵的掃描,第二個任務進行LED燈的點亮

需求:

掃描到按鍵按下后點亮 LED 燈,也就是說第二個任務永遠在等待第一個任務按鍵的掃描

實現:

首先 Task1 一直檢測按鍵是否按下,如果按鍵按下以后,使用一個全局變量 flag 并設置 flag=1

而在 Task2 當中,不停檢測 flag 值是否為 1,如果為 1,點亮 led 燈并把flag清零

此時 flag 提供的是一個信號量的作用,也就是說 Task1 按下按鍵以后,開始向 Task2 發送一個信號量 flag,Task2 接收到了 flag 信號量以后,就把LED燈點亮

2)互斥性信號量

假設有兩個任務 Task1 和 Task2,都需要來訪問一個共享的資源,如要訪問一個共享的打印機

需求:

假設第一個任務 Task1 要打印 hello,第二個任務 Task2 要打印 world,Task1 在使用打印機的時候,Task2是絕對不能使用的,兩個任務屬于互斥關系

如果 Task1 在使用打印機,Task2 也在使用打印機,那打印出來的數據可能會出現亂碼

實現:

為了防止 Task1 和 Task2 共同使用打印機,配置的時候就要使用一個約束,假設還是使用一個全局變量 flag 來表示

如果 flag=1,表示這個打印機處于空閑狀態,假設這個時候 Task1 要使用打印機,它首先要判斷 flag 的狀態,如果判斷 flag=1,它就開始使用打印機并且把 flag 置 0

同樣,假設這個時候,Task2也來使用打印機,它同樣要判斷 flag 的狀態是否等于 1,如果判斷這個時候flag=0,它就知道這個時候打印機處于忙的狀態

它就要等待 Task1 把打印機使用完畢,同時會把 flag 置為 1,這個時候 Task2 任務就可以使用打印機了

3)事件標志組

假設兩個任務 Task1 和 Task2,Task1 進行按鍵掃描,Task2 進行 LED 燈的點亮

同樣的道理,按鍵按下時 LED 燈點亮,但是如果是 N 個按鍵 控制 N 個 LED

使用一個全局變量 flag,但是使用 flag 的各個位來表明了按鍵按下的狀態,flag 的第 0 位為 1 表明第一個按鍵按下

同樣 flag 的第 1 位按鍵為 1,表明第二個按鍵已經按下,依次類推

此時 flag 已經不再是一個信號量了,而是一個事件的標志,它的一位標志著一個事件是否發生,比如說第0位為0,表明這個事件沒發生,第1位為1,表明這個事件發生了,這個時候這個flag就被稱為一個事件的標志

那Task2在使用的過程中,它就需要來判斷flag這個事件的各個位

當然事件的標志還有一些其他的高級標志,比如說你各個位能判斷某一個事件,還可以判斷一個組合事件:

比如第一個按鍵按下了,并且第二個按鍵也按下了,并且第三個按鍵也按下了,那你們都按下以后,我才讓某個燈亮

這樣我們就可以通過事件標志組來通過各個標志位,來相互的判斷,那這個就被稱為事件標志組,它不是信號量,但是它還是屬于信號量的范疇

2、freeRTOS事件標志組詳解


需求:

任務可能會需要與多個事件或任務進行同步,此時信號量就無
能為力了。 FreeRTOS 為此提供了一個可選的解決方法,那就是事件標志組。

簡介:

1)、事件位(事件標志)

事件位用來表明某個事件是否發生,事件位通常用作事件標志

比如下面的幾個例子:

● 當收到一條消息并且把這條消息處理掉以后就可以將某個位(標志)置 1,當隊列中沒有
消息需要處理的時候就可以將這個位(標志)置 0;

● 當把隊列中的消息通過網絡發送輸出以后就可以將某個位(標志)置 1,當沒有數據需要從網絡發送出去的話就將這個位(標志)置 0;

● 現在需要向網絡中發送一個心跳信息,將某個位(標志)置 1。現在不需要向網絡中發送心跳信息,這個位(標志)置 0。

2)、事件組

一個事件組就是一組的事件位, 事件組中的事件位通過位編號來訪問

同樣,以上面列出的三個例子為例:

● 事件標志組的 bit0 表示隊列中的消息是否處理掉。

● 事件標志組的 bit1 表示是否有消息需要從網絡中發送出去。

● 事件標志組的 bit2 表示現在是否需要向網絡發送心跳信息。

3)、事件標志組和事件位的數據類型

事件標志組的數據類型為 EventGroupHandle_t, 當 configUSE_16_BIT_TICKS 為 1 的時候事件標志組可以存儲 8 個事件位,當 configUSE_16_BIT_TICKS 為 0 的時候事件標志組存儲 24個事件位。

事件標志組中的所有事件位都存儲在一個無符號的 EventBits_t 類型的變量中, EventBits_t在 event_groups.h 中有如下定義:

typedef TickType_t EventBits_t;

數據類型 TickType_t 在文件 portmacro.h 中有如下定義:

#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#define portTICK_TYPE_IS_ATOMIC 1
#endif

可以看出當 configUSE_16_BIT_TICKS 為 0 的時候 TickType_t 是個 32 位的數據類型, 因此 EventBits_t 也是個 32 位的數據類型。 EventBits_t 類型的變量可以存儲 24 個事件位,另外的那高 8 位有其他用。事件位 0 存放在這個變量的 bit0 上,變量的 bit1 就是事件位 1,以此類推。對于 STM32 來說一個事件標志組最多可以存儲 24 個事件位。

3、測試試驗詳解


1)、需求

學習 FreeROTS 事件標志組的使用,包括創建事件標志組、將相應的事件位置 1、等待相應
的事件位置 1 等操作。

2)、實現

設計四個任務: start_task、 eventsetbit_task、 eventgroup_task 和 eventquery_task 

這四個任務的任務功能如下:

start_task:用來創建其他三個任務和事件標志組。

eventsetbit_task: 讀取按鍵值,根據不同的按鍵值將事件標志組中相應的事件位置 1,用來
模擬事件的發生。

eventgroup_task:同時等待事件標志組中的多個事件位,當這些事件位都置 1 的話就執行相應的處理,例程中是刷新 LCD 指定區域的背景色。

eventquery_task:查詢事件組的值,也就是各個事件位的值。獲取到事件組值以后就將其顯示到 LCD 上,并且也通過串口打印出來。

實驗中還創建了一個事件標志組: EventGroupHandler,實驗中用到了這個事件標志組的三個事件位,分別位 bit0, bit1 和 bit2。

實驗中會用到 3 個按鍵: KEY0、 KEY1 和 KEY2,其中按鍵 KEY1 和 KEY2 為普通的輸入模式。按鍵 KEY0 為中斷輸入模式,KEY0 用來演示如何在中斷服務程序調用事件標志組的 API函數。

3)、工程

●任務設置

#define START_TASK_PRIO 1 //任務優先級
#define START_STK_SIZE 256 //任務堆棧大小

TaskHandle_t StartTask_Handler; //任務句柄
void start_task(void *pvParameters); //任務函數

#define EVENTSETBIT_TASK_PRIO 2 //任務優先級
#define EVENTSETBIT_STK_SIZE 256 //任務堆棧大小

TaskHandle_t EventSetBit_Handler; //任務句柄
void eventsetbit_task(void *pvParameters); //任務函數

#define EVENTGROUP_TASK_PRIO 3 //任務優先級
#define EVENTGROUP_STK_SIZE 256 //任務堆棧大小

TaskHandle_t EventGroupTask_Handler; //任務句柄
void eventgroup_task(void *pvParameters); //任務函數

#define EVENTQUERY_TASK_PRIO 4 //任務優先級
#define EVENTQUERY_STK_SIZE 256 //任務堆棧大小

TaskHandle_t EventQueryTask_Handler; //任務句柄
void eventquery_task(void *pvParameters); //任務函數

EventGroupHandle_t EventGroupHandler; //事件標志組句柄
#define EVENTBIT_0 (1<<0) //事件位
#define EVENTBIT_1 (1<<1)
#define EVENTBIT_2 (1<<2)
#define EVENTBIT_ALL (EVENTBIT_0|EVENTBIT_1|EVENTBIT_2)

//LCD 刷屏時使用的顏色
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW, BROWN,
BRRED, GRAY };

● main()函數

int main(void)
{
  HAL_Init(); //初始化 HAL 庫
  Stm32_Clock_Init(360,25,2,8); //設置時鐘,180Mhz
  delay_init(180); //初始化延時函數
  uart_init(115200); //初始化串口
  LED_Init(); //初始化 LED
  KEY_Init(); //初始化按鍵
  PCF8574_Init(); //初始化 PCF8574
  EXTI_Init(); //初始化外部中斷
  SDRAM_Init(); //初始化 SDRAM
  LCD_Init(); //初始化 LCD
  my_mem_init(SRAMIN); //初始化內部內存池
  POINT_COLOR = RED;
  LCD_ShowString(30,10,200,16,16,"Apollo STM32F4/F7");
  LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 16-1");
  LCD_ShowString(30,50,200,16,16,"Event Group");
  LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
  LCD_ShowString(30,90,200,16,16,"2016/11/11");
  POINT_COLOR = BLACK;
  LCD_DrawRectangle(5,130,234,314); //畫矩形


  POINT_COLOR = BLUE;
  LCD_ShowString(30,110,220,16,16,"Event Group Value:0");
  //創建開始任務
  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(); //進入臨界區
  //創建事件標志組
  EventGroupHandler=xEventGroupCreate(); //創建事件標志組 (1)
  //創建設置事件位的任務
  xTaskCreate((TaskFunction_t )eventsetbit_task,
              (const char* )"eventsetbit_task",
              (uint16_t )EVENTSETBIT_STK_SIZE,
              (void* )NULL,
              (UBaseType_t )EVENTSETBIT_TASK_PRIO,
              (TaskHandle_t* )&EventSetBit_Handler);
  //創建事件標志組處理任務
  xTaskCreate((TaskFunction_t )eventgroup_task,
              (const char* )"eventgroup_task",
              (uint16_t )EVENTGROUP_STK_SIZE,
              (void* )NULL,
              (UBaseType_t )EVENTGROUP_TASK_PRIO,
              (TaskHandle_t* )&EventGroupTask_Handler);
  //創建事件標志組查詢任務
  xTaskCreate((TaskFunction_t )eventquery_task,
              (const char* )"eventquery_task",
              (uint16_t )EVENTQUERY_STK_SIZE,
              (void* )NULL,
              (UBaseType_t )EVENTQUERY_TASK_PRIO,
              (TaskHandle_t* )&EventQueryTask_Handler);
  vTaskDelete(StartTask_Handler); //刪除開始任務
  taskEXIT_CRITICAL(); //退出臨界區
}


//設置事件位的任務
void eventsetbit_task(void *pvParameters)
{
  u8 key;
  while(1)
  {
    if(EventGroupHandler!=NULL)
    {
      key=KEY_Scan(0);
      switch(key)
      {
        case KEY1_PRES:
          xEventGroupSetBits(EventGroupHandler,EVENTBIT_1); (2)
        break;
        case KEY2_PRES:
          xEventGroupSetBits(EventGroupHandler,EVENTBIT_2); (3)
        break;
       }
}
}
  
//事件標志組處理任務
void eventgroup_task(void *pvParameters)
{
  u8 num;
  EventBits_t EventValue;
  while(1)
  {
    if(EventGroupHandler!=NULL)
    {
      //等待事件組中的相應事件位
      EventValue=xEventGroupWaitBits((EventGroupHandle_t )EventGroupHandler, (4)
      (EventBits_t ) EVENTBIT_ALL,
      (BaseType_t )pdTRUE,
      (BaseType_t )pdTRUE,
      (TickType_t )portMAX_DELAY);
      printf("事件標志組的值:%drn",EventValue);ALIENTEK 阿波羅 FreeRTOS 開發教程
      303
      STM32F429 FreeRTOS 開發手冊
      LCD_ShowxNum(174,110,EventValue,1,16,0);
      num++;
      LED1=!LED1;
      LCD_Fill(6,131,233,313,lcd_discolor[num%14]);
}
    else
    {
      vTaskDelay(10); //延時 10ms,也就是 10 個時鐘節拍
    }
   }
}


//事件查詢任務
void eventquery_task(void *pvParameters)
{
  u8 num=0;
  EventBits_t NewValue,LastValue;
  while(1)
  {
    if(EventGroupHandler!=NULL)
    {
      NewValue=xEventGroupGetBits(EventGroupHandler); //獲取事件組的 (5)
      if(NewValue!=LastValue)
      {
        LastValue=NewValue;
        printf("事件標志組的值:%drn",NewValue);
        LCD_ShowxNum(174,110,NewValue,1,16,0);
      }
      num++;
      if(num==0) //每 500msLED0 閃爍一次
      {
        num=0;
        LED0=!LED0;
      }
        vTaskDelay(50); //延時 50ms,也就是 50 個時鐘節拍
    }
}


(1)、首先調用函數 xEventGroupCreate()創建一個事件標志組 EventGroupHandler。


(2)、按下 KEY1 鍵的時候就調用函數 xEventGroupSetBits()將事件標志組的 bit1 置 1。


(3)、按下 KEY2 鍵的時候調用函數 xEventGroupSetBits()將事件標志組的 bit2 值 1。


(4)、調用函數 xEventGroupWaitBits()同時等待事件標志組的 bit0, bit1 和 bit2,只有當這三個事件都置 1 的時候才會執行任務中的其他代碼。


(5)、調用函數 xEventGroupGetBits()查詢事件標志組 EventGroupHandler 的值變化,通過查看這些值的變化就可以分析出當前哪個事件位置 1 了。


● 中斷初始化及處理過程


事件標志組 EventGroupHandler的事件位 bit0 是通過 KEY0 的外部中斷服務函數來設置的,


注意中斷優先級的設置!本例程的中斷優先級設置如下:
//中斷線 3-PH3
HAL_NVIC_SetPriority(EXTI3_IRQn,6,0); //搶占優先級為 6,子優先級為 0
HAL_NVIC_EnableIRQ(EXTI3_IRQn); //使能中斷線 3
KEY0 的外部中斷服務函數如下:
//事件標志組句柄
extern EventGroupHandle_t EventGroupHandler;
//中斷服務函數
void EXTI3_IRQHandler(void)
{
  BaseType_t Result,xHigherPriorityTaskWoken;
  delay_xms(50); //消抖
  if(KEY0==0)
  {
    Result=xEventGroupSetBitsFromISR(EventGroupHandler,EVENTBIT_0, (1)
    &xHigherPriorityTaskWoken);
    if(Result!=pdFAIL)
    {
      portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
  }
  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); //清除中斷標志位
}


(1)、 在中斷服務函數中通過調用 xEventGroupSetBitsFromISR()來將事件標志組的事件位
bit0 置 1。

[1] [2]
關鍵字:STM32  ucosIII  freeRTOS  事件標志組 引用地址:STM32 系統級開發之 ucosIII 或 freeRTOS 事件標志組詳解

上一篇:STM32Cube 工具說明和安裝淺析
下一篇:STM32 IIC 詳解 之 stm32 IIC 從機模式(中斷方式收發數據)

小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

隨便看看

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京B2-20211791 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 舞阳县| 辽中县| 祁阳县| 宽城| 田东县| 吴旗县| 康平县| 专栏| 洪洞县| 土默特左旗| 宁陕县| 平安县| 宁蒗| 彰化县| 永善县| 西林县| 安阳市| 宁波市| 清水河县| 沁源县| 象州县| 虎林市| 正镶白旗| 温泉县| 汉源县| 霍城县| 济源市| 赣榆县| 吴忠市| 隆回县| 保德县| 大荔县| 南丰县| 丰宁| 漳平市| 鲜城| 阳朔县| 闵行区| 黄龙县| 辽中县| 大冶市|