STM32F103RCT6 TIM3编码器模式实战:从配置到方向检测

发布时间:2026/5/19 3:02:47

STM32F103RCT6 TIM3编码器模式实战:从配置到方向检测 1. STM32编码器模式基础认知第一次接触旋转编码器时我盯着那个会咔哒咔哒转的小玩意儿研究了半天。这看似简单的机械结构在工业控制、机器人关节、数控机床等领域却是不可或缺的位置传感器。编码器本质上是通过光电或磁电效应将机械旋转转化为电脉冲的装置。常见的有增量式编码器和绝对式编码器我们这里重点讨论增量式编码器它通过A、B两相脉冲信号的相位差来判定方向通过脉冲数量计算位移量。STM32的定时器外设有个隐藏技能——编码器接口模式。以STM32F103RCT6的TIM3为例它内置的编码器逻辑电路能自动处理两路正交信号省去了外部中断软件计数的麻烦。实测下来这种硬件级处理比软件方案更稳定可靠特别是在高速旋转场景下不会出现脉冲丢失的情况。TIM3支持三种编码器模式TI1仅用A相、TI2仅用B相以及TI1和TI2正交模式最后这种模式最适合常见的AB相编码器。2. 硬件连接与CubeMX配置去年给智能小车项目选编码器时我对比了欧姆龙E6B2和国产EC11最终选了后者——毕竟2000线的分辨率对轮速检测绰绰有余。硬件连接要注意三点首先编码器的VCC和GND要接稳定电源最好加个0.1μF去耦电容其次A、B相输出线建议用双绞线长距离传输时还要加上拉电阻最后STM32的TIM3_CH1(PA6)和TIM3_CH2(PA7)正好可以接编码器的两相输出。打开CubeMX配置界面时建议先开启TIM3的Clock Source为Internal Clock。然后在Parameter Settings里设置Prescaler为0Counter Mode选UpAutoReload Register设为6553516位最大值。关键步骤在Encoder Mode选项卡选择Encoder Mode TI1 and TI2IC1和IC2的Polarity都选Rising EdgeFilter值根据信号质量设0-15信号干净的话保持0即可。生成代码前别忘记在NVIC Settings里启用TIM3全局中断如果需要中断处理。3. 编码器方向检测的代码实战用HAL库初始化编码器模式时我踩过一个坑忘记调用HAL_TIM_Encoder_Start()函数结果计数器死活不变化。后来发现HAL库的操作流程是先初始化HAL_TIM_Encoder_Init再启动HAL_TIM_Encoder_Start。这里分享一个带方向检测的完整例程TIM_HandleTypeDef htim3; void Encoder_Init(void) { TIM_Encoder_InitTypeDef sConfig {0}; htim3.Instance TIM3; htim3.Init.Prescaler 0; htim3.Init.CounterMode TIM_COUNTERMODE_UP; htim3.Init.Period 65535; htim3.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; sConfig.EncoderMode TIM_ENCODERMODE_TI12; sConfig.IC1Polarity TIM_ICPOLARITY_RISING; sConfig.IC1Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC1Filter 0; sConfig.IC2Polarity TIM_ICPOLARITY_RISING; sConfig.IC2Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC2Filter 0; if (HAL_TIM_Encoder_Init(htim3, sConfig) ! HAL_OK) { Error_Handler(); } HAL_TIM_Encoder_Start(htim3, TIM_CHANNEL_ALL); } int32_t Get_Encoder_Diff(void) { static int16_t last_cnt 0; int16_t curr_cnt (int16_t)(htim3.Instance-CNT); int32_t diff curr_cnt - last_cnt; // 处理计数器溢出 if(diff 32767) diff - 65536; else if(diff -32768) diff 65536; last_cnt curr_cnt; return diff; }方向判断的逻辑很巧妙当A相上升沿时B相为高电平是正转B相为低电平则是反转。TIM3的CNT寄存器会随正转递增、反转递减。实际应用时要特别注意16位计数器的溢出问题我写的Get_Encoder_Diff()函数通过差值计算自动处理了溢出情况。4. 常见问题排查与优化调试编码器时遇到过最诡异的问题——电机转动时计数器正常但用手转动编码器轴时数值乱跳。后来用示波器抓波形发现是机械抖动导致的解决方法是在代码里增加数字滤波sConfig.IC1Filter 6; // 8个时钟周期滤波 sConfig.IC2Filter 6;另一个常见现象是低速时计数准确高速时漏脉冲。这时要检查定时器时钟是否够快STM32F103 TIM3最高72MHz编码器线数是否过高1000线以上建议用4倍频模式是否及时读取CNT值建议用DMA定期传输计数值对于需要精确测速的场景可以结合定时器中断每10ms读取一次计数器差值换算成转速。公式为 转速(RPM) (脉冲差 × 60) / (编码器线数 × 采样时间)5. 进阶应用Z相与零位校准有些高端编码器带Z相信号每转一圈输出一个索引脉冲。我们可以用EXTI中断捕获Z相在中断里将CNT清零实现软零位。接线时把Z相接在PA0TIM2_CH1这样的备用定时器通道上void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin GPIO_PIN_0) { __HAL_TIM_SET_COUNTER(htim3, 32768); // 设到中间值避免溢出 } }在精密定位系统中我还会在EEPROM里保存编码器的零点偏移值上电时自动恢复绝对位置。对于多轴同步控制所有TIM的编码器模式最好用同一个时钟源避免累积误差。

相关新闻