## 引言 在嵌入式系统中,电机驱动无处不在:从机器人关节到工业传送带,从无人机螺旋桨到智能家居门窗。然而,驱动电机远不止“给电就转”那么简单。H桥的拓扑选择、PWM的占空比与频率设计、以及堵转时的电流冲击,都是决定系统稳定性的关键。本文将以直流有刷电机为例,深入讲解H桥原理、PWM调速方法,并重点探讨堵转保护的实现策略,提供一套可落地的STM32代码方案。 ## H桥:电机换向的基石 ### 拓扑与工作原理 H桥由四个开关管(MOSFET或IGBT)组成,形似字母“H”,电机接在桥臂中点。通过控制四个开关的通断组合,可实现电机的正转、反转、制动和滑行: - **正转**:Q1和Q4导通,Q2和Q3关断,电流从左向右流过电机。 - **反转**:Q2和Q3导通,Q1和Q4关断,电流反向。 - **制动**:Q1和Q3导通(或Q2和Q4),电机两端短路,产生反向电动势制动。 - **滑行**:所有开关关断,电机自由旋转。 实际应用中,常用半桥驱动芯片(如IR2104)配合N-MOSFET,简化逻辑控制。 ### 死区时间:防止直通短路 若同一桥臂的上下管同时导通,电源将被短路,烧毁器件。因此,在切换开关状态时,必须插入“死区时间”(Dead Time),即先关闭上管,延迟一段时间后再打开下管。死区时间通常为几百纳秒到几微秒,由驱动芯片或软件定时器实现。 ```c // 示例:使用定时器产生带死区的互补PWM(STM32高级定时器) TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; // 配置定时器1为PWM模式1,输出比较通道1和通道1N互补 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = 500; // 占空比50% TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; TIM_OC1Init(TIM1, &TIM_OCInitStructure); // 设置死区时间:例如1us(假设时钟72MHz,死区寄存器值=72) TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime = 72; // 1us TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRInit(TIM1, &TIM_BDTRInitStructure); ``` ## PWM调速:从占空比到有效电压 ### 原理与频率选择 PWM(脉宽调制)通过改变占空比来调节电机两端的平均电压,从而控制转速。占空比D = Ton / T,有效电压V_avg = D * V_supply。 - **频率选择**:过低(<1kHz)会导致电机振动和噪声;过高(>50kHz)会增加开关损耗。常用范围:10kHz-20kHz(避开人耳敏感区)。 - **分辨率**:8位(0-255)或16位(0-65535),根据调速精度需求选择。 ### 软件实现要点 - 使用定时器产生固定频率的PWM,通过修改比较寄存器更新占空比。 - 避免在中断中频繁修改占空比,可采用双缓冲或DMA。 - 启动时逐渐增加占空比(软启动),防止电流冲击。 ```c // STM32定时器2通道1输出PWM,频率10kHz,占空比可调 void PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_InitStructure.TIM_Prescaler = 72 - 1; // 72MHz/72 = 1MHz TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_InitStructure.TIM_Period = 100 - 1; // 1MHz/100 = 10kHz TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2, &TIM_InitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比0% TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_Cmd(TIM2, ENABLE); } void Set_Motor_Speed(uint8_t duty) { TIM_SetCompare1(TIM2, duty); // duty范围0-100 } ``` ## 堵转保护:电流检测与响应策略 ### 堵转的危害 当电机负载过大或转子卡死时,转速为零,反电动势消失,电流急剧上升(可达额定电流的5-10倍),导致绕组过热烧毁,或损坏驱动MOSFET。因此,堵转保护是电机驱动系统的必备功能。 ### 硬件方案:采样电阻与比较器 - 在电机回路中串联低阻值采样电阻(如0.1Ω),通过差分放大器放大电压,送入ADC或比较器。 - 使用比较器设定阈值,一旦超过立即触发中断,关闭PWM输出。 ### 软件方案:ADC采样与状态机 软件方案更灵活,可设置不同阈值和响应时间。核心逻辑: 1. 周期性采样电流(如每1ms)。 2. 若电流超过阈值(如额定电流的1.5倍),启动计时器。 3. 若持续超限超过设定时间(如100ms),判定为堵转,关闭PWM并置位故障标志。 4. 可配置自动恢复:延时后重新尝试启动,若再次堵转则彻底停机。 ```c // 堵转检测状态机示例 #define CURRENT_THRESHOLD 1500 // 电流ADC值阈值 #define BLOCK_TIME_MS 100 // 堵转判定时间 #define RETRY_DELAY_MS 2000 // 重试延时 typedef enum { MOTOR_RUNNING, MOTOR_BLOCKED, MOTOR_RETRY } MotorState; MotorState state = MOTOR_RUNNING; uint16_t block_timer = 0; uint16_t retry_timer = 0; void Motor_Protection_Task(void) { uint16_t current = ADC_GetValue(); // 读取电流采样 switch(state) { case MOTOR_RUNNING: if (current > CURRENT_THRESHOLD) { block_timer++; if (block_timer >= BLOCK_TIME_MS) { state = MOTOR_BLOCKED; PWM_Disable(); // 关闭PWM Motor_Stop(); // 记录故障日志 } } else { block_timer = 0; } break; case MOTOR_BLOCKED: // 等待重试延时 retry_timer++; if (retry_timer >= RETRY_DELAY_MS) { retry_timer = 0; state = MOTOR_RETRY; PWM_Enable(); Set_Motor_Speed(30); // 低速重试 } break; case MOTOR_RETRY: // 检查是否恢复正常 if (current < CURRENT_THRESHOLD) { state = MOTOR_RUNNING; Set_Motor_Speed(target_speed); // 恢复目标速度 } else { // 再次堵转,停止重试 state = MOTOR_BLOCKED; PWM_Disable(); // 设置永久故障标志 } break; } } ``` ### 注意事项 - **采样滤波**:电流信号可能含有噪声,需进行软件滤波(如滑动平均)或硬件RC滤波。 - **阈值设定**:需考虑电机启动时的浪涌电流,通常启动时允许短暂过流,因此堵转判定需有延时。 - **热保护**:除电流外,可结合MOSFET温度传感器,实现双重保护。 - **安全冗余**:硬件比较器作为第一道防线,软件作为第二道,防止MCU死机时失控。 ## 完整示例:集成H桥与堵转保护 以下代码演示了基于STM32F103的完整驱动流程:初始化PWM和ADC,主循环中执行堵转检测。 ```c int main(void) { // 初始化系统时钟、GPIO、定时器、ADC等 SystemInit(); PWM_Init(); ADC_Init(); // 设置目标速度(占空比60%) Set_Motor_Speed(60); while (1) { Motor_Protection_Task(); // 每1ms调用一次(可用定时器中断) // 其他任务... } } ``` ## 总结 电机驱动看似简单,实则涉及功率电子、控制算法与保护机制。H桥的死区设计是硬件基础,PWM的频率与占空比决定调速性能,而堵转保护则关乎系统安全。本文提供的方案可直接应用于实际项目,但需根据具体电机参数和电源环境调整阈值与延时。建议开发者先在仿真环境中验证逻辑,再上电测试,并逐步优化保护策略。 掌握这些核心要点,你就能构建一个既高效又可靠的电机驱动系统,为你的嵌入式项目增添动力。