当前位置: 首页 > news >正文

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.lryc.cn/news/589531.html

相关文章:

  • MyBatis与Spring整合优化实战指南:从配置到性能调优
  • Conda 核心命令快速查阅表
  • 系统编程是什么
  • 22-C#的委托简单使用-2
  • ai问答推荐企业排名优化?:五大企业核心竞争力全景对比
  • 从0开始学习R语言--Day47--Nomogram
  • 【51单片机先流水2秒后数码显示2秒后显示END】2022-9-5
  • 判断QMetaObject::invokeMethod()里的函数是否调用成功
  • 密码协议的基本概念
  • 【Linux手册】重定向是如何实现的?Linux下为什么一切皆文件?
  • 【env环境】rtthread5.1.0使用fal组件
  • npm install failed如何办?
  • 差分信号接口选型指南:深入解析LVDS、SubLVDS、SLVDS与SLVDS-EC**
  • 回顾一下Docker的基本操作
  • 项目:从零开始制作一个微信小程序(第六天)
  • 专业文档搜索工具,快速定位文本内容
  • Spring AI Alibaba 1.0 vs Spring AI 深度对比
  • EPLAN 电气制图(九):直流电源绘制+端子排绘制
  • 3.创建表-demo
  • 深入解析环境变量:从基础概念到系统级应用
  • 墨刀原型图的原理、与UI设计图的区别及转换方法详解-卓伊凡|贝贝
  • TypeScript之旅
  • 基于STM32与中航ZH-E3L字符卡通信在LED屏显示数据
  • ArrayList列表解析
  • [附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+vue实现的酒店预订管理系统,推荐!
  • Nestjs框架: 数据库架构设计与 NestJS 多 ORM 动态数据库应用与连接池的配置
  • 缓存穿透的“黑暗森林”假说——当攻击者学会隐藏恶意流量
  • 园区用电成本直降方案:智能微网调控系统一键峰谷优化
  • PHP语法高级篇(三):Cookie与会话
  • OSPF过滤