单片机开发--RDEC旋转编码器编程

一、旋转编码器介绍

1、编码器工作原理

编码器内部有一个开槽圆盘,连接到公共接地引脚 C。它还具有两个接触针 io A 和io B,旋钮转动会生成下列波形
在这里插入图片描述

2、旋转编码器的半码和全码

半码编码器:编码器拧动一次,A相和B相同时由高到低,转动半个周期为半码编码器
全码编码器:编码器拧动一次,A相和B相同时由高到低,再到高,转动一个周期。下图红色部分为一个周期
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fbe5a2990b364cadbff88454f77b3e9d.png

二、代码实现过程和原理

1、硬件io配置

在这里插入图片描述

2、定时器配置

配置循环扫描定时器,扫描二个io的状态,rdec_key_scan_para参数里面有二个io的状态获取函数。

#if TCFG_RDEC_KEY_ENABLE
    extern const struct rdec_platform_data rdec_key_data;
    extern struct key_driver_para rdec_key_scan_para;
    err = rdec_key_init(&rdec_key_data);
    if (err == 0) {
        if(!rdec_timeid) {
            rdec_timeid = sys_s_hi_timer_add((void *)&rdec_key_scan_para, key_driver_scan, rdec_key_scan_para.scan_time); //注册按键扫描定时器
        }
    }
#endif

3、代码实现原理

1、把a和b的二个io转动过程中的io电平变化记录下来

static u8 arry[4] = {0,0,0,0};
ptr++;
 ptr %= 4;
 arry[ptr] = now_ph;

 s8 c_ptr=ptr;

 u8 now_4ph[4];
 for(u8 i=0;i<4;i++){
     now_4ph[i] = arry[c_ptr];
     c_ptr--;
     if(c_ptr<0){
         c_ptr+=4;
     }
 }

下面是全码编码器正转和反转的四种io电平状况。10代表a为1,b为0;
u8 io[4]={11,11,00,01};
u8 io[4]={11,10,00,01};
u8 io[4]={11,11,00,10};
u8 io[4]={11,01,00,10};

三、整体代码实现如下

#include "key_driver.h"
#include "gpio.h"
#include "system/event.h"
#include "app_config.h"
#include "audio_config.h"
#include "rdec_key.h"

#define TCFG_USR_RDEC_TIME  1

#define HALF_CODE_RDEC  1   //是否为半码编码器
#define     RDEC_PHASE_A_IO	   TCFG_RDEC0_ECODE1_PORT   // 编码器反转调换这两个口即可
#define     RDEC_PHASE_B_IO	   TCFG_RDEC0_ECODE2_PORT

#if TCFG_USR_RDEC_TIME
#define  SMARTWEAR_RDEC_KEY_NEW_METHOD_CFG   1
#if SMARTWEAR_RDEC_KEY_NEW_METHOD_CFG
/* #include "SmartWear_includes.h" */
#endif

#if TCFG_RDEC_KEY_ENABLE

static const struct rdec_platform_data *__this = NULL;

u8 rdec_get_key_value(void);

struct key_driver_para rdec_key_scan_para = {
    .scan_time 	  	  = 2,				//按键扫描频率, 单位: ms
    .last_key 		  = NO_KEY,  		//上一次get_value按键值, 初始化为NO_KEY;
    .filter_time  	  = 0,				//按键消抖延时;
    .long_time 		  = 75,  			//按键判定长按数量
    .hold_time 		  = (75 + 15),  	//按键判定HOLD数量
    .click_delay_time = 0,				//按键被抬起后等待连击延时数量
    .key_type		  = KEY_DRIVER_TYPE_RDEC,
    .get_value 		  = rdec_get_key_value,
};

extern s8 get_rdec_rdat(int i);
extern u32 timer_get_ms(void);

#if SMARTWEAR_RDEC_KEY_NEW_METHOD_CFG
#define     CAP_DIV         512
#define     CAP_CLK         24000000
#define     CEC_TMR         JL_TIMER3
#define     CEC_TMR_IDX     IRQ_TIME3_IDX

#define     CAP_RISING_EDGE    0b10
#define     CAP_FALLING_EDGE   0b11



static u32 cap_mode;
static u32 phase_b_pre_state, phase_b_state;
static volatile int phase_data;


static void rdec_timer()
{
    static u32 cnt = 0;
    static u8 last_a_io = 255;
    static u8 last_b_io = 255;

    u8 a_io = gpio_read(RDEC_PHASE_A_IO);
    u8 b_io = gpio_read(RDEC_PHASE_B_IO);

    if(last_a_io!=a_io) {
        last_a_io = a_io;
        goto _check;
    }

    if(last_b_io!=b_io) {
        last_b_io = b_io;
        goto _check;
    }

    return;

_check:

    wdt_clear();
    static u8 last_ph = 0;
    static s8 count = 0;

    static u8 now_ph =0;
    now_ph = a_io+(b_io*10);
    last_ph = now_ph;

    static u8 ptr=0;

    static u8 arry[4] = {0,0,0,0};

    ptr++;
    ptr %= 4;
    arry[ptr] = now_ph;

    s8 c_ptr=ptr;

    u8 now_4ph[4];
    for(u8 i=0;i<4;i++){
        now_4ph[i] = arry[c_ptr];
        c_ptr--;
        if(c_ptr<0){
            c_ptr+=4;
        }
    }


#if HALF_CODE_RDEC
    u8 a1[3]={00,10,11};
    u8 a2[3]={11,01,00};
    u8 b1[4]={11,10,00};
    u8 b2[4]={00,01,11};

    if(memcmp(now_4ph,a1,3)==0 ||  memcmp(now_4ph,a2,3)==0)
    {
        phase_data++;
        return ;
    }

    else if(memcmp(now_4ph,b1,3)==0 ||  memcmp(now_4ph,b2,3)==0)
    {
        phase_data--;
        return ;
    }
#else
    u8 a1[4]={11,11,00,01};
    u8 a2[4]={11,10,00,01};
    u8 b1[4]={11,11,00,10};
    u8 b2[4]={11,01,00,10};
    
    if(memcmp(now_4ph,a1,4)==0 ||  memcmp(now_4ph,a2,4)==0)
    {
        phase_data++;
        return ;
    }

    if(memcmp(now_4ph,b1,4)==0 ||  memcmp(now_4ph,b2,4)==0)
    {
        phase_data--;
        return ;
    }


#endif
}


static void timer_rdec_port_init(u8 port)
{
    gpio_set_pull_down(port, 0);
    gpio_set_pull_up(port, 1);
    gpio_set_die(port, 1);
    gpio_set_direction(port, 1);
}

static void timer_rdec_port_uninit(u8 port)
{
    gpio_set_pull_down(port, 1);
    gpio_set_pull_up(port, 0);
    gpio_set_die(port, 1);
    gpio_set_direction(port, 1);
}

int timer_rdec_init(const struct rdec_platform_data *user_data)
{
    timer_rdec_port_init(RDEC_PHASE_A_IO);
    timer_rdec_port_init(RDEC_PHASE_B_IO);

    phase_data = 0;

    return 0;
}
#endif

u8 rdec_get_key_value(void)
{
    int i;
    s8 rdec_data=0;
    u8 key_value = 0;

    if (!__this->enable) {
        return NO_KEY;
    }

#if SMARTWEAR_RDEC_KEY_NEW_METHOD_CFG
    for (i = 0; i < 1; i++)
#else
    for (i = 0; i < 3; i++)
#endif
    {
#if SMARTWEAR_RDEC_KEY_NEW_METHOD_CFG
        rdec_timer();
        rdec_data = phase_data;
        phase_data = 0;

        if (rdec_data < 0) {
            key_value = __this->rdec[i].key_value0;
            printf("rdec_data_1 = %d\n", rdec_data);
            return key_value;
        } else if (rdec_data > 0) {
            key_value = __this->rdec[i].key_value1;
            printf("rdec_data_2 = %d\n", rdec_data);
            return key_value;
        }
#else
        rdec_data = get_rdec_rdat(i);
#endif

    }

    return NO_KEY;
}

int rdec_key_init(const struct rdec_platform_data *rdec_key_data)
{
    __this = rdec_key_data;
    if (!__this) {
        return -EINVAL;
    }
    if (!__this->enable) {
        return KEY_NOT_SUPPORT;
    }
    //printf("rdec_key_init >>>> ");
#if SMARTWEAR_RDEC_KEY_NEW_METHOD_CFG
    return timer_rdec_init(rdec_key_data);
#else
    return rdec_init(rdec_key_data);
#endif
}



/*------------------------------------------------------*/
// low power
#include "asm/power_interface.h"
#include "asm/power/power_api.h"
#define AT_VOLATILE_RAM_CODE AT(.volatile_ram_code)
AT_VOLATILE_RAM_CODE
extern const struct rdec_platform_data rdec_key_data;
static void rdec_enter_deepsleep(void)
{
    // timer_rdec_port_uninit(RDEC_PHASE_A_IO);
    // timer_rdec_port_uninit(RDEC_PHASE_B_IO);
}

AT_VOLATILE_RAM_CODE
static void rdec_exit_deepsleep(void)
{
    timer_rdec_port_init(RDEC_PHASE_A_IO);
    timer_rdec_port_init(RDEC_PHASE_B_IO);
}

DEEPSLEEP_TARGET_REGISTER(rdec) = {
    .name   = "rdec",
    .enter  = rdec_enter_deepsleep,
    .exit   = rdec_exit_deepsleep,
};

/*------------------------------------------------------*/
#endif  /* #if TCFG_RDEC_KEY_ENABLE */
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值