HAL STM32+EC11编码器实现增减调节及单击、双击、长按功能
- 实现效果演示:
内容提要
-
本文主要实现,通过STM32 HAL库开发,实现的EC11编码器功能,按键结合状态机思想实现的拓展单击、双击、长按的综合功能。单片机硬件上使用了2个外部中断引脚实现。
- 该功能可以很方便实现移植,例如使用在OLED屏幕显示菜单上。
- 验证对象:STM32F401
- EC11编码器部分的原理图:
stm32cubemx配置
- 将EC11中键引脚配置为输入模式、开启内部上拉模式,其余2个引脚配置为外部中断引脚(一个配置为下降沿中断,另外一个配置为上、下降沿中断,这一点很关键!)。
✅EC11编码器增减功能,通过外部中断实现
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
UNUSED(GPIO_Pin);
static uint8_t count = 0;
static uint8_t b_flag;
GPIO_PinState a_value = HAL_GPIO_ReadPin(EC11_A_GPIO_Port, EC11_A_Pin);
GPIO_PinState b_value = HAL_GPIO_ReadPin(EC11_B_GPIO_Port, EC11_B_Pin);
if(GPIO_Pin == EC11_A_Pin) {
if(a_value == RESET && count == 0) {
b_flag = 0;
if(b_value) b_flag = 1;
count = 1;
}
if(a_value == SET && count == 1) {
if(b_value == RESET && b_flag == 1) {
test_num--;
dir_flag = 1;
}
if(b_value && b_flag == 0) {
test_num++;
dir_flag = 0;
}
count = 0;
}
}
}
单击、双击、长按功能实现驱动代码
#include "key.h"
#define KEY_STATUS_DOWN_CHECK 0x00
#define KEY_STATUS_DOWN_SHAKE 0x01
#define KEY_STATUS_DOWN_HANDLE 0x02
#define KEY_STATUS_LONG_CHECK 0x03
#define KEY_STATUS_SHORT_UP_SHAKE 0x04
#define KEY_STATUS_DOUBLE_CHECK 0x05
#define KEY_STATUS_SHORT_UP_HANDLE 0x06
#define KEY_STATUS_DOUBLE_DOWN_SHAKE 0x07
#define KEY_STATUS_DOUBLE_UP_CHECK 0x08
#define KEY_STATUS_DOUBLE_UP_SHAKE 0x09
#define KEY_STATUS_DOUBLE_UP_HANDLE 0x0a
#define KEY_STATUS_LONG_HANDLE 0x0b
#define KEY_STATUS_CONTINUE_CHECK 0x0c
#define KEY_STATUS_LONG_UP_SHAKE 0x0d
#define KEY_STATUS_LONG_UP_HANDLE 0x0e
#define KEY_READ_DOWN 0x00
#define KEY_READ_UP 0x01
#define KEY_BUF_SIZE 0x10
struct
{
unsigned short value[KEY_BUF_SIZE];
unsigned char rd;
unsigned char wr;
}key_buf;
struct key_dev
{
unsigned char status;
unsigned char num;
unsigned short count_ms;
unsigned short long_click_ms;
unsigned short shake_filter_ms;
unsigned short max_dclick_ms;
unsigned short continue_send_ms;
unsigned char (*read_key)(void);
};
unsigned char key0_read(void)
{
if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET)
{
return KEY_READ_DOWN;
}
else
{
return KEY_READ_UP;
}
}
struct key_dev key_dev[] = {
{
KEY_STATUS_DOWN_CHECK,
KEY0_NUM,
0,
1500,
20,
300,
1000,
(unsigned char (*)(void))key0_read,
},
};
static void key_write_value(unsigned short key_val);
static void key_status_down_check(struct key_dev *key_dev);
static void key_status_down_shake(struct key_dev *key_dev);
static void key_status_down_handle(struct key_dev *key_dev);
static void key_status_long_check(struct key_dev *key_dev);
static void key_status_short_up_shake(struct key_dev *key_dev);
static void key_status_double_check(struct key_dev *key_dev);
static void key_status_short_up_handle(struct key_dev *key_dev);
static void key_status_double_down_shake(struct key_dev *key_dev);
static void key_status_double_up_check(struct key_dev *key_dev);
static void key_status_double_up_shake(struct key_dev *key_dev);
static void key_status_double_up_handle(struct key_dev *key_dev);
static void key_status_long_hanle(struct key_dev *key_dev);
static void key_status_continue_check(struct key_dev *key_dev);
static void key_status_long_up_shake(struct key_dev *key_dev);
static void key_status_long_up_handle(struct key_dev *key_dev);
static void key_write_value(unsigned short key_val)
{
key_buf.value[key_buf.wr++] = key_val;
key_buf.wr %= KEY_BUF_SIZE;
if(key_buf.wr == key_buf.rd)
{
key_buf.rd++;
key_buf.rd %= KEY_BUF_SIZE;
}
}
unsigned short key_read_value(void)
{
unsigned short key_val;
if(key_buf.wr == key_buf.rd)
{
key_val = KEY_EVENT_NULL;
}
else
{
key_val = key_buf.value[key_buf.rd++];
key_buf.rd %= KEY_BUF_SIZE;
}
return key_val;
}
static void key_status_down_check(struct key_dev *key_dev)
{
unsigned char key_read;
key_read = key_dev->read_key();
if(key_read == KEY_READ_DOWN)
{
key_dev->status = KEY_STATUS_DOWN_SHAKE;
key_dev->count_ms = 0;
}
}
static void key_status_down_shake(struct key_dev *key_dev)
{
unsigned char key_read;
key_dev->count_ms++;
if(key_dev->count_ms < key_dev->shake_filter_ms)
{
return;
}
key_read = key_dev->read_key();
if(key_read == KEY_READ_DOWN)
{
key_dev->status = KEY_STATUS_DOWN_HANDLE;
}
else
{
key_dev->status = KEY_STATUS_DOWN_CHECK;
}
}
static void key_status_down_handle(struct key_dev *key_dev)
{
unsigned short key_val = key_dev->num<<8 | KEY_EVENT_DOWN;
key_write_value(key_val);
key_dev->status = KEY_STATUS_LONG_CHECK;
key_dev->count_ms = 0;
}
static void key_status_long_check(struct key_dev *key_dev)
{
unsigned char key_read;
key_dev->count_ms++;
key_read = key_dev->read_key();
if(key_dev->count_ms < key_dev->long_click_ms)
{
if(key_read == KEY_READ_UP)
{
key_dev->status = KEY_STATUS_SHORT_UP_SHAKE;
}
return;
}
key_dev->status = KEY_STATUS_LONG_HANDLE;
}
static void key_status_short_up_shake(struct key_dev *key_dev)
{
unsigned char key_read;
static unsigned short old = 0xffff;
if(old == 0xffff)
{
old = key_dev->count_ms;
key_dev->count_ms = 0;
}
key_dev->count_ms++;
if(key_dev->count_ms < key_dev->shake_filter_ms)
{
return;
}
key_read = key_dev->read_key();
if(key_read == KEY_READ_UP)
{
key_dev->status = KEY_STATUS_DOUBLE_CHECK;
key_dev->count_ms = 0;
}
else
{
key_dev->status = KEY_STATUS_LONG_CHECK;
key_dev->count_ms += old;
}
old = 0xffff;
}
static void key_status_double_check(struct key_dev *key_dev)
{
unsigned char key_read;
key_dev->count_ms++;
key_read = key_dev->read_key();
if(key_dev->count_ms < key_dev->max_dclick_ms)
{
if(key_read == KEY_READ_DOWN)
{
key_dev->status = KEY_STATUS_DOUBLE_DOWN_SHAKE;
key_dev->count_ms = 0;
}
}
else
{
key_dev->status = KEY_STATUS_SHORT_UP_HANDLE;
}
}
static void key_status_short_up_handle(struct key_dev *key_dev)
{
unsigned short key_val;
key_val= key_dev->num<<8 | KEY_EVENT_SHORT;
key_write_value(key_val);
key_val= key_dev->num<<8 | KEY_EVENT_UP_SHORT;
key_write_value(key_val);
key_dev->status = KEY_STATUS_DOWN_CHECK;
}
static void key_status_double_down_shake(struct key_dev *key_dev)
{
unsigned char key_read;
static unsigned short old = 0xffff;
if(old == 0xffff)
{
old = key_dev->count_ms;
key_dev->count_ms = 0;
}
key_dev->count_ms++;
if(key_dev->count_ms < key_dev->shake_filter_ms)
{
return;
}
key_read = key_dev->read_key();
if(key_read == KEY_READ_DOWN)
{
unsigned short key_val;
key_val= key_dev->num<<8 | KEY_EVENT_DOUBLE;
key_write_value(key_val);
key_dev->status = KEY_STATUS_DOUBLE_UP_CHECK;
key_dev->count_ms = 0;
}
else
{
key_dev->status = KEY_STATUS_DOUBLE_CHECK;
key_dev->count_ms += old;
}
old = 0xffff;
}
static void key_status_double_up_check(struct key_dev *key_dev)
{
unsigned char key_read;
key_read = key_dev->read_key();
if(key_read == KEY_READ_UP)
{
key_dev->status = KEY_STATUS_DOUBLE_UP_SHAKE;
key_dev->count_ms = 0;
}
}
static void key_status_double_up_shake(struct key_dev *key_dev)
{
unsigned char key_read;
key_dev->count_ms++;
if(key_dev->count_ms < key_dev->shake_filter_ms)
{
return;
}
key_read = key_dev->read_key();
if(key_read == KEY_READ_UP)
{
key_dev->status = KEY_STATUS_DOUBLE_UP_HANDLE;
}
else
{
key_dev->status = KEY_STATUS_DOUBLE_UP_CHECK;
}
}
static void key_status_double_up_handle(struct key_dev *key_dev)
{
unsigned short key_val;
key_val= key_dev->num<<8 | KEY_EVENT_UP_DOUBLE;
key_write_value(key_val);
key_dev->status = KEY_STATUS_DOWN_CHECK;
}
static void key_status_long_hanle(struct key_dev *key_dev)
{
unsigned short key_val;
key_val= key_dev->num<<8 | KEY_EVENT_LONG;
key_write_value(key_val);
key_dev->status = KEY_STATUS_CONTINUE_CHECK;
key_dev->count_ms = 0;
}
static void key_status_continue_check(struct key_dev *key_dev)
{
unsigned char key_read;
unsigned short key_val;
key_dev->count_ms++;
key_read = key_dev->read_key();
if(key_read == KEY_READ_UP)
{
key_dev->status = KEY_STATUS_LONG_UP_SHAKE;
}
if(key_dev->count_ms < key_dev->continue_send_ms)
{
return;
}
if(key_dev->continue_send_ms == 0)
{
return;
}
key_val= key_dev->num<<8 | KEY_EVENT_SHORT;
key_write_value(key_val);
key_dev->count_ms = 0;
}
static void key_status_long_up_shake(struct key_dev *key_dev)
{
unsigned char key_read;
static unsigned short old = 0xffff;
if(old == 0xffff)
{
old = key_dev->count_ms;
key_dev->count_ms = 0;
}
key_dev->count_ms++;
if(key_dev->count_ms < key_dev->shake_filter_ms)
{
return;
}
key_read = key_dev->read_key();
if(key_read == KEY_READ_UP)
{
key_dev->status = KEY_STATUS_LONG_UP_HANDLE;
}
else
{
key_dev->status = KEY_STATUS_CONTINUE_CHECK;
key_dev->count_ms += old;
}
old = 0xffff;
}
static void key_status_long_up_handle(struct key_dev *key_dev)
{
unsigned short key_val;
key_val= key_dev->num<<8 | KEY_EVENT_UP_LONG;
key_write_value(key_val);
key_dev->status = KEY_STATUS_DOWN_CHECK;
}
static void key_check_1ms(struct key_dev *key_dev)
{
switch(key_dev->status)
{
case KEY_STATUS_DOWN_CHECK :
key_status_down_check(key_dev);
break;
case KEY_STATUS_DOWN_SHAKE :
key_status_down_shake(key_dev);
break;
case KEY_STATUS_DOWN_HANDLE :
key_status_down_handle(key_dev);
break;
case KEY_STATUS_LONG_CHECK :
key_status_long_check(key_dev);
break;
case KEY_STATUS_SHORT_UP_SHAKE :
key_status_short_up_shake(key_dev);
break;
case KEY_STATUS_DOUBLE_CHECK :
key_status_double_check(key_dev);
break;
case KEY_STATUS_SHORT_UP_HANDLE :
key_status_short_up_handle(key_dev);
break;
case KEY_STATUS_DOUBLE_DOWN_SHAKE :
key_status_double_down_shake(key_dev);
break;
case KEY_STATUS_DOUBLE_UP_CHECK :
key_status_double_up_check(key_dev);
break;
case KEY_STATUS_DOUBLE_UP_SHAKE :
key_status_double_up_shake(key_dev);
break;
case KEY_STATUS_DOUBLE_UP_HANDLE :
key_status_double_up_handle(key_dev);
break;
case KEY_STATUS_LONG_HANDLE :
key_status_long_hanle(key_dev);
break;
case KEY_STATUS_CONTINUE_CHECK :
key_status_continue_check(key_dev);
break;
case KEY_STATUS_LONG_UP_SHAKE :
key_status_long_up_shake(key_dev);
break;
case KEY_STATUS_LONG_UP_HANDLE :
key_status_long_up_handle(key_dev);
break;
default:
key_dev->status = key_dev->status;
}
}
void key_check_all_loop_1ms(void)
{
unsigned char key_num, i;
key_num = sizeof(key_dev)/sizeof(struct key_dev);
for(i = 0; i < key_num; i++)
{
key_check_1ms(&key_dev[i]);
}
}
#ifndef __key_H
#define __key_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#define shortmaxclickms (300)
#define shortminclickms (10)
#define longclickms (800)
#define KEY_EVENT_NULL 0x0000
#define KEY_EVENT_DOWN 0x0001
#define KEY_EVENT_UP_SHORT 0x0002
#define KEY_EVENT_UP_LONG 0x0003
#define KEY_EVENT_UP_DOUBLE 0x0004
#define KEY_EVENT_SHORT 0x0005
#define KEY_EVENT_LONG 0x0006
#define KEY_EVENT_DOUBLE 0x0007
#define KEY_READ_DOWN 0x00
#define KEY_READ_UP 0x01
#define KEY0_NUM 0x0001
#define KEY0_DOWN (KEY_EVENT_DOWN | KEY0_NUM<<8)
#define KEY0_UP_SHORT (KEY_EVENT_UP_SHORT | KEY0_NUM<<8)
#define KEY0_UP_LONG (KEY_EVENT_UP_LONG | KEY0_NUM<<8)
#define KEY0_UP_DOUBLE (KEY_EVENT_UP_DOUBLE | KEY0_NUM<<8)
#define KEY0_SHORT (KEY_EVENT_SHORT | KEY0_NUM<<8)
#define KEY0_LONG (KEY_EVENT_LONG | KEY0_NUM<<8)
#define KEY0_DOUBLE (KEY_EVENT_DOUBLE | KEY0_NUM<<8)
void key_check_all_loop_1ms(void);
unsigned short key_read_value(void);
#ifdef __cplusplus
}
#endif
#endif
main函数中按键处理内容
#include "stdio.h"
#include "key.h"
int32_t test_num = 0;
uint8_t dir_flag = 2;
uint8_t key_click_flag = 0;
unsigned short key_value;
int main(void)
{
uint32_t tick2, tick3;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
uint32_t Main_Fosc = HAL_RCC_GetSysClockFreq();
printf("Main_Fosc:%dHz \r\n", Main_Fosc);
while(1) {
if(dir_flag != 2) {
switch(dir_flag) {
case 0:
printf("顺时针转动\r\n");
break;
case 1:
printf("逆时针转动\r\n");
break;
}
dir_flag = 2;
printf("num: %d\n", test_num);
}
if(HAL_GetTick() - tick2 >= 1) {
tick2 = HAL_GetTick();
key_check_all_loop_1ms();
}
if(HAL_GetTick() - tick3 >= 10) {
tick3 = HAL_GetTick();
key_value = key_read_value();
if(key_value == KEY0_UP_SHORT) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
test_num++;
printf("Press 单击,num:%d\r\n", test_num);
} else if(key_value == KEY0_UP_DOUBLE) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
test_num += 2;
printf("\r\nDouble Press 双击,num:%d\r\n", test_num);
} else if(key_value == KEY0_LONG) {
printf("\r\nLong Press 长按\r\n");
test_num = 0;
printf("按键计数清零,num:%d\r\n", test_num);
}
}
}
}
工程源码
链接:https:
提取码:4m2q