CH32V EC11旋转编码器开发指南:从硬件连接到软件消抖

1次阅读
没有评论

共计 2418 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

技术背景:EC11 编码器的工作原理

EC11 是一种机械式旋转编码器,通过内部机械结构产生两路相位差 90 度的正交信号(A 相和 B 相)。当旋钮转动时,两路信号会产生特定的跳变序列:

CH32V EC11 旋转编码器开发指南:从硬件连接到软件消抖

  • 顺时针旋转时,A 相跳变领先 B 相
  • 逆时针旋转时,B 相跳变领先 A 相

机械编码器由于物理接触特性,在跳变时会产生 5 -20ms 的抖动(bouncing),这是软件必须处理的关键问题。EC11 广泛应用于音量控制、参数调节等需要精确旋转输入的场合。

硬件设计

电路连接图

EC11          CH32V
-------------------
A 相 ------> GPIOA.0 (外部中断)
B 相 ------> GPIOA.1 (普通输入)
COM ------> GND

上拉电阻:A 相 --4.7kΩ-- 3.3V
B 相 --4.7kΩ-- 3.3V

PCB 布局注意事项

  • 信号线尽量短(<5cm)
  • 靠近 EC11 放置 0.1uF 去耦电容
  • 避免与高频信号线平行走线
  • 上拉电阻建议使用 1% 精度

软件实现

状态机消抖算法

// 状态定义
typedef enum {
    STATE_IDLE,
    STATE_A_RISING,
    STATE_A_FALLING,
    STATE_B_RISING,
    STATE_B_FALLING
} EncoderState;

// 全局变量
volatile EncoderState g_state = STATE_IDLE;
volatile uint32_t g_counter = 0;
volatile uint32_t g_lastTime = 0;

// 消抖时间阈值(单位:ms)#define DEBOUNCE_TIME 15

// 中断处理函数
void EXTI0_IRQHandler(void) {if(EXTI_GetITStatus(EXTI_Line0) != RESET) {uint32_t currentTime = GetSystemTick();

        // 消抖判断
        if((currentTime - g_lastTime) < DEBOUNCE_TIME) {EXTI_ClearITPendingBit(EXTI_Line0);
            return;
        }

        g_lastTime = currentTime;

        // 读取 B 相状态
        uint8_t bState = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1);

        // 状态机处理
        switch(g_state) {
            case STATE_IDLE:
                if(bState) g_counter++;
                else g_counter--;
                break;

            // 其他状态处理...
        }

        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

方向判断逻辑

// 获取旋转方向
int8_t GetEncoderDirection(void) {
    static int16_t lastCount = 0;
    int8_t dir = 0;

    if(g_counter > lastCount) dir = 1;
    else if(g_counter < lastCount) dir = -1;

    lastCount = g_counter;
    return dir;
}

性能优化

消抖时间参数调整

消抖时间 (ms) 响应速度 稳定性
5 快 较差
10-15 中等 好
20+ 慢 极好

中断优先级设置

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 中等优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

避坑指南

硬件常见问题

  • 未接上拉电阻导致信号浮动
  • 电源噪声导致误触发(加 0.1uF 电容可解决)
  • 信号线过长引入干扰

软件常见错误

  • 中断处理函数中执行耗时操作
  • 未做变量 volatile 声明导致值不同步
  • 消抖时间设置不合理

进阶建议

支持按键检测

// 连接 EC11 的 SW 引脚到 GPIO
#define ENC_SW_PIN  GPIO_Pin_2

bool IsEncoderPressed(void) {
    static uint32_t lastPressTime = 0;
    if(GPIO_ReadInputDataBit(GPIOA, ENC_SW_PIN) == 0) {if(GetSystemTick() - lastPressTime > 50) {lastPressTime = GetSystemTick();
            return true;
        }
    }
    return false;
}

多编码器管理

  1. 为每个编码器创建独立的结构体
  2. 使用指针传递实例数据
  3. 共享中断服务例程
typedef struct {
    GPIO_TypeDef* gpioA;
    uint16_t pinA;
    GPIO_TypeDef* gpioB;
    uint16_t pinB;
    int32_t counter;
} EncoderInstance;

void HandleMultipleEncoders(EncoderInstance* enc) {// 通用处理逻辑}

验证实验

  1. 连接 LED 到 GPIO
  2. 每转动一格改变 LED 状态
  3. 通过串口打印计数值
while(1) {if(g_counter != lastDisplayCount) {LED_Toggle();
        printf("Count: %d\n", g_counter);
        lastDisplayCount = g_counter;
    }
}

学习资源推荐

  • EC11 数据手册
  • CH32V 参考手册(GPIO 和 EXTI 章节)
  • 《嵌入式系统实时概念》
  • ARM Cortex- M 中断机制详解

通过本指南,你应该已经掌握了 EC11 旋转编码器在 CH32V 平台上的完整开发流程。实际开发时建议先用示波器观察信号质量,再逐步调试软件参数,最终实现稳定可靠的旋转输入功能。

正文完
 0
评论(没有评论)