3. GPIO与中断在工业信号采集中的应用

工业现场的数字量信号与消费电子中的按键有本质区别:它们往往来自24V直流回路,经过长线缆传输,伴随继电器触点抖动、感性负载反电动势、共模干扰和地电位差。STM32的GPIO引脚只能承受3.3V电平,因此从现场触点到达MCU引脚之间,必须经过电平转换与电气隔离。本节围绕“现场信号如何安全、可靠地变成MCU可读的数字状态”这一主线,讲清数字量输入输出、光耦隔离电路、外部中断配置、按键与限位开关采集、中断优先级管理和去抖动处理六个相互关联的问题。

数字量输入输出的电气边界

STM32的GPIO在输入模式下可配置为浮空、上拉、下拉或模拟输入;输出模式下可配置为推挽或开漏,并可选择2MHz、10MHz、50MHz等不同输出速度。工业采集里最常用的是“上拉输入”和“开漏输出”两种组合。

上拉输入用于干接点信号:MCU内部上拉约30k~50kΩ,触点闭合时引脚被拉到低电平,断开时被内部上拉拉高。这种方式的优点是接线简单,缺点是内部上拉电流小、抗干扰能力弱,长线缆上感应的干扰容易误触发。因此工程上更常见的做法是:引脚配置为浮空输入,外部在隔离侧提供上拉或下拉,由光耦的导通/截止决定引脚电平。

开漏输出用于驱动继电器、指示灯或与其它设备做“线与”逻辑。开漏输出只能拉低,不能主动拉高,必须外接上拉电阻。它的好处是输出电平由外部上拉电源决定,可以方便地实现3.3V到5V或24V的电平转换,也便于多个输出并联。

光耦隔离电路:现场与MCU之间的墙

光耦隔离的核心是用光传递信号,把现场侧和MCU侧的“地”彻底分开。以常见的PC817为例,其电流传输比CTR典型值为50%~600%,设计时要按最坏情况取最小值。假设现场侧为24V,光耦发光二极管正向压降约1.2V,希望导通电流为5mA,则限流电阻R=(24−1.2)/5mA≈4.56kΩ,取标准值4.7kΩ。此时实际电流约4.85mA,在CTR最差50%时,光敏三极管侧可提供约2.4mA的集电极电流。

接收侧通常采用“光耦集电极接MCU引脚,发射极接地,MCU引脚外接上拉电阻”的接法。当现场触点闭合、光耦导通时,MCU引脚被拉低;触点断开时,光耦截止,引脚被上拉电阻拉高。上拉电阻取4.7kΩ~10kΩ,太小会增加功耗,太大则上升沿变缓、易受干扰。若现场信号极性相反,可把光耦输出改为“集电极接上拉、发射极接MCU引脚”的射极跟随接法,但这种方式输出高电平会损失约0.7V,需确认MCU的VIH门限。

对于高速数字量信号,还要考虑光耦的响应时间。PC817的上升/下降时间在微秒级,若信号频率超过几十kHz,应改用6N137等高速光耦,并在输出侧加施密特触发器整形。

数字量输入通道:现场侧 → 光耦隔离 → MCU侧 现场侧(24V) 限位开关 / 触点 R 4.7kΩ 24V 回路 光耦 PC817 CTR ≥ 50% 电气隔离带 MCU侧(3.3V) R 10kΩ STM32 GPIO 浮空输入 / EXTI EXTI → NVIC 触点闭合 → 光耦导通 引脚拉低 → 触发中断

外部中断配置与边沿选择

STM32的EXTI(外部中断/事件控制器)可以把GPIO引脚上的电平跳变映射为中断请求。配置流程通常是:使能GPIO和AFIO时钟,把引脚配置为输入模式,通过AFIO_EXTICR寄存器把EXTI线映射到具体端口,再设置触发边沿(上升沿、下降沿或双边沿),最后在NVIC中使能对应的中断通道并设置优先级。

边沿选择直接决定采集行为。限位开关用于检测“到达位置”时,通常选下降沿或上升沿中的一种,取决于光耦输出极性;若需要同时捕捉“进入”和“离开”两个事件,则选双边沿。按键类信号若选双边沿,一次按下和一次释放会产生两次中断,需要在软件中区分。

一个常见误区是把EXTI当成“电平检测”。EXTI只在边沿到来时产生一次请求,如果信号在中断服务函数执行期间一直保持有效电平,不会再次触发。因此对于“持续按下”的状态,必须在ISR中读取引脚电平或使用定时器轮询来确认。

按键与限位开关的采集差异

按键和限位开关虽然都是机械触点,但工程处理重点不同。按键关注的是“人机交互的确定性”:一次按下只应产生一次有效动作,抖动时间通常5~20ms。限位开关关注的是“安全与位置”:它可能作为运动控制的停止信号,响应延迟直接影响设备安全,因此往往要求中断响应尽可能快,且去抖动不能引入过大延迟。

对于限位开关,推荐做法是:硬件上在光耦输出侧并联100nF电容做初步滤波,软件上在ISR中只做“置标志位”这一件小事,把去抖动和状态确认放到主循环或定时器任务中。这样中断服务函数执行时间可控制在几微秒,不会阻塞其它中断。

中断优先级管理

STM32的NVIC支持抢占优先级和子优先级。抢占优先级高的中断可以打断正在执行的低抢占优先级ISR;子优先级只在多个中断同时挂起时决定谁先执行,不能抢占。工业采集里通常这样分配:

  • 限位开关、急停等安全相关信号:抢占优先级最高(如0),确保第一时间响应。
  • 编码器、高速计数:抢占优先级次高(如1),避免丢脉冲。
  • 普通按键、指示灯状态:抢占优先级较低(如3~5),允许被安全信号打断。
  • 通信接收中断:根据协议实时性要求放在中间层级,避免长时间阻塞导致丢包。

优先级数值越小,优先级越高。配置时要注意:同一个EXTI线不能同时映射到两个端口;如果多个引脚共用一条EXTI线,需要在ISR中读取引脚状态来区分来源。

去抖动处理:硬件与软件的配合

去抖动不是“加个延时”这么简单。硬件去抖动的目标是让光耦输出侧的电平变化足够干净,常用手段是并联电容和施密特触发器。软件去抖动则要区分“中断触发”和“状态确认”两个阶段。

一种可靠的中断去抖动结构是:ISR中记录时间戳并置位“待确认”标志,然后启动一个10ms的单次定时器;定时器到期后再读取引脚电平,若与上次稳定状态不同,才更新状态并执行动作。这样既不会在ISR中长时间延时,又能过滤掉抖动。对于限位开关,可以把确认时间缩短到2~3ms,兼顾安全响应速度。

如果使用HAL库,EXTI回调函数是HAL_GPIO_EXTI_Callback(),注意它是在中断上下文中执行的,不要在里面调用HAL_Delay()或任何阻塞函数。

一个可参考的采集参数配置

以下是一组面向24V工业数字量输入的示例参数,可作为设计起点,实际需根据光耦型号、线缆长度和现场干扰强度调整:

项目示例值说明
现场电压24V DC工业标准数字量电平
光耦型号PC817CTR最差按50%计算
限流电阻4.7kΩ导通电流约4.85mA
输出上拉10kΩ兼顾功耗与上升沿
硬件滤波电容100nF并联在光耦输出侧
软件去抖时间10ms(按键)/ 3ms(限位)定时器确认方式
EXTI触发边沿下降沿对应光耦导通拉低
NVIC抢占优先级限位0,按键4数值越小优先级越高

把这组参数落到代码里,核心配置大致如下:

// GPIO与EXTI配置(以PA0为例,限位开关)
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_0;
gpio.Mode = GPIO_MODE_IT_FALLING;   // 下降沿触发
gpio.Pull = GPIO_NOPULL;            // 外部已有上拉
HAL_GPIO_Init(GPIOA, &gpio);

// NVIC优先级:抢占0,子优先级0
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);

// 中断回调:只置标志,不做延时
void HAL_GPIO_EXTI_Callback(uint16_t pin)
{
    if (pin == GPIO_PIN_0) {
        limit_pending = 1;          // 待确认标志
        debounce_start_ms = HAL_GetTick();
    }
}

主循环中再根据limit_pending和经过的时间做状态确认,确认后清除标志并执行限位动作。这样中断响应时间短,去抖动逻辑清晰,也便于后续把状态确认迁移到RTOS任务中。

整体来看,工业数字量采集的可靠性来自三层配合:光耦隔离解决电气安全与共模干扰,EXTI与NVIC解决响应实时性与优先级,硬件电容加软件定时确认解决触点抖动。三者缺一不可,任何一层被简化,都可能在现场表现为误触发、丢信号或响应迟滞。