学习旋转编码器与中断处理的思考总结

旋转编码器的原理
  • 旋转编码器通常有三个引脚:A、B 和 C(公共端)。

  • 顺时针旋转时,A引脚和B引脚会输出一个正交编码的信号(A引脚的相位领先B引脚)。

  • 逆时针旋转时,A引脚和B引脚的相位关系会反转(B引脚的相位领先A引脚)。

  • 通过检测A和B引脚的信号变化,可以判断旋转方向和旋转速度。

信号变化和中断处理
  • A引脚和B引脚的信号变化是正交的,即每次旋转会有四种状态变化:
  1. 顺时针:A上升,B不变 -> A不变,B上升 -> A下降,B不变 -> A不变,B下降

  2. 逆时针:B上升,A不变 -> B不变,A上升 -> B下降,A不变 -> B不变,A下降

  • 通过设置A和B引脚的中断,可以捕捉到这些状态变化。
双边沿中断的必要性
  • 仅设置一个引脚的上升沿或下降沿中断,会漏记另一引脚的状态变化,导致计数错误。

  • 当设置为双边沿触发时,可以捕获每个引脚的上升沿和下降沿变化,从而避免漏记。

双边沿中断的实现
  • 配置A和B引脚的中断为双边沿触发,即上升沿和下降沿都触发中断。

  • 在中断服务程序中,分别处理上升沿和下降沿的情况,读取另一个引脚的状态,判断旋转方向。

重要代码示例

旋转编码器初始化代码
#include "stm32f10x.h"  // Device header

int16_t Encoder_Count;

void Encoder_Init(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // Enable GPIOB clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);   // Enable AFIO clock

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);  // Initialize PB0 and PB1 as input pull-up

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);  // Map EXTI Line0 to PB0
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);  // Map EXTI Line1 to PB1

    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;  // Trigger on both edges
    EXTI_Init(&EXTI_InitStructure);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_Init(&NVIC_InitStructure);
}
中断服务程序
void EXTI0_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line0) == SET) {
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == Bit_RESET) {
            Encoder_Count++;  // 顺时针旋转
        } else {
            Encoder_Count--;  // 逆时针旋转
        }
        EXTI_ClearITPendingBit(EXTI_Line0);  // Clear interrupt flag
    }
}

void EXTI1_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line1) == SET) {
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == Bit_RESET) {
            Encoder_Count--;  // 逆时针旋转
        } else {
            Encoder_Count++;  // 顺时针旋转
        }
        EXTI_ClearITPendingBit(EXTI_Line1);  // Clear interrupt flag
    }
}
计数获取函数
int16_t Encoder_Get(void) {
    int16_t temp;
    temp = Encoder_Count;
    Encoder_Count = 0;
    return temp;
}

总结

  1. 旋转编码器的信号特点:A和B引脚输出正交编码信号。

  2. 中断处理的必要性:需要使用双边沿中断,以确保捕获每一次状态变化,避免漏记。

  3. 通过双边沿中断捕获:同时设置A和B引脚的中断,并在中断服务程序中处理每个引脚的状态变化,可以确保准确计数。

这种方式可以最大限度地减少漏记的可能性,并提高旋转编码器的计数精度。通过这些讨论和代码示例,解决了在高速旋转时可能发生的计数错误问题。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值