STM32裸機開發(中斷,輪詢,狀態機)與freeRTOS

  • 裸機:沒有操作系統,程序是單流程的(比如一個大循環里依次執行各個功能,或者用中斷嵌套處理事件)。優點是資源占用極少(幾乎不占 RAM/Flash)、執行流程直觀;但復雜項目里,多個功能(比如同時處理傳感器、通信、顯示)會互相阻塞,邏輯容易混亂(比如一個耗時的操作會卡住其他功能)。

  • 比如長期做單一類型的裸機項目(比如只寫循環 + 中斷的控制邏輯),可能會對復雜系統的任務管理、資源調度、多模塊協同這些 “上層設計” 接觸較少;遇到需要同時處理多個實時性任務時(比如一邊高速采數、一邊通信、一邊控外設),純裸機邏輯會越寫越繞,這時候可能會覺得 “效率低”。

? ? ? 裸機開發離不開中斷,輪詢,狀態機,假如將狀態機放在中斷里,1ms觸發一次,中斷中時間片調度仍有其他任務,功能簡單沒有大的問題,一旦功能復雜,無論是在中斷中即執行又判斷,還是中斷中只判斷,將執行放在了主函數,實時性將變得非常差,耦合性會很強,即使放在主函數中執行進行模塊分裝,仍然不便于維護。其次,用輪詢標志位去實現變量同步,代碼量大的情況下邏輯會非常繞。即使可以用 結構體+隊列 去完成任務解耦,利用緩沖特性去緩沖一些像閾值判斷,解決延遲和滯后問題,但本身這樣做已經再向架構思想,輕量級的RTOS靠近了。裸機開發也有架構思想(事件驅動架構,消費者-生產者架......),項目爛尾,其實就是沒有架構思想。RTOS內功玩的就是架構。

一.中斷中只做 “判斷和標記”,主循環中做 “執行”?

初始化系統 → 啟動定時器 → 進入主循環(輪詢標志位)│▼等待定時器溢出│▼觸發TIM2中斷│執行ISR:1. 清除硬件中斷標志2. 設置timerFlag = true│退出ISR,返回主循環│主循環檢測到timerFlag = true│1. 清除timerFlag = false2. 執行process_timer_event()│繼續主循環(等待下一次事件)

二.中斷中即判斷也執行

┌───────────────┐
│ ? 系統初始化 ? │  →  配置定時器、中斷使能、GPIO等(僅執行一次)
└───────┬───────┘↓
┌───────────────┐
│ ? 啟動定時器 ? │  →  定時器開始計數,主循環進入空閑/其他任務
└───────┬───────┘↓
┌───────────────┐
│ ? 主循環運行 ? │  →  執行非中斷相關任務(如傳感器采樣、顯示刷新)
└───────┬───────┘│▼(定時器溢出時觸發)
┌───────────────┐
│  進入TIM2中斷  │  →  CPU暫停主循環,轉去執行中斷服務程序
└───────┬───────┘↓
┌───────────────┐
│ 判斷中斷來源 ? │  →  檢查是否為定時器溢出(TIM_GetITStatus)
└───────┬───────┘├─ 否 → 退出中斷,返回主循環│▼ 是
┌───────────────┐
│ 清除硬件標志 ? │  →  清除定時器中斷標志(TIM_ClearITPendingBit)
└───────┬───────┘↓
┌───────────────┐
│ 直接執行任務 ? │  →  例如:LED_Toggle()(僅耗時極短的操作)
└───────┬───────┘↓
┌───────────────┐
│ 退出中斷服務 ? │  →  CPU返回主循環,繼續執行被中斷的任務
└───────┬───────┘↓
(回到主循環,等待下一次中斷)

簡單示例:

一.標志位

#include "stm32f10x.h"
?
// 共享標志位
volatile bool timerFlag = false;
?
// 定時器中斷服務程序(僅設置標志位)
void TIM2_IRQHandler(void) {if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除硬件中斷標志timerFlag = true;  // 設置軟件標志位}
}
?
// 主循環(輪詢標志位并執行任務)
int main(void) {// 系統初始化(省略)...while (1) {if (timerFlag) { ? ?  // 檢查標志位timerFlag = false;  // 清除標志位LED_Toggle(); ? ? // 翻轉LED狀態}// 執行其他任務...}
}

二.直接中斷執行

// 定時器中斷服務程序(直接執行任務)
void TIM2_IRQHandler(void) {if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除硬件中斷標志// 直接在中斷中執行任務(無需標志位)LED_Toggle();  // 翻轉LED狀態(假設此函數僅操作GPIO,耗時極短)}
}
?
// 主循環(無需輪詢標志位)
while (1) {// 其他任務...(不受定時器事件影響)
}

比較:

特性中斷內直接執行標志位 + 主循環執行
中斷服務程序 (ISR)完成判斷 + 執行(如翻轉 LED)僅設置標志位(輕量化)
主循環無需處理定時器事件輪詢標志位并執行任務
中斷響應時間短(直接完成任務)稍長(需等待主循環輪詢)
主循環實時性可能受影響(ISR 執行時主循環暫停)不受影響(ISR 快速返回)
任務復雜度限制僅支持極簡單任務(如 GPIO 操作)可處理復雜任務(如數據計算、通信)

總結:

  • 標志位是 “中斷輕量化” 的工具:通過分離 “事件檢測” 和 “事件處理”,保證中斷快速響應,主循環有序執行。

  • 中斷內直接執行的適用場景有限:僅適合極簡單任務,復雜任務必須避免,否則會破壞系統穩定性。

  • 實際開發中,優先用 “中斷設標志 + 主循環處理”,除非能確保任務耗時足夠短(通常建議 ISR 執行時間不超過中斷周期的 10%)。

三:狀態機

中斷僅僅作為狀態機的觸發器,在嵌入式系統中,中斷確實可以僅作為狀態機的觸發器,這種設計模式能有效分離 “事件檢測” 和 “事件處理”,提升系統的穩定性和可維護性。

一、核心設計思想

中斷的唯一職責:檢測特定事件(如定時器溢出、按鍵按下),并通過標志位通知狀態機。 狀態機的唯一職責:在主循環中根據標志位執行對應邏輯,完成狀態轉移。

優勢

  • 中斷輕量化:中斷服務程序(ISR)執行時間極短,避免阻塞其他中斷。

  • 邏輯解耦:狀態機邏輯與硬件中斷分離,便于修改和測試。

  • 可擴展性:可輕松添加新的中斷源和狀態,無需修改核心邏輯。

  • FreeRTOS作為輕量級 RTOS,本質是在裸機基礎上增加了 “任務調度器”,讓程序能像 “多線程” 一樣運行 —— 把復雜功能拆成多個獨立任務,由系統自動分配 CPU 時間。優點是任務間解耦,高優先級任務能及時響應(比如緊急報警);但會占用少量資源(比如幾十 KB RAM),且需要理解任務調度、同步等概念。

  • 實時操作系統(RTOS):專門用于實時控制的操作系統,能保證任務在規定時間內響應(比如工業控制中,傳感器數據必須在 10ms 內處理),FreeRTOS 就是輕量級 RTOS 的典型。
  • 任務(Task):系統中最小的執行單元,類似 “線程”,每個任務有獨立的棧空間和運行狀態(就緒、運行、阻塞等)。比如智能手表中,“顯示時間”“檢測觸摸”“計步” 就是不同任務。
  • 優先級(Priority):任務的重要程度標識(FreeRTOS 中數值越大優先級越高)。高優先級任務能打斷低優先級任務,比如無人機的 “避障任務” 優先級必須高于 “數據上傳任務”,否則可能撞機。
  • 調度器(Scheduler):RTOS 的核心組件,負責決定哪個任務運行(基于優先級或時間片),FreeRTOS 用的是 “搶占式調度”(高優先級任務隨時插隊)。
  • 上下文切換(Context Switch):調度器切換任務時,保存當前任務的寄存器、棧指針等狀態,加載下一個任務的狀態,相當于 “暫停 A 任務,繼續 B 任務” 的過程,速度越快,系統響應越流暢。
  • 信號量(Semaphore):任務間同步的工具,類似 “通行證”。比如兩個任務共用一個傳感器,用信號量控制:一個任務拿到信號量才能讀取,讀完放回,避免沖突。
  • 隊列(Queue):任務間傳遞數據的 “緩沖區”,比如傳感器任務采集到數據,通過隊列發給處理任務,支持異步通信(發送方不用等接收方立即處理)。
  • FreeRTOS 更適合的場景

  • 多任務并發且有優先級區分
    比如一個設備需要同時處理:傳感器數據采集、屏幕顯示、藍牙通信、電機控制,且某些任務必須優先響應(如電機故障檢測要比屏幕刷新緊急)。FreeRTOS 的搶占式調度能讓高優先級任務及時運行,避免裸機中 “一個任務卡殼導致全局癱瘓” 的問題。
  • 任務間需要靈活通信 / 同步
    當任務間需要傳遞數據(如傳感器任務給處理任務發數據)或協調操作(如兩個任務共用一個外設),FreeRTOS 的隊列、信號量等機制能簡化邏輯,而裸機需要手動設計狀態機或全局變量,容易出錯。
  • 系統未來可能擴展功能
    如果項目初期簡單,但后期可能增加更多模塊(如從單一傳感器擴展到多傳感器 + 聯網功能),用 FreeRTOS 能降低后期維護和擴展的難度,任務模塊化設計更清晰。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91297.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91297.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91297.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

電腦上如何查看WiFi密碼

打開控制面板>點擊網絡和Internet在查看網絡和共享中心找到網絡狀態和任務點擊進去點擊連接的WLAN在WLAN狀態中點擊無線屬性在無線網絡屬性中點擊安全,點擊顯示字符(H)就可以顯示密碼了

文心一言4.5企業級部署實戰:多模態能力與Docker容器化測評

隨著大語言模型在企業服務中的應用日益廣泛,如何選擇一款既能滿足多模態創作需求,又具備良好企業級適配性的AI模型成為了關鍵問題。文心一言4.5作為百度最新開源的大模型,不僅在傳統的文本處理上表現出色,更是在多模態理解和企業級…

VUE Promise基礎語法

目錄 異步和同步 異步的問題 new Promise語法 promise的狀態 promise.then() Promise.resolve() Promise.reject() Promise.all() Promise.race() Promise.catch() Promise.finally() 異步和同步 同步模式下,代碼按順序執行,前一條執行完畢后…

用TensorFlow進行邏輯回歸(六)

import tensorflow as tfimport numpy as npfrom tensorflow.keras.datasets import mnistimport time# MNIST數據集參數num_classes 10 # 數字0到9, 10類num_features 784 # 28*28# 訓練參數learning_rate 0.01training_steps 1000batch_size 256display_step 50# 預處…

【HTTP版本演變】

在瀏覽器中輸入URL并按回車之后會發生什么1. 輸入URL并解析輸入URL后,瀏覽器會解析出協議、主機、端口、路徑等信息,并構造一個HTTP請求(瀏覽器會根據請求頭判斷是否又HTTP緩存,并根據是否有緩存決定從服務器獲取資源還是使用緩存…

Android 16系統源碼_窗口動畫(一)窗口過渡動畫層級圖分析

一 窗口過渡動畫 1.1 案例效果圖1.2 案例源碼 1.2.1 添加權限 (AndroidManifest.xml) <!-- 系統懸浮窗權限&#xff08;Android 6.0需動態請求&#xff09; --> <uses-permission android:name"android.permission.SYSTEM_ALERT_WINDOW" />1.2.2 窗口顯示…

騰訊云WAF域名分級防護實戰筆記

基于業務風險等級、合規要求及騰訊云最佳實踐&#xff0c;提供可直接落地的配置方案&#xff0c;供學習借鑒&#xff1a;一、域名分級與防護原則1. ?域名分級清單&#xff08;核心資產&#xff09;???主域名??業務類型??風險等級??合規要求??防護等級?example.com…

1. 請說出你知道的水平垂直居中的方法

總結 容器 flex 布局&#xff0c;jsutify-content: center; align-items: center;容器 flex 布局&#xff0c;子項 margin: auto;容器 relative 布局&#xff0c;子項 absolute 布局&#xff0c;left: 50%; top: 50%; transform: translate(-50%, -50%);子項 absolute 布局&…

VS Code `launch.json` 完整配置指南:參數詳解 + 配置實例

文章目錄&#x1f4e6; 一、基本結構&#x1f50d; 二、單個配置項詳解示例配置&#xff1a;&#x1f9e9; 三、字段說明與可選值&#x1f4c1; 四、常用變量&#xff08;宏替換&#xff09;&#x1f6e0;? 五、常見配置實例1?? 調試當前打開的 .py 文件2?? 調試 Jupyter …

使用瀏覽器inspect調試wx小程序

edge://inspect/#devices調試wx小程序 背景&#xff1a; 在開發混合項目的過程中&#xff0c;常常需要在app環境排查問題&#xff0c;接口可以使用fiddler等工具來抓包&#xff0c;但是js錯誤就不好抓包了&#xff0c;這里介紹一種調試工具-瀏覽器。 調試過程 首先電腦打開edg…

【論文閱讀】-《Simple Black-box Adversarial Attacks》

簡單黑盒對抗攻擊 Chuan Guo Jacob R. Gardner Yurong You Andrew Gordon Wilson Kilian Q. Weinberger 摘要 我們提出了一種在黑盒&#xff08;black-box&#xff09;場景下構建對抗樣本&#xff08;adversarial images&#xff09;的極其簡單的方法。與白盒&#xff08;…

基于ASP.NET+SQL Server實現(Web)企業進銷存管理系統

企業進銷存管理系統的設計和實現一、摘要進銷存管理是現代企業生產經營中的重要環節&#xff0c;是完成企業資源配置的重要管理工作&#xff0c;對企業生產經營效率的最大化發揮著重要作用。本文以我國中小企業的進銷存管理為研究對象&#xff0c;描述了企業進銷存管理系統從需…

(LeetCode 面試經典 150 題 ) 15. 三數之和 (排序+雙指針)

題目&#xff1a;15. 三數之和 思路&#xff1a;排序雙指針&#xff0c;時間復雜度0(n^2nlogn)。 先將數組nums升序排序&#xff0c;方便去重和使用雙指針。第一層for循環來枚舉第一位數&#xff0c;后面使用雙指針來找到第二個、第三個數即可&#xff0c;細節看注釋。 C版本…

easy-springdoc

介紹 簡化springdoc的使用&#xff08;可以搭配knife4j-openapi3-jakarta-spring-boot-starter一起使用&#xff09; maven引用 <dependency><groupId>io.github.xiaoyudeguang</groupId><artifactId>easy-springdoc</artifactId><version>…

配置nodejs,若依

1.配置node.js環境 Node.js — Download Node.js 1.下載好一路下一步&#xff0c;可以安裝到d盤 裝完之后執行 npm -v 顯示版本號即安裝成功 2.安裝好后新建兩個文件夾&#xff0c;node_cache和node_global 3.配置環境變量 新建變量 在path里編輯變量 4.配置用戶變量 5.…

Python學習之路(十二)-開發和優化處理大數據量接口

文章目錄一、接口設計原則二、性能優化策略1. 數據庫優化2. 緩存機制3. 并發模型三、內存管理技巧1. 內存優化實踐2. 避免內存泄漏四、接口測試與監控1. 性能測試2. 日志與監控3. 錯誤處理與限流五、代碼示例&#xff08;Flask 流式處理&#xff09;六、部署建議一、接口設計原…

【實時Linux實戰系列】實時數據流的網絡傳輸

在實時系統中&#xff0c;數據流的實時傳輸是許多應用場景的核心需求之一。無論是工業自動化中的傳感器數據、金融交易中的高頻數據&#xff0c;還是多媒體應用中的視頻流&#xff0c;都需要在嚴格的時間約束內完成數據的傳輸。實時數據流的傳輸不僅要求高吞吐量&#xff0c;還…

C#數組(一維數組、多維數組、交錯數組、參數數組)

在 C# 中&#xff0c;數組是一種用于存儲固定大小的相同類型元素的集合。數組可以包含值類型、引用類型或對象類型的元素&#xff0c;并且在內存中是連續存儲的。以下是關于 C# 數組的詳細介紹&#xff1a;1. 一維數組聲明與初始化// 聲明數組 int[] numbers; // 聲…

Dify離線安裝包-集成全部插件、模板和依賴組件,方便安可內網使用

項目介紹 Dify一鍵離線安裝包&#xff0c;集成安裝了全部插件、模板&#xff0c;并集成了dify全部插件所需的依賴組件。方便你在內網、安可環境等離線狀態下使用。 Dify是一個開源的LLM應用開發平臺。其直觀的界面結合了AI工作流、RAG管道、Agent、模型管理、可觀測性功能等&…

面試150 翻轉二叉樹

思路 采用先序遍歷&#xff0c;可以通過新建根節點node&#xff0c;將原來root的右子樹連到去node的左子樹中&#xff0c;root的左子樹連到去node的右子樹中。 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): …