4. CubeMX配置编码器模式:STM32CubeMX配置步骤、参数设置、时钟与中断配置
好,咱们接着往下走。上一节我们把编码器的硬件原理和接口讲清楚了,这一节就进入实战环节——用STM32CubeMX把编码器模式配出来。
说实话,我刚开始用CubeMX配编码器时,也踩过几个坑。比如计数器方向反了、中断没响应、毛刺导致误计数……这些我都经历过。今天我把这些经验揉碎了讲给你听,你照着配,基本一次过。
4.1 新建工程与选择芯片
打开CubeMX,点“New Project”。芯片选型嘛,我习惯用STM32F103C8T6,便宜又好买。当然你用F4、G0系列也行,配置思路完全一样。
选好芯片后,双击进入Pinout & Configuration界面。这里我要提醒一句:先配时钟,再配外设。这是我的个人习惯,因为时钟树会影响定时器的计数频率,搞反了容易出问题。
4.2 配置定时器为编码器模式
在左侧“Timers”列表里,找到你要用的定时器。比如我用TIM2,它支持编码器模式。
点开TIM2的“Mode”选项卡,你会看到“Combined Channels”这个选项。下拉菜单里选“Encoder Mode”。
嗯,这里要注意:编码器模式有两种——TI1和TI2、TI1和TI2(带反相)。一般我们用第一种,也就是TI1和TI2都参与计数。第二种是给特殊场景用的,比如信号反相了,或者你想反向计数。
选好模式后,下面会出现“Encoder Mode”的详细配置:
- Encoder Mode:选“Encoder Mode TI1 and TI2”
- Polarity:默认“Rising Edge”就行。如果你信号是低电平有效,再改。
- Input Filter:这个我建议设成“4”或“8”。为什么?因为编码器在低速转动时,触点会有抖动。加个滤波能滤掉毛刺。我在项目里遇到过不加滤波,电机一停就乱跳的情况,加了滤波就好了。
关键参数:
- Counter Mode:自动设为“Up/Down”,不用改
- Counter Period:设成0xFFFF(65535),这是16位定时器的最大值
- Auto-reload preload:建议开启,防止更新事件时计数器跳变
4.3 时钟配置
时钟这块,我直接说结论:定时器的时钟源来自APB总线。比如TIM2挂在APB1上,APB1的时钟是36MHz(如果HCLK是72MHz的话)。
但注意:如果APB1的预分频系数不是1,那么定时器的时钟会翻倍。具体公式是:
定时器时钟 = APB时钟 × 2(如果APB预分频 > 1)
举个例子:APB1设为36MHz,预分频系数为2,那么TIM2的时钟就是36MHz × 2 = 72MHz。
这个细节我当年也迷糊过。后来看参考手册才明白,定时器内部有个倍频器。你配时钟时,记得在“Clock Configuration”里确认一下APB1的预分频值。
4.4 中断配置
编码器模式一般不需要中断,除非你想在计数值溢出或达到某个阈值时做处理。但如果你需要,可以开启“Update Interrupt”或“Capture/Compare Interrupt”。
具体操作:在“NVIC Settings”选项卡里,勾选“TIM2 global interrupt”。然后去“GPIO”里把编码器A、B相的两个引脚配成“Alternate Function”模式。
这里有个坑:中断优先级不要设太高。我建议设成2或3(数值越小优先级越高)。因为编码器中断频率可能很高,优先级太高会抢了系统其他任务的资源。
我曾经踩过的坑:
有一次我把中断优先级设成了0(最高),结果电机一转,系统直接卡死。后来发现是中断太频繁,CPU一直在处理中断,主循环根本跑不动。所以优先级设低一点,或者干脆不用中断,用轮询读计数值。
4.5 生成代码与验证
配置完成后,点“Project” -> “Generate Code”。生成后打开工程,你会看到main.c里自动生成了TIM2的初始化代码。
验证方法很简单:在while循环里读一下TIM2->CNT寄存器的值,然后通过串口打印出来。用手转动编码器,看数值是否变化。
// 读取编码器计数值
int16_t encoder_value = (int16_t)(TIM2->CNT);
printf("Encoder: %d\r\n", encoder_value);
注意:TIM2->CNT是16位的,范围0~65535。如果你需要正负值,可以强制转成int16_t,这样0xFFFF就是-1,0x0001就是+1。这个技巧我在做电机位置控制时经常用。
4.6 核心逻辑流程图
下面我用一张SVG图,把整个配置流程串起来。你一看就明白:
我的小技巧:
如果你用的是增量式编码器,建议在初始化时把TIM2->CNT清零。这样每次上电都是从0开始计数,方便做位置归零。代码就一行:TIM2->CNT = 0;
好了,这一节的内容就到这。你按这个步骤配一遍,编码器数据采集的基础就搭好了。下一节我们会讲怎么在代码里解析这些数据,包括方向判断、速度计算、滤波处理等。到时候我会把我在电机控制项目里用的那套代码直接给你看。