CMS32L051使用旋转编码器

文章目录

概要

CMS32L051使用外部中断的方式识别旋转编码器的方向。

  1. 选取其中一个信号A进行外部中断触发,由于信号A空闲时处于高电平,因此初始化时外部中断使用下降沿触发;
  2. 触发第一个下降沿后,判断当前是否已经触发了上升沿,如果已经触发上升沿,则需要判断当前与触发上升沿的时间间隔是否大于1ms,如果小于则不往下执行。大于1ms则清除上升沿触发标志,置位下降沿触发标志,记录当前触发的时间戳,改用上升沿触发。
  3. 如果触发第一个下降沿后,没有触发上升沿则置位下降沿触发标志,记录当前触发的时间戳,改用上升沿触发。
  4. 触发上升沿后,判断当前时间戳和第一个下降沿的时间戳差值,如果大于2ms则根据另一个信号B的电平状态判断旋钮的方向,低电平则是逆时针,高电平则是顺时针。清除下升沿触发标志,置位上降沿触发标志,记录当前触发的时间戳,改用上升沿触发。
  5. 如果小于2ms则不往下执行。加入触发间隔判断是为了消抖。消抖结果如下图所示,绿色的是使用GPIO在有效下降沿和上升沿进行的翻转,黄色是信号A。
    在这里插入图片描述

代码

  1. bsp_knob.c
#include "UserConfigure.h"

typedef struct
{
    uint8_t a_first_falling;
	uint8_t a_first_rising;
    uint8_t knob_value;
    uint8_t last_knob_value;

    uint32_t a_first_falling_tick;
	uint32_t a_first_rising_tick;
} knob_mgr_t;

/* Private variables ---------------------------------------------------------*/
static knob_mgr_t knob_mgr = {
    0
};

void bsp_knob_set_exti_rising(void)
{
	INTM->EGN0 &= ~(1 << 2);
	INTM->EGP0 &= ~(1 << 2);
	INTM->EGN0 |= 0 << 2;
	INTM->EGP0 |= 1 << 2;
}

void bsp_knob_set_exti_falling(void)
{
	INTM->EGN0 &= ~(1 << 2);
	INTM->EGP0 &= ~(1 << 2);
	INTM->EGN0 |= 1 << 2;
	INTM->EGP0 |= 0 << 2;
}

/********************************************************************************
*******************************************************************************/
void ENCODER_A_EXT_ISR(void)
{
	uint32_t diff_tick = 0;
	
	if (!knob_mgr.a_first_falling) {
		if (knob_mgr.a_first_rising) {
			diff_tick = TICK_DIFF(HAL_GetTick(), knob_mgr.a_first_rising_tick);
			if (diff_tick >= 1) {  // 大于1ms
				knob_mgr.a_first_rising = 0;
				knob_mgr.a_first_falling = 1;
				bsp_knob_set_exti_rising();  // 上升沿
				knob_mgr.a_first_falling_tick = HAL_GetTick();
				DBG_OUT_L();
			}
		} else {
			knob_mgr.a_first_falling = 1;
			bsp_knob_set_exti_rising();  // 上升沿
			knob_mgr.a_first_falling_tick = HAL_GetTick();
			DBG_OUT_L();
		}
	} else {
		diff_tick = TICK_DIFF(HAL_GetTick(), knob_mgr.a_first_falling_tick);
		if (diff_tick >= 2) {  // 大于2ms
			if (Bit_RESET == GPIO_ReadInputDataBit(GPIO_PORT1, GPIO_Pin_3)) {
				if (knob_mgr.knob_value) {
					knob_mgr.knob_value--;
				}
			} else {
				if (knob_mgr.knob_value < 0xff) {
					knob_mgr.knob_value++;
				}
			}
			DBG_OUT_H();
//			printf("%u\r",diff_tick);
			knob_mgr.a_first_falling = 0;
			knob_mgr.a_first_rising = 1;
			bsp_knob_set_exti_falling();
			knob_mgr.a_first_rising_tick = HAL_GetTick();
		}
	}
	
	INTC_ClearPendingIRQ(INTP2_IRQn);
}

/**************************************************************************************
***************************************************************************************/
void bsp_knob_init(void)
{
	INTP_InitTypeDef INTP_InitStructure;

	INTP_InitStructure.INTP_Select  = INTP2 ;           //  选择外部中断INTP0
	INTP_InitStructure.EXTI_Trigger = Trigger_Falling;  //  设置外部中断,下降沿触发
	INTP_Init(&INTP_InitStructure);

	ISR_Register(INTP2_IRQn, ENCODER_A_EXT_ISR);        //  中断服务路径注册
	NVIC_SetPriority(INTP2_IRQn, 1);
	INTP_Start(INTP2);                                  //  Enable INTP2 Interrupt
}

void bsp_knop_poll(void)
{
	if (knob_mgr.last_knob_value != knob_mgr.knob_value) {
		printf("%u\r", knob_mgr.knob_value);
		bsp_ws2812b_fill_solid_rgb(bsp_ws2812b_set_rgb(0, 0, knob_mgr.knob_value));
		bsp_ws2812b_send();
		knob_mgr.last_knob_value = knob_mgr.knob_value;
	}
}

/***********************END OF FILE***********************/

小结

  1. 当前使用的时间计数是在定时器1ms中断中的,计时可能不是很准,不过对于旋钮的信号是够用的,如果需要使用精准定时,可以单独使用一个定时器进行计时。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值