99久久全国免费观看_国产一区二区三区四区五区VM_久久www人成免费看片中文_国产高清在线a视频大全_深夜福利www_日韩一级成人av

嵌入式客棧
認(rèn)證:普通會(huì)員
作者動(dòng)態(tài)
去除warning的一個(gè)騷操作~
2024-09-04 15:31
開發(fā)板給電腦自動(dòng)分配IP?手把手教部署零配置網(wǎng)絡(luò)實(shí)現(xiàn)電腦與開發(fā)板直連
2024-09-02 13:08
加個(gè)默認(rèn)參數(shù)還是重載呢?
2024-09-01 10:45
驅(qū)動(dòng)調(diào)試神器printk你掌握了嗎?
2024-08-27 09:45
準(zhǔn)度、精度傻傻分不清?
2024-08-25 10:10

用FreeRTOS搭建Event-Driven應(yīng)用框架

[導(dǎo)讀] 大家好,我是逸珺。

今天來分享一下,之前項(xiàng)目中使用FreeRTOS搭建的Event-Driven事件驅(qū)動(dòng)框架。

什么是Event-Driven?Event-DrivenEvent在計(jì)算機(jī)編程方法中,是一種廣為使用的編程范式。比如Windows中的鼠標(biāo)、鍵盤輸入,就被Windows操作系統(tǒng)管理成了外部輸入事件,由操作系統(tǒng)向不同的應(yīng)用分發(fā)這些輸入事件,再由用戶應(yīng)用程序完成相應(yīng)的動(dòng)作Action。在GUI編程中,這是一種主要的編程范式。

其基本結(jié)構(gòu)可以用下面這張圖來描述:

事件生產(chǎn)者:對(duì)系統(tǒng)產(chǎn)生各種事件,并發(fā)送事件給系統(tǒng)

事件分發(fā):將外部輸入的事件進(jìn)行分發(fā)管理

事件隊(duì)列:事件分發(fā)后,對(duì)應(yīng)的的事件處理者,有可能有多個(gè)事件,因此需要按先后次序依次排隊(duì)處理,所以就有事件隊(duì)列管理

事件消費(fèi)者:負(fù)責(zé)處理由事件生產(chǎn)者發(fā)送給它的對(duì)應(yīng)事件,產(chǎn)生響應(yīng)。事件消費(fèi)者一般有一個(gè)循環(huán)程序,一直偵聽事件隊(duì)列,如果接收到事件,則調(diào)用相應(yīng)的處理函數(shù)。

為什么推崇事件驅(qū)動(dòng)?常規(guī)的做法是程序按照固有的順序執(zhí)行,這樣的編程方式,靈活性比較差。一旦需求稍有變動(dòng),可能就需要比較大的修改。在現(xiàn)代編程方法論中,軟件的復(fù)雜度越來越大,傳統(tǒng)過程方法不能滿足復(fù)雜軟件的需求,可維護(hù)性很差。用戶與軟件的交互體驗(yàn)也很差。

要回答為什么要推崇事件驅(qū)動(dòng)范式,先來看看其特點(diǎn):

多播通信:事件生產(chǎn)者產(chǎn)生的事件可以將事件發(fā)送給多個(gè)消費(fèi)者,也就是事件接收端,因此具備很強(qiáng)的靈活性

實(shí)時(shí)傳輸:事件可以被事件分發(fā)者實(shí)時(shí)的傳輸給事件接收端。這在嵌入式應(yīng)用中尤為明顯

異步通信:事件發(fā)布端不需要等待事件處理端處理前一個(gè)事件,發(fā)的管發(fā),處理的管處理,這也是一種解耦設(shè)計(jì)的體現(xiàn)。

細(xì)粒度通信:事件生產(chǎn)者,可以持續(xù)發(fā)送細(xì)粒度事件,而不需要將一系列事件與其業(yè)務(wù)邏輯關(guān)聯(lián),不需要聚合處理。

通過上面簡(jiǎn)要的總結(jié)其特征,再來看看為什么這個(gè)范式比較好:

敏捷性:敏捷性是指應(yīng)對(duì)系統(tǒng)外部需求的快速變化的響應(yīng)能力。在事件驅(qū)動(dòng)編程范式中,功能域是松散耦合的。這可確保發(fā)生在一個(gè)組件上的更改不會(huì)影響系統(tǒng)中的其他組件。因此,事件驅(qū)動(dòng)編程范式提供的敏捷程度很高。

易于部署:在事件驅(qū)動(dòng)編程范式中,組件是松散耦合的。這在嵌入式Linux多應(yīng)用程序組成的系統(tǒng)比較常見,在單片機(jī)中體現(xiàn)不出來。

可測(cè)試性:事件驅(qū)動(dòng)編程范式中單元測(cè)試難度適中,因?yàn)樗枰厥獾臏y(cè)試客戶端和測(cè)試工具來生成測(cè)試所需的事件。需要考慮其他因素,例如跨功能域的交互順序。事件的組合和交互的順序在系統(tǒng)行為中起著關(guān)鍵作用,需要成為測(cè)試的關(guān)鍵考慮因素。

性能:事件驅(qū)動(dòng)編程范式能夠并行執(zhí)行異步操作。這帶來更好性能,而不管消息排隊(duì)和出隊(duì)所涉及的時(shí)間延遲如何。

可擴(kuò)展性:由于組件的高度解耦特性,事件驅(qū)動(dòng)編程范式提供了高度的可擴(kuò)展性。

易于開發(fā):由于該模式的異步性質(zhì),使用該模式的開發(fā)難度較低。

用FreeRTOS搭事件驅(qū)動(dòng)框架FreeRTOS的Queue提供了任務(wù)到任務(wù)、任務(wù)到中斷、中斷到任務(wù)、中斷到任務(wù)間的通訊機(jī)制。關(guān)于FreeRTOS隊(duì)列本身應(yīng)如何使用的細(xì)節(jié),這里不作展開。

假定Task0需要處理這樣一些事件,可以定義如下枚舉:

typedef enum  {
    TASK0_EVENT_0,
    TASK0_EVENT_1,
    TASK0_EVENT_2
    .....
} Task0EventType;
typedef struct Task0Event_t {
    Task0EventType  type;
    union {
       float para1;
       int  para2;
       bool on;
       struct {
         xxx;
       }xxx;
    } params;    
} Task0Event;

定義一個(gè)聯(lián)合params放在Task0Event內(nèi),可以使事件發(fā)送附加信息的能力,使用union則可以考慮到不同的事件發(fā)送方需要傳送的附加信息不一樣的需求,比如有的中斷需要發(fā)送開關(guān)量信息,有的甚至可能是一條報(bào)文或者很多信息。

將Task0的任務(wù)循環(huán)寫成下面這樣的形式:

xQueueHandle  task0_queue;
//假定每10毫秒循環(huán)一次
#define TASK0_INTERVAL_MS           10 
 
void task0_main(void)
{   
   Task0Event event;
   if(xQueueReceive(task0_queue,&event,(TASK0_INTERVAL_MS/portTICK_RATE_MS))==pdTRUE) 
   {
       prv_event_process(&event);
   }   
   /*其他處理*/
   .....
}
 
static void prv_event_process( Task0Event* event)
{
   switch( event->type )
   {
      case TASK0_EVENT_0:
         .....
         break;
         
      case TASK0_EVENT_1:
         .....
         break;
      
      case TASK0_EVENT_2:
     .....
         break;
         
      default:
        .....
        break;
   }
}

這樣就寫好了事件處理端了,只需要分析出與該任務(wù)有哪些外設(shè)或其他任務(wù)會(huì)對(duì)該任務(wù)發(fā)送事件,就可以很好的寫出事件發(fā)送相關(guān)的代碼了。

對(duì)于事件處理的函數(shù),如果不用switch-case語句,定義一個(gè)這樣的事件回調(diào)函數(shù)表也是可以的,一定要討論哪種好,哪種不好,我覺得意義不是很大,看個(gè)人喜歡吧:

//函數(shù)指針這里舉個(gè)簡(jiǎn)單的例子,實(shí)際使用的時(shí)候,可能需要加參數(shù),返回值等
typedef void (*Event_Handler)( Task0Event *event );
typedef struct EventProcessor_t
{
    Task0Event     event;
    Event_Handler  handler;
} EventProcessor;
 
EventProcessor task0_event_table[] = {
  {TASK0_EVENT_0,event0_handler},
  {TASK0_EVENT_1,event1_handler},
  {TASK0_EVENT_2,event2_handler},
  ......
}
 
void task0_main(void)
{   
   Task0Event event;
   if (xQueueReceive(task0_queue,&event, (TASK0_INTERVAL_MS/portTICK_RATE_MS)) == pdTRUE) 
   {
       task0_event_table[event.type].handler();
   }
   
   /*其他處理*/
   .....
}

用一張圖來描述這個(gè)思路,就是這樣的:

中斷中發(fā)送

比如是一個(gè)中斷需要對(duì)該任務(wù)發(fā)送事件0,就可以在該中斷函數(shù)內(nèi)如下發(fā)送事件:

void xxx_ISR(void)
{
    ....
    Task0Event event;
    event.type = TASK0_EVENT_0;
    portBASE_TYPE woken = pdFALSE;
    xQueueSendFromISR(task0_queue, &event, &woken);
}

對(duì)參數(shù)pxHigherPriorityTaskWoken,做個(gè)簡(jiǎn)要說明:

單個(gè)隊(duì)列可能會(huì)阻塞一個(gè)或多個(gè)任務(wù),就是該事件可以被多個(gè)任務(wù)處理。調(diào)用這三個(gè)函數(shù):

xQueueSendFromISR()

xQueueSendToFrontFromISR() 

xQueueSendToBackFromISR()

這三個(gè)函數(shù)使等待該事件的任務(wù)離開阻塞態(tài)。如果調(diào)用API函數(shù)導(dǎo)致任務(wù)離開阻塞狀態(tài),并且未阻塞任務(wù)的優(yōu)先級(jí)等于或高于當(dāng)前正在執(zhí)行的任務(wù)(被中斷的任務(wù)),那么在API內(nèi)部函數(shù)會(huì)將 *pxHigherPriorityTaskWoken設(shè)置為真。如果這些函數(shù)將此值設(shè)置為 pdTRUE,則應(yīng)在退出中斷之前執(zhí)行上下文切換。這將確保中斷直接返回到最高優(yōu)先級(jí)的就緒狀態(tài)任務(wù)。

BaseType_t xQueueSendFromISR( QueueHandle_t xQueue,  
                 const void *pvItemToQueue,  
                 BaseType_t *pxHigherPriorityTaskWoken ); 
 
BaseType_t xQueueSendToBackFromISR( QueueHandle_t xQueue,  
                    const void *pvItemToQueue,  
                    BaseType_t *pxHigherPriorityTaskWoken ); 
 
BaseType_t xQueueSendToFrontFromISR( QueueHandle_t xQueue,  
                     const void *pvItemToQueue,  
                     BaseType_t *pxHigherPriorityTaskWoken ); 

這三個(gè)函數(shù)的作用基本類似,都是在中斷中可以使用的發(fā)送事件到隊(duì)列的API:

xQueueSendFromISR或xQueueSendToBackFromISR

將發(fā)送事件至隊(duì)尾;

xQueueSendToFrontFromISR發(fā)送至對(duì)首。

void xxx_f(void)
{
   ....
   Task0Event event;
   event.type = TASK0_EVENT_1;
   xQueueSend(task0_queue, &event, portMAX_DELAY);
   ...
}

可被使用的API有這樣三個(gè):

BaseType_t xQueueSend( QueueHandle_t xQueue,  
             const void * pvItemToQueue,  
             TickType_t xTicksToWait ); 
 
BaseType_t xQueueSendToFront( QueueHandle_t xQueue,  
                 const void * pvItemToQueue,  
                 TickType_t xTicksToWait ); 
 
BaseType_t xQueueSendToBack( QueueHandle_t xQueue,  
                const void * pvItemToQueue,  
                TickType_t xTicksToWait );  

這三個(gè)函數(shù)的作用類似,區(qū)別與前面中斷版本類似,就不贅述了。

總結(jié)一下:利用FreeRTOS搭建這樣一個(gè)事件驅(qū)動(dòng)應(yīng)用框架,可以很容易開發(fā),后期維護(hù)也很方便。需要加個(gè)功能或修改功能,很容易擴(kuò)展,這樣一種編程范式在其他的RTOS中也可以使用,只不過不同的RTOS提供的API會(huì)有差異,方法是相通的。

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 2
收藏 1
關(guān)注 79
成為作者 賺取收益
全部留言
0/200
成為第一個(gè)和作者交流的人吧
主站蜘蛛池模板: 麻豆精品在线视频 | 国产精久久久久久 | 成人国产精品色哟哟 | 国产高潮流白浆喷水在线观看 | 久久久成人999亚洲区美女 | 日韩欧美小视频 | 成人午夜片av在线看 | 一本一道久久a久久综合蜜桃 | 台湾十八成人网 | 国产成人精品综合久久久久99 | 91看大片 | 久久精品无码AV | 成熟少妇XXXXX高清视频 | 久久99精品久久久噜噜最新章节 | 性色AV一区二区三区V视界影院 | 少妇无力反抗慢慢张开双腿 | 成人片黄网站色大片免费毛片 | 91精品国产经典在线观看 | 九色最新 | 亚洲成人生活片 | 黄色免看| 亚洲AV久久无码 | 麻豆久久久久久久 | 亚洲国产成人无码AV在线播放 | www国产成人免费观看视频深夜成人网 | 国产日韩精品中文字无码樱花 | 欧美破处在线视频 | 日本少妇高潮正在线播放 | 国产999精品久久久影片官网 | 日韩一区国产在线观看 | 久久网av| 久久香蕉三级国产黑人 | 无人高清视频免费观看在线 | 正能量免费网站WWW正能量免费 | 浴室洗澡偷拍一区二区 | 91色片 | 国内91视频| 秋霞久久久 | 日日干狠狠操 | 美国一级毛片aa | 少妇人妻陈艳和黑人教练 |