STM32 PWM驱动舵机与直流电机实战指南
1. STM32 PWM驱动舵机实战
1.1 舵机控制原理剖析
舵机作为一种常见的角度执行器,其核心控制原理是通过PWM信号的占空比来指定输出轴的角度位置。标准舵机通常接受周期为20ms(50Hz)的PWM信号,其中高电平持续时间在0.5ms到2.5ms之间对应0°到180°的旋转角度。
在STM32中实现这一控制,我们需要精确配置定时器的时基单元:
- 时钟源:通常使用内部72MHz时钟
- 预分频器(PSC):设置为71(72-1),将时钟分频至1MHz
- 自动重装载值(ARR):设置为19999(20000-1),实现20ms周期
- 捕获比较寄存器(CCR):根据角度计算具体值
注意:不同品牌舵机的脉宽范围可能略有差异,建议在使用前查阅具体型号的数据手册。部分舵机支持更宽的脉宽范围(如0.3ms-2.7ms),可提供更大的转动角度。
1.2 硬件连接与初始化
典型SG90舵机接线方式:
- 红色线:接5V电源正极
- 棕色线:接GND
- 橙色线:接STM32的PWM输出引脚(如PA1)
初始化代码关键点解析:
// GPIO初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 定时器基础配置
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; // ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; // PSC
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
// PWM通道配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_Pulse = 1500; // 初始占空比(1.5ms)
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
1.3 角度控制实现
将角度转换为CCR值的计算公式:
CCR = (Angle / 180) * 2000 + 500
其中:
- 500对应0.5ms(0°位置)
- 2500对应2.5ms(180°位置)
- 2000是180°对应的脉宽增量范围(2.5ms-0.5ms=2ms),换算为1MHz时钟下的计数值
实用角度设置函数:
void Servo_SetAngle(float Angle) {
// 限制角度范围
Angle = Angle > 180 ? 180 : (Angle < 0 ? 0 : Angle);
// 转换为CCR值并更新
PWM_SetCompare2(Angle / 180 * 2000 + 500);
}
1.4 按键控制实现
通过外部按键控制舵机角度递增的典型实现:
float currentAngle = 0;
while(1) {
if(Key_GetNum() == 1) { // 检测按键按下
currentAngle += 30;
if(currentAngle > 180) currentAngle = 0;
Servo_SetAngle(currentAngle);
OLED_ShowNum(1, 7, (uint16_t)currentAngle, 3);
}
Delay_ms(20); // 消抖延时
}
实际应用建议:添加软件消抖和角度渐变效果,避免舵机快速跳动导致机械磨损。可以使用线性插值算法实现平滑的角度过渡。
2. PWM驱动直流电机方案
2.1 直流电机驱动原理
直流电机转速与PWM占空比基本呈线性关系,通过H桥电路可以同时控制电机的转速和转向。STM32产生PWM信号驱动电机控制器(如L298N),典型参数配置:
- PWM频率:10kHz-20kHz(高于人耳听觉范围,避免啸叫)
- 占空比:0-100%对应电机转速
- 方向控制:通过两个GPIO引脚的电平组合决定
2.2 硬件连接方案
典型L298N模块连接方式:
- ENA:接STM32 PWM输出(PA2)
- IN1:接方向控制GPIO(PA4)
- IN2:接方向控制GPIO(PA5)
- 电机电源:建议与MCU电源隔离
2.3 代码实现详解
PWM初始化(简化参数配置):
// 时基单元配置
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // ARR=100便于百分比计算
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; // 72MHz/(36*100)=20kHz
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
// PWM通道3配置
TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比0%
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
方向控制与速度设置函数:
void Motor_SetSpeed(int8_t Speed) {
// 方向控制
if(Speed >= 0) { // 正转
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
} else { // 反转
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
}
// 设置PWM占空比(绝对值)
PWM_SetCompare3(abs(Speed));
}
重要提示:电机启动时应避免突然施加高占空比,建议实现加速度控制。可通过逐步增加PWM占空比的方式实现软启动,延长电机寿命。
2.4 按键调速实现
带速度回显的按键控制示例:
int8_t motorSpeed = 0;
OLED_ShowString(1, 1, "Speed:");
while(1) {
if(Key_GetNum() == 1) {
motorSpeed += 20;
if(motorSpeed > 100) motorSpeed = -100;
Motor_SetSpeed(motorSpeed);
OLED_ShowSignedNum(1, 7, motorSpeed, 3);
}
}
3. PWM频率与占空比测量技术
3.1 测量原理分析
输入捕获模式通过记录信号边沿的定时器计数值来计算信号参数:
- 频率测量:捕获连续两个上升沿的时间间隔
- 占空比测量:捕获一个周期内高电平持续时间
PWMI模式(PWM输入模式)是STM32提供的特殊测量模式,可自动配置两个通道分别捕获上升沿和下降沿。
3.2 硬件连接方式
测量信号连接:
- 待测PWM信号 → PA6(TIM3_CH1)
- 共地连接确保参考电平一致
3.3 代码配置详解
输入捕获初始化关键步骤:
// GPIO配置为上拉输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 定时器时基配置(1MHz计数频率)
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
// PWMI模式配置
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF; // 强滤波
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
// 从模式配置
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
测量函数实现:
uint32_t IC_GetFreq(void) {
return 1000000 / (TIM_GetCapture1(TIM3) + 1); // 1MHz时钟
}
uint32_t IC_GetDuty(void) {
return (TIM_GetCapture2(TIM3) + 1) * 100 /
(TIM_GetCapture1(TIM3) + 1);
}
3.4 测量误差分析与优化
常见误差来源及解决方案:
- 高频信号测量:当信号周期接近定时器分辨率时,误差增大。可降低定时器时钟分频提高分辨率
- 信号抖动:适当增加数字滤波器值(TIM_ICFilter)
- 中断延迟:对于高频测量,建议使用DMA传输捕获值
实测技巧:对于低频PWM信号(<1kHz),可多次测量取平均值提高精度。高频信号建议使用更高主频的定时器(如TIM2/TIM5为32位计数器)。
4. 旋转编码器测速实现
4.1 编码器工作原理
增量式旋转编码器通过两路正交信号(A/B相)输出旋转信息:
- 旋转方向:A/B相信号的相位差决定
- 旋转速度:单位时间的脉冲数决定
- 旋转角度:累计脉冲数决定
STM32的编码器接口模式可自动处理正交信号,实现四倍频计数。
4.2 硬件连接方式
典型EC11编码器连接:
- CLK(A相)→ PA6(TIM3_CH1)
- DT(B相)→ PA7(TIM3_CH2)
- SW(按键)→ 单独GPIO(未使用可接地)
4.3 代码配置详解
编码器模式初始化:
// GPIO配置为上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 定时器时基配置
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; // 16位最大值
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
// 编码器接口配置
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,
TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
速度读取函数:
int16_t Encoder_Get(void) {
int16_t count = TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3, 0); // 读取后清零
return count;
}
4.4 速度计算与显示
定时中断中读取编码器计数:
void TIM2_IRQHandler(void) {
if(TIM_GetITStatus(TIM2, TIM_IT_Update)) {
Speed = Encoder_Get(); // 获取单位时间脉冲数
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
速度换算公式:
实际转速(RPM) = (Speed * 60) / (PPR * 采样周期)
其中:
- PPR:编码器每转脉冲数(EC11通常为20)
- 采样周期:定时中断间隔(秒)
工程实践建议:对于高速旋转测量,应缩短采样周期或使用更高PPR的编码器。低速测量时可适当延长采样周期并启用定时器溢出中断处理。
更多推荐



所有评论(0)