跳到正文

GPIO、定时器与中断

本文性质声明:本机无开发板,全部内容未实测,为手册级框架。站内对照:conc-mutex(临界区与数据竞争实测)、os-scheduling(优先级与调度延迟)、c-restricted-environment-and-volatile(volatile 与寄存器)。

一、GPIO 的输出模式:推挽 vs 开漏

模式行为用途
推挽(push-pull)输出强 0 或强 1,能灌/拉电流驱动 LED、MOS 管、电平信号
开漏(open-drain)只能拉低或浮空(高阻)线与(多设备共享一根线)、电平转换(上拉电阻到目标电平)、I2C

开漏 + 上拉的三个场合:多主共享总线(I2C/1-Wire)、电平不匹配(3.3V MCU 驱动 5V 传感器:开漏 + 上拉到 5V,MCU 只拉低——本站 win-audio 量过的跨电压场景的 GPIO 版)、以及”断电时不让它拖累总线”。

输入侧:上拉/下拉/浮空三选一。浮空输入在干扰下乱跳(CMOS 输入阻抗极高,天线效应)——没用到的引脚也要配:要么上拉、要么模拟模式,这是低功耗和 EMC 的共同要求。施密特触发输入能消抖,但别依赖它做按键消抖(第二节)。

二、按键消抖:硬件与状态机两条路

机械触点的弹跳持续 1–20ms——不处理就是一次按下被读成多次。

硬件三法:RC 低通 + 施密特触发器(经典,省软件)、专用消抖芯片、MCU 内置的数字滤波器(有的定时器有输入滤波配置)。软件两法:

  1. 延时法(简单粗暴):检测到按下 delay(20ms) 再读——阻塞式,浪费 CPU,只适合初始化或裸机小循环。
  2. 状态机法(推荐):定时器(如 5ms tick)里采样,用计数窗口确认:
// 每 5ms 调一次:连续 4 次同状态才认为稳定
if (raw == last_raw) { if (cnt < 4) cnt++; }
else { cnt = 0; last_raw = raw; }
if (cnt == 4) report_stable(last_raw);   // 消抖后的稳定状态

状态机法还能直接带上长按/连发/组合键:稳定为按下后开始计时,>1s 报长按、之后每 200ms 报连发——旋钮和键盘的手感全靠这层。中断 + 定时器窗口的组合(中断唤醒、定时器确认)兼顾低功耗和可靠。

三、定时器:计数、PWM、捕获

通用定时器的三种用法,都建立在”预分频器 + 自动重装载计数器”上:

  1. 基本计数/时基:PSC 分频时钟,ARR 定周期——整个系统的心跳(RTOS 的 tick、消抖窗口、超时计时)。SysTick 是 Cortex-M 内置的专用时基(24 位递减),RTOS 通常优先用它。
  2. PWM:CNT < CCR 输出一种电平、反之另一种——占空比 = CCR/ARR。三板斧:中心对齐 vs 边沿对齐(电机控制关心)、死区(半桥上下管不能同时导通——高级定时器的互补输出+死区插入就是为它)、分辨率陷阱(ARR 定小了占空比调不细,电机高频啸叫的常见原因)。
  3. 输入捕获:记录外部事件发生时的 CNT 值——测频率/占空比/脉宽。测高频用间接法:两个捕获边沿的差值 ÷ 时钟频率。超声波测距、红外解码、编码器读数都走这条路。正交编码器接口(QEI,有的定时器带)把 A/B 相的解码也硬件化了。

定时器的 DMA 联动是性能分水岭:PWM 的 CCR 数组用 DMA 自动搬运(波形合成不占 CPU)、ADC 结果用 DMA 收(emb-adc 会展开)。

四、中断优先级:分组、嵌套与临界区

NVIC 的优先级机制(emb-mcu 提过数值小=优先级高):

  1. 抢占优先级 vs 子优先级:NVIC_SetPriorityGrouping 把 8 位优先级切成两段。抢占优先级决定嵌套(高的打断低的),子优先级只决定同抢占级时的排队(不嵌套)。分组设错 = “明明配了优先级却看到中断嵌套了”。
  2. 优先级位数由芯片定:M3 常见可配 4 位(16 级),M0 只有 2 位——移植代码时别假设级数。
  3. 同优先级不嵌套:低抢占级的中断处理中,同级的后来者排队——临界区的黄金窗口:把”读改写共享变量”的中断源临时降到比使用者低一档,或用 __disable_irq() 包住几个指令。

临界区的三条军规:能短必短(本站实测过:一次条件变量唤醒 11.35µs = 186 次原子自旋交接——中断里做的事要按这个尺度掂量);中断里不能等锁(等 = 死等,持锁的中断处理进不来);ISR 和任务共享的数据,要么 volatile + 单字访问,要么关中断保护复合操作(本站 c-restricted-environment 与 conc-mutex 分别从语言和并发侧讲过)。

五、排障索引

症状入口
按键一次触发多次没消抖(第二节);或消抖阈值低于弹跳时长
PWM 高频啸叫ARR 太小分辨率不足;死区没配(半桥)
测频在高频时偏低捕获中断处理太慢漏边沿;改用 DMA/定时器从模式
中断优先级不生效分组理解错(子优先级不嵌套);位数配超了被截断
偶发死机中断里调了会阻塞的东西;临界区里嵌套了中断改共享数据
低功耗下电流大IO 浮空、定时器时钟没关(emb-lowpower)

六、未实测清单

  • 本文所有 GPIO/定时器行为——无开发板,未测。
  • 具体型号的寄存器与中断级数——以你的 Reference Manual 为准。
  • 消抖/PWM 的实测效果——未测。
  • 用户 Linux 开发机上的 RV1103 项目外设——该机不可达,未涉及。