stm32 HAL库 4X4 矩阵键盘 附原理图和C语言代码

目录

原理图:


鉴于最近实训,需要写一份矩阵键盘的代码,看到网上大部分矩阵键盘不是很方便修改引脚,遂自己手敲了一份,可以随便修改引脚的代码方便移植。

不过我是直接把函数写在了main函数的while循环里,没有消抖,有需求的同志可以自行添加,或者可以进行一点修改放到定时器里也可以。这里只把代码放出来供大家参考学习,有错误也请各位大佬指出,一起学习。

原理图:

使用的是立创EDA专业版,单片机使用的是stm32C8T6,OLED和HX177可以忽略,主要还是看矩阵键盘。左下角哪个8P的排针是留给矩阵键盘模块用的,我为了以防万一预留的,他跟键盘主体其实是一个东西,可以不用管。

这里简述一下原理,矩阵键盘原理就是动态扫描,Key0-3配置为输出,Key4-7配置成上拉输入,一定要是上拉输入。

首先Key3输出低电平(扫描哪一行就把那一行拉低),Key0-2输出高电平,记为0x07(行);然后检测Key4-7的输入,举个栗子,假设SW1按下,因为Key3行我们输出低电平,同时1脚和3脚导通,所以Key4就被拉低了,读引脚就会读出低电平,而其他没有被按下的并没有导通,所以他们还是高电平,就可以记为0x07(列);同理,SW5、9、13按下时分别为0x0b(列)、0x0d(列)和0x0e(列),就可以判断出第一行是哪个按键被按下,要是都没被按下就是0x0f(列)。

然后同理扫描Key2、Key1、Key0行,分别是0x0b(行)、0x0d(行)和0x0e(行),再次重复判断哪一列被按下后就可以得到16个按键的情况了。

代码

key.c

#include "key.h"

uchar key_scan;		//键盘扫描的值

/*********
*
*函数:按键GPIO输出重写
*
*传参:key(0-3):按键号;		lev(0/1);电平高低
*
*例:Key_GpioOut(0, 1)	Key_0置高
*********/
void Key_GpioOut(uchar key, uchar lev)
{
	switch(key)
	{
		case 0:
			if(lev)	HAL_GPIO_WritePin(KEY_0_GPIO_Port, KEY_0_Pin, GPIO_PIN_SET);
			else		HAL_GPIO_WritePin(KEY_0_GPIO_Port, KEY_0_Pin, GPIO_PIN_RESET);
		break;
		
		case 1:
			if(lev)	HAL_GPIO_WritePin(KEY_1_GPIO_Port, KEY_1_Pin, GPIO_PIN_SET);
			else		HAL_GPIO_WritePin(KEY_1_GPIO_Port, KEY_1_Pin, GPIO_PIN_RESET);
		break;
		
		case 2:
			if(lev)	HAL_GPIO_WritePin(KEY_2_GPIO_Port, KEY_2_Pin, GPIO_PIN_SET);
			else		HAL_GPIO_WritePin(KEY_2_GPIO_Port, KEY_2_Pin, GPIO_PIN_RESET);
		break;
		
		case 3:
			if(lev)	HAL_GPIO_WritePin(KEY_3_GPIO_Port, KEY_3_Pin, GPIO_PIN_SET);
			else		HAL_GPIO_WritePin(KEY_3_GPIO_Port, KEY_3_Pin, GPIO_PIN_RESET);
		break;
	}
}

/*********
*
*函数:按键GPIO输出重写
*
*传参:key(0-3):按键号;
*
*传回参数:lev(0/1): 0:低		1:高
*
*例:Key_GpioIn(4)		读取Key_4的值
*********/
uchar Key_GpioIn(uchar key)
{
	uchar lev;		//防止warning
	switch(key)
	{
		case 4:
			if(HAL_GPIO_ReadPin(KEY_4_GPIO_Port, KEY_4_Pin) == GPIO_PIN_SET)	lev = 1;
			else		lev = 0;
		break;
		
		case 5:
			if(HAL_GPIO_ReadPin(KEY_5_GPIO_Port, KEY_5_Pin) == GPIO_PIN_SET)	lev = 1;
			else		lev = 0;
		break;
		
		case 6:
			if(HAL_GPIO_ReadPin(KEY_6_GPIO_Port, KEY_6_Pin) == GPIO_PIN_SET)	lev = 1;
			else		lev = 0;
		break;
		
		case 7:
			if(HAL_GPIO_ReadPin(KEY_7_GPIO_Port, KEY_7_Pin) == GPIO_PIN_SET)	lev = 1;
			else		lev = 0;
		break;
	}
	
	if(lev)	return 1;
	else		return 0;
}

/*********
*
*函数:按键输出
*
*传参:out(0x0a):方便按键扫描
*
*例:Key_Output(0x07)		Key_3置低,Key_0-2置高
*********/
void Key_Output(uchar out)
{
	uchar temp;
	for(uchar i=0; i<4; i++)
	{
		temp = out & (0x01<<i);
		temp = temp >> i;
		Key_GpioOut(i, temp);
	}
}

/*********
*
*函数:按键读取
*
*传参:out(0x0a):方便按键扫描
*
*例:Key_Output(0x07)		Key_3置低,Key_0-2置高
*********/
uchar Key_Input()
{
	uchar back = 0x00;
	
	back |= Key_GpioIn(4);
	
	for(uchar i=5; i<8; i++)
	{
		back = back << 1;
		back |= Key_GpioIn(i);
	}
	
	return back;
}

/*********
*
*函数:按键扫描
*
*传参:无
*********/
void Key_Scan()
{
	uchar temp;					//临时储存
	
	//扫描第一行---------------------------------
	Key_Output(0x07);		//Key_3置低
	
	if(Key_Input() != 0x0f)
	{
		temp = Key_Input();
		
		switch(temp)
		{
			case 0x07:	key_scan = 1;	break;
			case 0x0b:	key_scan = 2;	break;
			case 0x0d:	key_scan = 3;	break;
			case 0x0e:	key_scan = 4;	break;
		}
	}
	
	//扫描第二行---------------------------------
	Key_Output(0x0b);		//Key_2置低
	
	if(Key_Input() != 0x0f)
	{
		temp = Key_Input();
		
		switch(temp)
		{
			case 0x07:	key_scan = 5;	break;
			case 0x0b:	key_scan = 6;	break;
			case 0x0d:	key_scan = 7;	break;
			case 0x0e:	key_scan = 8;	break;
		}
	}
	
	//扫描第三行---------------------------------
	Key_Output(0x0d);		//Key_1置低
	
	if(Key_Input() != 0x0f)
	{
		temp = Key_Input();
		
		switch(temp)
		{
			case 0x07:	key_scan = 9;	break;
			case 0x0b:	key_scan = 10;	break;
			case 0x0d:	key_scan = 11;	break;
			case 0x0e:	key_scan = 12;	break;
		}
	}
	
	//扫描第四行---------------------------------
	Key_Output(0x0e);		//Key_1置低
	
	if(Key_Input() != 0x0f)
	{
		temp = Key_Input();
		
		switch(temp)
		{
			case 0x07:	key_scan = 13;	break;
			case 0x0b:	key_scan = 14;	break;
			case 0x0d:	key_scan = 15;	break;
			case 0x0e:	key_scan = 16;	break;
		}
	}
}

key.h

#ifndef _KEY_H
#define _KEY_H

#include "main.h"

#define KEY_0_Pin 				GPIO_PIN_15
#define KEY_0_GPIO_Port 	GPIOA

#define KEY_1_Pin 				GPIO_PIN_3
#define KEY_1_GPIO_Port 	GPIOB

#define KEY_2_Pin 				GPIO_PIN_4
#define KEY_2_GPIO_Port 	GPIOB

#define KEY_3_Pin 				GPIO_PIN_5
#define KEY_3_GPIO_Port 	GPIOB

#define KEY_4_Pin 				GPIO_PIN_6
#define KEY_4_GPIO_Port 	GPIOB

#define KEY_5_Pin 				GPIO_PIN_7
#define KEY_5_GPIO_Port 	GPIOB

#define KEY_6_Pin 				GPIO_PIN_8
#define KEY_6_GPIO_Port 	GPIOB

#define KEY_7_Pin 				GPIO_PIN_9
#define KEY_7_GPIO_Port 	GPIOB

void Key_GpioOut(uchar key, uchar lev);
uchar Key_GpioIn(uchar key);
void Key_Output(uchar out);
uchar Key_Input(void);
void Key_Scan(void);

#endif

同志们可以在key.h中修改管脚定义,但各位最好对照原理图来修改,行和列的顺序还是要看好的。

main.c

//记得添加头文件
#include "key.h" 

while (1)
  {
		Key_Scan();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

只需要在while(1)中添加扫描函数即可,键盘读取的值就是key.c前面的 key_scan 这个参数,用的时候记得加extern,还有记得添加key.h的头文件。

main.h

#define uint 	unsigned int
#define uchar unsigned char

我在main.h里面添加了两个定义,方便我自己敲代码。

演示视频

VID_20240614_160059

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值