一、使用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组合按键去抖动延时计数器*/ucKeyLock_01_16 = 0; /*S1和S16组合按键触发后自锁的变量标志*/}if((uiKeyStatus & 0x1008) == 0x0000)   /*S4和S13的组合键盘被按下。*/{if(ucKeyLock_04_13 == 0){uiKeyTimeCnt_04_13 ++;if(uiKeyTimeCnt_04_13 > const_key_time_comb){uiKeyTimeCnt_04_13 = 0;ucKeyLock_04_13 = 1;ucKeySec = 18;}}}  else{uiKeyTimeCnt_04_13 = 0; /*S4和S13组合按键去抖动延时计数器*/ucKeyLock_04_13 = 0; /*S4和S13组合按键触发后自锁的变量标志*/}uiKeyStatus = 0xffff;   /*及时恢复状态,方便下一次扫描*/ucKeyStep = 1;    /*返回到第一个运行步骤重新开始扫描*/break;      }
}
/**
* @brief  按键服务函数
* @param  无
* @retval 根据扫描得到的值,进行数据处理
**/
void key_Service(void)
{switch(ucKeySec){case 1: /*1号键*/case 2: /*2号键*/case 3: /*3号键*/case 4: /*4号键*/case 5: /*5号键*/case 6: /*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;case 17:LED = 1;uiVoiceCnt = const_voice_short;ucKeySec = 0;break;case 18:LED = 0;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<uiDelayLong;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单片机实现矩阵键盘的组合按键触发相关推荐

  1. 跟着吴坚鸿学单片机——第16天:矩阵键盘的组合按键触发

    原文链接:第十六节:矩阵键盘的组合按键触发. 文章目录 原文 读后感 自我练习 原文 第十六节:矩阵键盘的组合按键触发. 开场白: 上一节讲了矩阵键盘单个触发的压缩代码编程.这节讲矩阵键盘的组合按键触 ...

  2. 单片机学习笔记————51单片机实现用LED灯和按键来模拟工业自动化设备的运动控制

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  3. 单片机学习笔记————51单片机实现带数码管显示的象棋比赛专用计时器

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  4. 单片机学习笔记————51单片机实现数码管中的倒计时程序

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  5. 单片机学习笔记————51单片机实现带数码管显示的加法简易计算器

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  6. 单片机学习笔记————51单片机实现在数码管中实现iphone4S开机密码锁的程序

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  7. 单片机学习笔记————51单片机实现主机的串口收发

    proteus虚拟串口的实现:https://mp.csdn.net/console/editor/html/107251649 一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 / ...

  8. 单片机学习笔记————51单片机实现按住一个独立按键不松手的加速匀速触发

    一.使用proteus绘制简单的电路图,用于后续仿真 二.编写程序 /***************************************************************** ...

  9. C51汇编语言寻址方式,单片机学习:51单片机寻址方式详解

    原标题:单片机学习:51单片机寻址方式详解 51单片机是对所有兼容Intel 8031指令系统的单片机的统称.该系列单片机的始祖是Intel 8031单片机,后来随着Flash rom 技术的发展,8 ...

最新文章

  1. VPS批量管理软件--远程桌面批量管理
  2. [转]Excel导入异常Cannot get a text value from a numeric cell解决
  3. python token post403原因_Django的POST请求时因为开启防止csrf,报403错误,及四种解决方法...
  4. 高通宣布与华为达成新专利授权协议,华为砸下18亿美元
  5. mongodb聚合查询-aggregate
  6. java对象数组排序的一种方式
  7. DOM疑惑点整理(三)
  8. 12月中旬计算机会议,2019年12月泰国曼谷--深度学习与计算机视觉国际会议(DLCV 2019)...
  9. Arduino与Proteus仿真实例-AD5242数字电位器驱动仿真
  10. 预测算法用java实现
  11. C语言 冒泡排序 程序流程图,C语言冒泡排序及流程图(思路解析)
  12. vmware 7.0 序列号_更改solidworks序列号及修改安装
  13. 统计小写英文字母的个数 c语言,输入一行字符,统计英文字母,空格,和其他字符的个数...
  14. 双线服务器托管的三大优势
  15. draco3D轻量化技术在Unity3D中应用
  16. 硬件信息查看PHP,如何查看电脑硬件信息|查看电脑硬件信息软件 查看电脑CPU/显卡/内存条/主板型号等配置...
  17. android studio 使用lint工具优化app时全过程记录
  18. 一些关于SLG手游的想法
  19. 【特征工程】词袋模型/TF-IDF模型/词汇表模型的代码实现(文本特征提取)
  20. markdown(Latex)连乘符号

热门文章

  1. #10. 三角形的个数
  2. 怎么删除supervisor_supervisord进程管理工具
  3. IP数据包经由路由转发的时候,源ip和目的IP是否改变
  4. mysql中编写匿名块_Oracle_PL/SQL(1) 匿名块
  5. u-boot 启动代码start.S详解(for mini2440)
  6. 为什么奶块进不去显示连接服务器,奶块怎么进别的服务器 | 手游网游页游攻略大全...
  7. 2018/10/02
  8. C语言如何输入输出一个字符串
  9. 2022数学建模c题思路解析
  10. 宝宝为什么会出现乳糖不耐受?