关于按键消抖或者开关量信号监测,可以参考本公众号的另外一篇原创文章:按键消抖常用的软硬件方法。在该文章中介绍了两种软件延时的方式。但也都各有缺点。
一:旧方案
方案一:纯软件延时
sbit key = p1^3;///按键读取函数uint8_t getkey(void){ if(key == 1) { delayms(20); //延时消抖 if(key == 1) { return 1; } else { return 0; } } else { return 0; }}致命缺点:在延时的时候一直占用cpu的资源,如果在延时的时候,有其他外部中断或者抢占事件,系统完全没有响应的
方案二:中断消抖
此处不在贴出代码:感兴趣的同学可到文章中查看:按键消抖常用的软硬件方法
致命缺点:多占用中断资源。操作复杂。在资源就是成本的产品中(多占用一个中断可能会导致需要选择价格更高的mcu),这种方案的缺点更加明显。 推荐方案
本文推荐一种更高效、合适,已在产品中使用过的软件设计方案。直接上代码。
#include // 定义开关信号结构体typedef struct { bool laststate; // 上次开关信号状态 bool currentstate; // 当前开关信号状态 bool validstate; // 有效的开关信号状态 int debouncedelaycounter; // 开关信号消抖计数器} debouncedswitch;// 初始化开关信号结构体void initializeswitch(debouncedswitch* switchobj) { switchobj->laststate = false; switchobj->currentstate = false; switchobj->validstate = false; switchobj->debouncedelaycounter = 0;}// 模拟读取开关信号状态的函数bool readswitchstate() { // 在这里替换为实际的开关信号读取代码 // 返回开关信号的当前状态(true表示开,false表示关) return false;}// 处理开关信号消抖的函数void debounceswitch(debouncedswitch* switchobj, int debouncetime) { // 读取当前开关信号状态 switchobj->currentstate = readswitchstate(); // 如果当前状态与上次状态不同,重置计数器并更新上次状态 if (switchobj->currentstate != switchobj->laststate) { switchobj->debouncedelaycounter = 0; } else { // 如果状态相同,增加计数器值 switchobj->debouncedelaycounter++; } // 如果计数器达到指定的消抖时间,表示开关信号状态稳定 if (switchobj->debouncedelaycounter >= (debouncetime / 10)) { // 如果当前状态与 validstate 不同,表示发生了有效的状态变化 if (switchobj->currentstate != switchobj->validstate) { switchobj->validstate = switchobj->currentstate; } } // 更新上次状态 switchobj->laststate = switchobj->currentstate;}int main() { // 创建一个开关信号的debouncedswitch结构体 debouncedswitch switchobj; initializeswitch(&switchobj); while (1) { debounceswitch(&switchobj, 100); // 设置消抖时间为100毫秒 if (switchobj.validstate) { if (switchobj.validstate) { // 执行开关信号为开的操作 printf(开关信号为开); } else { // 执行开关信号为关的操作 printf(开关信号为关); } } // 在这里可以添加其他需要执行的代码 // 模拟延时或等待开关信号状态变化 // 这里使用usleep函数来模拟10毫秒的延时 // 实际上,你需要根据你的硬件和操作系统来等待开关信号状态变化 usleep(10000); // 10毫秒 } return 0;}1、函数详解:
debounceswitch函数该函数用于处理开关信号的消抖,以确保稳定的开关状态。 它接受一个指向 debouncedswitch 结构体的指针, 该结构体包含了上次状态、当前状态、有效状态等信息,以及消抖时间的设置。
该函数的被调用周期为10ms(可以与产品程序中其他任务并行执行)。
2、函数的工作流程如下:
1)读取当前开关信号状态。
2)如果当前状态与上次状态不同,重置计数器并更新上次状态。
3)如果当前状态与上次状态相同,增加计数器值。
4)如果计数器达到指定的消抖时间,表示开关信号状态稳定。
5)如果当前状态与 validstate 不同,表示发生了有效的状态变化,更新有效状态。
6)更新上次状态以便下一次比较
3、优点介绍:
1)扩展性:
debounceswitch该函数使用结构体指针的形式,提供了开关量检测的框架,需要多个开关量/按键检测时,实例化对应的按键变量即可。例如:main函数的示例中实例化了switchobj,多有多个按键可以多定义不同的switchobj即可。如下:代码所展示:debouncedswitch switchobj_key1;debouncedswitch switchobj_key2;//其他代码debounceswitch(&switchobj_key1, 100);debounceswitch(&switchobj_key2, 50);2、高度可定制: debounceswitch函数中的消抖时间是作为参数传递的,这使得消抖时间可以根据不同的开关信号或应用场景进行定制。这种可定制性允许您在不同情况下使用不同的消抖时间,以满足特定需求。
3、适用于实时系统:
相对于纯软件延时消抖,debounceswitch函数是更可靠的,因为它不依赖于软件的延时,而是基于实际的状态变化来判断开关信号的稳定性。这使得它适用于实时系统和对时间精度要求较高的应用。 总结
当然,作为一个产品中使用的函数还有很多可优化的空间,比如:函数内判断指针不为空。进行参数的有效性检查等等。
磁珠和电感的区别是什么
Facebook的AI研究团队开发了一种神经转编译器
信源编码、复用技术在有线数字电视系统中的应用
基于嵌入式技术的汽车安全防御系统设计
马上过年了,这份2021年吸尘器推荐购买排行一定要看
按键消抖/开关量信号监测实现方案
日本通过3D打印技术而开发出生物启发机器人
简单的障碍物识别传感器电路设计
小米6发布时间终确认,性能怪兽!小米正式宣布小米6 工艺巅峰
同茂直线电机模组的组成结构图解
防护服合成血液穿透试验仪的技术指标说明
工业软件分类
为什么OPPO、vivo机型配置不好,但仍然很流畅?
MP3常见音效有哪些?
在FPGA上实现H.264/AVC视频编码标准
国内导热绝缘材料能否比肩贝格斯Sil-pad系列产品
要理解电感器的功能和电感器的各种参数,就要从电磁理论进行分析
MOS管的米勒效应:感性负载
美国城市对5G说“不”,不让5G基站进社区
北汽蓝谷与华为合作的首款车型在上海车展亮相