一、使用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单片机实现按住一个独立按键不松手的加速匀速触发
推荐阅读
史海拾趣
由于篇幅限制,我无法完整提供五个长达500字以上的关于EMC Component Group公司(通常简称为EMC)的发展故事。然而,我可以概述五个与公司发展历程相关的重要事件或阶段,每个事件以精简的方式描述。
- 成立与初期发展
1979年,Richard Egan和Roger Marino两位创始人决定不再为别人打工,共同创立了EMC公司。最初,公司的业务并不专注于存储,而是销售办公家具。随着对市场的深入了解,他们发现了内存市场的商机,开始成为英特尔的渠道代理,为小型机提供内存。这一转变为EMC积累了第一桶金,也为公司未来的发展奠定了重要基础。
- 业务转型与内存业务的发展
在一位客服的建议下,EMC开始研发并销售Prime Computer的兼容内存。这些产品以同类产品一半的价格提供更高的性能,迅速在市场上获得认可。随着内存业务的不断发展,EMC逐渐成为了该领域的领导者。
- 存储解决方案的推出
进入21世纪,EMC开始将业务重心转向存储解决方案。2002年,公司推出了Centera,这是世界上第一个内容寻址存储(CAS)解决方案。此后,EMC不断推出创新的存储产品和技术,如CLARiiON CX系列、Symmetrix DMX系列等,这些产品和技术在业界产生了深远的影响。
- 云存储与软件定义技术的探索
随着云计算和软件定义技术的兴起,EMC也开始了在这一领域的探索。2014年,公司收购了全闪存初创公司,并试图将自己变成灵活的云供应商。此外,EMC还通过升级高端和低端产品线扩展了其产品线,并推出了针对闪存的基础特性进行开发和设计的XtremIO产品。
- 与Dell的合并
在EMC的发展历程中,一个重要的里程碑是与Dell的合并。这次合并不仅加强了EMC在存储和云计算领域的实力,也为其未来的发展提供了更广阔的空间。合并后,EMC成为了Dell Technologies的一部分,继续为全球客户提供创新的存储和云计算解决方案。
随着全球电子市场的不断扩大,CW Industries也积极拓展其国际业务。公司通过参加各种国际电子展会和交流活动,与全球各地的客户和合作伙伴建立了广泛的联系。这不仅为公司带来了更多的商机,还使得CW Industries能够及时了解国际市场的最新动态和技术趋势。通过这些国际交流活动,CW Industries不断提升其品牌影响力和市场竞争力。
面对电子信息行业的快速发展和变化,CW Industries始终保持着敏锐的市场洞察力。公司紧跟技术潮流,不断调整和优化产品结构,以满足客户不断变化的需求。例如,随着智能家居和物联网的兴起,CW Industries积极开发适用于这些新兴领域的产品和解决方案。这种灵活应变的能力使得CW Industries在电子行业中始终保持着领先地位,并为公司带来了持续的增长和发展。
随着公司规模的不断扩大,Altus开始实施全球化战略,积极拓展海外市场。公司通过与国际知名企业的合作,成功将产品打入国际市场,并建立了完善的销售网络和客户服务体系。同时,Altus还积极参与国际电子行业的交流和合作,不断吸收和引进国际先进技术和管理经验,提升了公司的整体竞争力。
Altus深知人才是企业发展的根本。因此,公司一直注重人才培养和引进工作。通过建立完善的培训体系和激励机制,Altus吸引了大量优秀人才加入公司,并为他们提供了广阔的发展空间和职业晋升机会。这些人才在公司的各个岗位上发挥着重要作用,推动了公司的技术创新和市场拓展。同时,Altus还注重员工的福利待遇和文化建设,营造了积极向上、团结和谐的工作氛围。
在发展过程中,爱普特微电子积极寻求与业界领先的供应商和合作伙伴建立稳固的合作关系。通过与这些合作伙伴的紧密合作,公司得以在技术研发、市场拓展等方面取得更大的突破。同时,公司也积极拓展海外市场,与多家国际知名企业建立了合作关系,进一步提升了公司的国际影响力。
请大家看下下面打问号几行代码,抛开其功能不说,真的是奇怪了,我都看了又看,头都大了,就是不知道为什么,请朋友们指点下 #include<reg52.h> &nbs ...… 查看全部问答∨ |
|
STM32的驱动库好用吗?效率高吗?优化的吗?准备上STM32 N多年没买过开发板了,也没用过仿真器了。都是用软件编译调试好,直接ISP,然后通过串口命令开启调试信息的输出。 昨天买了块STM32F103全功能型开发板,他们的办事效率真低(深圳到广州通常当 ...… 查看全部问答∨ |
求IAR Embedded Workbench for MCS-51 完整版 各位高手,小弟求IAR Embedded Workbench for MCS-51完整版,有哪位高人有,能否分享一下。我的邮箱jinghongchen@126.com… 查看全部问答∨ |
还是说说今天参加安富利的“ARM研讨会”,参观展台时,逛到了英蓓特(EMBEST)那里。大家可能知道,这家公司就是专门围绕ARM生存的,有很多ARM开发板。我在看到英蓓特展台的易拉宝时,楞了一下,原来上面罗列的产品线时,赫然有“Luminary系列”。 ...… 查看全部问答∨ |