矩形键盘

介绍

什么是矩阵键盘

矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组,由于电路设计时需要更多的外部输入,单独的控制一个按键需要浪费很多的IO资源,所以就有了矩阵键盘,常用的矩阵键盘有4X4和8X8,其中用的最多的是4X4。
4

矩阵键盘的原理

矩阵键盘又称为行列式键盘,它是用4条I/O线作为行线,4条I/O线作为列线组成的键盘。
在行线和列线的每一个交叉点上,设置一个按键。这样键盘中按键的个数是4×4个。
这种行列式键盘结构能够有效地提高单片机系统中I/O口的利用率。由于单片机IO端口具有线与的功能,因此当任意一个按键按下时,行和列都有一根线被线与,通过运算就可以得出按键的坐标从而判断按键键值。
原理如同矩阵数列的行列式。

驱动电路图

按4*4矩阵搭建的按键矩阵还是比较简单的,也有的人为了保证电路的稳定性,加上二极管保护和上拉电阻,但是一般要求不太高的电路就不需要加了,向下面设置的电路那样就可以了。

软件程序实现

在这里宏定义一些GPIO的信息。

KEY.h

#ifndef _KEY_H
#define _KEY_H
#include "stm32f10x.h"
//引脚
#define S0 GPIO_Pin_0
#define S1 GPIO_Pin_1
#define S2 GPIO_Pin_2
#define S3 GPIO_Pin_3
#define S4 GPIO_Pin_4
#define S5 GPIO_Pin_5
#define S6 GPIO_Pin_6
#define S7 GPIO_Pin_7
//GPIO寄存器
#define KEY_PORT GPIOB
//时钟
#define RCC_APB2_KEY  RCC_APB2Periph_GPIOB
//函数定义
void InitKey(void);
int NumKey(void);
//延时
void Delay( uint32_t count )
{
 for(; count!=0; count--);
}
#endif /* _KEY_H  */

在这里存放两个函数,一个是初始化矩形键盘GPIO口的函数,在函数里把前四个定义为推挽输出,后四个GPIO口定义为下拉输入。
另一个函数是键盘扫描函数,通过函数返回值确定是举行键盘的哪一个按键被按下。

KEY.c

#include "KEY.h"
void InitKey(void)//初始化KEY的GPIO
{
 //打开GPIO时钟
 RCC_APB2PeriphClockCmd(RCC_APB2_KEY,ENABLE);
 //把S0,S1,S2,S3配置为推挽输出
 GPIO_InitTypeDef   GPIOInit;
 GPIOInit.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
 GPIOInit.GPIO_Speed=GPIO_Speed_50MHz;
 GPIOInit.GPIO_Pin=S0|S1|S2|S3;
 GPIO_Init(KEY_PORT,&GPIOInit); 
 
 //把S4,S5,S6,S7配置为下拉输入
 GPIOInit.GPIO_Mode=GPIO_Mode_IPU;
 GPIOInit.GPIO_Pin=S4|S5|S6|S7;
 GPIO_Init(KEY_PORT,&GPIOInit); 
 
  //0--3输出高,4--7输出低
  GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
  GPIO_ResetBits(GPIOC,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); 
  
}
int NumKey(void)  //扫描键值
{
 int KeyVal=0;     //键值,后面自己设定的,用来设置按键的序号
 u16 KeyWrite=0;   //写给GPIO的值 
 GPIO_Write(KEY_PORT,(KEY_PORT->ODR & 0xfff0 | 0xf));//0--3全部输出高 
 if((KEY_PORT->IDR&0x00f0)==0x0000)   //如果4--7全为0,表示没有按键按下,返回值设置为-1
  return -1;
  
 else
 {
  Delay(0xF);//消抖
   if((KEY_PORT->IDR&0x00f0)==0x0000)   //如果4-7全为0,表示刚才是抖动造成的
  return -1; 
 }
 GPIO_Write(KEY_PORT,(KEY_PORT->ODR & 0xfff0|0x1));//让0-3输出0001
 
 switch(KEY_PORT->IDR&0x00f0)//对4--7进行判断
 {
  case 0x0010: KeyVal=16;break;
  case 0x0020: KeyVal=12;break;
  case 0x0040: KeyVal=8; break;
  case 0x0080: KeyVal=4; break; 
 }
 
 GPIO_Write(KEY_PORT,(KEY_PORT->ODR & 0xfff0|0x2));//让0-3输出0010
 switch(KEY_PORT->IDR&0x00f0)//对4--7进行判断
 {
  case 0x0010: KeyVal=15;break;
  case 0x0020: KeyVal=11;break;
  case 0x0040: KeyVal=7; break;
  case 0x0080: KeyVal=3; break; 
 }
 GPIO_Write(KEY_PORT,(KEY_PORT->ODR & 0xfff0|0x4));//让0-3输出0100
 switch(KEY_PORT->IDR&0x00f0)//对4--7进行判断
 {
  case 0x0010: KeyVal=14;break;
  case 0x0020: KeyVal=10;break;
  case 0x0040: KeyVal=6; break;
  case 0x0080: KeyVal=2; break; 
 }
 GPIO_Write(KEY_PORT,(KEY_PORT->ODR & 0xfff0|0x8));//让0-3输出1000
 switch(KEY_PORT->IDR&0x00f0)//对4--7进行判断
 {
  case 0x0010: KeyVal=13;break;
  case 0x0020: KeyVal=9;break;
  case 0x0040: KeyVal=5; break;
  case 0x0080: KeyVal=1; break;
 }
 return KeyVal;
}

想了解更多嵌入式知识,欢迎关注我的项目实战专栏。
还可关注公众号,了解更多。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是使用Keil5编写4*4矩形键盘模块三位数以内加减乘除计算器的代码: ```c #include <reg52.h> #define uchar unsigned char #define uint unsigned int uchar code keymap[4][4] = { // 键盘按键映射表 {'1', '2', '3', '+'}, {'4', '5', '6', '-'}, {'7', '8', '9', '*'}, {'C', '0', '=', '/'} }; uchar tmp, num1, num2, op, result; // 定义变量 sbit D0 = P2^0; // 显示数码管位选引脚 sbit D1 = P2^1; sbit D2 = P2^2; sbit D3 = P2^3; sbit LSA = P2^4; // 显示数码管片选引脚 sbit LSB = P2^5; sbit LSC = P2^6; void delay(uint t) // 延时函数 { uint i, j; for(i=0; i<t; i++) { for(j=0; j<120; j++); } } void scan_key() // 扫描键盘函数 { uchar i, j; for(i=0; i<4; i++) { P1 = 0x0f ^ (0x01 << i); // 设置引脚电平 tmp = P1; // 读取列引脚电平 for(j=0; j<4; j++) { if(!(tmp & (0x01 << j))) // 判断是否有按键按下 { delay(10); // 延时去抖动处理 if(!(tmp & (0x01 << j))) // 再次判断是否有按键按下 { while(!(tmp & (0x01 << j))); // 等待按键释放 if(keymap[i][j] >= '0' && keymap[i][j] <= '9') // 如果是数字键 { if(op == 0) // 如果还没有操作符 { num1 = num1 * 10 + (keymap[i][j] - '0'); // 计算第一个数 P0 = num1; // 显示第一个数 } else // 如果已经有操作符 { num2 = num2 * 10 + (keymap[i][j] - '0'); // 计算第二个数 P0 = num2; // 显示第二个数 } } else if(keymap[i][j] == 'C') // 如果是清除键 { num1 = 0; num2 = 0; op = 0; P0 = 0; // 清除显示 } else if(keymap[i][j] == '=') // 如果是等于键 { switch(op) { case '+': result = num1 + num2; break; case '-': result = num1 - num2; break; case '*': result = num1 * num2; break; case '/': result = num1 / num2; break; default: break; } num1 = result; num2 = 0; op = 0; P0 = result; // 显示结果 } else // 如果是操作符键 { op = keymap[i][j]; } } } } } } void display(uchar num) // 显示数码管函数 { switch(num) { case 0: LSA = 0, LSB = 0, LSC = 0, D0 = 1, D1 = 1, D2 = 1, D3 = 1; break; case 1: LSA = 1, LSB = 0, LSC = 0, D0 = 0, D1 = 1, D2 = 1, D3 = 1; break; case 2: LSA = 0, LSB = 1, LSC = 0, D0 = 1, D1 = 0, D2 = 1, D3 = 1; break; case 3: LSA = 1, LSB = 1, LSC = 0, D0 = 0, D1 = 0, D2 = 1, D3 = 1; break; case 4: LSA = 0, LSB = 0, LSC = 1, D0 = 1, D1 = 1, D2 = 0, D3 = 1; break; case 5: LSA = 1, LSB = 0, LSC = 1, D0 = 0, D1 = 1, D2 = 0, D3 = 1; break; case 6: LSA = 0, LSB = 1, LSC = 1, D0 = 1, D1 = 0, D2 = 0, D3 = 1; break; case 7: LSA = 1, LSB = 1, LSC = 1, D0 = 0, D1 = 0, D2 = 0, D3 = 1; break; case 8: LSA = 0, LSB = 0, LSC = 0, D0 = 1, D1 = 1, D2 = 1, D3 = 0; break; case 9: LSA = 1, LSB = 0, LSC = 0, D0 = 0, D1 = 1, D2 = 1, D3 = 0; break; default: break; } } void main() { while(1) { scan_key(); // 扫描键盘 display(num1 % 10); // 显示个位数字 delay(5); display(num1 / 10 % 10); // 显示十位数字 delay(5); display(num1 / 100); // 显示百位数字 delay(5); } } ``` 在以上代码中,我们通过扫描键盘来获取用户的输入,并根据不同的按键进相应的计算操作。同时,我们还使用了数码管来显示计算结果。需要注意的是,由于使用了延时函数来控制数码管的显示,可能会导致按键响应速度变慢,因此可以考虑使用定时器来代替延时函数来控制数码管的显示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联网知识

编写不易,打赏支持一下我吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值