2、基础知识:掌握STM32基本外设(GPIO、定时器、ADC、中断)在异常保护中的应用基础
机器人异常保护系统的实现,本质上是对单片机(MCU)输入信号进行实时采集、逻辑判断与快速执行的过程。STM32作为机器人主控的核心,其GPIO、定时器、ADC和中断四大基本外设,构成了异常保护机制的物理基础。本章将深入剖析这四大外设如何在卡死检测、碰撞感知、低电量判断和急停响应中发挥关键作用,帮助学习者建立从寄存器操作到系统级保护策略的完整认知。
2.1 核心原理:外设如何支撑异常保护
异常保护的本质是“感知-判断-执行”的闭环控制。STM32的四大外设分别承担着不同的角色:GPIO负责数字信号的输入输出,是急停开关、碰撞传感器等开关量信号的直接接口;定时器提供时间基准和PWM输出,既能检测电机堵转导致的脉冲异常,也能控制舵机或电机的安全输出;ADC将模拟电压转换为数字量,用于监测电池电量、电机电流等连续变化的物理量;中断系统则赋予系统“即时响应”的能力,确保紧急事件能够打断当前任务流,优先执行保护动作。
这四大外设并非孤立工作。例如,在电机卡死检测中,定时器捕获编码器脉冲频率,当频率低于阈值时触发中断,中断服务函数中通过GPIO拉低电机使能引脚,同时ADC采集电流值确认堵转状态。这种多外设协同的架构,是构建可靠异常保护系统的关键。
2.2 判断方法与操作流程:外设配置的关键步骤
在实际工程中,正确配置外设是异常保护功能实现的前提。以下以STM32F103系列为例,说明各外设在异常保护场景中的标准配置流程。
2.2.1 GPIO配置:急停与碰撞检测
急停按钮和碰撞传感器通常输出开关量信号。GPIO需配置为上拉输入或下拉输入模式,并开启外部中断功能。关键配置参数包括:
- 输入模式:浮空输入(外部已有上/下拉电阻)或上拉/下拉输入(MCU内部电阻)。
- 触发方式:上升沿、下降沿或双边沿触发。急停按钮通常使用下降沿触发(按下时电平由高变低)。
- 滤波配置:启用输入滤波器,防止机械抖动产生误触发。
// GPIO初始化示例:PA0作为急停输入,下降沿触发外部中断
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
2.2.2 定时器配置:卡死与堵转检测
定时器在异常保护中有两种典型应用:一是作为看门狗,监测主循环是否“卡死”;二是通过输入捕获模式检测电机编码器脉冲,判断是否发生堵转。配置要点包括:
- 时基单元:设置预分频器和自动重载值,确定定时周期(如1ms中断一次)。
- 输入捕获通道:配置为上升沿捕获,测量脉冲间隔。
- PWM输出:用于控制电机速度,在异常时能快速输出低电平或高阻态。
// 定时器2输入捕获配置:捕获编码器A相脉冲
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 72MHz/72=1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0F; // 输入滤波
TIM_ICInit(TIM2, &TIM_ICInitStructure);
2.2.3 ADC配置:低电量检测
电池电压检测通常使用ADC的规则通道或注入通道。注入通道具有更高优先级,适合在紧急情况下抢占采样。配置流程包括:
- 开启ADC时钟,设置ADC时钟分频(通常为PCLK2/6)。
- 配置采样通道、采样时间和分辨率。
- 启用扫描模式或连续转换模式。
- 通过DMA或中断读取转换结果。
// ADC1通道1采样配置:PA1连接电池电压分压点
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
2.2.4 中断优先级配置:急停的“快车道”
STM32的NVIC支持抢占优先级和子优先级。急停信号必须配置为最高抢占优先级,确保无论主程序处于何种状态,都能立即响应。配置要点:
- 使用
NVIC_PriorityGroupConfig()设置优先级分组。 - 为急停中断分配抢占优先级0(最高),子优先级0。
- 在中断服务函数中执行“只置标志位,不处理逻辑”的原则,快速退出中断。
2.3 案例拆解:四外设协同的急停保护系统
下面通过一个完整的工程案例,展示四大外设如何协同实现急停保护。该案例来自一款差速驱动移动机器人底盘。
| 项目 | 参数/配置 |
|---|---|
| 主控芯片 | STM32F103RCT6,72MHz主频 |
| 急停输入 | PA0,上拉输入,下降沿触发外部中断,抢占优先级0 |
| 电机使能 | PB5、PB6,推挽输出,低电平有效 |
| 电池电压 | PA1,ADC1通道1,采样电阻分压(10k:3.3k),量程0-16.8V |
| 编码器输入 | PA8(TIM1_CH1),输入捕获,用于堵转检测 |
初始现象与目标:机器人运行中偶发“失控”现象,表现为电机持续运转无法停止。经排查,发现主程序在复杂运算时存在长时间阻塞,导致GPIO无法及时响应急停信号。目标是将急停响应时间从“不确定”缩短至10ms以内。
分析判断过程:通过逻辑分析仪抓取急停信号到电机停止的延时,发现最差情况达到120ms。原因是主循环中有一个耗时80ms的路径规划算法,且急停处理代码被放在主循环末尾。此外,ADC采样采用阻塞式查询,进一步加剧了响应延迟。
实际操作步骤:
- 中断优先级重构:将EXTI0中断抢占优先级设为0,子优先级设为0;将定时器中断设为抢占优先级1,ADC DMA中断设为抢占优先级2。
- 中断服务函数精简:EXTI0_IRQHandler中仅设置全局标志位
emergency_stop_flag = 1,并直接操作GPIO拉低电机使能引脚(PB5、PB6),不执行任何延时或复杂运算。 - ADC改为DMA模式:将电池电压采样改为DMA循环传输,CPU不再阻塞等待转换完成。
- 堵转检测联动:在TIM1捕获中断中计算脉冲间隔,若间隔超过500ms(对应电机转速低于阈值),则同样置位急停标志并关闭PWM输出。
结果对比:改造后,急停响应时间稳定在3-5μs(中断响应+GPIO操作),远优于10ms目标。同时,ADC采样不再影响主循环,主程序运行效率提升约15%。
风险与代价:中断优先级调整后,需注意定时器中断可能被急停中断打断,导致PWM波形短暂异常。解决方案是在急停中断中直接关闭定时器输出(TIM_Cmd(TIM1, DISABLE)),而非仅修改占空比。
复盘经验:异常保护设计必须遵循“中断里只做最紧急的事”原则。任何复杂的保护逻辑(如记录日志、发送通知)都应放在主循环中处理,中断服务函数只负责“断电”和“置标志”。
2.4 常见误区与总结复盘
在实际开发中,工程师常陷入以下误区,导致异常保护功能失效或误动作:
1. 先确定所有异常事件的紧急程度,分配中断优先级;
2. 再设计GPIO输入电路(上拉/下拉、滤波);
3. 然后配置定时器用于超时检测和PWM安全输出;
4. 最后实现ADC采样,并采用DMA模式避免阻塞;
5. 在系统联调时,使用逻辑分析仪或示波器验证各环节的响应时间。