3、GPIO与定时器基础:GPIO模式配置(推挽/开漏)、定时器PWM输出原理、频率与占空比计算、我用PWM控制电机转速的踩坑记录

3.1 GPIO模式:推挽与开漏,别选错了

做步进电机驱动,GPIO是第一道关卡。很多人觉得GPIO嘛,不就是输出高低电平?其实没那么简单。

先说说推挽输出。这是最常用的模式。内部有两个MOS管,一个推上去输出高电平,一个拉下来输出低电平。速度快,驱动能力强。我习惯在控制电机方向(DIR)和使能(EN)引脚上用推挽输出。为什么呢?因为这些信号需要快速跳变,推挽模式最合适。

再说开漏输出。这个模式只有下拉MOS管,没有上拉。想输出高电平?必须靠外部上拉电阻。你想想看,这有什么好处?好处就是可以接不同电压的设备。比如你的MCU是3.3V,但电机驱动器需要5V信号。用开漏输出,外部上拉到5V,完美解决电平匹配问题。

我在项目中遇到过一个问题:用推挽输出直接驱动一个5V的步进电机驱动器,结果MCU引脚烧了。后来查手册才发现,推挽输出时引脚电压被钳位在3.3V,而驱动器内部有上拉电阻,形成了电流倒灌。嗯,从那以后,凡是跨电压域的信号,我都用开漏加外部上拉。

核心建议:

  • 同电压域、需要快速切换的信号 → 推挽输出
  • 跨电压域、需要电平匹配的信号 → 开漏输出 + 外部上拉
  • 开漏输出的上拉电阻一般选4.7kΩ~10kΩ,频率高时选小一点

3.2 定时器PWM输出原理:其实没那么玄乎

PWM,脉宽调制。说白了就是让一个引脚以固定的频率输出高低电平,通过改变高电平占一个周期的时间比例,来模拟不同的电压值。

定时器是怎么产生PWM的?核心就是一个计数器和一个比较寄存器。计数器从0开始,每个时钟周期加1,一直加到自动重装载值(ARR),然后归零重新开始。这个过程叫计数周期。

同时,还有一个比较寄存器(CCR)。当计数器的值小于CCR时,输出高电平;大于等于CCR时,输出低电平。你看,改变CCR的值,就改变了高电平的宽度,也就是占空比。

举个例子:ARR设为999,CCR设为500。计数器从0跑到999,前500个周期输出高,后500个周期输出低。占空比就是50%。

小技巧:很多定时器支持中心对齐模式,计数器先向上计数再向下计数。这种模式产生的PWM对称性更好,电机运行更平稳。我个人习惯在要求低噪声的场合用中心对齐模式。

3.3 频率与占空比计算:公式很简单,但容易算错

PWM的频率由定时器的时钟频率和分频系数决定。公式如下:

PWM频率 = 定时器时钟频率 / (分频系数 + 1) / (自动重装载值 + 1)

占空比的计算更简单:

占空比 = 比较值 / (自动重装载值 + 1) × 100%

举个例子,STM32的定时器时钟是72MHz,我设置分频系数为71,自动重装载值为999:

PWM频率 = 72,000,000 / (71 + 1) / (999 + 1) = 72,000,000 / 72 / 1000 = 1000 Hz

频率就是1kHz。如果比较值设为500,占空比就是50%。

这里有个坑:分频系数和自动重装载值都是16位的,最大值65535。如果你想要很低的频率,比如1Hz,分频系数和重装载值都要设得很大。我曾经算错过一次,把分频系数设成了0,结果PWM频率直接飙到72MHz,电机根本没反应,反而把驱动器搞发热了。

注意:步进电机驱动的PWM频率一般选在20kHz以上,避开人耳可听范围。我通常用25kHz或50kHz。频率太低会有啸叫声,频率太高会增加MOS管的开关损耗。

3.4 我用PWM控制电机转速的踩坑记录

这部分全是血泪史。我一个个说。

坑一:占空比突变导致电机抖动

刚开始做的时候,我直接在主循环里修改CCR的值。结果电机一卡一卡的,像在跳舞。后来才明白,PWM的占空比不能突变,要平滑过渡。解决方案是用定时器的更新中断,在中断里逐步改变CCR,每次只变一点点。或者用硬件自动的斜坡发生器,如果芯片支持的话。

坑二:频率选错了,电机嗡嗡响

我曾经把PWM频率设成了1kHz,结果电机发出刺耳的尖叫声。同事还以为我在搞什么实验。后来查资料才知道,步进电机在低频时会产生机械共振。我建议避开电机的固有频率,一般选20kHz以上。如果电机还是响,可以试试随机PWM频率,把能量分散到更宽的频带上。

坑三:死区时间没设置,MOS管烧了

这个最惨。我用定时器的互补PWM驱动H桥,上下管同时导通,瞬间短路。MOS管直接冒烟。嗯,从那以后,我每次配置PWM都会检查死区时间设置。死区时间一般设为几百纳秒到几微秒,具体看MOS管的关断延迟。

坑四:定时器溢出中断和PWM更新冲突

我在中断里修改CCR,结果发现有时候修改不生效。原因是定时器的影子寄存器机制。CCR的值并不是立即生效的,而是等到下一个更新事件才加载。所以修改CCR时,要确保在正确的时机操作。我现在的做法是:在更新中断里修改CCR,或者用软件触发更新事件。

总结一下我的PWM配置清单:

  1. 确定PWM频率(步进电机推荐20kHz~50kHz)
  2. 计算分频系数和自动重装载值
  3. 配置GPIO为复用推挽输出
  4. 设置PWM模式(边沿对齐或中心对齐)
  5. 配置死区时间(互补PWM必须做)
  6. 使能预装载寄存器(防止CCR更新不同步)
  7. 启动定时器

最后说一句:PWM控制电机转速,看似简单,但细节决定成败。我见过太多人卡在频率计算或者占空比突变上。你想想看,一个电机转不起来,可能不是硬件坏了,而是软件里某个寄存器的值没设对。所以,调试的时候,先用示波器看PWM波形,确认频率和占空比都对,再连电机。这个习惯帮我省了无数时间。