在小型單片機項目開發初期,由于業務邏輯相對簡單,我們往往較少關注程序架構層面的設計。
然而隨著項目經驗的積累,開發者會逐漸意識到模塊間的耦合問題:當功能迭代時,一處修改可能引發連鎖反應。
此時,構建松耦合的軟件架構便成為提升系統擴展性的關鍵。
當前的代碼框架采用了一種基于全局變量的解耦設計模式。各模塊函數僅依賴底層驅動接口,無需跨模塊調用其他功能函數,而是通過修改特定標志位傳遞狀態信息。系統借助時間片輪詢機制,在每個調度周期內由輸出函數統一解析標志位狀態,據此決定執行邏輯或輸出動作。
這種設計有效隔離了模塊間的直接依賴,使得代碼維護與功能擴展更為靈活。
松耦合設計的核心特征
1. 全局變量驅動的通信機制
通過統一的狀態標識實現模塊間信息交互:
- 狀態控制:
lock_flag
?作為門鎖狀態標志,被解鎖模塊、報警模塊等共同讀寫; - 模式切換:
mode
?變量定義系統工作模式(如待機、運行、調試),供電源管理、數據采集等模塊動態調用; - 異常追蹤:
password_error
?記錄密碼錯誤次數,聯動提示音模塊、鎖定計時模塊觸發對應邏輯。
2. 任務調度的隔離性
各核心任務(如?key_proc()
?按鍵處理、lcd_proc()
?屏幕刷新、as608_proc()
?指紋識別)遵循 “獨立執行” 原則:
- 無交叉調用:任務間僅通過調度器分配的時間片(如 10ms / 次)輪詢激活,避免函數嵌套帶來的耦合風險;
- 職責單一:每個任務專注處理專屬功能,如?
lcd_proc()
?僅負責界面渲染,不涉及其他模塊的業務邏輯。
3. 中斷服務的原子性
- 串口中斷:各串口(UART1/2/3)中斷函數獨立解析接收數據,更新對應緩沖區全局變量(如?
uart1_rx_buf
),不介入其他模塊控制; - 定時器中斷:周期性刷新系統時鐘、采樣間隔等基礎變量(如?
tick_count
),與業務邏輯解耦,確保時序穩定性。
架構設計的顯著優勢
1. 高度模塊化開發
- 并行協作:開發團隊可獨立調試單個模塊(如單獨測試指紋識別算法),無需依賴完整系統環境;
- 敏捷擴展:新增功能(如藍牙通信模塊)僅需編寫獨立任務函數并注冊至調度器,零侵入式集成。
2. 低風險維護特性
- 修改隔離:調整?
lock_flag
?的邏輯判斷條件時,僅需驗證門鎖模塊,不影響 LCD 顯示或串口通信功能; - 精準調試:通過監控全局變量(如?
password_error
?計數),可快速定位異常狀態,降低調試復雜度。
3. 嵌入式場景適配性
- 資源優化:減少函數調用棧深度,避免因嵌套調用導致的內存溢出風險,適合 RAM/ROM 受限的 MCU(如 STM32F103);
- 簡化同步:通過全局變量與時間片輪詢替代復雜的鎖機制或信號量,降低多任務協作的開發成本
舉個實際的例子:
在我定義的門鎖控制函數中,整個項目上下僅僅只有定義,和在主函數中調用兩個地方引用,在其他函數中卻沒有被調用。那么 門鎖處理函數 是在什么時候知道他需要實現函數呢?
我們可以看到在函數內部,調用了自身驅動的底層函數,他的形參告訴了這個函數什么時候使用。
所以我們只需要在其他函數內部去修改形參這個全局變量就行。
如下圖是全局標志位:可以看到在多個函數內容被修改讀寫。
類似的處理,我們可以稍加修改,在函數內部用判斷的方式來決定什么時候開什么時候關。
同理lock_flag 作為全局變量 被其他任意函數讀寫和修改,而lock_proc() 只需要做好判斷這個標志位并且執行對應操作就行。
那什么時候執行呢,當時是開始運行這個函數的時候,那問題又來了,什么時候運行呢。
這里我使用的是時間片輪詢的方式進行任務調度。
void lock_proc() //門鎖處理函數
{if(lock_flag==1){lock(1); //開舵機}else{lock(0); //關舵機}}
-
業務邏輯大致可以分為兩個部分,但是其實沒有很必要去根據這個再去分層,因為上述的邏輯框架已經很清晰
輸入處理應該包含 :- 硬件層面的輸入獲取
- 輸入數據的預處理(如按鍵消抖)
- 核心業務邏輯處理
- 狀態標志位的設置
- 輸出處理應該包含 :- 狀態標志位的檢查
- 簡單的顯示邏輯(如格式化)
- 硬件輸出控制