STM32——单个按键+矩阵键盘:轮询读取键值

一、单个按键读取键值——轮询方式

1.初始化

void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOE,&GPIO_InitStructure);	
}

2.获取键值操作

        重点理解按键消抖的过程:当我们读取到键值变化时,先延迟20ms之后,检测按键是否松手,若没有就一直等待松手,直到松手之后,在延迟20ms,然后再给变量赋键值。

uint8_t Get_KeyNum(void)
{
	uint8_t keynum=0;
	if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==0)//检测按键是否按下
	{
		Delay_ms(20);//延迟20ms等待按下的机械抖动消除
		while(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==0);//等待按键松手,若不松手则一直while循环等待松手
		Delay_ms(20);//延迟20ms等待松开的机械抖动消除
		keynum=1;//给变量赋键值
	}
	if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0);
		Delay_ms(20);
		keynum=2;
	}
	return keynum;
}

3.主函数中调用

        通过轮询的方式检测按键,这里注意每次调用函数的时候当按键不按下的时候,键值一直时0。某一时刻按键按下之后便会执行对应的操作,但注意下一次循环依然会把变量keynum赋值为0.

int main(void)
{
	OLED_Init();
	Key_Init();
	Led_Init();
	while(1)
	{
		keynum=Get_KeyNum();
		if(keynum==1)
		{
			LedB_Turn();
		}
		if(keynum==2)
		{
			LedE_Turn();
		}

		OLED_ShowHexNum(1,1,keynum,4,OLED_8X16);
		OLED_Update();
		if(keynum!=0)Delay_ms(500);
		
	}
	
}

二、矩阵按键读取键值——轮询方式

原理相同,但是要对键盘进行扫描,这里采用行扫描的方式进行:

1.端口定义:

#define   C4   GPIO_Pin_0
#define   C3   GPIO_Pin_1
#define   C2   GPIO_Pin_2
#define   C1   GPIO_Pin_3
#define   R4   GPIO_Pin_4
#define   R3   GPIO_Pin_5
#define   R2   GPIO_Pin_6
#define   R1   GPIO_Pin_7

2.端口初始化 

这里注意如果是按行扫描,那么控制列的端口需要配置成输入模式,控制行的端口配置成输出模式

void Matrix_Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin=C1|C2|C3|C4;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin=R1|R2|R3|R4;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
}

3.按键扫描——按行扫描

uint8_t Matrix_Key_GetNum(void)
{
	uint8_t keynum=0;
	GPIO_Write(GPIOA,0X00FF);
	GPIO_WriteBit(GPIOA,R1,Bit_RESET);
	if(GPIO_ReadInputDataBit(GPIOA,C1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C1)==0);Delay_ms(20);keynum=16;}
	if(GPIO_ReadInputDataBit(GPIOA,C2)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C2)==0);Delay_ms(20);keynum=15;}
	if(GPIO_ReadInputDataBit(GPIOA,C3)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C3)==0);Delay_ms(20);keynum=14;}
	if(GPIO_ReadInputDataBit(GPIOA,C4)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C4)==0);Delay_ms(20);keynum=13;}

	GPIO_Write(GPIOA,0X00FF);
	GPIO_WriteBit(GPIOA,R2,Bit_RESET);
	if(GPIO_ReadInputDataBit(GPIOA,C1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C1)==0);Delay_ms(20);keynum=12;}
	if(GPIO_ReadInputDataBit(GPIOA,C2)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C2)==0);Delay_ms(20);keynum=11;}
	if(GPIO_ReadInputDataBit(GPIOA,C3)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C3)==0);Delay_ms(20);keynum=10;}
	if(GPIO_ReadInputDataBit(GPIOA,C4)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C4)==0);Delay_ms(20);keynum=9;}

	GPIO_Write(GPIOA,0X00FF);
	GPIO_WriteBit(GPIOA,R3,Bit_RESET);
	if(GPIO_ReadInputDataBit(GPIOA,C1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C1)==0);Delay_ms(20);keynum=8;}
	if(GPIO_ReadInputDataBit(GPIOA,C2)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C2)==0);Delay_ms(20);keynum=7;}
	if(GPIO_ReadInputDataBit(GPIOA,C3)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C3)==0);Delay_ms(20);keynum=6;}
	if(GPIO_ReadInputDataBit(GPIOA,C4)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C4)==0);Delay_ms(20);keynum=5;}

	GPIO_Write(GPIOA,0X00FF);
	GPIO_WriteBit(GPIOA,R4,Bit_RESET);
	if(GPIO_ReadInputDataBit(GPIOA,C1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C1)==0);Delay_ms(20);keynum=4;}
	if(GPIO_ReadInputDataBit(GPIOA,C2)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C2)==0);Delay_ms(20);keynum=3;}
	if(GPIO_ReadInputDataBit(GPIOA,C3)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C3)==0);Delay_ms(20);keynum=2;}
	if(GPIO_ReadInputDataBit(GPIOA,C4)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOA,C4)==0);Delay_ms(20);keynum=1;}

	return keynum;
}

4.主循环调用验证

#include "main.h"
uint8_t keynum;
int main(void)
{
	OLED_Init();
	Matrix_Key_Init();
	while(1)
	{
		keynum=Matrix_Key_GetNum();
		if(keynum!=0)
		{
			OLED_ShowString(1,1,"KEYNUM: ",OLED_8X16);
			OLED_ShowNum(66,1,keynum,2,OLED_8X16);
			OLED_Update();	
		}
		
	}
}

PS:最后发现键值反了,最后倒着把键值改了,不过影响不大

三、矩阵键盘密码锁

实现密码锁逻辑(key1-10表示数字,10代表0,11为确认,12为退格)

#include "main.h"
uint8_t keynum,count;
uint16_t user_input,password;
int main(void)
{
	OLED_Init();
	Matrix_Key_Init();
	OLED_ShowString(0,0,"PLEASE INPUT PASSWORD:",OLED_6X8);
	OLED_Update();
	password=3030;
	while(1)
	{
		OLED_ShowNum(0,32,count,4,OLED_8X16);
		OLED_Update();
		keynum=Matrix_Key_GetNum();
		if(keynum<=10 && keynum>0 &&count<4&&count>=0)
		{
			keynum%=10;
			user_input*=10;
			user_input+=keynum;
			OLED_ShowNum(0,16,user_input,4,OLED_8X16);
			OLED_Update();
			count++;
		}
		if(keynum==11)
		{
				if(user_input==password)
			{
				OLED_Clear();
				OLED_ShowString(0,0,"PASSWORD RIGHT!",OLED_6X8);
				OLED_Update();
				Delay_ms(2000);
				count=user_input=keynum=0;
				OLED_ShowString(0,0,"PLEASE INPUT PASSWORD:",OLED_6X8);
				OLED_Update();

			}
			else
			{
				OLED_Clear();
				OLED_ShowString(0,0,"PASSWORD ERRO!",OLED_6X8);
				OLED_Update();
				Delay_ms(2000);
				count=user_input=keynum=0;
				OLED_ShowString(0,0,"PLEASE INPUT PASSWORD:",OLED_6X8);
				OLED_Update();
			}
		}
		if(keynum==12)
		{
			user_input/= 10;
			OLED_ShowNum(0,16,user_input,4,OLED_8X16);
			OLED_Update();
			count--;
		}
	}
}

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在51单片机中,可以通过串口接收中断来读取串口助手发送的键值。以下是一个简单的示例代码: ``` #include <reg51.h> // 定义串口接收缓冲区 #define RX_BUF_SIZE 8 volatile unsigned char rx_buf[RX_BUF_SIZE]; volatile unsigned char rx_head = 0; volatile unsigned char rx_tail = 0; // 串口接收中断处理函数 void serial_isr() interrupt 4 { if(RI) { // 判断是否接收到数据 RI = 0; // 清除接收中断标志位 rx_buf[rx_head] = SBUF; // 读取接收到的数据 rx_head = (rx_head + 1) % RX_BUF_SIZE; // 更新接收缓冲区头指针 } } // 读取键值函数 unsigned char read_key() { if(rx_head != rx_tail) { // 判断是否有数据可读 unsigned char key = rx_buf[rx_tail]; // 读取接收缓冲区中的数据 rx_tail = (rx_tail + 1) % RX_BUF_SIZE; // 更新接收缓冲区尾指针 return key; // 返回读取到的键值 } return 0; // 没有数据可读,返回0 } void main() { // 初始化串口 TMOD |= 0x20; // 设置定时器1为模式2,用于串口通信 TH1 = 0xFD; // 波特率为9600bps TL1 = 0xFD; SCON = 0x50; // 8位数据,无校验,1位停止位,启用接收 ES = 1; // 启用串口中断 EA = 1; // 启用总中断 while(1) { unsigned char key = read_key(); // 读取键值 if(key) { // 判断是否有数据可读 // 处理读取到的键值 } } } ``` 在这个示例代码中,我们定义了一个大小为8的接收缓冲区`rx_buf`和两个指针`rx_head`和`rx_tail`,分别指向接收缓冲区的头和尾。当接收到串口数据时,串口中断会触发,将数据存储到接收缓冲区中。在主函数中,我们可以通过调用`read_key`函数来读取接收缓冲区中的键值,如果有数据可读,函数将返回读取到的键值;否则返回0。 需要注意的是,在使用串口接收中断时,需要将串口接收标志位RI清零,以便下一次接收。另外,为了防止接收缓冲区溢出,需要在中断处理函数中对接收缓冲区进行判断。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值