实验五:矩阵键盘实验
来自丢石头百科
Yousimaier17(讨论 | 贡献)2024年12月2日 (一) 11:37的版本
目录
扫描原理
矩阵键盘的结构相较于独立键盘复杂一些,单片机对其进行的识别也会复杂一些。矩阵键盘的扫描方式有两种:行列扫描法和逐行/逐列扫描法。行列扫描法也称为线反法,适用于矩阵键盘受单片机连续的I/O口控制的情况;逐行/逐列扫描法适用于矩阵键盘被接入了单片机的任意I/O口的情况。在实际单片机应用中更为常用的是行列扫描法。 下面以4*4矩阵键盘为例,其中四条行线(第一行开始)接入单片机的P1.0-P1.3,四条列线(第一列开始)接入P1.4-P1.7。
行列扫描法
- 使P1口的高四位输出高电平,低四位输出低电平,此时列线被拉高,行线被拉低。假设有按键按下,则某一列的电平将会被拉低,此时读取P1口高四位(四个列)的电平,若读取到的值不全为高电平,说明有按键按下,可通过读取到的值判断是第几列。再使P1口的高四位输出低电平,低四位输出高电平,读取P1口低四位(四个行)的电平,此时读取到的值不再全为高电平,可通过读取到的值判断是第几行。将两次读取的结果组合起来就可以得到当前按键的键值,从而确定按下按键的位置。
逐行/逐列扫描法
- 逐行/逐列扫描法本质和行列扫描法类似,即给某一行/某一列输出低电平,其余七个全部为高电平,此时读取电平变化,若由低电平则说明有按键键按下,可根据读取的键值判断按键按下的位置。
- 具体操作如下:将第一行置为低电平,其余三行和四列置为高电平。读取列线的数据,若列线不全为高电平表示第一行有按键按下,可根据读取的数据判断是第一行的哪一列按键按下;若列线全为高电平,则将第二行置为低电平,其余三行和四列置为高电平,读取列线的数据,判断是否有按键按下。重复上述动作,并以此类推。
Arduino
实验现象
- 串口输出按下按键的键值
电路连接
矩阵键盘 Arduino UNO R3 R1 D2 R2 D3 R3 D4 R4 D5 C1 D6 C2 D7 C3 D8 C4 D9
主要程序
int R[] = {2,3,4,5}; int C[] = {6,7,8,9}; void setup() { Serial.begin(9600); for (int i = 0; i < 4; i++) { pinMode(R[i], INPUT_PULLUP); pinMode(C[i], OUTPUT); } } void loop() { //列线输出0 for (int i = 0; i < 4; i++) { digitalWrite(C[i], LOW); } if (!digitalRead(R[0]) || !digitalRead(R[1]) || !digitalRead(R[2])|| !digitalRead(R[3])) { delay(10); if (!digitalRead(R[0]) || !digitalRead(R[1]) || !digitalRead(R[2])|| !digitalRead(R[3])) { digitalWrite(C[0], LOW);//扫描第一列 digitalWrite(C[1], HIGH); digitalWrite(C[2], HIGH); digitalWrite(C[3], HIGH); for (int j = 0; j < 4; j++) { if (!digitalRead(R[j])) { Serial.print("S"); Serial.print(j * 4 + 1);//在串口监视器中输出键盘编号 Serial.println(" has been pressed"); while (!digitalRead(R[j])); Serial.println("The button has been loosened"); } } digitalWrite(C[0], HIGH);//扫描第二列 digitalWrite(C[1], LOW); digitalWrite(C[2], HIGH); digitalWrite(C[3], HIGH); for (int j = 0; j < 4; j++) { if (!digitalRead(R[j])) { Serial.print("S"); Serial.print( j * 4 + 2); Serial.println(" has been pressed"); while (!digitalRead(R[j])); Serial.println("The button has been loosened"); } } digitalWrite(C[0], HIGH);//扫描第三列 digitalWrite(C[1], HIGH); digitalWrite(C[2], LOW); digitalWrite(C[3], HIGH); for (int j = 0; j < 4; j++) { if (!digitalRead(R[j])) { Serial.print("S"); Serial.print(j * 4 + 3); Serial.println(" has been pressed"); while (!digitalRead(R[j])); Serial.println("The button has been loosened"); } } digitalWrite(C[0], HIGH);//扫描第三列 digitalWrite(C[1], HIGH); digitalWrite(C[2], HIGH); digitalWrite(C[3], LOW); for (int j = 0; j < 4; j++) { if (!digitalRead(R[j])) { Serial.print("S"); Serial.print(j * 4 + 4); Serial.println(" has been pressed"); while (!digitalRead(R[j])); Serial.println("The button has been loosened"); } } } } }
注意事项
- 需将按键连接引脚配置为输入上拉模式,这样该引脚在没有外接信号输入的情况可下保持高电位,则写为:pinMode(9, INPUT_PULLUP);
- 若单纯写为:pinMode(9, INPUT),则该引脚的状态会不稳定。出现0和1无规律变化,从而影响程序判断。
树莓派
电路连接
矩阵键盘 Raspberrypi BCM编号 物理引脚序号 R1 GPIO6 31 R2 GPIO13 33 R3 GPIO19 35 R4 GPIO26 37 C1 GPIO12 32 C2 GPIO16 36 C3 GPIO20 38 C4 GPIO21 40
程序运行
Python
- 安装gpiozero库
- 可以使下面命令来安装该库
sudo apt update sudo apt install python3-gpiozero
- 其它树莓派上的系统可以使下面命令来安装该库:
sudo pip3 install gpiozero
- 运行以下语句可以查看树莓派GPIO口定义
pinout
- 下载树莓派参考例程,将文件解压后拷贝放在用户名目录下,运行
cd raspberrypi/5/python_gpiozero python button.py
- 此时可看见树莓派在正确运行矩阵键盘程序,按下任意按键串口打印对应的键值。若想退出,按ctrl+C即可
- 指令说明:gpiozero.ButtonBoard(pin, pull_up, active_state, bounce_time, hold_time, hold_repeat)
- 主要参数:
- pin:GPIO口编号;
- pull_up: 内部上下拉电阻设置,
- 设置为True(默认)时,GPIO引脚被拉高,需将按键的另一端接地。
- 设置为Flase时,GPIO引脚被拉高低,需将按键的另一端接3V3
- 设置为None时,GPIO引脚悬空,gpiozero无法猜测活动状态,必须设置active_state
- active_state:
- 设置为True时,当硬件引脚状态为“高”,软件显示引脚状态也为“高”
- 设置为False时,则输入的极性相反,当硬件引脚状态为“高”,软件显示引脚状态为“低”
- 当pull_up设置为None时,使用该参数设置未知的引脚活动状态
- 当pull_up设置为True或者False时,引脚的活动状态被将自动赋值
- bounce_time: 软件消抖时间。一般开关在大约20ms内信号不稳定,存在所谓的“开关抖动
- 设置为None时,将不执行软件抖动补偿,否则该参数是组件在初始更改后忽略的时间长度(秒),默认1s
- hold_time: 按下按钮后直到触发when_held的时间,单位秒
- hold_repeat:
- 如果为True,则只要按钮持续被按下when_held会每隔hold_time时间持续被触发
- 如果为False,则when_held只会触发一次;
- 主要参数:
- 指令说明:LEDBoard(pin, pwm, active_high, initial_value)
- 主要参数:
- pin: GPIO口编号,
- pwm:
- 如果为True,则为每个引脚构造PWMLED实例。
- 如果为False(默认值),则构造常规LED实例。
- active_high: 内部上下拉电阻设置,
- 设置为True(默认)时,on()将引脚设置为High,off()将引脚设置为LOW。
- 设置为Flase时,on()将引脚设置为LOW,off()将引脚设置为High。
- initial_value:
- 如果为False(默认值),则所有LED初始状态为关闭。
- 如果为“None”,则所有LED初始状态不稳定。
- 如果为True,则所有LED初始状态为关闭打开。
- 主要参数:
- 更多指令请查看gpiozero文档