3、软件限位逻辑基础:基于GPIO中断的限位检测、轮询模式与中断模式对比、去抖动的必要性
限位检测,说白了就是让单片机知道「机械结构走到头了」。这个信号通常来自一个机械开关或者光电传感器,通过GPIO电平变化告诉CPU。嗯,这里要注意,信号本身很简单,但怎么去读它、什么时候去读它,这里面的门道可不少。
3.1 两种检测模式:轮询 vs 中断
我个人习惯把这两种模式比作「盯梢」和「被通知」。你想想看,轮询就是CPU一直盯着那个引脚看,每隔一小会儿就问一句「变了吗?变了吗?」。而中断模式呢,是让引脚自己喊一嗓子:「嘿,我变了!」。
我在项目中遇到过不少新手,上来就用轮询,结果CPU大部分时间都在空转。其实这两种方式各有适用场景,我整理了一个对比表,你一看就明白:
| 对比项 | 轮询模式 | 中断模式 |
|---|---|---|
| CPU占用率 | 高(持续占用) | 低(事件触发) |
| 响应延迟 | 取决于轮询周期 | 微秒级响应 |
| 代码复杂度 | 简单直观 | 稍复杂(需处理嵌套) |
| 适用场景 | 低速、非实时系统 | 高速、实时性要求高 |
| 功耗 | 高(CPU无法休眠) | 低(可进入低功耗) |
说白了,如果你的电机转速很慢,限位开关动作间隔几百毫秒,轮询完全够用。但如果是高速运动控制,比如伺服电机,那必须用中断,否则等你轮询到信号,机械结构可能已经撞坏了。
3.2 基于GPIO中断的限位检测实现
中断模式的实现,核心就三步:配置GPIO、使能中断、写中断服务函数。我拿STM32举个例子,这是我最常用的配置方式:
// 限位开关中断配置(以PA0为例)
void LimitSwitch_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 1. 使能GPIO时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
// 2. 配置为输入,上拉
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 下降沿触发
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 3. 使能NVIC中断
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
// 中断服务函数
void EXTI0_IRQHandler(void)
{
// 检查中断标志
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET)
{
// 清除中断标志(必须!)
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
// 设置限位触发标志
g_limit_triggered = 1;
// 记录触发时间戳(用于去抖动)
g_limit_timestamp = HAL_GetTick();
}
}
3.3 去抖动的必要性
为什么需要去抖动?你想想看,机械开关在闭合或断开的瞬间,触点会弹跳几次。这个弹跳时间通常持续5-20ms。如果不做处理,一次限位动作可能会触发几十次中断。
我在项目中遇到过最夸张的一次,一个微动开关弹跳了将近30ms,触发了47次中断。电机每收到一次中断就反转一次,结果电机在原地疯狂抖动,差点把机械结构震散架。
去抖动的常用方法有两种:
- 硬件去抖:RC低通滤波 + 施密特触发器。简单粗暴,但需要额外元件。
- 软件去抖:延时采样或时间戳过滤。零成本,灵活可控。
我个人更推荐软件去抖,因为改参数方便。下面是我常用的时间戳去抖方案:
// 主循环中处理限位逻辑
void LimitSwitch_Process(void)
{
if(g_limit_triggered)
{
// 去抖动:检查是否已经稳定超过20ms
if((HAL_GetTick() - g_limit_timestamp) > DEBOUNCE_MS)
{
// 再次读取GPIO确认状态
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
{
// 确认限位触发,执行动作
Motor_Stop();
g_limit_active = 1;
}
// 清除触发标志
g_limit_triggered = 0;
}
}
}
3.4 知识体系总览
为了让你对整个限位检测逻辑有个全局认识,我画了一张流程图。这张图把轮询和中断两条路径都串起来了:
🔑 核心要点总结:
- 轮询模式适合低速场景,代码简单但浪费CPU
- 中断模式响应快,但ISR里只能做轻量操作
- 去抖动是必须的,20ms时间戳过滤是最实用的方案
- 无论哪种模式,最终都要二次确认GPIO状态,防止误触发
嗯,到这里限位检测的基础逻辑就讲完了。你可能会问,去抖时间设多少最合适?其实没有标准答案,跟你的开关型号、机械振动环境都有关系。我的建议是:先设20ms跑起来,然后用示波器抓一下开关波形,看看实际弹跳时间,再微调参数。这样最靠谱。