现在我已经获得了非常全面的信息。让我来整理回答。
根据我的理解,用户只是提供了一个论坛帖子的链接让我查看。这个论坛帖子是关于STC32G12K128单片机上使用旋转编码器(EC11)出现跳码问题的求助帖。
让我综合分析已有信息,给用户一个完整的技术分析和解决方案。
我仔细阅读了你提供的论坛帖子链接(TID 25526),这是国芯人工智能技术交流社区关于旋转编码器实现程序的求助帖。下面我作为STC FAE工程师给你完整的分析。
一、帖子内容摘要
楼主问题:
- 使用 STC32G12K128 单片机
- 旋转编码器AB相接 P3.3、P3.6
- 尝试双中断方式,刚开始正常,用了几天后出现跳码现象
- 用其他AI工具提供的程序效果不佳,寻求验证过的可靠方案
论坛回复(wul*):**
建议编码器A接P3.2(INT0),B接任意IO,用下降沿中断立即读B判断方向,且编码器需有硬件消抖。
二、问题根因分析
你提到的"双中断+用了几天出现跳码",通常由以下因素导致:
- 机械抖动:旋转编码器(如EC11)旋转时触点抖动会产生大量毛刺,如果中断触发过密,会在一个编码脉冲上重复计数。
- 两个I/O口各自独立中断:P3.3(INT1)和P3.6(INT2)分别触发中断,两个中断可能在编码器状态切换的临界时刻竞争/重入,导致方向判断错误。
- 缺少输入滤波/去抖:STC32G的I/O口中断虽然有上升/下降沿配置,但本身没有硬件去抖。编码器信号若不经过RC硬件消抖,软件上又没做滤波,就极易跳码。
- 中断响应时间过长:在中断里做较多运算会丢掉编码器的快速脉冲。
三、推荐方案
针对你的应用,我给你两种可靠方案:
方案一:硬件正交编码器模式(最推荐)
STC32G12K128 的 PWMA 高级PWM定时器原生支持正交编码器接口模式,硬件自动处理方向判断和计数,无需软件去抖、无需中断竞争,这是最稳定可靠的方案。
根据《STC32G系列手册》第「26 16位高级PWM定时器,支持正交编码」章节,配置编码器接口模式的关键步骤如下:
// 正交编码器模式示例(PWMA定时器)
// 编码器A相接PWMA_TI1,编码器B相接PWMA_TI2
#include "stc32g.h"
#include "intrins.h"
void main(void)
{
unsigned char enc_cnt_h, enc_cnt_l;
EAXFR = 1; // 使能访问XFR
CKCON = 0x00; // 外部数据总线速度最快
WTST = 0x00; // 程序代码等待参数最快
// 配置PWMA编码器输入引脚为I/O输入模式
// 具体引脚映射取决于PWMA_PS寄存器的设置
// 默认PWMA_PS=0x00时,PWM通道在P1端口
PWMA_ENO = 0x00; // 关闭PWM输出,配置为输入
PWMA_PS = 0x00; // 00:PWM at P1
PWMA_PSCRH = 0x00; // 预分频寄存器高
PWMA_PSCRL = 0x00; // 预分频寄存器低
PWMA_CCMR1 = 0x21; // 通道1配置为输入,接编码器,滤波器4时钟
PWMA_CCMR2 = 0x21; // 通道2配置为输入,接编码器,滤波器4时钟
PWMA_SMCR = 0x03; // 编码器模式3(TI1和TI2双边沿计数)
PWMA_CCER1 = 0x55; // 配置通道使能和极性
PWMA_CCER2 = 0x55; // 配置通道使能和极性
PWMA_IER = 0x02; // 使能PWMA中断
PWMA_CR1 |= 0x01; // 使能计数器
EA = 1;
while (1)
{
// 周期读取计数器值
enc_cnt_h = PWMA_CCR1H;
enc_cnt_l = PWMA_CCR1L;
// 使用enc_cnt_h/enc_cnt_l得到当前编码器位置
}
}
// PWMA中断服务函数
void PWMA_ISR() interrupt 26
{
if (PWMA_SR1 & 0x02)
{
PWMA_SR1 &= ~0x02; // 清除中断标志
}
}
注意: 使用PWMA正交编码器模式时,需要确认编码器A/B信号映射到PWMA的TI1/TI2输入引脚上。你可以通过查阅STC32G管脚图确认对应的引脚。
方案二:外部中断 + 软件状态机去抖(移植性更好)
如果你更习惯用外部中断方式,建议使用单边沿中断 + 状态机判断,避免两个中断竞争:
- 编码器A相接 P3.2(INT0),用下降沿触发
- 编码器B相接任意普通I/O口(如P3.4),不用中断
- 在INT0中断中读B相电平判断方向
#include "stc32g.h"
#include "intrins.h"
volatile int encoder_count = 0; // 编码器计数值
volatile unsigned char enc_dir = 0;
void main(void)
{
unsigned char last_a;
// 确保P3M0/P3M1配置为准双向
P3M1 = 0x00;
P3M0 = 0x00;
// INT0下降沿触发
IT0 = 1; // INT0下降沿触发
EX0 = 1; // 使能INT0中断
EA = 1;
last_a = P32; // 保存初始状态
while (1)
{
// 主循环处理编码器计数
// encoder_count 在中断中更新
}
}
// INT0中断服务函数(外部中断0)
void INT0_ISR() interrupt 0
{
// 在P3.2下降沿时读取B相判断方向
if (P34) // B相为高 -> 正转
{
encoder_count++;
}
else // B相为低 -> 反转
{
encoder_count--;
}
}
重要提示:此方案依赖编码器自身的硬件消抖(如RC滤波)。如果编码器没有硬件消抖,建议在硬件上添加RC滤波电路(典型值为10kΩ电阻+0.1μF电容),或在软件中做简单的去抖处理。
四、跳码问题排查建议
根据你的描述"用了几天后出现跳码",建议按以下顺序排查:
| 排查项 |
说明 |
| 硬件消抖 |
编码器A/B相是否接入RC滤波?没有的话务必加 |
| 引脚配置 |
编码器输入的I/O口配置为准双向或高阻输入,避免内部上拉影响 |
| 中断配置 |
确认IT0/IT1/IT2的中断触发方式与编码器信号匹配 |
| 供电稳定性 |
编码器供电与MCU是否共地?电源纹波是否过大? |
| 长线干扰 |
编码器与MCU之间连线过长时,考虑增加隔离/滤波 |
如需我进一步针对你的具体电路给出更精确的配置代码,请告诉我:
- 你的编码器型号(EC11?还是其他?)
- 编码器A/B相分别接在哪两个引脚
- 是否有硬件RC消抖电路
- 你期望的计数精度(1倍/2倍/4倍频)
我可以根据你的实际情况,给出完全量身定制且经过验证的代码方案。
信息来源:
- 论坛帖子TID 25526(回复内容为论坛用户建议)
- 《STC32G系列手册》第「26 16位高级PWM定时器,支持正交编码」章节
- 《STC32G系列手册》第「14 中断系统」章节
- 《STC32G系列手册》第「15 普通I/O口均可中断,不是传统外部中断」章节
- 《STC32G系列手册》第「4 STC32G系列选型简介」章节(管脚图)
🔍 搜索 "STC8H 单片机 例程 下载"
⏱️ 查找用时 29.9s | 总回答用时 47.9s