本帖最后由 shentqlf 于 2019-5-17 08:25 编辑
好久没发帖子了,露个脸,对之前发的那个事件驱动做了一些优化
按键程序是单片机中最常用的一个功能了,但是想写好一个通用的按键驱动程序并不太简单,我在eBox的架构下写了一个全功能的按键程序,分享出来。请各路大神斧正优化。
先介绍下按键的功能
1、
单击--按键按下后触发一个事件
2、
释放--按键释放后触发一个事件
3、
长按--按键按下后不松开事件,在这个状态下会有两种需求,
A、
单次触发--当系统检测到长按发生后,触发一次事件
B、
连续触发--当系统检测到长按发生后,需要每隔一段时间触发一次事件。
4、
双击--在特定的间隔时间内连续按下两次按键,触发一个事件(本驱动为支持,个人认为这个功能在单片机上可由别的逻辑方法代替。所以我就没上心做这个这支持)
5、
软件滤波--为了防止IO的抖动(一次按下可能会触发多次),在没有硬件滤波的情况下需要做软件滤波,最好是
非阻塞的滤波,如果是阻塞模式的,则会让单片机大大浪费时间在延时上。
实现方法
1、初始化按键对象
A、是哪个GPIO,
B、初始态是高还是低- EventGpio(Gpio *io,uint8_t first_state)
- {
- this->io = io;
- this->first_state = first_state;
- state = first_state;
- click_pushed = 0;
- click_released = 0;
- long_pressed = 0;
-
- event_high = NULL;
- event_low = NULL;
- event_pos_edge = NULL;
- event_neg_edge = NULL;
- event_click = NULL;
- event_release = NULL;
- event_long_press = NULL;
- long_press_type = Continue;
- }
复制代码
2、所有事件的入口
- void (*event_high)();
- void (*event_low)();
- void (*event_pos_edge)();
- void (*event_neg_edge)();
- void (*event_click)();
- void (*event_release)();
- void (*event_long_press)();
复制代码
3、需要一个初始化传递过来的GPIO和一个循环函数
- void EventGpio::begin()
- {
- if(this->first_state == 0)
- io->mode(INPUT_PD);
- else
- io->mode(INPUT_PU);
- }
- virtual void loop(void);
复制代码
4、一些宏定义配置,类型和变量
- //软件滤波时间ms
- #define IO_EDGE_FILTER_COUNTS 0//默认不使用软件滤波
- //长按事件触发事件
- #define LONG_PRESS_COUNTS 2000//2000ms
- //长按事件连续触发间隔
- #define LONG_PRESS_INTERVAL 100//100ms
- public:
- typedef enum type{
- Single = 0,
- Continue = 1
- }LongPressType_t;
- LongPressType_t long_press_type;
- private:
- Gpio *io;
- uint8_t state;
- uint32_t last_time;
- uint16_t long_pressed;
- uint8_t click_pushed;
- uint8_t click_released;
- uint8_t first_state;
- uint8_t changed;
- uint16_t long_press_triger_time;
复制代码
附加功能
除了按键的功能外还支持了
上升沿事件、
下降沿事件,当然还有更简单的
高低电平事件。这些触发是
电平绝对值触发的事件。按键的单击,释放是相对的。
变量检测
事件驱动还支持了变量变化触发功能,由
EvnentVar实现
1、
变量变化事件--当变量发生变化后触发事件
2、
变量变大事件--当变量变大触发事件
3、
变量减小事件--当变量变小触发事件
EventManager
前面所说的EventGpio和EvnetVar用户可能需要创建出很多对象,为了统一管理这些对象,使用了一个链表,用户可以将EventVar和EvnetGpio对象添加到管理器中。通过管理的一个一个loop实现刷新。
- EventGpio btn(&PA8, 1);
- uint8_t volume = 0;
- EventVar<uint8_t> var(&volume);
- EventManager event_manager;
- void setup()
- {
- ebox_init();
- UART.begin(115200);
- print_log(EXAMPLE_NAME, EXAMPLE_DATE);
- //event_io_1.begin(1);
-
-
- btn.event_click = click;
- btn.event_release = release;
- btn.event_long_press = long_press;
- btn.long_press_type = EventGpio::Continue;
- // btn.event_high = high;
- // btn.event_low = low;
- // btn.event_neg_edge = neg;
- // btn.event_pos_edge = pos;
-
- var.event_changed = change;
- var.event_nag_edge = down;
- var.event_pos_edge = up;
- btn.begin();
-
- event_manager.add(&btn);
- event_manager.add(&var);
- }
- uint32_t last;
- uint8_t flag = 0;
- int main(void)
- {
- setup();
- while(1)
- {
- event_manager.loop();
- delay_ms(1);
- if(millis() - last > 1000)
- {
- last = millis();
- if(flag==0)
- volume++;
- else
- volume--;
- if(volume >= 3)
- flag = 1;
- else if (volume == 0)
- flag = 0;
- }
-
- }
- }
复制代码
详细实现内容,我就不贴了,太长太啰嗦,大家可以直接下载工程浏览,
如有优化空间还请各路大神指导
工程文件目录:eBox_FrameworkProject
stm32f10x-mdmdk
ggithub持续更新地址:
https://github.com/eboxmaker/eBox_Framework
工程文件:
eBox_Framework.rar
(14.91 MB, 下载次数: 19)
2019-5-17 08:25 上传
点击文件名下载附件
eBox_Framework
各种需求不带参数当然就是能满足,但是现在的码农(比如我)都被养刁了,就是懒,能少敲一下是一下。
比如我要实现一个数字键盘,有0~9、删除、确认、取消几个按键,很少。但我就不愿每个按键都写一次事件,而是把0~9这10个按键统一处理,一个事件搞定。菜单也是,好多都是同类的我都习惯在一个事件处理,尤其是动态生成时。
貌似可以减少些工作量~~~
TIM截图20190522103750.jpg (34.43 KB, 下载次数: 0)
下载附件
2019-5-22 10:39 上传
就是这个意思呗
一周热门 更多>