參考B站up主【架構分析】嵌入式祼機事件驅動框架
感謝大佬分享
-
任務ID : TASK_XXX
TASK_XXX 在系統中每個任務的ID是唯一的,范圍是 0 to 0xFFFE,0xFFFF保留為SYS_TSK_INIT。
同時任務ID的大小也充當任務調度的優先級,ID越大,優先級越高,越排在任務鏈表的最前面 -
事件ID :EVE_XXX
EVE_XXX和任務綁定,對于一個任務來說,一個任務的事件集有16位,最高位1<<15 保留為系統消息事件SYS_EVE_MSG,剩下的1<<0 到 1<<14由用戶定義
對于不同的任務,EVE_XXX可以相同,但是對于某一個任務,EVE_XXX應是唯一的 -
消息事件ID : EVE_MSG_XXX
EVE_MSG_XXX被消息的bdy所攜帶,當將消息發送給任務時,會觸發任務的系統消息事件SYS_EVE_MSG,然后在任務的事件處理函數handler中,取出消息事件EVE_MSG_XXX和數據data,根據EVE_MSG_XXX做不同的處理。
EVE_MSG_XXX與EVE_XXX是不同的,EVE_MSG_XXX是消息事件中的消息所攜帶的事件,EVE_XXX是某個任務事件集中的某個事件。
EVE_MSG_XXX的范圍是 0 到 0xFFFF,盡可能使用不同的EVE_MSG_XXX
(注:此架構圖來自B站up主的視頻【架構分析】嵌入式祼機事件驅動框架)
創建任務,初始化(包括硬件方面,軟件邏輯方面等)
也可以在初始化中創建軟件定時器,軟件定時器超時后會把對應任務的事件置位,即觸發事件。
系統調度后在osal_system_start中會循環檢查有沒有觸發事件的任務,有則通過task_handler處理
消息通過osal_send_msg發送消息到消息隊列,因為消息其實是和任務task_id綁定起來的,消息發送到消息隊列后會把對應的任務中的 SYS_MSG_EVE置位,即觸發消息事件。然后在task_handler中通過osal_recv_msg讀取 消息,把消息提取出來,然后釋放消息內存
也可以直接通過調用osal_task_seteve觸發指定任務的事件
核心就是任務task,應用層中 通過 task_id和event_id實現事件驅動的調度
中斷中如何往OSAL中去集成
- 通過直接觸發相應的事件osal_task_seteve
- 通過消息隊列
如果數據比較少,可以直接通過消息隊列發送。
或者使用數據緩沖層,在任務處理task_handler中取數據
在app.h中聲明所有的任務id,事件id,以及處理接口ops
調度函數
osal_system_start
在主程序中調用osal_system_start
- 尋找觸發事件的任務
- 執行任務事件處理函數
- 將執行完的事件在事件集中剔除掉
通過osal_task_active獲取有效任務,即有事件觸發的任務,將其事件集提取出來賦值給events變量。
將task_active->events給清理掉,最開始是一個多線程的考慮,在邏輯輪詢中
調用任務的事件處理函數task_active->ops->handler,這個函數由用戶提供,參數是任務id和事件集,在此函數中需要剔除掉對應的事件,然后將剔除事件 過后 的事件集 返回,然后將返回值 或上任務的事件集
(注:此架構圖來自B站up主的視頻【架構分析】嵌入式祼機事件驅動框架)
/********************************************************************* * @fn osal_system_start * * @brief * * This function is the main loop function of the task system. It * will look through all task events and call the task_event_processor() * function for the task with the event. If there are no events (for * all tasks), this function puts the processor into Sleep. * This Function doesn't return. * * @param void * * @return none *//*可以考慮不加臨界區,直接用原子操作,減少開銷*/
void osal_system_start(void)
{ event_asb_t events,ret_events; osal_task_t *task_active; while(1) { task_active = osal_task_active(); if ( task_active != NULL ) { OSAL_ENTER_CRITICAL(); events = task_active->events; task_active->events = SYS_EVE_NONE; OSAL_EXIT_CRITICAL(); if(events != SYS_EVE_NONE) { if(task_active->ops->handler != NULL) { ret_events = task_active->ops->handler(task_active->task_id,events); OSAL_ENTER_CRITICAL(); task_active->events |= ret_events; OSAL_EXIT_CRITICAL(); } } } }
}
osal.h
#ifndef OSAL_H
#define OSAL_H //#include "heap.h"
#include "stm32h7xx_hal.h" #define OSAL_ERROR 0
#define OSAL_SUCCESS 1
#define INVALID_TASK 2
#define INVALID_MSG_POINTER 3
#define INVALID_EVENT_ID 4
#define INVALID_TIMER 5 //芯片硬件字長
typedef unsigned int halDataAlign_t; // Unsigned numbers
typedef unsigned char osal_bool_t;
typedef unsigned char osal_byte_t;
typedef unsigned char osal_uint8_t;
typedef unsigned short osal_uint16_t;
typedef unsigned int osal_uint32_t; // Signed numbers
typedef signed char osal_int8_t;
typedef signed short osal_int16_t;
typedef signed int osal_int32_t; #define osal_container_of(ptr, type, member) ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) /**進入臨界區和退出臨界區**/
//#define CLI() __set_PRIMASK(1) // Disable Interrupts
//#define SEI() __set_PRIMASK(0) // Enable Interrupts
#define CLI() __disable_irq() // Disable Interrupts
#define SEI() __enable_irq() // Enable Interrupts #define OSAL_ENABLE_INTERRUPTS() SEI() // Enable Interrupts
#define OSAL_DISABLE_INTERRUPTS() CLI() // Disable Interrupts
#define OSAL_ENTER_CRITICAL() CLI()
#define OSAL_EXIT_CRITICAL() SEI() /**內存管理**/
//#define osal_mem_alloc pvHeapMalloc
//#define osal_mem_free vHeapFree #define osal_delay(ms) HAL_Delay(ms) osal_uint8_t osal_init_system(void);
void osal_system_start(void); int osal_strlen( char *pString );
void *osal_memcpy( void *dst, const void *src, unsigned int len );
void *osal_revmemcpy( void *dst, const void *src, unsigned int len );
void *osal_memdup( const void *src, unsigned int len );
osal_uint8_t osal_memcmp( const void *src1, const void *src2, unsigned int len );
void *osal_memset( void *dest, osal_uint8_t value, int len ); #endif
osal.c
/********************************************************************* * @fn osal_init_system * * @brief * * This function initializes the "task" system by creating the * tasks defined in the task table (OSAL_Tasks.h). * * @param void * * @return ZSUCCESS */osal_uint8_t osal_init_system( void )
{ // Initialize the Memory Allocation System
#if OSALMEM_METRICS osal_mem_init();
#endif return ( OSAL_SUCCESS );
} /********************************************************************* * @fn osal_system_start * * @brief * * This function is the main loop function of the task system. It * will look through all task events and call the task_event_processor() * function for the task with the event. If there are no events (for * all tasks), this function puts the processor into Sleep. * This Function doesn't return. * * @param void * * @return none *//*可以考慮不加臨界區,直接用原子操作,減少開銷*/
void osal_system_start(void)
{ event_asb_t events,ret_events; osal_task_t *task_active; while(1) { task_active = osal_task_active(); if ( task_active != NULL ) { OSAL_ENTER_CRITICAL(); events = task_active->events; task_active->events = SYS_EVE_NONE; OSAL_EXIT_CRITICAL(); if(events != SYS_EVE_NONE) { if(task_active->ops->handler != NULL) { ret_events = task_active->ops->handler(task_active->task_id,events); OSAL_ENTER_CRITICAL(); task_active->events |= ret_events; OSAL_EXIT_CRITICAL(); } } } }
}