清翔零基础教你学51单片机_个人学习笔记(7)_矩阵按键

说明

本人使用的是清翔的51单片机开发板,如果型号相同最方便,但是如果型号不同也可以参考,因为芯片都是一样的,只是外设不同而已,使用时只需要对照自己的开发板原理图稍微修改下引脚即可。

本次笔记对应清翔视频教程的第21、22集 矩阵按键(理论+编程)

目录

一、矩阵按键理论部分

1.1 原理图

 1.2 扫描方法

二、switch-case语句

2.1 switch-case语句和if-else语句的区别

2.2 switch-case语句使用方法

三、编程

3.1创建工程

3.2 创建一个main.h头文件

3.3 矩阵按键程序

3.3.1 main.c

3.3.2 main.h 

 3.4 在矩阵按键程序中添加独立按键


一、矩阵按键理论部分

矩阵按键有4行4列,可以通过列扫描和行扫描来确定哪个键被按下。

1.1 原理图

 1.2 扫描方法

先进行列扫描列扫描时把所有列的IO口拉高,行IO口拉低,这样当检测到某列的IO口是低,那么就知道这一列有按键被按下;

再进行行扫描,把所有行的IO口拉高,列的IO口拉低,这样当检测到某行的IO口是0,那么就证明这一行有按键被按下。

经过这一行一列的扫描,就能够把具体的按键确定下来

例如:假设s11被按下,在进行列扫描时,我们让P3 = b0000 1111,结果读取到的P3 是b0000 1011,那么就说明第2列有按键被按下了

然后进行行扫描,我们让P3 = b1111 0000,结果读取到的P3是b1011 0000,说明第2行有按键被按下,第2列第2行,那么就可以唯一确定这个按键是s11。

总结分析一下,可以发现,如果在列扫描中发现某列有按键被按下

①假设在行扫描中第1行被按下:那么被按下的按键顺序=列顺序

②假设在行扫描中第2行被按下:那么被按下的按键顺序=列顺序+4;

③假设在行扫描中第3行被按下:那么被按下的按键顺序=列顺序+8;

④假设在行扫描中第4行被按下:那么被按下的按键顺序=列顺序+12;

二、switch-case语句

2.1 switch-case语句和if-else语句的区别

switch-case语句适用于多个固定选项的条件判断。它的语法结构是由一个switch关键字和多个case语句组成。在switch关键字后面,你需要提供一个表达式或变量,这个表达式的值会与每个case语句后的值进行比较。当表达式的值与某个case语句的值相等时,程序将执行该case语句后的代码块。如果没有匹配的case语句,你可以使用default关键字来指定一个默认的代码块。switch-case语句的优点是可以清晰地展示多个选项的处理逻辑,使代码更易读。

相比之下,if-else语句则更加灵活,适用于多种条件的判断。if-else语句的语法结构由一个if关键字和一个或多个条件语句组成。当条件语句的结果为真时,程序将执行if语句后的代码块;当条件语句的结果为假时,程序将执行else语句后的代码块。if-else语句的优点是可以根据具体的条件灵活地控制程序的执行流程。

总结来说,switch-case语句适用于多个固定选项的条件判断,而if-else语句则更适用于多种条件的判断。

2.2 switch-case语句使用方法

一般格式:

switch (表达式)
{
    case 常量表达式1: 语句1;break;
    case 常量表达式2: 语句2;break;
    case 常量表达式3: 语句3;break;
    case 常量表达式4: 语句4;break;
    ...
}

 当表达式与case后面的常量相等时,就执行对应的语句

三、编程

3.1创建工程

复制一份工程模板,修改名称为“7.矩阵按键”,进入项目文件夹,打开工程文件

3.2 创建一个main.h头文件

在Source Group 1上右键,选择Add New Itemto Group'Source Group 1'..,

 选择.h文件,名字为main.h,Add,这样在左侧边栏就会有一个main.h文件,里面可以放一些函数的声明,数组,宏定义等,以此来简化main.c函数,在我以后的代码中,我将同时给出我的main.h和main.c中的代码。可以直接在工程模板中创建一个,这样以后复制的工程模板改名文件里面都有main.h了,也可以在工程模板中直接写入

#include <reg52.h>
#include <main.h>    //只有创建并使用了main.h才需要写这一行代码

void main()
{
    
}

上面这段内容,因为这是每个工程都要有的,也算模板的一部分

在main.h文件中写入

#ifndef __MAIN_H
#define __MAIN_H




#endif

 然后我们就可以在中间空白处放入内容了

比如一个显示三位数的程序,有了main.h,main.h中写入

#ifndef __MAIN_H
#define __MAIN_H

typedef unsigned char uchar;
typedef unsigned int uint;

void delay(unsigned int i);
void SEG_DIS(uchar position, uchar number);
void SEG_DIS3(uchar i);

sbit DU = P2^6; //数码管段选
sbit WE = P2^7; //数码管位选
sbit key_s2 = P3^0;
sbit key_s3 = P3^1;

uchar we[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
uchar du[]={ 
                0x3F,  //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"B"
                0x39,  //"C"
                0x5E,  //"D"
                0x79,  //"E"
                0x71,  //"F"
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                0x00  //自定义
                         };
#endif

main.c写入

#include <reg52.h>
#include <main.h>


void main()
{
    while(1)
    {
        SEG_DIS3(137);
    }
}

void SEG_DIS(uchar position, uchar number)
{
    DU = 0;
    WE = 0;
    P0 = we[position - 1];
    WE = 1;
    WE = 0;
    
    P0 = du[number];
    DU = 1;
    DU  = 0;
    delay(1);
}

void SEG_DIS3(uchar i)
{
    SEG_DIS(1, i / 100);
    SEG_DIS(2, i % 100 / 10);
    SEG_DIS(3, i % 10);
}



void delay(unsigned int i)
{
    unsigned int j;
    for (; i > 0; i--)
        for (j = 114; j > 0; j--);
}

 这样main.c函数就会简洁很多

3.3 矩阵按键程序

由于刚开始使用main.h,初学者可能难以把握,所以在本次笔记中,我将每次都给出完整的main.c和main.h中的程序,在以后的笔记中,我将只给出变化的部分,以此减小笔记的长度,也便于识别出程序变化的部分,有利于学习51的编程

3.3.1 main.c

#include <reg52.h>
#include <main.h>

uchar keyval = 22;  //初始值是22,这样在第11行的程序SEG_DIS(1,keyval);就会显示du[22]的数值‘-’

void main()
{
    while(1)
    {
        key_scan();
        SEG_DIS(1,keyval);
    }
}

void key_scan()
{
    P3 = 0xF0;  //列扫描b1111 0000
    if (P3 != 0xF0)
    {
        delay(10);  //软件消抖
        if (P3 != 0xF0)
        {
            switch (P3)
            {
                case 0xE0: keyval = 0;break;    //11100000  第1列按下
                case 0xD0: keyval = 1;break;    //11010000  第2列按下
                case 0xB0: keyval = 2;break;    //10110000  第3列按下
                case 0x70: keyval = 3;break;    //01110000  第4列按下
            }
            P3 = 0x0F;  //行扫描   b0000 1111
            switch (P3)
            {
                case 0x0E: keyval = keyval;break;           //11100000  第1行按下
                case 0x0D: keyval = keyval + 4;break;       //11010000  第2行按下
                case 0x0B: keyval = keyval + 8;break;       //10110000  第3行按下
                case 0x07: keyval = keyval + 12;break;      //01110000  第4行按下
            }
            while (P3 != 0x0F); //松手检测
        }
    }
}

void SEG_DIS(uchar position, uchar number)
{
    DU = 0;
    WE = 0;
    P0 = we[position - 1];
    WE = 1;
    WE = 0;
    
    P0 = du[number];
    DU = 1;
    DU  = 0;
    delay(1);
}

//void SEG_DIS3(uchar i)    //注释掉是因为在本次矩阵按键扫描程序中未使用到
//{
//    SEG_DIS(1, i / 100);
//    SEG_DIS(2, i % 100 / 10);
//    SEG_DIS(3, i % 10);
//}



void delay(unsigned int i)
{
    unsigned int j;
    for (; i > 0; i--)
        for (j = 114; j > 0; j--);
}

3.3.2 main.h 

#ifndef __MAIN_H
#define __MAIN_H

typedef unsigned char uchar;
typedef unsigned int uint;

void delay(unsigned int i);
void SEG_DIS(uchar position, uchar number);
//void SEG_DIS3(uchar i);
void key_scan();
    
sbit DU = P2^6; //数码管段选
sbit WE = P2^7; //数码管位选
sbit key_s2 = P3^0;
sbit key_s3 = P3^1;

uchar we[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
uchar du[]={ 
//0    1     2     3     4     5     6     7     8
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,
//9     A     B    C     D     E     F     H     L     
0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x76, 0x38,
//n    u      -   熄灭
0x37, 0x3E, 0x40, 0x00 };
#endif

 3.4 在矩阵按键程序中添加独立按键

只需要在key_scan函数末尾添加上这段代码

    //加入独立按键扫描
    P3 = 0XFF;  //b1111 1111
    if (P3 != 0xFF)
    {
        delay(10);  //软件消抖
        if (P3 != 0xFF)
        {
            switch (P3)
            {
                case 0xFE: keyval = 16;break;       //1111 1110  s2按下
                case 0xFD: keyval = 17;break;       //1111 1101  s3按下
                case 0xFB: keyval = 18;break;       //1111 1011  s4按下
                case 0xF7: keyval = 19;break;       //1111 0111  s5按下
            }
            while (P3 != 0XFF);
        }
    }

本次笔记对应清翔视频教程的第21、22集 矩阵按键(理论+编程),到此结束,下一篇笔记将对应视频教程的23,24,25 8x8点阵屏(理论+实践)

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值