学习目标
- 能够读取按键操作
-
学习内容
原理图
按键消抖
软件延时法:在按键按下时,使用软件延时一段时间,例如10毫秒,然后再检测按键是否还处于按下状态,如果是,则认为按键有效。这种方法简单易行,但会浪费一定的处理器时间,同时需要根据实际情况调整延时时间。
- 硬件滤波法:在按键输入引脚上添加RC滤波电路,可以有效地去除按键信号上的瞬间噪声。这种方法对于高频噪声的去除效果较好,但需要一定的电路设计能力。
- 程序消抖法:在程序中记录按键前后两次的状态,如果两次状态不同,则认为按键有效。这种方法可以根据需要调整检测时间,消抖效果较好,但需要额外的程序设计。
软件设计
要求
当用户按下,或者松开按键时,捕获到这个事件。将事件通过串口发出来。
分析
监控引脚的高低电平变化。记录状态,比对实时状态。
- 监控:死循环去读取电平信息
- 记录与比对:通过变量记录,实时拿到当前状态,与记录的上一次进行比对。
实现单个按钮
```cinclude “Config.h”
include “Delay.h”
include “GPIO.h”
include “UART.h”
include “NVIC.h”
include “Switch.h”
define KEY1 P51
void GPIO_config(void) { P5_MODE_IO_PU(GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4); }
void UART_config(void) { COMx_InitDefine COMx_InitStructure; //结构定义 COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2) COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200 COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}
u8 last_key_state = 1; // 抬起
void main(){
GPIO_config();UART_config();EA = 1;while(1){if(KEY1 == 1 && last_key_state == 0){ // 当前是抬起Up 1, 上一次是按下Down 0printf("KEY1 up\n");last_key_state = 1;}else if(KEY1 == 0 && last_key_state == 1){// 当前是按下Down 0, 上一次是抬起Up 1printf("KEY1 down\n");last_key_state = 0;}delay_ms(20);}
}
<a name="jAsDH"></a>#### 实现多个按钮```c#include "Config.h"#include "Delay.h"#include "GPIO.h"#include "UART.h"#include "NVIC.h"#include "Switch.h"#define KEY1 P51#define KEY2 P52#define KEY3 P53#define KEY4 P54void GPIO_config(void) {P5_MODE_IO_PU(GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4);}void UART_config(void) {COMx_InitDefine COMx_InitStructure; //结构定义COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44}#define DOWN 0#define UP 1u8 last_key_states[] = {UP, UP, UP, UP}; // key的最后一次状态// 判断指定位置【是否是】按下或抬起#define IS_KEY_DOWN(i) last_key_states[i] == DOWN#define IS_KEY_UP(i) last_key_states[i] == UP// 将指定位置值【设置】为按下或抬起#define SET_KEY_DOWN(i) last_key_states[i] = DOWN#define SET_KEY_UP(i) last_key_states[i] = UPvoid main(){GPIO_config();UART_config();EA = 1;while(1){if(KEY1 && IS_KEY_DOWN(0)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY1 up\n");SET_KEY_UP(0);}else if(!KEY1 && IS_KEY_UP(0)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY1 down\n");SET_KEY_DOWN(0);}if(KEY2 && IS_KEY_DOWN(1)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY2 up\n");SET_KEY_UP(1);}else if(!KEY2 && IS_KEY_UP(1)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY2 down\n");SET_KEY_DOWN(1);}if(KEY3 && IS_KEY_DOWN(2)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY3 up\n");SET_KEY_UP(2);}else if(!KEY3 && IS_KEY_UP(2)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY3 down\n");SET_KEY_DOWN(2);}if(KEY4 && IS_KEY_DOWN(3)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY4 up\n");SET_KEY_UP(3);}else if(!KEY4 && IS_KEY_UP(3)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY4 down\n");SET_KEY_DOWN(3);}delay_ms(20);}}
使用位操作存储状态
// P51, P52, P53, P54//u8 last_key_states[] = {UP, UP, UP, UP};// 0b 0 0 0 0 - 1 1 1 1u8 last_key_states = 0x0F; // KEY最后一次状态的8个位(只使用低4位)// 判断指定位置【是否】是按下// 0b 0 0 0 0 - 0 0 0 0//& 0b 0 0 0 0 - 0 1 0 0 ----- 判断指定位i=2是否是0// 0b 0 0 0 0 - 0 0 0 0 == 0#define IS_KEY_DOWN(i) (last_key_states & (1 << i)) == 0// 判断指定位置【是否】是抬起// 0b 0 0 0 0 - 1 1 0 0//& 0b 0 0 0 0 - 1 0 0 0 ----- 判断指定位i=3是否是1// 0b 0 0 0 0 - 1 0 0 0 > 0#define IS_KEY_UP(i) (last_key_states & (1 << i)) > 0// 将指定位置值【设置】为按下// 0b 0 0 0 0 - 1 1 0 0//&= 0b 1 1 1 1 - 1 0 1 1 ------ 将指定位i=2设置为0,按下//&=~0b 0 0 0 0 - 0 1 0 0// 0b 0 0 0 0 - 1 0 0 0#define SET_KEY_DOWN(i) last_key_states &= ~(1 << i)// 将指定位置值【设置】为抬起// 0b 0 0 0 0 - 1 1 0 0//|= 0b 0 0 0 0 - 0 0 1 0 ------ 将指定位i=1设置为1,抬起// 0b 0 0 0 0 - 1 1 1 0#define SET_KEY_UP(i) last_key_states |= (1 << i)
- u16存储状态: 16个
1 << i只能存 16 位 - u32存储状态: 32个,
1 << i要改成1L << i能存32位
练习题
- 实现按键操作
- 通过按键控制震动马达震动
