當(dāng)單片機(jī)遇到狀態(tài)機(jī)——入門QP
前言
前些日子在微信上看到李肖遙的公眾號,里面系統(tǒng)講述了QP框架,我很有感觸。我用QP框架很多年了,一開始是使用QM和QPC ,到后來拋棄了QM,直接使用QPC裸寫程序,到后來自己寫狀態(tài)機(jī)框架。
- 入門QP
- 從switch-case到框架的進(jìn)化
- QP的高階使用和QM的使用
- QP的哲學(xué)
- 其他
入門QP
我們學(xué)習(xí)一個(gè)語言,或者一項(xiàng)技術(shù),第一件要做的事情,就是實(shí)現(xiàn)一個(gè)類似于Hello world的最小程序。在單片機(jī)上,當(dāng)然就是LED燈的閃爍。不說廢話了,先上代碼。
代碼結(jié)構(gòu)
代碼結(jié)構(gòu),可以在Keil工程中看到,是一個(gè)QP的運(yùn)行最小系統(tǒng)。QP版本使用的是最新的V6.9.3版本。
-
main.c 包含了硬件的初始化、QP框架的初始化、各狀態(tài)機(jī)模塊(暫定稱呼,嚴(yán)謹(jǐn)應(yīng)叫AO模塊)的構(gòu)建,框架的啟動等一系列流程。
-
bsp.c 硬件初始化,此處僅包含SysTick的初始化和SysTick中斷函數(shù)。
-
ao_led.c LED狀態(tài)機(jī)的源碼。
-
hook.c QP框架的回調(diào)函數(shù)的實(shí)現(xiàn),此處都為空函數(shù),暫時(shí)不予實(shí)現(xiàn)。
-
evt_def.h 事件的定義。QP框架的事件定義,使用枚舉實(shí)現(xiàn)。個(gè)人覺得,事件的定義,如果用字符串實(shí)現(xiàn),更加有利于模塊的解耦和對分布式的支持(這個(gè)問題可參考后續(xù)的博客《將軟總線進(jìn)行到底》)。QP使用枚舉來定義事件,個(gè)人認(rèn)為是為了降低RAM和CPU的開銷。
-
其他
- QP源碼
- QP接口代碼
- QP框架對硬件平臺或者RTOS的接口源碼。
- MCU相關(guān)代碼,包含Startup文件、CMSIS相關(guān)、固件庫相關(guān)代碼
QP的啟動流程
以下代碼就是QP框架的啟動過程。
#include "evt_def.h" // 事件定義頭文件
#include "bsp.h" // 硬件初始化
#include "ao_led.h" // LED狀態(tài)機(jī)
Q_DEFINE_THIS_MODULE("Main") // 定義當(dāng)前的模塊名稱,此名稱在QS和斷言中會使用。
ao_led_t led; // 狀態(tài)機(jī)LED對象
int main(void)
{
static QSubscrList sub_sto[MAX_PUB_SIG]; // 定義訂閱緩沖區(qū)
static QF_MPOOL_EL(m_evt_t) sml_pool_sto[128]; // 定義事件池
QF_init(); // 狀態(tài)機(jī)框架初始化
QF_psInit(sub_sto, Q_DIM(sub_sto)); // 發(fā)布-訂閱緩沖區(qū)的初始化
QF_poolInit(sml_pool_sto, // 事件池的初始化
sizeof(sml_pool_sto),
sizeof(sml_pool_sto[0]));
ao_led_ctor(