0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用PIC16F877A连接4x4矩阵键盘的教程

科技观察员 来源:circuitdigest 作者:苏拉夫·古普塔 2022-11-15 16:49 次阅读

键盘是广泛用于各种电子嵌入式项目的输入设备。它们用于以数字和字母的形式获取输入,并将其输入系统以进行进一步处理。在本教程中,我们将使用PIC16F877A 连接 4x4 矩阵键盘。

为什么我们需要 4x4 键盘:

通常,我们使用微控制器单元的单个I / O引脚来读取数字信号,例如开关输入。在少数需要 9、12、16 个键进行输入的应用中,如果我们在微控制器端口中添加每个键,我们最终将使用 16 个 I/O 端口。这 16 个 I/O 端口不仅用于读取 I/O 信号,还可以用作外设连接,如 ADC 支持、I2C、SPI 连接也由这些 I/O 引脚支持。由于这些引脚与开关/键连接,因此我们不能将它们用作I / O端口。这完全没有意义。那么,如何减少引脚数呢?答案是,使用十六进制键盘或矩阵键盘;我们可以减少引脚数量,这些引脚数与4x4矩阵键相关联。它将使用 8 个引脚,其中 4 个成行连接,4 个以列连接,因此节省了微控制器的 8 个引脚。

4x4 矩阵键盘的工作原理

poYBAGNzUqqAJJNdAACfU54PC0o273.png

在上图中,矩阵键盘模块显示在左侧。右侧显示了内部连接以及端口连接。如果我们看到端口有 8 个引脚,从左到右的前 4 个是 X1、X2、X3 和 X4 是行,从左到右的最后 4 个是Y1、Y2、Y3、Y4是四列。如果我们制作 4 行或 X 侧作为输出并使它们逻辑低或0,并将 4列作为输入并读取键,我们将在对应Y 得到 0时读取开关按下。

同样的事情也会发生在 nxn 矩阵中,其中 n是数字。可以是 3x3、6x6 等。

现在只要认为1 被按下了。然后1 位于 X1 行和 Y1 列。如果 X1 为 0,则 Y1 将为 0。以同样的方式,我们可以通过感应列 Y1、Y2、Y3 和 Y4 来感知 X1 行中的每个键。每个开关都会发生这种情况,我们将读取矩阵中开关的位置。

每个绿色圆圈都是开关,它们都以相同的方式连接在一起。

在本教程中,我们将使用以下规格连接键盘-

我们将使用内部上拉

我们将添加密钥去抖动选项

但是当开关没有被按下时,我们需要使Y1、Y2、Y3 和 Y4达到高或 1。否则,我们无法检测到按下开关时的逻辑变化。但是我们无法通过代码或程序来实现它,因为这些引脚用作输入,而不是输出。因此,我们将在微控制器中使用内部操作寄存器,并将这些引脚作为弱上拉使能模式运行。通过使用此功能,当它处于默认状态时,将有一个逻辑高使能模式。

此外,当我们按键时,开关触点会产生尖峰或噪音,因此会发生多次开关按下,这是意料之外的。因此,我们将首先检测开关按下,等待几毫秒,再次检查开关是否仍然按下,如果开关仍然按下,我们将接受开关按下最终,否则不会。这称为开关的去抖动。

我们将在代码中实现这一切,并在面包板上建立连接。

所需材料:

面包板

PC中的Pic-kit 3和开发环境,即MPLABX

电线和连接器

字符液晶屏 16x2

20兆赫晶体

2 个 33pF 陶瓷盘盖。

4.7k 电阻

10k 预设(可变电阻)

4x4 矩阵键盘

一个 5 V 适配器

电路图:

pYYBAGNzUk6AXZc_AAFD1_Jc-rc776.png

poYBAGNzUqyAVEg3AADztX9_qas970.jpg

我们将连接相关引脚中的晶体和电阻器。此外,我们将通过PORTD 以 4 位模式连接LCD。我们将六角键盘或矩阵键盘连接到端口RB4。

编程说明:

最后给出了矩阵键盘与PIC微控制器接口的完整代码。代码简单易懂。键盘库只是在代码中要理解的东西。在这里,我们使用 keyboard.h 和 lcd.h 库来连接键盘和 16x2 LCD。让我们看看里面发生了什么。

在keypad.h内部,我们将看到我们使用了默认寄存器库的xc.h标头,晶体频率是为使用kepad.c文件中使用的延迟而定义的。我们在PORTRB寄存器上定义了键盘端口,并将各个引脚定义为行 (X)和列(Y)。

我们还使用了两个函数,一个用于键盘初始化,它将端口重定向为输出和输入,另一个是开关按下扫描,它将在调用时返回开关按下状态。

#include

#define _XTAL_FREQ 200000000 //Crystal Frequency, used in delay

#define X_1 RB0

#define X_2 RB1

#define X_3 RB2

#define X_4 RB3

#define Y_1 RB4

#define Y_2 RB5

#define Y_3 RB6

#define Y_4 RB7

#define Keypad_PORT PORTB

#define Keypad_PORT_Direction TRISB

void InitKeypad(void);

char switch_press_scan(void);

在keypad.c中,我们将看到当键盘扫描仪函数未返回“n”时,下面的函数将返回按键。

char switch_press_scan(void) // Get key from user

{

char key = 'n'; // Assume no key pressed

while(key=='n') // Wait untill a key is pressed

key = keypad_scanner(); // Scan the keys again and again

return key; //when key pressed then return its value

}

下面是键盘读取功能。在每个步骤中,我们将行 X1、X2、X3 和 X4 设为 0,并读取 Y1、Y2、Y3 和 Y4 状态。延迟用于去抖动效果,当仍然按下开关时,我们将返回与之关联的值。当没有按下开关时,我们将返回'n'。

char keypad_scanner(void)

{

X_1 = 0; X_2 = 1; X_3 = 1; X_4 = 1;

if (Y_1 == 0) { __delay_ms(100); while (Y_1==0); return '1'; }

if (Y_2 == 0) { __delay_ms(100); while (Y_2==0); return '2'; }

if (Y_3 == 0) { __delay_ms(100); while (Y_3==0); return '3'; }

if (Y_4 == 0) { __delay_ms(100); while (Y_4==0); return 'A'; }

X_1 = 1; X_2 = 0; X_3 = 1; X_4 = 1;

if (Y_1 == 0) { __delay_ms(100); while (Y_1==0); return '4'; }

if (Y_2 == 0) { __delay_ms(100); while (Y_2==0); return '5'; }

if (Y_3 == 0) { __delay_ms(100); while (Y_3==0); return '6'; }

if (Y_4 == 0) { __delay_ms(100); while (Y_4==0); return 'B'; }

X_1 = 1; X_2 = 1; X_3 = 0; X_4 = 1;

if (Y_1 == 0) { __delay_ms(100); while (Y_1==0); return '7'; }

if (Y_2 == 0) { __delay_ms(100); while (Y_2==0); return '8'; }

if (Y_3 == 0) { __delay_ms(100); while (Y_3==0); return '9'; }

if (Y_4 == 0) { __delay_ms(100); while (Y_4==0); return 'C'; }

X_1 = 1; X_2 = 1; X_3 = 1; X_4 = 0;

if (Y_1 == 0) { __delay_ms(100); while (Y_1==0); return '*'; }

if (Y_2 == 0) { __delay_ms(100); while (Y_2==0); return '0'; }

if (Y_3 == 0) { __delay_ms(100); while (Y_3==0); return '#'; }

if (Y_4 == 0) { __delay_ms(100); while (Y_4==0); return 'D'; }

return 'n';

}

我们还将在最后四个位上设置弱上拉,并将端口的方向设置为最后 4 个输入和前 4 个作为输出。 OPTION_REG &= 0x7F;用于在最后一个引脚上设置弱上拉模式。

void InitKeypad(void)

{

Keypad_PORT = 0x00; // Set Keypad port pin values zero

Keypad_PORT_Direction = 0xF0; // Last 4 pins input, First 4 pins output

OPTION_REG &= 0x7F;

}

在主PIC程序中(如下所示),我们首先设置了配置位,并包含了一些需要的库。然后在无效的system_init功能中,我们初始化键盘和LCD。最后在主函数中,我们通过调用switch_press_scan()函数并将值返回给 lcd 来读取键盘。

/*

* File: main.c

* Author: Sourav Gupta

* By:- circuitdigest.com

* Created on April 13, 2018, 2:26 PM

*/


// PIC16F877A Configuration Bit Settings


// 'C' source line config statements


// CONFIG

#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)

#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)

#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)

#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)

#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)

#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)

#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)

#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)





#include

#include

#include

#include "supporing_cfile/lcd.h"

#include "supporing_cfile/Keypad.h"


/*

Hardware related definition

*/

#define _XTAL_FREQ 200000000 //Crystal Frequency, used in delay


/*

Other Specific definition

*/

void system_init(void);



void main(void){

system_init();

char Key = 'n';

lcd_com(0x80);

lcd_puts("CircuitDigest");

lcd_com(0xC0);

while(1){

Key = switch_press_scan();

lcd_data(Key);

}


}


/*

* System Init

*/



void system_init(void){

TRISD = 0x00;

lcd_init(); // This will initialise the lcd

InitKeypad();

}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • PIC16F877A
    +关注

    关注

    2

    文章

    43

    浏览量

    21689
  • 矩阵键盘
    +关注

    关注

    7

    文章

    204

    浏览量

    31138
收藏 人收藏

    评论

    相关推荐

    谁有pic16f877a中文资料?

    谁有pic16f877a中文资料? 
    发表于 07-15 13:22

    PIC16F877A

    菜鸟想问下各位,我想用PIC16F877A做个流水灯,所有端口输出高电平1S,然后输出低电平1s 。 单片机放在学习板上测试的时候是正常的,用prpteus仿真也正常,可是放到电路板上就不正常了,低电平时间很短,Led只是闪了一下。  哪位高手指点一下是什么原因,还是要怎样测试找出问题?
    发表于 07-28 14:32

    PIC16F877A在proteus中读写AT24C512

    此时把I2C DEBUGGER的SCL线连接PIC16F877A和AT24C512的SCL线上,这样PIC16F877A可以正常的写AT24C512。当PIC16F877A发送启动信
    发表于 12-30 16:09

    PIC16F877A使用宏定义读写FlashROM

    MPLAB IDE v8.80PICC9.83读写PIC16F877A内部的EEPROM时可以使用头文件中的两个宏定义EEPROM_READ(unsigned char addr
    发表于 12-31 14:01

    PIC16F877A的中断优先级问题

    现在我需要通过串口来接收指令控制PIC16F877A的捕获脉冲行为,可以做到的是:接收到开捕获指令后,能正常开始捕获脉冲,但是再发送关闭指令却不能让它停下来,通过KIT3发现,在捕获的时候,串口不能
    发表于 06-06 21:18

    基于FPGA的4x4键盘矩阵

    基于FPGA的4x4键盘矩阵
    发表于 12-14 01:26

    4x4矩阵键盘PIC16F877A问题接口

    嗨,我正在做一个项目,我需要使用一个4x4键盘,我已经写了代码,但我不知道为什么它不是沃金。当我想按下一个按钮,例如7,这是在CulnN1(C1)和ROW1(R1)中,我写一个像IF(R1==1
    发表于 10-16 08:04

    PIC16F877A复位问题

    嗨,我还是新手,但是我有一个使用PIC16F877a的倒计时计划,而不是运行一个4位数的7段显示,并有5个按钮来选择倒计时的时间。在倒计时结束时,它发出3次哔哔声。它运行得很完美,但是会产生随机
    发表于 04-01 09:39

    PIC16F877A单片机相关资料下载

    PIC16F877A单片机(配置字)1 MPLAB X V5.0,编译器为XC8(V2.0)2MPLAB V5.0,编译器为PICC1 MPLAB X V5.0,编译器为XC8(V2.0)单击
    发表于 11-24 08:22

    PIC16F877A看门狗定时器实验的相关资料推荐

    状态 //PORTA.4(RA4)为开漏输出 // //WDT运行于独立的内部RC振荡器,即使器件时钟停振,WDT仍正常工作 //PIC16F877A单片机的WDT只...
    发表于 11-25 07:52

    带有stm32的宏键盘4x4矩阵

    描述带有stm32的宏键盘4x4矩阵
    发表于 08-16 06:48

    pic16f877a中文资料pdf

    pic16f877a中文资料
    发表于 07-15 13:20 4542次下载
    <b class='flag-5'>pic16f877a</b>中文资料pdf

    PIC16F877矩阵键盘的识别

    PIC16F877矩阵键盘的识别
    发表于 11-16 19:51 7次下载
    <b class='flag-5'>PIC16F877</b><b class='flag-5'>矩阵</b><b class='flag-5'>键盘</b>的识别

    PIC16F877矩阵键盘的识别

    PIC16F877矩阵键盘的识别
    发表于 11-16 21:06 17次下载
    <b class='flag-5'>PIC16F877</b><b class='flag-5'>矩阵</b><b class='flag-5'>键盘</b>的识别

    PIC16F877A开发板原理图

    PIC16F877A开发板原理图免费下载。
    发表于 03-21 15:47 8次下载