富芮坤FR800X系列之按键检测模块设计


FR800X系列按键检测模块


读者对象:
本文档主要适用以下工程师:
嵌入式系统工程师
单片机软件工程师
IOT固件工程师
BLE固件工程师

文章目录

  • 1.概要
  • 2.用户如何设计按键检测模块
    • 2.1 GPIO初始化
    • 2.2按键模块初始化
    • 2.3设计中断函数:
    • 2.4循环检测按键和输出事件
    • 2.5按键任务处理
    • 2.6 事件处理函数
  • 3.按键模块调试细节
  • 4.小结

1.概要

FR800X系列软件开发中基于官方SDK中如何设计按键检测模块。按键检测需满足两个要求分别为消除抖动干扰和快速响应。要想消除抖动干扰,就需要做滤波处理,比如间隔10ms持续检测3(2-5)次为低电平为按键按下有效。快速响应就需要中断触发,中断触发后开启定时器循环检测按键。那用户怎样设计按键检测模块呢?
设计按键模块化好处:
灵活性:模块化的按键设计能够提供更多的选择和灵活性。不同的按键模块可以根据需求进行组合和更换,从而满足不同的功能需求。

易于维护:按键模块化可以使维护更加简单。当一个按键出现故障时,只需替换该模块,而无需更换整个设备。这节省了时间和资源,并减少了停机时间。

可扩展性:按键模块化允许在需要时添加更多的按键。这种扩展性使得设备能够适应不断变化的需求和功能。

互换性:按键模块化使不同厂商的按键能够互相兼容。这意味着用户可以更容易地找到合适的按键模块,并使用它们来替换原始设备中的按键。

降低成本:按键模块化可以降低成本,因为只需购买需要的按键模块,而无需购买整个设备。此外,模块化还可以减少对专门技术的需求,从而降低维修和维护的成本。
在这里插入图片描述
按键模块框图
本文主要讲述:①用户如何设置GOIO中断唤醒、IO中断怎样处理;②如何设计软件检测多个独立按键的;③用户发送按键事件,短按、长按、超长按;④然后统一处理按键事件,在按键事件中定义业务功能。

2.用户如何设计按键检测模块

首先建立键模块化文件app_buttons.c和app_buttons.h。app_buttons.c存放程序内容,app_buttons.h存放相关接口。实现了正常模式和低功耗模式下的按键检测,代码如下:

2.1 GPIO初始化

// 按键 PD7 PC2 PC3 exti_enablesystem_set_port_mux(GPIO_PORT_D, GPIO_BIT_7, PORTD7_FUNC_D7);system_set_port_mux(GPIO_PORT_D, GPIO_BIT_6, PORTD6_FUNC_D6);system_set_port_mux(GPIO_PORT_C, GPIO_BIT_2, PORTC2_FUNC_C2);system_set_port_mux(GPIO_PORT_C, GPIO_BIT_3, PORTC3_FUNC_C3);system_set_port_pull(GPIO_PD7, GPIO_PULL_UP, true);system_set_port_pull(GPIO_PD6, GPIO_PULL_UP, true);system_set_port_pull(GPIO_PA4, GPIO_PULL_UP, true);system_set_port_pull(GPIO_PA5, GPIO_PULL_UP, true);exti_enable(GPIO_PD7|GPIO_PD6|GPIO_PC3|GPIO_PC2);NVIC_EnableIRQ(GPIO_IRQn);// 按键PD7 PC2 PC3 wakeuppmu_set_pin_pull(GPIO_PORT_D, GPIO_PIN_7, GPIO_PULL_UP);pmu_set_pin_pull(GPIO_PORT_D, GPIO_PIN_6, GPIO_PULL_UP);pmu_set_pin_pull(GPIO_PORT_C, GPIO_PIN_2, GPIO_PULL_UP);pmu_set_pin_pull(GPIO_PORT_C, GPIO_PIN_3, GPIO_PULL_UP);pmu_port_wakeup_func_set(GPIO_PORT_D, GPIO_PIN_7);pmu_port_wakeup_func_set(GPIO_PORT_D, GPIO_PIN_6);pmu_port_wakeup_func_set(GPIO_PORT_C, GPIO_PIN_2);pmu_port_wakeup_func_set(GPIO_PORT_C, GPIO_PIN_3);button_init(GPIO_PD7|GPIO_PD6|GPIO_PC3|GPIO_PC2);NVIC_EnableIRQ(PMU_IRQn);

2.2按键模块初始化

    uart_printf("buttons_init,%x\r\n",enable_io);/*  清除RAM */memset(&button_curr_list,0,sizeof(button_curr_list));memset(&button_last_list,0,sizeof(button_last_list));/*  检测的IO mask */button_io_mask = enable_io;/*  检测变量初始化 */for(uint8_t i=0; i<GPIO_DIO_MAX; i++){if(enable_io & (0x01 <<i)){DEBUG_PRINTF("DIO num : %d\r\n",i);button_curr_list[i].io_enable = 1;button_curr_list[i].count     = 0;button_curr_list[i].flag      = 1;button_curr_list[i].io_mask   = (0x01 << i);button_last_list[i].io_enable = 1;button_last_list[i].count     = 0;button_last_list[i].flag      = 1;button_last_list[i].io_mask   = (0x01 << i);}}// 按键检测定时器初始化os_timer_init(&button_check_timer, button_timeout_handler, NULL);

2.3设计中断函数:

/** @fn      pmu_gpio_isr_ram** @brief   pmu_gpio_isr** @param   None.** @return  None.*/
__attribute__((section("ram_code"))) void pmu_gpio_isr_ram(void)
{uint32_t gpio_value = ool_read32(PMU_REG_PORTA_LAST_STATUS);button_toggle_detected(gpio_value);ool_write32(PMU_REG_PORTA_LAST_STATUS, gpio_value);
}

2.4循环检测按键和输出事件

/*  中断检查IO状态  */
void BUTTON_CheckHandler(void)
{static uint8_t released_type=0;static uint32_t curr_button=0;static uint32_t button_check_sleep=0;//DEBUG_PRINTF("but: %04X \r\n",ool_read32(PMU_REG_PORTA_LAST_STATUS));curr_button = ool_read32(PMU_REG_PORTA_LAST_STATUS);for(uint8_t index=0; index<GPIO_DIO_MAX; index++){if(button_curr_list[index].io_enable == 0) continue;//DEBUG_PRINTF("[%d]\r\n",index);button_curr_list[index].flag = (curr_button & (0x01<<index)) ? 1 : 0;//DEBUG_PRINTF("%d[%d][%d]\r\n",index,button_curr_list[index].flag,button_last_list[index].flag);if(button_curr_list[index].flag == button_last_list[index].flag){//button_check_timer_begin |= button_curr_list[index].io_mask;//DEBUG_PRINTF("Count[%d]\r\n",button_curr_list[index].count);button_curr_list[index].count ++;if(button_curr_list[index].count > BUTTON_LONG_LONG_TIME)            // 超长按 5s{button_curr_list[index].count = BUTTON_LONG_LONG_TIME;button_check_sleep &= ~button_curr_list[index].io_mask;         // 清除进入 循环检查}else if(button_curr_list[index].count >= BUTTON_LONG_LONG_TIME)      // 超长按 5s{if(button_curr_list[index].flag == 0){button_send_event(BUTTON_LONG_LONG_PRESSED,index);button_curr_list[index].out_type = BUTTON_LONG_LONG_PRESSED;}}else if(button_curr_list[index].count == BUTTON_LONG_TIME)         // 长按 1s{//DEBUG_PRINTF("BUTTON_LONG_TIME\r\n");if(button_curr_list[index].flag == 0){button_send_event(BUTTON_LONG_PRESSED,index);button_curr_list[index].out_type = BUTTON_LONG_PRESSED;}else{if(released_type == BUTTON_NOP){// 无按下按键或者按下时间不够button_send_event(BUTTON_NOP,index);}}}else if(button_curr_list[index].count == BUTTON_SHORT_TIME)   // 短按 50ms{if(button_curr_list[index].flag == 0){button_send_event(BUTTON_PRESSED,index);button_curr_list[index].out_type = BUTTON_PRESSED;released_type = BUTTON_PRESSED;}else{if(button_curr_list[index].out_type == BUTTON_PRESSED){button_send_event(BUTTON_RELEASED,index);}else if(button_curr_list[index].out_type == BUTTON_LONG_PRESSED){button_send_event(BUTTON_LONG_RELEASED,index);}else if(button_curr_list[index].out_type == BUTTON_LONG_LONG_PRESSED){button_send_event(BUTTON_LONG_LONG_RELEASED,index);}button_check_sleep &= ~button_curr_list[index].io_mask;         // 清除进入 循环检查//DEBUG_PRINTF("button_check %x %x\r\n",button_check_sleep,~button_curr_list[index].io_mask);}}}else{button_curr_list[index].count = 0;released_type = BUTTON_NOP;button_check_sleep |= button_curr_list[index].io_mask;button_last_list[index].flag = button_curr_list[index].flag;}}//DEBUG_PRINTF("button_check %x %x\r\n",button_check_sleep,button_io_mask);if((button_check_sleep & button_io_mask ) == 0){DEBUG_PRINTF("button os_timer_stop\r\n");os_timer_stop(&button_check_timer);}
}

2.5按键任务处理

如何处理按键事件?
这里需要用到消息任务,如下:发送一个按键事件

void button_send_event(button_type_t type, uint8_t but_code)
{os_event_t button_event;struct button_msg_t msg;msg.button_index = (0x01<<but_code);msg.button_type  = type;msg.button_cnt   = 0;button_event.event_id = USER_EVT_BUTTON;button_event.src_task_id = user_task_id;button_event.param = (void *)&msg;button_event.param_len = sizeof(msg);DEBUG_PRINTF("button_send_event %d\r\n",type);os_msg_post(user_task_id, &button_event);
}

2.6 事件处理函数

最后在用户任务中,处理相关按键事件任务

static int user_task_func(os_event_t *param)
{switch(param->event_id){case USER_EVT_AT_COMMAND://app_at_cmd_recv_handler(param->param, param->param_len);break;case USER_EVT_BUTTON:{struct button_msg_t *button_msg;const char *button_type_str[] = {"BUTTON_PRESSED","BUTTON_RELEASED","BUTTON_SHORT_RELEASED","BUTTON_MULTI_PRESSED","BUTTON_LONG_PRESSED","BUTTON_LONG_PRESSING","BUTTON_LONG_RELEASED","BUTTON_LONG_LONG_PRESSED","BUTTON_LONG_LONG_RELEASED","BUTTON_COMB_PRESSED","BUTTON_COMB_RELEASED","BUTTON_COMB_SHORT_PRESSED","BUTTON_COMB_LONG_PRESSED","BUTTON_COMB_LONG_PRESSING","BUTTON_COMB_LONG_RELEASED","BUTTON_COMB_LONG_LONG_PRESSED","BUTTON_COMB_LONG_LONG_RELEASED",};button_msg = (struct button_msg_t *)param->param;co_printf("%x TYPE:%s.\r\n", button_msg->button_index,button_type_str[button_msg->button_type]);switch( button_msg->button_type ){case BUTTON_PRESSED:ProcessPress(button_msg->button_index);break;case BUTTON_LONG_PRESSED:ProcessLongPress(button_msg->button_index);break;case BUTTON_LONG_LONG_PRESSED:ProcessLongLongPress(button_msg->button_index);break;case BUTTON_SHORT_RELEASED:ProcessRelease(button_msg->button_index);break;case BUTTON_LONG_RELEASED:ProcessLongRelease(button_msg->button_index);break;case BUTTON_LONG_LONG_RELEASED:ProcessLongLongRelease(button_msg->button_index);break;default:break;}}break;case DSP_EVT_COMMAND:break;default:break;}return EVT_CONSUMED;
}

3.按键模块调试细节

1)BLE工作在低功耗模式和正常工作模式下,按键皆可以正常使用
2)GPIO中断函数回调函数要处理好,放入相关的中断回调的接口
3)启动定时器轮询检测按键,检测超时关闭定时器,减少功耗

4.小结

按键检测处理方法有很多,这里采用中断+定时器检测并发送事件+事件处理的方法,好处有①可以实现按键的模块化;②中断按键响应速度快;③按键触发稳定,定时间隔滤波防止误处理。④支持32个独立按键检测。按键检测是软件开发必备知识,相信还有很多中方法;作者常用这种方法来开发按键检测,不知您还有哪种更好按键检测的方法,欢迎评论,谢谢!。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1489030.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Florence2:Advancing a unified representation for a variety of vision tasks

Florence-2模型:开启统一视觉基础模型的新篇章_florence -2-CSDN博客文章浏览阅读1.1k次,点赞108次,收藏109次。Florence-2是由微软Azure AI团队开发的一款多功能、统一的视觉模型。它通过统一的提示处理不同的视觉任务,表现出色且优于许多大型模型。Florence-2的设计理念是…

ArcSDE超过连接数解决方案

问题说明&#xff1a;服务器间歇性的会报连接数超限的问题&#xff0c;经常需要手动释放部分连接才能解决。之前遇到过类似的问题&#xff0c;主要是增大数据库连接数&#xff0c;同时检查死链接的情况&#xff0c;因为修改配置需要重启数据库&#xff0c;所以前期一直手动释放…

谷粒商城实战笔记-62-商品服务-API-品牌管理-OSS整合测试

文章目录 一&#xff0c;Java中上传文件到阿里云OSS1&#xff0c;整合阿里云OSS2&#xff0c;测试上传文件 二&#xff0c;Java中整合阿里云OSS服务指南引言准备工作1. 注册阿里云账号2. 获取Access Key3. 添加依赖 实现OSS客户端1. 初始化OSSClient2. 创建Bucket3. 上传文件4.…

初识Play Framework框架和第一个Java play web项目的创建

文章目录 初识Play Framework框架和第一个Java play web项目的创建一、简介特点架构开发流程示例代码总结 二、创建第一个Java play web项目1、下载play框架&#xff0c;配置系统环境变量(jdk的安装就不再说了) 2、检查play的版本和创建第一个play项目3、将项目通过idea或eclip…

福特汽车:总是悲喜交加时

每辆电动汽车的亏损高达6.94万美元&#xff0c;这把全美最大汽车制造商——福特汽车&#xff0c;也整不会了。 燃油车全美销量第一、电动车全美销量第二&#xff0c;销量大增的福特汽车增收不增利&#xff0c;息税前利润下滑27%至28亿美元&#xff0c; 因盈利远不及预期&#x…

【Python】pandas:查看数据(head, tail, values属性, at, iat, loc, iloc, [ ], sample)

pandas是Python的扩展库&#xff08;第三方库&#xff09;&#xff0c;为Python编程语言提供 高性能、易于使用的数据结构和数据分析工具。 pandas官方文档&#xff1a;User Guide — pandas 2.2.2 documentation (pydata.org) 帮助&#xff1a;可使用help(...)查看函数说明文…

Spring Boot:图书管理系统(一)

1.编写用户登录接口 代码&#xff1a; package com.example.demo;import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotatio…

Linux 查找命令

目录 1. 查看二进制文件 which 2. 查看指定文件 find ​2.1 文件名查找 2.2 文件大小查找 前面学习过的 Linux 命令&#xff0c;其实质是一个个的二进制可执行程序&#xff0c;与 Windows 系统中的 .exe 文件是一个意思。 1. 查看二进制文件 which 语法&#xff1a; w…

sonar代码扫描报错:ERROR: Something went wrong storing the PDF at server side.

原因&#xff1a; URL带“/”引起的&#xff0c;去掉即可。 去掉之后成功&#xff1a;

2、从0搭建企业门户网站——云服务器租用

目录 正文 1、登录阿里云 2、进入云服务器界面 3、租用云服务器 正文 云服务器厂商很多,这里主要以阿里云服务器为主介绍云服务器的相关知识。 1、登录阿里云 阿里云官网地址 2、进入云服务器界面 登录后,点击控制台,进入主界面。

当AI遇上“近亲繁殖”:牛津剑桥Nature封面揭秘

在这个AI无所不能的时代,一项新的研究再次刷新了我们的认知边界。牛津大学、剑桥大学、帝国理工学院和多伦多大学的研究团队,携手登上《自然》杂志封面,揭露了一个令人震惊的事实:AI也可能遭遇“近亲繁殖”的问题! 更多信息,请关注微信公众号:JAVA和人工智能 “近亲繁…

[Unity] ShaderGraph实现不同贴图素材的同一材质球复用

无意间发现的ShaderGraph小技巧&#xff0c; 可以实现同一个ShaderGraph&#xff0c;同一个Material材质球&#xff0c; 但使用不同的Texture贴图&#xff0c;而Sprite显示不会相互覆盖。 具体实现方法如下&#xff1a; 声明Texture2D时&#xff0c;把名字命名成&#xff1a…

github-page静态网页将字符串写入github库中文本文档

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

echarts使用案例

1.配置legend icon 根据点击事件动态更换样式 <template><div ref"chart" style"width: 600px; height: 400px;"></div></template><script>import * as echarts from echarts;export default {name: EchartsExample,data(…

Canvas生成动画---显示一组彩色气泡

一、JS版本 <!--* Author: LYM* Date: 2024-07-26 13:51:47* LastEditors: LYM* LastEditTime: 2024-07-26 16:14:40* Description: Please set Description --> <!DOCTYPE html> <html> <head><title>canvas动态气泡</title><style&g…

JMeter接口测试:测试中奖概率!

介绍 Apache JMeter 是 Apache 组织基于 Java 开发的压力测试工具&#xff0c;用于对软件做压力测试。JMeter 最初被设计用于 Web 应用测试&#xff0c;但后来扩展到了其他测试领域&#xff0c;可用于测试静态和动态资源&#xff0c;如静态文件、Java 小服务程序、CGI 脚本、J…

学习日志:JVM垃圾回收

文章目录 前言一、堆空间的基本结构二、内存分配和回收原则对象优先在 Eden 区分配大对象直接进入老年代长期存活的对象将进入老年代主要进行 gc 的区域空间分配担保 三、死亡对象判断方法引用计数法可达性分析算法引用类型总结1&#xff0e;强引用&#xff08;StrongReference…

联想教育电脑硬盘保护同传EDU系统使用简明教程

目录 一、原理概述 二、简明使用方法 1、软件下载 2、开机引导 3、开始安装 4、使用 &#xff08;1&#xff09;进入底层 &#xff08;2&#xff09;进行分区设置 &#xff08;3&#xff09;系统设置 &#xff08;4&#xff09;安装硬盘保护驱动 &#xff08;5&…

VUE3学习第三篇:报错记录

1、在我整理好前端代码框架后&#xff0c;而且也启动好了对应的后台服务&#xff0c;访问页面&#xff0c;正常。 2、报错ReferenceError: defineModel is not defined 学到这里报错了 在vue网站的演练场&#xff0c;使用没问题 但是在我自己的代码里就出问题了 3、watchEffec…

【YOLOv5/v7改进系列】引入中心化特征金字塔的EVC模块

一、导言 现有的特征金字塔方法过于关注层间特征交互而忽视了层内特征的调控。尽管有些方法尝试通过注意力机制或视觉变换器来学习紧凑的层内特征表示&#xff0c;但这些方法往往忽略了对密集预测任务非常重要的被忽视的角落区域。 为了解决这个问题&#xff0c;作者提出了CF…