共计 1429 个字符,预计需要花费 4 分钟才能阅读完成。
硬件设计:从源头抑制抖动
机械编码器的金属触点闭合时会产生 5 -10ms 的物理抖动(数据来自欧姆龙 EE-SX670 手册),这会导致单片机直接采集时出现多次误触发。通过示波器实测,原始信号抖动峰值可达数十微秒:

RC 滤波电路设计
硬件消抖是解决问题的第一道防线。根据经验公式:
- 临界电阻值 R ≥ Vcc/(2×I_max)(I_max 为编码器最大输出电流)
- 时间常数 τ=RC 应大于抖动持续时间(通常取 3 - 5 倍)
推荐参数表:
| 编码器类型 | 电压 | 电阻值 | 电容值 | 滤波效果 |
|---|---|---|---|---|
| EC11 | 5V | 10kΩ | 0.1μF | >95% |
| E6B2 | 12V | 4.7kΩ | 1μF | >98% |
实际电路示例:
Encoder_A ────┬──── 10kΩ ────┐
| │
0.1μF INT0
| │
GND GND
软件方案:双重保险机制
状态机实现核心逻辑
采用格雷码编码的旋转编码器,其状态转换遵循特定序列。建立 4 状态机:
stateDiagram
[*] --> S0: 00
S0 --> S1: 01(顺时针)
S0 --> S3: 10(逆时针)
S1 --> S2: 11
S3 --> S2: 11
S2 --> S0: 00
定时器消抖算法
在中断服务程序中启动定时器作为二次验证:
void Timer0_ISR() interrupt 1 {
static uint8_t debounce_count;
if (++debounce_count >= DEBOUNCE_TICKS) {
TR0 = 0; // 关闭定时器
current_state = (P1 & 0x03); // 读取最终稳定状态
process_rotation(); // 处理有效旋转}
}
关键参数注释:
– DEBOUNCE_TICKS 对应 5ms(12MHz 晶振时约 6000 个机器周期)
– 使用 xdata 存储历史状态避免堆栈溢出
完整代码实现
基于 Keil C51 的工程核心片段:
#define ENCODER_PORT P1
volatile xdata uint8_t encoder_history;
void EX0_ISR() interrupt 0 {
EA = 0; // 关总中断
uint8_t new_state = ENCODER_PORT & 0x03;
// 正交解码核心算法
uint8_t transition = (encoder_history << 2) | new_state;
switch(transition) {
case 0b0001: // 00→01
case 0b1110: // 11→10
counter++;
break;
case 0b0010: // 00→10
case 0b1101: // 11→01
counter--;
break;
}
encoder_history = new_state;
EA = 1; // 开总中断
}
避坑实践指南
- 中断优化:
- 绝对避免在中断内进行
float运算(实测会增加 300+ 周期) -
使用
static变量替代全局变量减少访问时间 -
电气兼容性:
- 3.3V 编码器连接 5V 单片机时,需串联 1kΩ 电阻限流
-
工业环境必须加 TVS 二极管(如 SMAJ5.0A)
-
资源竞争处理:
- 多轴编码器建议采用分时复用策略
- 优先级设置:旋转编码器 > 按键编码器
移植到 STM8 的思考
- 硬件层调整:
- STM8 的 GPIO 内部有弱上拉,可省去外部电阻
-
利用 STM8 的捕获 / 比较功能实现硬件解码
-
代码优化方向:
- 改用 IAR 编译器的
@tiny内存模型 - 利用 STM8 的自动重装载定时器简化消抖逻辑
通过这套方案,我们在食品包装机械上实现了 200RPM 转速下±1 的计数精度,连续运行 3000 小时无异常。关键点在于硬件滤波和软件状态机的双重验证机制,既保证实时性又确保可靠性。
正文完
