51单片机实现矩阵键盘的单个触发

发布者:码字奇思最新更新时间:2021-11-12 来源: eefocus关键字:51单片机  矩阵键盘  单个触发 手机看文章 扫描二维码
随时随地手机看文章

一、使用proteus绘制简单的电路图,用于后续仿真

二、编写程序


/********************************************************************************************************************

---- @Project: Matrix-KEY

---- @File: main.c

---- @Edit: ZHQ

---- @Version: V1.0

---- @CreationTime: 20200508

---- @ModifiedTime: 20200513

---- @Description: 16个按键中,每按一个按键都能触发一次蜂鸣器发出“滴”的一声。

---- 单片机:AT89C52

********************************************************************************************************************/

#include "reg52.h"

/*——————宏定义——————*/

#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   /*1ms timer calculation method in 12Tmode*/

 

#define const_voice_short  80   /*蜂鸣器短叫的持续时间*/

 

#define const_key_time  40    /*按键去抖动延时的时间*/

/*——————变量函数定义及声明——————*/

/*行*/

sbit Key1 = P0^0; /*第一行输入*/

sbit Key2 = P0^1; /*第二行输入*/

sbit Key3 = P0^2; /*第三行输入*/

sbit Key4 = P0^3; /*第四行输入*/

 

/*列*/

sbit Key5 = P0^4; /*第一列输入*/

sbit Key6 = P0^5; /*第二列输入*/

sbit Key7 = P0^6; /*第三列输入*/

sbit Key8 = P0^7; /*第四列输入*/

 

/*定义蜂鸣器*/

sbit BUZZER = P2^7;

 

unsigned char ucKeyStep = 1;   /*按键扫描步骤变量*/

 

unsigned char ucKeySec = 0;   /*被触发的按键编号*/

 

unsigned int  uiKeyTimeCnt = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock = 0; /*按键触发后自锁的变量标志*/

 

unsigned char ucRowRecord = 1; /*记录当前扫描到第几列了*/

 

unsigned int  uiVoiceCnt = 0;  /*蜂鸣器鸣叫的持续时间计数器*/

 

 

/**

* @brief  定时器0初始化函数

* @param  无

* @retval 初始化T0

**/

void Init_T0(void)

{

TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/

TL0 = T1MS;                     /*initial timer0 low byte*/

TH0 = T1MS >> 8;                /*initial timer0 high byte*/

}

/**

* @brief  外围初始化函数

* @param  无

* @retval 初始化外围

**/

void Init_Peripheral(void)

{

ET0 = 1;/*允许定时中断*/

TR0 = 1;/*启动定时中断*/

EA = 1;/*开总中断*/

 

}

 

/**

* @brief  初始化函数

* @param  无

* @retval 初始化单片机

**/

void Init(void)

{

BUZZER = 1;

Init_T0();

}

/**

* @brief  扫描按键函数

* @param  无

* @retval 矩阵按键扫描的详细过程:

*  先输出某一列低电平,其它三列输出高电平,这个时候再分别判断输入的四行,

*  如果发现哪一行是低电平,就说明对应的某个按键被触发。依次分别输出另外三列

*  中的某一列为低电平,再分别判断输入的四行,就可以检测完16个按键。内部详细的

*  去抖动处理方法跟独立按键去抖动方法是一样的。

**/

void Key_Scan(void)

{

switch(ucKeyStep)

{

case 1: /*按键扫描输出第ucRowRecord列低电平*/

if(ucRowRecord == 1) /*第一列输出低电平*/

{

Key5 = 0;

Key6 = 1;

Key7 = 1;

Key8 = 1;

}

else if(ucRowRecord == 2) /*第二列输出低电平*/

{

Key5 = 1;

Key6 = 0;

Key7 = 1;

Key8 = 1;

}

else if(ucRowRecord == 3) /*第三列输出低电平*/

{

Key5 = 1;

Key6 = 1;

Key7 = 0;

Key8 = 1;

}

else /*第四列输出低电平*/

{

Key5 = 1;

Key6 = 1;

Key7 = 1;

Key8 = 0;

}

uiKeyTimeCnt = 0; /*按键延时计数器清零*/

ucKeyStep ++; /*切换到下一步*/

break;

case 2: /*此处的小延时用来等待刚才列输出信号稳定,再判断输入信号。不是去抖动延时。*/

uiKeyTimeCnt ++;

if(uiKeyTimeCnt > 1)

{

uiKeyTimeCnt = 0;

ucKeyStep ++; /*切换到下一步*/

}

break;

case 3: /*判断是否有键按下*/

if(Key1 == 1 && Key2 == 1 && Key3 == 1 && Key4 == 1) /*如果没有按键按下*/

{

ucKeyStep = 1; /*返回第一步,重新进行扫描*/

ucKeyLock = 0; /*自锁标志清零*/

uiKeyTimeCnt = 0; /*按键去抖动延时计数器清零*/

ucRowRecord ++; /*扫描下一列*/

if(ucRowRecord > 4)

{

ucRowRecord = 1; /*依次输出完四列之后,继续从第一列开始输出低电平*/

}

}

else if(ucKeyLock == 0) /*有按键按下,且是第一次触发*/

{

if(Key1 == 0 && Key2 == 1 && Key3 == 1 && Key4 == 1)

{

uiKeyTimeCnt ++;

if(uiKeyTimeCnt > const_key_time) /*去抖*/

{

uiKeyTimeCnt = 0;

ucKeyLock = 1; /*自锁按键置位,避免一直触发,只有松开按键,此标志位才会被清零*/

if(ucRowRecord == 1)

{

ucKeySec = 1; /*触发1号键*/

}

else if(ucRowRecord == 2)

{

ucKeySec = 2; /*触发2号键*/

}

else if(ucRowRecord == 3)

{

ucKeySec = 3; /*触发3号键*/

}

else

{

ucKeySec = 4; /*触发4号键*/

}

}

}

else if(Key1 == 1 && Key2 == 0 && Key3 == 1 && Key4 == 1)

{

uiKeyTimeCnt ++;

if(uiKeyTimeCnt > const_key_time) /*去抖*/

{

uiKeyTimeCnt = 0;

ucKeyLock = 1; /*自锁按键置位,避免一直触发,只有松开按键,此标志位才会被清零*/

if(ucRowRecord ==7)

{

ucKeySec = 5; /*触发5号键*/

}

else if(ucRowRecord == 2)

{

ucKeySec = 6; /*触发6号键*/

}

else if(ucRowRecord == 3)

{

ucKeySec = 7; /*触发7号键*/

}

else

{

ucKeySec = 8; /*触发8号键*/

}

}

}

else if(Key1 == 1 && Key2 == 1 && Key3 == 0 && Key4 == 1)

{

uiKeyTimeCnt ++;

if(uiKeyTimeCnt > const_key_time) /*去抖*/

{

uiKeyTimeCnt = 0;

ucKeyLock = 1; /*自锁按键置位,避免一直触发,只有松开按键,此标志位才会被清零*/

if(ucRowRecord == 1)

{

ucKeySec = 9; /*触发9号键*/

}

else if(ucRowRecord == 2)

{

ucKeySec = 10; /*触发10号键*/

}

else if(ucRowRecord == 3)

{

ucKeySec = 11; /*触发11号键*/

}

else

{

ucKeySec = 12; /*触发12号键*/

}

}

}

else if(Key1 == 1 && Key2 == 1 && Key3 == 1 && Key4 == 0)

{

uiKeyTimeCnt ++;

if(uiKeyTimeCnt > const_key_time) /*去抖*/

{

uiKeyTimeCnt = 0;

ucKeyLock = 1; /*自锁按键置位,避免一直触发,只有松开按键,此标志位才会被清零*/

if(ucRowRecord == 1)

{

ucKeySec = 13; /*触发13号键*/

}

else if(ucRowRecord == 2)

{

ucKeySec = 14; /*触发14号键*/

}

else if(ucRowRecord == 3)

{

ucKeySec = 15; /*触发15号键*/

}

else

{

ucKeySec = 16; /*触发16号键*/

}

}

}

}

break;

}

}

/**

* @brief  按键服务函数

* @param  无

* @retval 根据扫描得到的值,进行数据处理

**/

void key_Service(void)

{

switch(ucKeySec)

{

case 1: /*1号键*/

case 2: /*2号键*/

case 3: /*3号键*/

case 4: /*4号键*/

case 5: /*6号键*/

case 7: /*7号键*/

case 8: /*8号键*/

case 9: /*9号键*/

case 10: /*10号键*/

case 11: /*11号键*/

case 12: /*12号键*/

case 13: /*13号键*/

case 14: /*14号键*/

case 15: /*15号键*/

case 16: /*16号键*/

uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/

ucKeySec = 0; /*响应按键服务处理程序后,按键编号清零,避免一致触发*/

break;

}

}

/**

* @brief  定时器0中断函数

* @param  无

* @retval 无

**/

void ISR_T0(void) interrupt 1

{

TF0 = 0;  /*清除中断标志*/

  TR0 = 0; /*关中断*/

/*扫描按键*/

Key_Scan();

if(0 != uiVoiceCnt)

{

uiVoiceCnt --;

BUZZER = 0;

}

else

{

BUZZER = 1;

}

TL0 = T1MS;                     /*initial timer0 low byte*/

TH0 = T1MS >> 8;                /*initial timer0 high byte*/

  TR0 = 1; /*开中断*/

}

/**

* @brief  延时函数

* @param  无

* @retval 无

**/

void Delay_Long(unsigned int uiDelayLong)

{

   unsigned int i;

   unsigned int j;

   for(i=0;i   {

      for(j=0;j<500;j++)  /*内嵌循环的空指令数量*/

          {

             ; /*一个分号相当于执行一条空语句*/

          }

   }

}

/*——————主函数——————*/

/**

* @brief  主函数

* @param  无

* @retval 实现LED灯闪烁

**/

void main()

{

/*单片机初始化*/

Init();

/*延时,延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定*/

Delay_Long(100);

/*单片机外围初始化*/

Init_Peripheral();

while(1)

{

/*按键服务函数*/

key_Service();

}

}


三、仿真实现

关键字:51单片机  矩阵键盘  单个触发 引用地址:51单片机实现矩阵键盘的单个触发

上一篇:51单片机实现矩阵键盘的组合按键触发
下一篇:51单片机实现按住一个独立按键不松手的加速匀速触发

推荐阅读最新更新时间:2024-11-02 17:07

时钟芯片DS1302和MCS51单片机的接口程序C51
#pragma small #include #include /******************************************** * DS1302 PIN Configuration * ******************************************** sbit DS_CLK = P1^6 sbit DS_IO = P1^5; sbit DS_RST = P1^4; /******************************************** * Shift Data from Mcu in DS1302 * **************************
[单片机]
基于51单片机的步进电机驱动器
 步进电机在控制系统中具有广泛的应用。它可以把脉冲信号转换成角位移,并且可用作电磁制动轮、电磁差分器、或角位移发生器等。   有时从一些旧设备上拆下的步进电机(这种电机一般没有损坏)要改作它用,一般需自己设计驱动器。本文介绍的就是为从一日本产旧式打印机上拆下的步进电机而设计的驱动器。本文先介绍该步进电机的工作原理,然后介绍了其驱动器的软、硬件设计。   1. 步进电机的工作原理   该步进电机为一四相步进电机,采用单极性直流电源供电。只要对步进电机的各相绕组按合适的时序通电,就能使步进电机步进转动。图1是该四相反应式步进电机工作原理示意图。   图1 四相步进电机步进示意图      开始时,开关SB接
[单片机]
基于<font color='red'>51单片机</font>的步进电机驱动器
常用的51单片机程序
51程序集 ;片内RAM初始化子程序 IBCLR:MOVA,R0 MOVR1,A CLRA IBC1:MOV@R1,A INCR1 DJNZR7,IBC1 RET ;片外RAM初始化子程序 EBCLR1:MOVA,ADDPL MOVDPL,A MOVA,ADDPH MOVDPH,A CLRC EBC11:MOVX@DPTR,A INCDPTR DJNZR7,EBC11 RET ;片外RAM初始化子程序(双字节个单元) EBCLR2:MOVA,ADDPL MOVDPL,A MOVA,ADDPH MOVDPH,A MOVA,R7 JZEBC21 INCR6 EBC21:CLRA MOVX@DPTR,A INCD
[单片机]
51单片机教程第2讲_下载程序
stc是国内最大的51单片机提供商,他的产品也是非常的丰富,应用广泛,所以我们以stc51单片机为例进行学习。其它厂家的51单片机大同小异。 stc51单片机都可以使用串口下载程序,即ISP下载。串口分为电脑的串口和单片机的串口。每个单片机都有串口,外部表现为2个引脚,即RXD和TXD。以前,每个电脑上都有串口,现在,家用型电脑已经不配置串口,只有工控电脑还带有串口。但是,电脑不带串口并不会影响你下载程序,你不必非要买一个带有串口的电脑。因为现在市面上,有一种线,叫做“USB转串口线”,它可以把你电脑的USB口变成串口,和以前电脑上的串口外表和功能一模一样,如下图所示:   DB9串口头一共9个引脚,其中两个是RXD 和TXD
[单片机]
C51单片机的中断号以及中断向量
一、中断号   二、interrupt 和 using 在C51中断中的使用   8051 系列 MCU 的基本结构包括:32 个 I/O 口(4 组8 bit 端口);两个16 位定时计数器;全双工串行通信;6 个中断源(2 个外部中断、2 个定时/计数器中断、1 个串口输入/输出中断),两级中断优先级;128 字节内置RAM;独立的 64K 字节可寻址数据和代码区。中断发生后,MCU 转到 5 个中断入口处之一,然后执行相应的中断服务处理程序。中断程序的入口地址被编译器放在中断向量中,中断向量位于程序代码段的最低地址处,注意这里的串口输入/输出中断共用一个中断向量。8051的中断向量表如下:
[模拟电子]
C<font color='red'>51单片机</font>的中断号以及中断向量
51单片机汇编语言实验(三)-----定时/计数器实验
一、实验目的:    学习定时/计数器的工作方式,掌握程序设计方法。 二、实验设备:    PC计算机一台,Dais-52PRO+实验系统一套。 三、实验内容:    1. 定时器实验    2. 计数器实验 四、 定时器实验    1、实验原理:    使用T0进行定时,编写程序,使P1.0控制的发光二极管L0每隔2秒交替点亮或熄灭。    2、实验步骤:   ① 将试验箱IO区的P1.0与LED区的L0按图下图连线;   ② 编写程序,经编译、链接无语法错误后装载到实验系统;   ③ 运行程序,观察发光二极管L0,应每隔2秒交替点亮或熄灭;   ④ 实验完毕后,应使用暂停命令中止程序的运行。    3、参考代码: //实验
[单片机]
<font color='red'>51单片机</font>汇编语言实验(三)-----定时/计数器实验
如何将UCOSII移植到51单片机
一、准备工作 1. 开发环境: Keil C集成开发环境 2. 源代码:UCOSII的源代码,网上可以自己下载 3. 文件分析: 1)UCOSII文件中与处理器无关的文件: OS_CORE.C OS_FLAG.C OS_MBOX.C OS_MEM.C OS_MUTEX.C OS_Q.C OS_SEM.C OS_TASK.C OS_TIME.C UCOS_II.C UCOS_II.H 以上这些文件在c51移植过程中只需给函数加上可重入性即可,即在每个函数后面添加关键字:reentrant 2)与应用相关的文件: INCLUDES.H——其中包含51单片机头文件和相关应用头文件 OS_CFG.H——这个文件对于要应用系统中的相关工
[单片机]
如何将UCOSII移植到<font color='red'>51单片机</font>上
3×4的矩阵键盘电路图及汇编语言源程序
3×4的矩阵键盘通过并行接口芯片8255A与微机相连。8255A的A口定义为输出口,与键盘行线相连;B口定义为输入口,与键盘列线相连。设8255A A口地址为40H,B口地址为41H,控制寄存器地址为43H。 MOV AL,82H OUT 43H,AL BEGIN:MOV AL,0 OUT 40H,AL WAIT : IN AL,41H AND AL,0FH CMP AL,0FH JZ WAIT MOV CX,7FFH L0: LOOP L0 ST: MOV BL,3 MOV BH,4 MOV AL,0FEH
[模拟电子]
3×4的<font color='red'>矩阵键盘</font>电路图及汇编语言源程序
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved