历史上的今天
返回首页

历史上的今天

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

正在发生

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

2021-11-12 来源:eefocus

一、使用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();

}

}


三、仿真实现

推荐阅读

史海拾趣

远东福斯特公司的发展小趣事

对于光检测T型反馈电路,网友可能提出多方面的问题,以下是一些可能的问题及相应的回答:

一、电路结构与原理

问题1:光检测T型反馈电路的基本结构是怎样的?

回答:光检测T型反馈电路通常由光电探测器(如光电二极管、光电三极管等)、运算放大器、T型反馈网络及相关的电阻、电容等元件组成。光电探测器负责将光信号转换为电信号,运算放大器对电信号进行放大,而T型反馈网络则用于调整放大电路的增益和稳定性。

问题2:T型反馈电路相比传统反馈电路有哪些优势?

回答:T型反馈电路的主要优势在于其能够使用较小的电阻组合来实现较大的放大倍数,从而避免了使用高阻值电阻带来的实装困难和稳定性问题。此外,T型反馈电路还能有效减少温度漂移引起的静态误差,提高电路的整体性能。

二、电路设计与调试

问题3:在设计光检测T型反馈电路时,如何选择合适的电阻值?

回答:在设计电路时,电阻值的选择应基于所需的放大倍数、稳定性及功耗等因素。通常,R1和R11的阻值应相等或相近,而R12和R13的阻值则根据所需的增益进行调整。此外,还应注意选择稳定性高的电阻,以减少温度漂移对电路性能的影响。

问题4:如何进行光检测T型反馈电路的调试?

回答:电路调试时,首先应检查各元件的连接是否正确,然后逐步加电观察电路的工作状态。在调试过程中,可使用可调电阻对电路的增益进行微调,以达到预期的放大效果。同时,还应注意观察电路的稳定性和噪声水平,确保电路满足设计要求。

三、应用与性能

问题5:光检测T型反馈电路在哪些领域有应用?

回答:光检测T型反馈电路在光电检测、信号处理、通信技术等领域有着广泛的应用。例如,在光电传感系统中,它可用于将微弱的光信号转换为放大的电信号;在信号处理电路中,它可用于提高信号的信噪比和动态范围;在通信系统中,它可用于增强信号的传输距离和稳定性。

问题6:如何评估光检测T型反馈电路的性能?

回答:评估光检测T型反馈电路的性能时,应关注其增益、稳定性、噪声水平、带宽等关键指标。增益是指电路对输入信号的放大能力;稳定性则是指电路在不同工作环境下的工作可靠性;噪声水平则反映了电路内部噪声对信号质量的影响;带宽则决定了电路能够处理信号的频率范围。这些指标的综合表现将直接影响电路在实际应用中的效果。

ebm-papst公司的发展小趣事

在巩固欧洲市场的基础上,ebm-papst不断拓展全球市场,特别是亚洲市场。近年来,公司在亚洲市场的营收增长率一直保持在较高水平。为了进一步拓展亚洲市场,ebm-papst加大了在中国的产能建设,陆续在上海、西安等地进行扩建和新建产能。这些措施使得ebm-papst能够更好地满足亚洲市场的需求,并为其在全球市场的进一步发展奠定了坚实基础。

Amveco Toroidal Power Products公司的发展小趣事

Amveco Toroidal Power Products公司成立于XXXX年,初始阶段主要专注于环形变压器的研发与生产。创始人凭借对环形变压器技术的深入了解和市场需求的敏锐洞察,带领团队克服了初创期的种种困难,成功开发出了具有高效能、低噪音特点的环形变压器产品,并赢得了客户的初步认可。随着市场口碑的逐渐积累,公司的业务规模开始稳步扩大。

BERNSTEIN公司的发展小趣事

在公司的快速发展中,BERNSTEIN公司逐渐将目光投向了国际市场。通过与国际知名企业的合作与交流,公司不断引进先进的技术和管理经验,提升了自身的竞争力。同时,BERNSTEIN公司的产品也逐渐在国际市场上赢得了广泛的认可和好评,为公司的发展注入了新的动力。

ADTech公司的发展小趣事

AdTech公司一直注重创新,不断投入研发资源以推出新产品和解决方案。公司通过优化芯片结构设计、提升器件封装技术等手段,不断提升QCL的性能和稳定性。此外,公司还积极探索QCL在新能源、环保等领域的应用潜力,开发出了一系列具有创新性和实用性的产品。这些创新成果不仅提升了公司的核心竞争力,也为行业的发展注入了新的活力。

BOPLA公司的发展小趣事

BOPLA公司成立于XXXX年,初期主要致力于电子开关、熔断器等基础电子元件的研发与生产。创始人凭借对电子行业的深厚理解和敏锐的市场洞察力,带领公司逐步在竞争激烈的市场中站稳脚跟。通过不断的技术创新和品质提升,BOPLA的产品逐渐获得了客户的认可,为公司后续的发展奠定了坚实的基础。

问答坊 | AI 解惑

SMD802做成的日光灯驱动板装进铝壳,电流下降原因

方案及问题:SMD802 非隔离式做成的T8日光灯非隔离方案 装进日光灯铝壳容易引起电流下降; 多次实验 查明原因是由于其中的电感采用的是开放式的; 那样磁场容易被铝壳吸收;引起能量部分消失; 是否属实? 欢迎回帖讨论。…

查看全部问答>

关于阳初2440的VGA的一个疑问,谢谢答疑(头像终于改过来了)

请教下研究过阳初2440开发板驱动的高手们,阳初BSP里CH7004芯片的驱动是在DISPLAY里面吗?我看了电路图该芯片是通过I2C和2400连接的但是DISPLAY里找不到任何I2C的东西,也没有找到任何CH7004的初始化配置方面的信息,谢谢指导下!…

查看全部问答>

STR912定时器问题~~请大侠帮我看一下

void SCU_Configuration(void){  GPIO_InitTypeDef  GPIO_InitStructure;  TIM_InitTypeDef   TIM_InitStructure;  UART_InitTypeDef UART_InitStructure;  /*&n ...…

查看全部问答>

DSP系统的设计过程

DSP系统的设计还没有非常好的正规设计方法。   在设计DSP系统之前,首先必须根据应用系统的目标确定系统的性能指标、信号处理 的要求,通常可用数据流程图、数学运算序列、正式的符号或自然语言来描述。第二步是根据系统的要求进行高级语言的模 ...…

查看全部问答>

使用PLCXpresso快速定位

使用PLCXpresso时,怎么快速定位到函数?????????     少了个X。。。 [ 本帖最后由 zhaojun_xf 于 2012-4-25 20:27 编辑 ]…

查看全部问答>

SYSBIOS On-line Training视频教程+PPT

下载地址:https://download.eeworld.com.cn/detail/qinkaiabc/9158 [ 本帖最后由 qinkaiabc 于 2013-3-20 12:56 编辑 ]…

查看全部问答>

哥哥姐姐们,上班时间别用QQ找我交流技术行吗?

每天都是如此 [img]file:///C:\\DOCUME~1\\ADMINI~1\\LOCALS~1\\Temp\\{H$]5UNO{S70ZEF2HL7[CF0.png[/img]交谈中请勿轻信汇款、中奖信息、陌生电话,勿使用外挂软件。 行者无疆  21:31:10 您好,我想请假您一个问题 可以吗? 行者无 ...…

查看全部问答>

【推荐下载】开关电源基础知识 课程精华笔记下载

开关电源基础知识 课程精华笔记下载 开关电源基础知识(PWM与PFM)开关电源基础知识(隔离与非隔离式)开关电源基础知识(同步与非同步)开关电源基础知识(效率与VOUT关系)开关电源基础知识(开关电源的类型)欢迎大家点击下载 …

查看全部问答>

台式机电源12V输出功率

手头有个台式机的电源,想用上面的12V供电,不知道功率大约是多少?哪位知道的介绍一下。…

查看全部问答>