题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。

题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。  
============================================================================ 
用户基本操作定义: 
    1。短按操作:按键按下,按下时间<1s,属于一次短按操作 
    2。长按操作:按键按下,按下时间>1s,属于一次长按操作 

在正常0.5s内无按键操作为启始按键扫描条件下,扫描按键将产生以下3种按键事件: 
    1。长按事件:任何1次出现的长按操作都属于长按事件 
    2。单击事件:1次短按操作后,间隔0.5内没有短按操作 
    3。双击事件:2次短按操作间隔时间<0.5s,则2次短按操作为1次双击事件,且2次短按都取消 

特别操作情况定义: 
    1。短按操作和长按操作间隔<0.5s,以及,长按操作和短按操作间隔<0.5s,均不产生双击事件 
    2。连续n次(n为奇数)短按操作,且间隔均<0.5s,产生(n-1)/2次双击事件+1次单击事件 
    3。连续n次(n为偶数)短按操作,且间隔均<0.5s,产生n/2次双击事件 

对按键操作者的建议:     
    由于按键的多功能性质,建议操作者每次在单击/长按/双击按键事件发生后,隔0.5s后再进行下一次的按键操作。因为在特别操作情况下,程序是保证按定义进行判断和处理的,主要是怕操作者自己记不清楚导致操作失误。 

对软件设计者的要求: 
    1。应该全面进行分析,给出严格定义和判断条件,如上所示。如果自己都不清楚,你的设计出的系统就不稳定,不可靠。 
    2。在1的基础上,编写出符合要求的程序,并进行全面测试。 

/*============= 
低层按键(I/0)扫描函数,即低层按键设备驱动,只返回无键、短按和长按。具体双击不在此处判断。参考本人教材的例9-1,稍微有变化。教材中为连_发。 
===============*/ 

#define key_input    PIND.7    // 按键输入口 

#define N_key    0             //
16、基于嵌入式 Linux 的电子沙漏与环境监测终端 以正点原子阿尔法 Linux 开发板为核心,C 语言进行代码开发,Qt Creator 开发图形界 面,实现电子沙漏等功能。 (1)利用 MPU6050 倾角传感器,通过 I2C 实时采集角度数据,精准判断翻转动作。 (2)通过 I2C 入 DHT11 温湿度传感器,实现温度、湿度采集子线程,Qt 界面同步显 示温湿度曲线(每 1 分钟更新 1 个数据点,保留 1 小时历史数据);设置温湿度阈值(如温 度>30℃或湿度>70%),触发蜂鸣器鸣报警,LED 点阵屏显示“温湿度异常”提示,同 时通过 WiFi 推送报警信息至云平台。 (3利用 LED 点阵屏,通过 SPI 显示生动的沙粒下落动画,利用蜂鸣器,用于计时结 束提醒。 (4)利用 ESP8266 WiFi 模块,配置为 TCP 客户端连云平台(如 OneNet),实现子线程 定时(每 30 秒)上传当前温度、沙漏剩余时间、设备状态至云平台;支持通过云平台远程 设置沙漏计时档位(1/3/5 分钟)、开启/关闭蜂鸣器报警;网络断开时,Qt 界面显示“离 线”提示,数据暂存本地,网络恢复后自动补传。 (5)利用电容触摸屏实现触摸手势操作(如“单击”启动/暂停沙漏、“左右滑动”切换计 时档位、“双击”清除温湿度历史曲线、“按”关闭报警);触摸操作时,屏幕显示对应 手势动画反馈,提升交互体验;同时保留原按键控制,支持触摸/按键双模式切换
最新发布
09-12
#include "stm32f4xx.h" // Device header #include "systick.h" #include "io_bit.h" // 按键引脚定义,假设在 GPIOA 的 PA0 #define KEY_GPIO_PORT GPIOA #define KEY_GPIO_PIN GPIO_Pin_0 #define KEY_GPIO_CLK RCC_AHB1Periph_GPIOA // 风扇控制引脚,假设在 GPIOB 的 PB0 #define FAN_GPIO_PORT GPIOB #define FAN_GPIO_PIN GPIO_Pin_0 #define FAN_GPIO_CLK RCC_AHB1Periph_GPIOB // 继电器控制引脚,假设在 GPIOB 的 PB1 #define RELAY_GPIO_PORT GPIOB #define RELAY_GPIO_PIN GPIO_Pin_1 #define RELAY_GPIO_CLK RCC_AHB1Periph_GPIOB // LCD 显示相关,需包含对应 LCD 驱动头文件,这里假设已有基础显示函数 //#include "lcd.h" // 按键状态枚举 typedef enum { KEY_STATE_IDLE, // 空闲状态 KEY_STATE_PRESSED, // 按下状态 KEY_STATE_RELEASED, // 0释放状态 KEY_STATE_LONG_PRESS, // 按状态 KEY_STATE_DOUBLE_CLICK// 双击状态 } KeyState; KeyState key_state = KEY_STATE_IDLE; uint8_t key_press_flag = 0; // 按键按下标志 uint16_t key_press_time = 0; // 按键按下计时 uint16_t key_double_click_time = 0; // 双击检测计时 uint8_t key_double_click_flag = 0; // 双击标志 // 按键 GPIO 初始化 void Key1_Init(void) { GPIO_InitTypeDef gpio_config={0}; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); gpio_config.GPIO_Mode = GPIO_Mode_OUT; gpio_config.GPIO_Pin = GPIO_Pin_0; gpio_config.GPIO_Speed = GPIO_Speed_25MHz; gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL; gpio_config.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOA, &gpio_config); PAout(0)=1; } void Key2_Init(void) { GPIO_InitTypeDef gpio_config={0}; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); gpio_config.GPIO_Mode = GPIO_Mode_OUT; gpio_config.GPIO_Pin = GPIO_Pin_0; gpio_config.GPIO_Speed = GPIO_Speed_25MHz; gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL; gpio_config.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOB, &gpio_config); PBout(0)=1; } void Key3_Init(void) { GPIO_InitTypeDef gpio_config={0}; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); gpio_config.GPIO_Mode = GPIO_Mode_OUT; gpio_config.GPIO_Pin = GPIO_Pin_0; gpio_config.GPIO_Speed = GPIO_Speed_25MHz; gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL; gpio_config.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOB, &gpio_config); PBout(1)=1; } // 风扇 GPIO 初始化(输出) void Fan_GPIO_init(void) { GPIO_InitTypeDef gpio_config={0}; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); gpio_config.GPIO_Mode = GPIO_Mode_OUT; gpio_config.GPIO_Pin = GPIO_Pin_8; gpio_config.GPIO_Speed = GPIO_Speed_25MHz; gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL; gpio_config.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOC, &gpio_config); PCout(8) = 0; // 初始状态关闭 } // 继电器 GPIO 初始化(输出) void relay_init(void) { GPIO_InitTypeDef gpio_config={0}; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); gpio_config.GPIO_Mode = GPIO_Mode_OUT; gpio_config.GPIO_Pin = GPIO_Pin_0; gpio_config.GPIO_Speed = GPIO_Speed_25MHz; gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL; gpio_config.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOE, &gpio_config); PEout(0) = 0; // 初始状态关闭 } // 整体初始化,可在 main 函数开头调用 void Hardware_Init(void) { Key1_Init(); Key3_Init(); Key3_Init(); Fan_GPIO_init(); relay_init(); // beep_init(); // LCD_Init(); // 假设 LCD 初始化函数 } // 按键扫描(简易消抖,也可用定时器中断更精准消抖) uint8_t Key_Scan(void) { static uint8_t key_state = 1; uint8_t read_value = GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN); if (read_value != key_state) { // delay_ms(10); // 消抖延时,需实现 delay_ms 函数 read_value = GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN); if (read_value != key_state) { key_state = read_value; return key_state == 0 ? 1 : 0; // 按下返回 1,释放返回 0 } } return 0; } // 按键状态机处理,建议在定时器中断或主循环定时调用(如 10ms 一次) void Key_State_Machine_Process(void) { static uint8_t key_last_state = 1; uint8_t key_current_state = Key_Scan(); switch (key_state) { case KEY_STATE_IDLE: if (key_current_state == 1 && key_last_state == 0) // 检测到按键按下 { key_state = KEY_STATE_PRESSED; key_press_time = 0; key_double_click_flag = (key_double_click_time < 300) ? 1 : 0; // 双击判断,300ms 内第二次按下算双击 key_double_click_time = 0; } else if (key_double_click_flag) { key_state = KEY_STATE_DOUBLE_CLICK; // LCD_DisplayString(0, 0, "Double Click"); // LCD 显示双击状态,需适配 LCD 驱动函数参数 key_double_click_flag = 0; } break; case KEY_STATE_PRESSED: key_press_time++; if (key_press_time > 100) // 按判断,100*10ms=1s,可调整 { key_state = KEY_STATE_LONG_PRESS; // LCD_DisplayString(0, 0, "Long Press"); // LCD 显示按状态 GPIO_SetBits(FAN_GPIO_PORT, FAN_GPIO_PIN); // 按开风扇 } else if (key_current_state == 0 && key_last_state == 1) // 短按释放 { key_state = KEY_STATE_RELEASED; // LCD_DisplayString(0, 0, "Short Press"); // LCD 显示短按状态 GPIO_SetBits(RELAY_GPIO_PORT, RELAY_GPIO_PIN); // 短按开继电器 } break; case KEY_STATE_LONG_PRESS: if (key_current_state == 0 && key_last_state == 1) // 按释放 { key_state = KEY_STATE_IDLE; GPIO_ResetBits(FAN_GPIO_PORT, FAN_GPIO_PIN); // 关闭风扇 } break; case KEY_STATE_RELEASED: key_state = KEY_STATE_IDLE; GPIO_ResetBits(RELAY_GPIO_PORT, RELAY_GPIO_PIN); // 关闭继电器 break; case KEY_STATE_DOUBLE_CLICK: key_state = KEY_STATE_IDLE; // 可扩展双击后动作,这里仅显示 break; default: key_state = KEY_STATE_IDLE; break; } if (key_double_click_flag) { key_double_click_time++; if (key_double_click_time > 300) // 超过 300ms 未第二次按下,清除双击标志 { key_double_click_flag = 0; } } key_last_state = key_current_state; } int main(void) { Hardware_Init(); while (1) { Key_State_Machine_Process(); // delay_ms(10); // 定时扫描,也可用定时器中断实现更精准时序 } } 题目十七:基于STM32F4按键设计 ·基本要求: (1)按键具有按短按功能 (2)按开风扇 (3)短按开继电器 (4)LCD显示状态 (5)加入状态机思想实现双击短按按 必选元器件: (1)系统板蜂鸣器模块 (2)系统板按键模块 (3)LCD模组,作为一名高级工程师,用尽可能简洁修改代码完成题目要求,LCD模块暂时不配置
06-23
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值