mcu_ab568x/app/platform/bsp/bsp_qdec.c
2025-05-30 18:03:10 +08:00

368 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "include.h"
#include "bsp_sys.h"
#define TRACE_EN 0
#if TRACE_EN
#define TRACE(...) printf(__VA_ARGS__)
#else
#define TRACE(...)
#endif
#if USER_KEY_QDEC_EN
#define QDEC_ORIGINAL_PLAN_EN 0
#if !QDEC_ORIGINAL_PLAN_EN
#define QDEC_PRESSED_CNT_MAX 3
#define QDEC_DEBOUNCE_CNT_MAX 5
typedef struct
{
bool back_pressed; // 检测释放
uint32_t back_pressed_cnt; // 释放消抖次数
uint32_t back_debounce_cnt; // 按下消抖次数
bool for_pressed; // 检测释放
uint32_t for_pressed_cnt; // 释放消抖次数
uint32_t for_debounce_cnt; // 按下消抖次数
} qdec_button_t;
static qdec_button_t qdec_button = {0};
AT(.com_text.qdec)
static void qdec_key_for_clear(void)
{
qdec_button.for_pressed = false;
qdec_button.for_pressed_cnt = 0;
qdec_button.for_pressed_cnt = 0;
}
AT(.com_text.qdec)
static void qdec_key_back_clear(void)
{
qdec_button.back_pressed = false;
qdec_button.back_pressed_cnt = 0;
qdec_button.back_debounce_cnt = 0;
}
AT(.com_text.qdec)
void qdec_key_msg_enqueue(u8 msg)
{
static u32 interrupt_time = 0;
if (tick_check_expire(interrupt_time, 30)) {
interrupt_time = tick_get();
reset_sleep_delay_all(); // 复位休眠计数
my_msg_enqueue(msg);
}
}
AT(.com_text.qdec)
void bsp_qdec_process(void)
{
bool forward_state = false;
bool backward_state = false;
#if (USER_QDEC_MAPPING == QDEC_MAP_G1)
forward_state = !(GPIOB & BIT(1)) ? false : true;
backward_state = !(GPIOB & BIT(0)) ? false : true;
#elif (USER_QDEC_MAPPING == QDEC_MAP_G2)
forward_state = !(GPIOE & BIT(2)) ? false : true;
backward_state = !(GPIOE & BIT(1)) ? false : true;
#elif (USER_QDEC_MAPPING == QDEC_MAP_G3)
forward_state = !(GPIOE & BIT(7)) ? false : true;
backward_state = !(GPIOE & BIT(6)) ? false : true;
#endif
/* BACKWARD */
if (!backward_state) {
if (qdec_button.back_debounce_cnt < QDEC_DEBOUNCE_CNT_MAX) {
qdec_button.back_debounce_cnt++;
} else {
if (!qdec_button.back_pressed) {
qdec_button.back_pressed_cnt = 0;
qdec_button.back_pressed = true;
} else {
/* 编码器处于长触发未释放状态 */
qdec_key_for_clear();
}
}
} else {
qdec_button.back_debounce_cnt = 0;
if (qdec_button.back_pressed)
{
if (++qdec_button.back_pressed_cnt > QDEC_PRESSED_CNT_MAX) {
qdec_key_back_clear();
qdec_key_msg_enqueue(MSG_QDEC_BACKWARD);
}
qdec_key_for_clear();
}
}
/* FORWARD */
if (!forward_state) {
if (qdec_button.for_debounce_cnt < QDEC_DEBOUNCE_CNT_MAX) {
qdec_button.for_debounce_cnt++;
} else {
if (!qdec_button.for_pressed) {
qdec_button.for_pressed_cnt = 0;
qdec_button.for_pressed = true;
} else {
/* 编码器处于长触发未释放状态 */
qdec_key_back_clear();
}
}
} else {
qdec_button.for_debounce_cnt = 0;
if (qdec_button.for_pressed)
{
if (++qdec_button.for_pressed_cnt > QDEC_PRESSED_CNT_MAX) {
qdec_key_for_clear();
qdec_key_msg_enqueue(MSG_QDEC_FORWARD);
}
qdec_key_back_clear();
}
}
}
#else
AT(.com_text.qdec)
void qdec_key_msg_enqueue(u8 msg)
{
/* 硬件正交解码额外消抖间隔时长 (unit:ms) */
static u32 interrupt_time = 0;
if (tick_check_expire(interrupt_time, 30)) {
interrupt_time = tick_get();
reset_sleep_delay_all(); // 复位休眠计数
my_msg_enqueue(msg);
}
}
/*
* 旋转编码器Quadrate Decode
* QDEC_MAP_G1: A -> PB0, B -> PB1
* QDEC_MAP_G2: A -> PE1, B -> PE2
* QDEC_MAP_G3: A -> PE6, B -> PE7
*/
AT(.com_text.qdec)
void qdec_isr(void)
{
u32 qdeccon = QDECCON;
if (qdeccon & BIT(1)) { //interrupt is enbale?
if (qdeccon & BIT(30)) { //forward
QDECCPND = BIT(30);
qdec_key_msg_enqueue(MSG_QDEC_BACKWARD);
}
if (qdeccon & BIT(31)) { //reverse
QDECCPND = BIT(31);
qdec_key_msg_enqueue(MSG_QDEC_FORWARD);
}
}
}
AT(.com_text.qdec)
void bsp_qdec_process(void)
{
}
#endif
void bsp_qdec_init(void)
{
CLKGAT2 |= BIT(2); //qdec clk enable
#if (USER_QDEC_MAPPING == QDEC_MAP_G1)
GPIOBDIR |= 0x03;
GPIOBDE |= 0x03;
GPIOBFEN |= 0x03;
GPIOBPU |= 0x03;
#elif (USER_QDEC_MAPPING == QDEC_MAP_G2)
GPIOEDIR |= 0x06;
GPIOEDE |= 0x06;
GPIOEFEN |= 0x06;
GPIOEPU |= 0x06;
#elif (USER_QDEC_MAPPING == QDEC_MAP_G3)
GPIOEDIR |= 0xc0;
GPIOEDE |= 0xc0;
GPIOEFEN |= 0xc0;
GPIOEPU |= 0xc0;
#endif
#if QDEC_ORIGINAL_PLAN_EN
sys_irq_init(IRQ_QDEC_VECTOR, 0, qdec_isr);
FUNCMCON2 = USER_QDEC_MAPPING;
QDECCON = 63 << 3; //quadrate decode filter length
QDECCPND = BIT(30) | BIT(31);
QDECCON = BIT(0) | BIT(1); //qdec decode enable, interrupt enable
#endif
}
#elif USER_ADKEY_QDEC_EN
/*
* QDEC_A串接5.1KQEC_B串接10K接到同一IO上。IO开内部10K上拉用ADC来采电压。
* 正旋3.3v -- 1.113v -- 0.825v -- 1.65v -- 3.3v
* 正旋: AH_BH - AL_BH -- AL_BL -- AH_BL -- AH_BH
* 反旋3.3v -- 1.65v -- 0.825v -- 1.113v -- 3.3v
* 反旋AH_BH - AH_BL -- AL_BL -- AL_BH -- AH_BH
*/
enum {
QEC_AH_BH, //A输出高电平B输出高电平空闲状态
QEC_AL_BH, //A输出低电平B输出高电平
QEC_AL_BL, //A输出低电平B输出低电平
QEC_AH_BL, //A输出高电平B输出低电平
};
typedef struct {
u8 status[3];
u8 cnt;
u8 pre_sta;
u8 new_sta;
u8 new_sta_cnt;
} qdec_cb_t;
static qdec_cb_t qdec_cb;
AT(.com_rodata.pwrkey.table)
const adkey_tbl_t qdec_adkey_table[6] = {
{0x30, QEC_AH_BH},
{0x4C, QEC_AL_BL},
{0x6A, QEC_AL_BH},
{0x8A, QEC_AH_BL},
{0xFF, QEC_AH_BH},
};
void bsp_qdec_init(void)
{
u8 io_num = get_adc_gpio_num(USER_QDEC_ADCH);
memset(&qdec_cb, 0, sizeof(qdec_cb_t));
if (io_num != IO_NONE) {
gpio_t gpio;
gpio_cfg_init(&gpio, io_num);
gpio.sfr[GPIOxDE] |= gpio.pin;
gpio.sfr[GPIOxDIR] |= gpio.pin;
gpio.sfr[GPIOxPU] |= gpio.pin;
saradc_set_channel(BIT(USER_QDEC_ADCH));
}
}
AT(.com_text.qdec)
void qdec_key_msg_enqueue(u8 msg)
{
reset_sleep_delay_all(); //复位休眠计数
my_msg_enqueue(msg);
}
#if TRACE_EN
AT(.com_text.str)
char qdec_str0[] = "(qdec)%d->%d[%d %d %d]\n";
AT(.com_text.str)
char qdec_str1[] = "(qdec)[%d %d %d]\n";
AT(.com_text.str)
char qdec_str2[] = "(qdec)[%d %d %d]!!!!!\n";
AT(.com_text.str)
char qdec_str3[] = "(qdec)0x%x\n";
#endif // TRACE_EN
//每毫秒ADC采样值进行处理
AT(.com_text.qdec)
void bsp_qdec_adc_process(u8 adc_val)
{
u8 num = 0;
u8 qdec_cur_sta;
while ((u8)adc_val > qdec_adkey_table[num].adc_val) {
num++;
}
qdec_cur_sta = qdec_adkey_table[num].usage_id;
if (qdec_cb.new_sta) { //消抖
if (qdec_cb.new_sta == qdec_cur_sta) {
qdec_cb.new_sta_cnt++;
if (qdec_cb.new_sta_cnt >= 1) { //增大该值以提高消抖程度
qdec_cb.new_sta = 0;
qdec_cb.new_sta_cnt = 0;
if (qdec_cur_sta != qdec_cb.pre_sta) {
if (qdec_cur_sta != QEC_AH_BH) {
if (qdec_cb.pre_sta == QEC_AH_BH) {
qdec_cb.cnt = 0;
}
if (qdec_cb.cnt < 3) {
qdec_cb.status[qdec_cb.cnt++] = qdec_cur_sta;
}
}
TRACE(qdec_str0, qdec_cb.pre_sta , qdec_cur_sta, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
qdec_cb.pre_sta = qdec_cur_sta;
}
}
} else {
qdec_cb.new_sta = qdec_cur_sta;
qdec_cb.new_sta_cnt = 0;
}
} else if (qdec_cur_sta != qdec_cb.pre_sta) {
qdec_cb.new_sta = qdec_cur_sta;
qdec_cb.new_sta_cnt = 0;
}
if (qdec_cur_sta == QEC_AH_BH) { //结束
#if !USER_ADKEY_QDEC_NO_STD
if (qdec_cb.cnt == 3 && qdec_cb.status[1] == QEC_AL_BL) {
TRACE(qdec_str1, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
if (qdec_cb.status[0] == QEC_AL_BH && qdec_cb.status[2] == QEC_AH_BL) {
qdec_key_msg_enqueue(MSG_QDEC_FORWARD);
// uart_putchar('F');
} else if (qdec_cb.status[2] == QEC_AL_BH && qdec_cb.status[0] == QEC_AH_BL) {
qdec_key_msg_enqueue(MSG_QDEC_BACKWARD);
// uart_putchar('R');
}
} else if (qdec_cb.cnt >= 1) {
TRACE(qdec_str2, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
}
#else
if (qdec_cb.status[1] == QEC_AL_BL) {
if (qdec_cb.status[0] == QEC_AL_BH) {
#if defined(SETTING_MSG_QDEC_WARD)
qdec_key_msg_enqueue(MSG_QDEC_FORWARD);
#else
qdec_key_msg_enqueue(MSG_QDEC_BACKWARD);
#endif
// uart_putchar('F');
if (qdec_cb.cnt == 3 && qdec_cb.status[2] == QEC_AH_BL) {
TRACE(qdec_str1, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
} else {
TRACE(qdec_str2, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
}
} else if (qdec_cb.status[0] == QEC_AH_BL) {
#if defined(SETTING_MSG_QDEC_WARD)
qdec_key_msg_enqueue(MSG_QDEC_BACKWARD);
#else
qdec_key_msg_enqueue(MSG_QDEC_FORWARD);
#endif
// uart_putchar('R');
if (qdec_cb.cnt == 3 && qdec_cb.status[2] == QEC_AL_BH) {
TRACE(qdec_str1, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
} else {
TRACE(qdec_str2, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
}
} else {
TRACE(qdec_str2, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
}
} else if (qdec_cb.cnt >= 1) {
TRACE(qdec_str2, qdec_cb.status[0], qdec_cb.status[1], qdec_cb.status[2]);
}
#endif
memset(&qdec_cb, 0, sizeof(qdec_cb_t));
}
}
#else
void bsp_qdec_init(void)
{
}
#endif // USER_ADKEY_QDEC_EN