历史上的今天
返回首页

历史上的今天

今天是:2024年11月12日(星期二)

正在发生

2021年11月12日 | 51单片机实现矩阵键盘的组合按键触发

2021-11-12 来源:eefocus

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

二、编写程序


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

---- @Project: Matrix-KEY

---- @File: main.c

---- @Edit: ZHQ

---- @Version: V1.0

---- @CreationTime: 20200514

---- @ModifiedTime: 20200514

---- @Description: 16个按键中,每按一个按键都能触发一次蜂鸣器发出“滴”的一声。在同时按下S1和S16按键时,将会点亮一个LED灯。在同时按下S4和S13按键时,将会熄灭一个LED灯。

---- 单片机:AT89C52

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

#include "reg52.h"

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

#define FOSC 11059200L

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

 

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

 

/* 

*  注意:组合按键的去抖动延时const_key_time_comb千万不能等于单击按键

*  的去抖动延时const_key_time,否则组合按键会覆盖单击按键的触发。

*/

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

#define const_key_time_comb  28    /*组合按键去抖动延时的时间*/

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

/*行*/

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;

 

/*LED灯*/

sbit LED = P3^5;

 

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

 

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

 

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

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

 

unsigned int  uiKeyTimeCnt_01_16 = 0; /*S1和S16组合按键去抖动延时计数器*/

unsigned char ucKeyLock_01_16 = 0; /*S1和S16组合按键触发后自锁的变量标志*/

 

unsigned int  uiKeyTimeCnt_04_13 = 0; /*S4和S13组合按键去抖动延时计数器*/

unsigned char ucKeyLock_04_13 = 0; /*S4和S13组合按键触发后自锁的变量标志*/

 

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

 

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

 

unsigned int uiKeyStatus = 0xffff; /*此变量每一位代表一个按键的状态,共16个按键。1代表没有被按下,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;

LED = 0;

Init_T0();

}

/**

* @brief  扫描按键函数

* @param  无

* @retval 详细过程:

*  第一步:先把16个按键翻译成独立按键。

*  第二步: 再按独立按键的去抖动方式进行按键识别。

**/

void Key_Scan(void)

{

switch(ucKeyStep)

{

case 1: /*把16个按键的状态快速记录在uiKeyStatus变量的每一位中,相当于把矩阵键盘翻译成独立按键。*/

for(ucRowRecord = 1; ucRowRecord < 5; ucRowRecord ++)

{

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

{

Key5 = 0;

Key6 = 1;

Key7 = 1;

Key8 = 1;

/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/

if(Key1 == 0)

{

uiKeyStatus = uiKeyStatus & 0xfffe; /*S1*/

}

if(Key2 == 0)

{

uiKeyStatus = uiKeyStatus & 0xffef; /*S5*/

}

if(Key3 == 0)

{

uiKeyStatus = uiKeyStatus & 0xfeff; /*S9*/

}

if(Key4 == 0)

{

uiKeyStatus = uiKeyStatus & 0xefff; /*S13*/

}

}

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

{

Key5 = 1;

Key6 = 0;

Key7 = 1;

Key8 = 1;

/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/

if(Key1 == 0)

{

uiKeyStatus = uiKeyStatus & 0xfffd; /*S2*/

}

if(Key2 == 0)

{

uiKeyStatus = uiKeyStatus & 0xffdf; /*S6*/

}

if(Key3 == 0)

{

uiKeyStatus = uiKeyStatus & 0xfdff; /*S10*/

}

if(Key4 == 0)

{

uiKeyStatus = uiKeyStatus & 0xdfff; /*S14*/

}

}

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

{

Key5 = 1;

Key6 = 1;

Key7 = 0;

Key8 = 1;

/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/

if(Key1 == 0)

{

uiKeyStatus = uiKeyStatus & 0xfffb; /*S3*/

}

if(Key2 == 0)

{

uiKeyStatus = uiKeyStatus & 0xffbf; /*S7*/

}

if(Key3 == 0)

{

uiKeyStatus = uiKeyStatus & 0xfbff; /*S11*/

}

if(Key4 == 0)

{

uiKeyStatus = uiKeyStatus & 0xbfff; /*S15*/

}

}

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

{

Key5 = 1;

Key6 = 1;

Key7 = 1;

Key8 = 0;

/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/

if(Key1 == 0)

{

uiKeyStatus = uiKeyStatus & 0xfff7; /*S4*/

}

if(Key2 == 0)

{

uiKeyStatus = uiKeyStatus & 0xff7f; /*S8*/

}

if(Key3 == 0)

{

uiKeyStatus = uiKeyStatus & 0xf7ff; /*S12*/

}

if(Key4 == 0)

{

uiKeyStatus = uiKeyStatus & 0x7fff; /*S16*/

}

}

}

ucKeyStep = 2; /*切换到下一个运行步骤*/

break;

case 2: /*像独立按键一样进行去抖动和翻译。*/

if((uiKeyStatus & 0x0001) == 0x0001) /*说明1号键没有被按下来*/

{

uiKeyTimeCnt[0] = 0;

ucKeyLock[0] = 0;

}

else if(ucKeyLock[0] == 0)

{

uiKeyTimeCnt[0] ++;

if(uiKeyTimeCnt[0] > const_key_time)

{

uiKeyTimeCnt[0] = 0;

ucKeyLock[0] =1;

ucKeySec = 1;

}

}

if((uiKeyStatus & 0x0002) == 0x0002) /*说明2号键没有被按下来*/

{

uiKeyTimeCnt[1] = 0;

ucKeyLock[1] = 0;

}

else if(ucKeyLock[1] == 0)

{

uiKeyTimeCnt[1] ++;

if(uiKeyTimeCnt[1] > const_key_time)

{

uiKeyTimeCnt[1] = 0;

ucKeyLock[1] =1;

ucKeySec = 2;

}

}

if((uiKeyStatus & 0x0004) == 0x0004) /*说明3号键没有被按下来*/

{

uiKeyTimeCnt[2] = 0;

ucKeyLock[2] = 0;

}

else if(ucKeyLock[2] == 0)

{

uiKeyTimeCnt[2] ++;

if(uiKeyTimeCnt[2] > const_key_time)

{

uiKeyTimeCnt[2] = 0;

ucKeyLock[2] =1;

ucKeySec = 3;

}

}

if((uiKeyStatus & 0x0008) == 0x0008) /*说明4号键没有被按下来*/

{

uiKeyTimeCnt[3] = 0;

ucKeyLock[3] = 0;

}

else if(ucKeyLock[3] == 0)

{

uiKeyTimeCnt[3] ++;

if(uiKeyTimeCnt[3] > const_key_time)

{

uiKeyTimeCnt[3] = 0;

ucKeyLock[3] =1;

ucKeySec = 4;

}

}

if((uiKeyStatus & 0x0010) == 0x0010) /*说明5号键没有被按下来*/

{

uiKeyTimeCnt[4] = 0;

ucKeyLock[4] = 0;

}

else if(ucKeyLock[4] == 0)

{

uiKeyTimeCnt[4] ++;

if(uiKeyTimeCnt[4] > const_key_time)

{

uiKeyTimeCnt[4] = 0;

ucKeyLock[4] =1;

ucKeySec = 5;

}

}

if((uiKeyStatus & 0x0020) == 0x0020) /*说明6号键没有被按下来*/

{

uiKeyTimeCnt[5] = 0;

ucKeyLock[5] = 0;

}

else if(ucKeyLock[5] == 0)

{

uiKeyTimeCnt[5] ++;

if(uiKeyTimeCnt[5] > const_key_time)

{

uiKeyTimeCnt[5] = 0;

ucKeyLock[5] =1;

ucKeySec = 6;

}

}

if((uiKeyStatus & 0x0040) == 0x0040) /*说明7号键没有被按下来*/

{

uiKeyTimeCnt[6] = 0;

ucKeyLock[6] = 0;

}

else if(ucKeyLock[6] == 0)

{

uiKeyTimeCnt[6] ++;

if(uiKeyTimeCnt[6] > const_key_time)

{

uiKeyTimeCnt[6] = 0;

ucKeyLock[6] =1;

ucKeySec = 7;

}

}

if((uiKeyStatus & 0x0080) == 0x0080) /*说明8号键没有被按下来*/

{

uiKeyTimeCnt[7] = 0;

ucKeyLock[7] = 0;

}

else if(ucKeyLock[7] == 0)

{

uiKeyTimeCnt[7] ++;

if(uiKeyTimeCnt[7] > const_key_time)

{

uiKeyTimeCnt[7] = 0;

ucKeyLock[7] =1;

ucKeySec = 8;

}

}

if((uiKeyStatus & 0x0100) == 0x0100) /*说明9号键没有被按下来*/

{

uiKeyTimeCnt[8] = 0;

ucKeyLock[8] = 0;

}

else if(ucKeyLock[8] == 0)

{

uiKeyTimeCnt[8] ++;

if(uiKeyTimeCnt[8] > const_key_time)

{

uiKeyTimeCnt[8] = 0;

ucKeyLock[8] =1;

ucKeySec = 9;

}

}

if((uiKeyStatus & 0x0200) == 0x0100) /*说明10号键没有被按下来*/

{

uiKeyTimeCnt[9] = 0;

ucKeyLock[9] = 0;

}

else if(ucKeyLock[9] == 0)

{

uiKeyTimeCnt[9] ++;

if(uiKeyTimeCnt[9] > const_key_time)

{

uiKeyTimeCnt[9] = 0;

ucKeyLock[9] =1;

ucKeySec = 10;

}

}

if((uiKeyStatus & 0x0400) == 0x0400) /*说明11号键没有被按下来*/

{

uiKeyTimeCnt[10] = 0;

ucKeyLock[10] = 0;

}

else if(ucKeyLock[10] == 0)

{

uiKeyTimeCnt[10] ++;

if(uiKeyTimeCnt[10] > const_key_time)

{

uiKeyTimeCnt[10] = 0;

ucKeyLock[10] =1;

ucKeySec = 11;

}

}

if((uiKeyStatus & 0x0800) == 0x0800) /*说明12号键没有被按下来*/

{

uiKeyTimeCnt[11] = 0;

ucKeyLock[11] = 0;

}

else if(ucKeyLock[11] == 0)

{

uiKeyTimeCnt[11] ++;

if(uiKeyTimeCnt[11] > const_key_time)

{

uiKeyTimeCnt[11] = 0;

ucKeyLock[11] =1;

ucKeySec = 12;

}

}

if((uiKeyStatus & 0x1000) == 0x1000) /*说明13号键没有被按下来*/

{

uiKeyTimeCnt[12] = 0;

ucKeyLock[12] = 0;

}

else if(ucKeyLock[12] == 0)

{

uiKeyTimeCnt[12] ++;

if(uiKeyTimeCnt[12] > const_key_time)

{

uiKeyTimeCnt[12] = 0;

ucKeyLock[12] =1;

ucKeySec = 13;

}

}

if((uiKeyStatus & 0x2000) == 0x2000) /*说明14号键没有被按下来*/

{

uiKeyTimeCnt[13] = 0;

ucKeyLock[13] = 0;

}

else if(ucKeyLock[13] == 0)

{

uiKeyTimeCnt[13] ++;

if(uiKeyTimeCnt[13] > const_key_time)

{

uiKeyTimeCnt[13] = 0;

ucKeyLock[13] =1;

ucKeySec = 14;

}

}

if((uiKeyStatus & 0x4000) == 0x4000) /*说明15号键没有被按下来*/

{

uiKeyTimeCnt[14] = 0;

ucKeyLock[14] = 0;

}

else if(ucKeyLock[14] == 0)

{

uiKeyTimeCnt[14] ++;

if(uiKeyTimeCnt[14] > const_key_time)

{

uiKeyTimeCnt[14] = 0;

ucKeyLock[14] =1;

ucKeySec = 15;

}

}

if((uiKeyStatus & 0x8000) == 0x8000) /*说明16号键没有被按下来*/

{

uiKeyTimeCnt[15] = 0;

ucKeyLock[15] = 0;

}

else if(ucKeyLock[15] == 0)

{

uiKeyTimeCnt[15] ++;

if(uiKeyTimeCnt[15] > const_key_time)

{

uiKeyTimeCnt[15] = 0;

ucKeyLock[15] =1;

ucKeySec = 16;

}

}

if((uiKeyStatus & 0x8001) == 0x0000) /*S1和S16的组合键盘被按下。*/

{

if(ucKeyLock_01_16 == 0)

{

uiKeyTimeCnt_01_16 ++;

if(uiKeyTimeCnt_01_16 > const_key_time_comb)

{

uiKeyTimeCnt_01_16 = 0;

ucKeyLock_01_16 = 1;

ucKeySec = 17;

}

}

}

else

{

uiKeyTimeCnt_01_16 = 0; /*S1和S16组合按键去抖动延时计数器*/

推荐阅读

史海拾趣

ECLIPSE公司的发展小趣事

随着Eclipse项目的不断发展,越来越多的知名公司加入到这一开源社区中,如Oracle、Red Hat等。这些公司不仅为Eclipse贡献了代码,还提供了资金支持。Eclipse的功能日益完善,逐渐成为了Java开发领域的佼佼者。同时,Eclipse也支持其他编程语言,如C/C++、Python等,进一步扩大了其用户群体。

FOSLINK公司的发展小趣事

FOSLINK公司自成立以来,始终将技术创新视为企业发展的核心驱动力。在早期,公司专注于研发高性能的电子元器件,如混合积体电路(IC)和单石数位积体电路(ASIC)。通过不断的技术积累和优化,FOSLINK成功推出了多款具有行业领先地位的产品,不仅满足了市场对高质量电子元器件的需求,还引领了行业的技术进步。这一系列的创新成果,使FOSLINK在电子行业中逐渐崭露头角,赢得了众多客户的信赖和好评。

Alorium Technology公司的发展小趣事

面对全球气候变化的严峻挑战,FOSLINK公司积极响应国家关于绿色发展的号召,将绿色转型作为企业发展的重要方向。公司致力于研发和生产低能耗、环保型的电子产品,并不断优化生产工艺流程,减少资源消耗和环境污染。同时,FOSLINK还积极推广绿色供应链管理,与供应商和客户共同构建绿色、低碳的产业链生态。这一系列的绿色转型举措,不仅彰显了FOSLINK的社会责任感,也为其赢得了更多消费者的青睐和支持。

Continental Industries公司的发展小趣事

面对电子行业日益激烈的竞争和不断变化的市场需求,Continental Industries积极应对挑战。公司加强了对市场趋势的研究和分析,不断调整产品结构和市场策略。同时,公司还加大了对新技术和新材料的研发力度,努力提升产品的竞争力和附加值。

Anatech Electronics Inc公司的发展小趣事

经过多年的发展,Continental Industries已经成为电子行业中的佼佼者。公司不断追求创新和发展,积极拓展新的业务领域和市场空间。未来,随着电子行业的不断发展和变革,Continental Industries将继续保持敏锐的市场洞察力和强大的技术实力,努力成为行业的领导者。

这五个故事展示了Continental Industries在电子行业中的发展历程和取得的成就。虽然无法涵盖公司的全部发展细节,但通过这些故事,我们可以感受到公司在技术创新、市场拓展、合作共赢、应对挑战以及持续发展等方面的努力和成果。

Fibrefab Limited公司的发展小趣事

Fibrefab始终坚持以客户为中心的服务理念。为了提升客户满意度和忠诚度,Fibrefab不断加强售前咨询、售中服务和售后支持等方面的投入。公司建立了一套完善的服务体系,为客户提供从方案设计、产品选型、安装调试到后期维护等全方位的服务支持。此外,Fibrefab还积极收集客户反馈和建议,不断优化产品和服务以满足客户需求。

问答坊 | AI 解惑

DC-DC转换

最近用max1846按电源设计手册做了一个   5V转-5V的电路   但不知怎么调整!…

查看全部问答>

【藏书阁】晶体管偏流表(油印内发)

详细信息: 书籍作者:天津市半导体器件厂   图书出版社:内发 图书类别:理科、工程技术    出版时间:1970-10 印刷时间:1970-10-01 开本:大16开    页数:135 页     装订:平装  & ...…

查看全部问答>

有没有朋友能详细解说一下漏电开关的问题

本信息来自合作QQ群:电子工程师技术交流(12425841) 群主在坛子ID:Kata 有没有朋友能详细解说一下漏电开关的问题 我知道是测试火零之间的电流差,来控制断路。 我现在的问题是,火零之间的电流差是如何形成的?能否举例画个图给看下?…

查看全部问答>

wince renderfile rmvb问题

    小弟在WINCE上用directshow做一个视频播放器。     在播放RMVB文件时非常奇怪,每个文件播放大约     四秒后在换下一曲就没有问题,如果很快的更换     下一曲时程序就会崩溃掉。     ...…

查看全部问答>

vxworks 如何动态加载.0文件?

驱动文件以.0给出,需要检测到有该硬件再加载其驱动,如何实现?有什么命令可以?谢谢…

查看全部问答>

cadence问题求助------5!

这个问题非常基础但是有几个地方不是很明白: 在画原理图时,大部分需要自己画芯片,一些主要的芯片,库里面总是没有 在画芯片时,关于芯片引脚习惯上都是定义成什么? 我看芯片引脚有:3 state、Bidirectional 、 Input 、Open Collector &nbs ...…

查看全部问答>

资深嵌入式主板开发

概述 MB8695X 是基于 KS8695X 处理器的通讯主板。 KS8695X 是高集成化的网络通讯处理器,它内核为 166M Hz 主频的 ARM922T ,具有 3 个带有 MAC 单元和收发器的网络接口,性价比极高,非常适合用作宽带接入的路由器平台。 MB8695X 特征与优势 极 ...…

查看全部问答>

关于发送串形数据的疑问

                                 单片机STM8S903K3,现在要用3个口线和TM1628进行通讯,实现显示的驱动和按键的扫描功能。其中一个口线为片选信号, ...…

查看全部问答>

采用单电源模块设计的电路

目前在系统设计中,为了兼容各种电压也常采用48-5V单电源模块和加直流电压转换器的方案。单电源模块也存在上电顺序先后的问题。因此小于5V的电压上电肯定晚于5V.   在蓄电池供电的情况下,由于蓄电池的本身特性,在上电的时候其电压是缓慢上升的 ...…

查看全部问答>