单片机89C52行列式键盘扫描程序(汇编)
- 格式:docx
- 大小:877.47 KB
- 文档页数:4
STC89c52单片机计算器C语言程序STC89C52|/***************89C51单片机【计算器】C语言程序******************//**************** P2位选P0段选时钟12MHZ *********************/#include<reg52.h> /*包含的头文件*/#define uchar unsigned char /* 宏定义*/#define uint unsigned intuchar Led[17] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f,0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x00}; /* 数码管段选*/long float Number[]={0,0,0,0}; /* 数码管显示位控制寄存器*/uchar A[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};long int D[] = {0,0,0,0,0,0,0,0}; //数码管显示内容寄存器uchar code C[] = {0x0, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}; /* 数码管位选*//* 列扫描控制LED 1位2位3位4位5位6位7位8位*/uchar k=16; /* 按键对外控制*/uchar b; /* 按键【+】【-】【*】【/】对外的控制*/long float Out_put; /* 定义变量【Out_put】作为结果*/uchar e=0; /* 数字的位存储递进的控制*/uchar g=0; /* 运算方式的控制变量*/uchar L=0; /* 运算方式的控制变量*/uchar g1=0; /* 运算方式的控制变量*/uchar g2=0; /* 运算方式的控制变量*/uchar g3=0; /* 运算方式的控制变量*/uchar g4=0; /* 运算方式的控制变量*/char j=-1; /* 与Number[]数组连用*/uchar m=0; /* 按键【=】的控制变量*/uchar n=0; /* 按键【.】的控制变量*/uchar x=0; /* 小数点个数的记录变量*/uchar xo=0; /* 控制开始计数小数点的变量*/long int result;void Delay(uint o) /* 延时函数delay() 的定义*/{uint i,j;for(i = 0; i < o; i++){for(j = 0; j < 121; j++) {;}}}void show(long float Out_put){ uchar r;uchar k;long int q,p;uchar s=0;uchar i;long int temp;temp=Out_put ;if( (Out_put-temp)!=0) {result=Out_put*10000; r=4;}else { result=Out_put; r=0; }p=result;if(m==1){if(result<0){ result=-result; p=result; q=result; for(i=1;i<=8;i++) { q=q/10; if(q==0) {k=i;i=9; } } P0=0x40; P2=C[8-k];Delay(1); } //负号的显示P0=0x80; P2=C[r]; Delay(1); P0=0x00;result=p;P0=Led[result%10]; P2=C[8]; result=result/10; Delay(1);if( (result%10==0)&&(result%100==0)&&(result%1000==0)&&(result%10000==0)&&(r esult%100000==0)&&(result%1000000==0) ) {P0=0x00;}else {P0=Led[result%10]; P2=C[7]; result=result/10; Delay(1);}if( (result%10==0)&&(result%100==0)&&(result%1000==0)&&(result%10000==0)&&(result%100000==0) ) {P0=0x00;}else {P0=Led[result%10]; P2=C[6]; result=result/10; Delay(1);}if( (result%10==0)&&(result%100==0)&&(result%1000==0)&&(result%10000==0) ) {P0=0x00;}else {P0=Led[result%10]; P2=C[5]; result=result/10; Delay(1);}if( (result%10==0)&&(result%100==0)&&(result%1000==0) ) {P0=0x00;}else {P0=Led[result%10]; P2=C[4]; result=result/10; Delay(1);}if( (result%10==0)&&(result%100==0) ) {P0=0x00;}else {P0=Led[result%10]; P2=C[3]; result=result/10; Delay(1);}if( (result%10==0) ) {P0=0x00;}else {P0=Led[result%10]; P2=C[2]; result=result/10; Delay(1);}if(result==0) {P0=0x00;}else {P0=Led[result%10]; P2=C[1]; result=result/10; Delay(1);}}}void In_put() // 输入函数输入小数加小数点{uchar i;if(k>=0&&k<=9)switch(e){case 8: D[7]=D[6];A[7]=A[6]; //用来存放数值case 7: D[6]=D[5];A[6]=A[5];case 6: D[5]=D[4];A[5]=A[4];case 5: D[4]=D[3];A[4]=A[3];case 4: D[3]=D[2];A[3]=A[2];case 3: D[2]=D[1];A[2]=A[1];case 2: D[1]=D[0];A[1]=A[0];case 1: if(n==0) { D[0]=k; A[0]=Led[k]; if(xo==1) x++; }if(n==1) { A[0]=Led[k]|0x80; xo=1; n=0;}}if(k>=11&&k<=15&&b==1){ switch(k){case 11: g1++;g++;if(g2==1) L=1; if(g3==1) L=2; if(g4==1) L=3;break; // +case 12: g2++;g++;if(g1==1) L=4; if(g3==1) L=5; if(g4==1) L=6;break; // -case 13: g3++;g++;if(g1==1) L=7; if(g2==1) L=8; if(g4==1) L=9;break; // *case 14: g4++;g++;if(g1==1) L=10;if(g2==1) L=11;if(g3==1) L=12;break; // /}j++;Number[j]=10000000*D[7]+1000000*D[6]+100000*D[5]+10000*D[4]+1000*D[3]+100*D [2]+10*D[1]+D[0];for(i=1;i<=x;i++) {Number[j]=(float)Number[j]/10;}x=0;for(i=0;i<=7;i++) // 数据存储器清零D[i]=0;for(i=0;i<=8;i++) // 数据显示清零{A[i]=0x00;}b=0;e=0;xo=0;}}void Key_scan() // 键盘扫描函数Key_scan(){unsigned char X,Y,Z;P3 = 0xff;P3 = 0x0f; //先对P2置数行扫描if(P3!=0x0f) //判断是否有键按下{Delay(20); //延时10ms,软件去干扰if(P3!=0x0f) //确认按键按下;{X=P3; //保存行扫描时有键按下时状态P3=0xf0; //列扫描Y=P3; //保存列扫描时有键按下时状态Z=X|Y; //取出键值while(P3!=0xf0); // 按键防止抖动switch ( Z ) //判断键值(那一个键按下){case 0xe7: k=0; e++; In_put(); break; //数字【0】case 0xd7: k=1; e++; In_put(); break; //数字【1】case 0xdb: k=2; e++; In_put(); break; //数字【2】case 0xdd: k=3; e++; In_put(); break; //数字【3】case 0xb7: k=4; e++; In_put(); break; //数字【4】case 0xbb: k=5; e++; In_put(); break; //数字【5】case 0xbd: k=6; e++; In_put(); break; //数字【6】case 0x77: k=7; e++; In_put(); break; //数字【7】case 0x7b: k=8; e++; In_put(); break; //数字【8】case 0x7d: k=9; e++; In_put(); break; //数字【9】case 0xeb: n=1; In_put(); break; //小数点【 .】case 0x7e: k=11;b=1; In_put(); break; //字符【B +】case 0xbe: k=12;b=1; In_put(); break; //字符【C -】case 0xde: k=13;b=1; In_put(); break; //字符【D *】case 0xee: k=14;b=1; In_put(); break; //字符【E /】case 0xed: k=15;m=1;b=1;In_put();break; //字符【F =】}}}}void Yun_suan(){if(g1==1&&g==1) Out_put=Number[0]+Number[1];if(g2==1&&g==1) Out_put=Number[0]-Number[1];if(g3==1&&g==1) Out_put=Number[0]*Number[1];if(g4==1&&g==1) Out_put=Number[0]/Number[1];if(g1==2&&g==2) Out_put=Number[0]+Number[1]+Number[2]; if(g2==2&&g==2) Out_put=Number[0]-Number[1]-Number[2]; if(g3==2&&g==2) Out_put=Number[0]*Number[1]*Number[2]; if(g4==2&&g==2) Out_put=Number[0]/Number[1]/Number[2];if(L==1) Out_put=Number[0]-Number[1]+Number[2];if(L==2) Out_put=Number[0]*Number[1]+Number[2];if(L==3) Out_put=Number[0]/Number[1]+Number[2];if(L==4) Out_put=Number[0]+Number[1]-Number[2];if(L==5) Out_put=Number[0]*Number[1]-Number[2];if(L==6) Out_put=Number[0]/Number[1]-Number[2]; if(L==7) Out_put=Number[0]+Number[1]*Number[2]; if(L==8) Out_put=Number[0]-Number[1]*Number[2]; if(L==9) Out_put=Number[0]/Number[1]*Number[2]; if(L==10) Out_put=Number[0]+Number[1]/Number[2]; if(L==11) Out_put=Number[0]-Number[1]/Number[2]; if(L==12) Out_put=Number[0]*Number[1]/Number[2]; }void Xian_shi(){if(m!=1){Key_scan();/* 显示函数与A[i]有关*/P0=A[0]; P2=C[8];Delay(1);P0=A[1]; P2=C[7];Delay(1);P0=A[2]; P2=C[6];Delay(1);P0=A[3]; P2=C[5];Delay(1);P0=A[4]; P2=C[4];Delay(1);P0=A[5]; P2=C[3];Delay(1);P0=A[6]; P2=C[2];Delay(1);P0=A[7]; P2=C[1];Delay(1);}}void main(){while(1){Xian_shi();Yun_suan();show( Out_put );}}//。
实验4 键盘实验一、实验目的:1.掌握8255A编程原理。
2.了解键盘电路的工作原理。
3.掌握键盘接口电路的编程方法。
二、实验设备:CPU挂箱、8031CPU模块三、实验原理:1.识别键的闭合,通常采用行扫描法和行反转法。
行扫描法是使键盘上某一行线为低电平,而其余行接高电平,然后读取列值,如所读列值中某位为低电平,表明有键按下,否则扫描下一行,直到扫完所有行。
本实验例程采用的是行反转法。
行反转法识别键闭合时,要将行线接一并行口,先让它工作于输出方式,将列线也接到一个并行口,先让它工作于输入方式,程序使CPU通过输出端口往各行线上全部送低电平,然后读入列线值,如此时有某键被按下,则必定会使某一列线值为0。
然后,程序对两个并行端口进行方式设置,使行线工作于输入方式,列线工作于输出方式,并将刚才读得的列线值从列线所接的并行端口输出,再读取行线上的输入值,那么,在闭合键所在的行线上的值必定为0。
这样,当一个键被按下时,必定可以读得一对唯一的行线值和列线值。
2.程序设计时,要学会灵活地对8255A的各端口进行方式设置。
3.程序设计时,可将各键对应的键值(行线值、列线值)放在一个表中,将要显示的0~F字符放在另一个表中,通过查表来确定按下的是哪一个键并正确显示出来。
实验题目利用实验箱上的8255A可编程并行接口芯片和矩阵键盘,编写程序,做到在键盘上每按一个数字键(0~F),用发光二极管将该代码显示出来。
四、实验步骤:将键盘RL10~RL17接8255A的PB0~PB7;KA10~KA12接8255A的PA0~PA2;PC0~PC7接发光二极管的L1~L8;8255A芯片的片选信号8255CS接CS0。
五、实验电路:六、程序框图7.程序清单八、附:8251/8255扩展模块该模块由8251可编程串行口电路和8255可编程并行口电路两部分组成,其电源、数据总线、地址总线和片选信号均由接口挂箱上的接口插座提供。
一、8251可编程串行口电路(1)8251可编程串行接口芯片引脚及功能8251A是通用同步/异步收发器USART,适合作异步起止式数据格式和同步面向字符数据格式的接口,其功能很强。
键盘是单片机常用输入设备,在按键数量较多时,为了节省I/O口等单片机资源,一般采取扫描的方式来识别到底是哪一个键被按下。
即通过确定被按下的键处在哪一行哪一列来确定该键的位置,获取键值以启动相应的功能程序。
矩阵键盘的四列依次接到单片机的P1.0~P1.3,四行依次接到单片机的P1.4~P1.7;同时,将列线上拉,通过10K电阻接电源。
查找哪个按键被按下的方法为:一个一个地查找。
先第一行输出0,检查列线是否非全高;否则第二行输出0,检查列线是否非全高;否则第三行输出0,检查列线是否非全高;如果某行输出0时,查到列线非全高,则该行有按键按下;根据第几行线输出0与第几列线读入为0,即可判断在具体什么位置的按键按下。
下面是具体程序:void Check_Key(void){unsigned char row,col,tmp1,tmp2;tmp1 = 0x10;//tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f)// 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00)// 该列如果为低电平则可以判定为该列{key_val =key_Map[ row*4 +col ];// 获取键值,识别按键;key_Map为按键的定义表return; // 退出循环}tmp2*=2; // tmp2左移一位}}}} //结束。
单⽚机AT89C522总体⽅案设计2.1⽅案⽐较⽅案⼀设计的太阳能热⽔器控制系统以89C52单⽚机为检测控制中⼼单元,采⽤DSl2887实时时钟,不仅实现了时间、温度和⽔位三种参数实时显⽰功能,⽽且具有时间设定、温度设定与控制功能。
控制系统可以根据天⽓情况利⽤辅助加热装置(电加热器)使蓄⽔箱内的⽔温达到预先设定的温度,从⽽达到24⼩时供应热⽔的⽬的。
实际应⽤结果表明,该控制器和以往显⽰仪相⽐具有性价⽐⾼、温度控制与显⽰精度⾼、使⽤⽅便和性能稳定等优点。
AT89C52图2-1 系统硬件结构图⽅案⼆采⽤系统的温度采集选⽤PTl000铂电阻温度传感器,采集到的电压信号经集成运放LM324放⼤到2.O⼀5.0伏之间,送⼊串⾏加转换器11LCl543N,转换结果由单⽚机处理,其电路原理如图3所⽰.设计时将加转换器的参考电压设置为vREF+=5.0V,VREF=1.5V.LM324按照同相⽐例放⼤电路连接,则Vo=vi*(Rt/R+1)=0.5*(Rt/300+1).Rt 值的变化表⽰了PtlooO温度传感器温度的变化,每个温度值对应⼀定的转换结果。
可以在程序中建⽴⼀个查找表,表中每个元素的地址即为转换结果,元素值即为所对应的温度值。
图2-2 系统硬件结构图12.2⽅案选择⽅案⼀硬件电路简单,程序设计复杂⼀些,但是我已经使⽤开发⼯具KEIL⽤汇编语⾔对系统进⾏了程序设计,⽤仿真软件PROTEUS对系统进⾏了仿真,达到了预期的结果。
由此可见,该⽅案完成具有可⾏性,体现了技术的先进性,经济上也没有问题。
根据设计的要求,以及设计的便捷性,综上所述,本课题采⽤⽅案⼀对系统进⾏设计。
3.单元模块设计3.1各单元模块功能介绍及电路设计3.1.1单⽚机系统设计单⽚机系统由AT89C52和⼀定功能的外围电路组成,包括为单⽚机提供复位电压的复位电路,提供系统频率的晶振。
这部分电路主要负责程序的存储和运⾏。
上图中MCS-51内部时钟⽅式电路外接晶体以及电容C5和C6构成并联谐振电路,接在放⼤器的反馈回路中。
University of South China单片机课程设计总结报告设计题目:单片机最小系统及外围电路设计班级:学院: 机械工程学号:姓名:指导教师:袁锋伟蒋彦王玉林摘要【摘要】本次课程设计主要是关于单片机简易开发板的设计。
实现8位流水灯控制,按键扫描双位数码管显示。
本次设计主要采用89C52单片机芯片制作而成,包括流水灯电路,按键扫描电路,数码管显示电路,ISP及USB供电部分,单片机P1口控制数码管,P0口控制八位流水灯,P2控制扫描键盘,通过读写口进行ISP下载。
【关键词】流水灯、按键扫描、数码管显示、ISP下载目录1. 课程设计的目标与设计任务 ..........................1.1设计的任务...............................................2、硬件电路设计方案及功能分析...................2.1 原理图.................................................2.2 单元电路设计及分析.....................................2.2.189C52芯片简介....................................2.2.2 下载线电路........................................2.2.3 最小外围电路......................................3、程序的设计...................................3.1开发软件及编程语言简介...................................3.2软件程序的编写及调试.....................................4、电路板的制作.................................5、电路板的焊接与调试 ..........................6、课程设计总结.................................7、参考文献..................................... 附录1主要电子元件清单..........................1. 课程设计的设计任务1.1 设计任务图1 系统设计要求方框图根据题目要求,系统可以划分为最小外围电路,指示灯及流水电路,按键扫描,数码管显示电路,及ISP下载模块。
stc89c52单片机下的矩阵键盘程序
stc89c52单片机就是51 52 系列单片机,就和AT89C52 差不多,没有什么大的区别,可以直接替换,只是内部多了一个EEPROM 空间,可以串口下载程序,指令执行速度快一倍。
STC89C52是一种带8K字节闪烁可编程可檫除只读存储器(FPEROM-Flash Programable and Erasable Read Only Memory )的低电压,高性能COMOS8的微处理器,俗称单片机。
该器件采用ATMEL搞密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。
下面是一个stc89c52单片机下的矩阵键盘程序,P0口接键盘,显示在P2口。
#include
#define uchar unsigned char
#define uint unsigned int
sbit key1=P3 ;
sbit key2=P3 ;
uchar code tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; //定义八个灯的工作状态。
uchar code wep[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
void yanshi(uint t)
{
while(--t);
}
void main()
{
uchar han,lei,key;
while(1)
{。
目录1绪论 (1)1.1本设计的研究背景与研究目的 (1)1.2国内外研究现状 (2)2电子密码锁的总体设计方案 (3)2.1方案论证 (3)2.1.1方案一采用单片机控制方案 (3)2.1.2方案二采用数字电路控制方案 (4)2.1.3方案三采用EDA控制方案 (5)2.2方案比较以及可行性 (5)3电子密码锁硬件电路的设计 (6)3.1中央控制模块的设计 (6)3.1.1主控芯片STC89C52单片机的简介 (6)3.1.2时钟电路的设计 (7)3.1.3复位电路的设计 (8)3.2键盘输入模块的设计 (9)3.2.1矩阵键盘工作原理 (9)3.2.2单片机键盘扫描法 (10)3.3LCD显示密码模块的设计 (10)3.3.1LCD1602简介 (11)3.3.2LCD1602液晶显示模块与单片机连接电路 (12)3.4开锁模块的设计 (13)3.5报警模块的设计 (13)3.6硬件电路总体设计 (14)4电子密码锁的软件设计 (15)4.1主程序流程介绍 (15)4.2键盘模块流程图 (16)4.3显示模块流程图 (18)4.4修改密码流程图 (19)4.5开锁和报警模块流程图 (20)5电子密码锁的系统调试及分析 (22)5.1硬件电路调试及结果分析 (22)5.2软件调试及功能分析 (22)5.2.1调试过程 (22)5.2.2仿真结果分析 (24)5.3系统调试 (26)6结论及展望 (28)6.1结论 (28)6.2展望 (28)谢辞 (29)参考文献 (30)附录 (32)附1部分代码 (32)附2总电路图 (40)电子密码锁的设计与制作1绪论1.1本设计的研究背景与研究目的随着人们生活水平的提高和社会科技的进步,锁已发展到了密码锁、磁性锁、电子锁、激光锁、声控锁等等。
在传统钥匙的基础上,加了一组或多组密码,不同声音,不同磁场,不同声波,不同光束光波,不同图像。
(如指纹、眼底视网膜等)来控制锁的开启。
实验八键盘扫描显示实验所需软硬件:KeilSTC-ISPMCS-51 89C52实验箱程序清单:基于汇编语言//连线P0接8列(同时也是数码管的位选线)高电平选中某位。
P3低两位接行P1接数码管(段选线)低电平选中某段亮。
ORG 0000HLJMP MAINMAIN:MOV 30H,#00HMOV 31H,#00HMOV 32H,#00HMOV 33H,#00HMOV 34H,#00HMOV 35H,#00HBEGIN:ACALL SCANACALL CHECKACALL DISPSJMP BEGIN//子程序SCAN 全扫描2次扫描去抖SCAN: ;全扫描MOV R0,#00H ;去抖,扫描2次计数标志MOV A,#00HMOV P0,A ;送列扫描码LOOP:MOV A,P3 ;回读行信号ANL A,#03H ;只取低两位INC R0CJNE A,#03H,K1CLR F0 ;无键,置标志位为0K1:NOPNOPCJNE R0,#02H,LOOP;去抖,扫描2次SETB F0 ;有键,置标志位为1RET//子程序CHECK 逐列扫描确定键码CHECK:MOV R1,#0FEH ;开始逐列扫描,从第0列开始MOV R4,#00H ;记录列号MOV R5,#00H ;记录行号MOV A,R1PUSH ACC ;压栈保留第0列扫描码LOOP1:MOV P0,A ;送列扫描码MOV A,P3ANL A,#03HCJNE A,#03H,K2 ;有键转K2确定为哪一行POP ACC ;无键扫描下一列RL AINC R4CJNE R4,#08H,LOOP1 ; 是否扫描进行到最后一列RETK2:DEC SP ;为保证堆栈平衡CJNE A,#02H,K3 ;分支判断,看是否为第一行SJMP OVERK3:INC R5 ;不是第一行,就是第二行,行码加1 OVER:MOV A,R4ADD A,R5 ;行码+列码=键码PUSH ACC ;键码入栈保护NOPNOPLCALL SCAN ;扫描看手是否松开CJNE A,#03H,OVER ;A=03H,表示手未松开,继续扫描POP ACC ;手松开,键码出栈RET//子程序DISP 键码分离送数码管显示DISP:JNB F0,LOOP3 ;无键不分离键码MOV B,#10 ;有键,要进行十位和个位的分离DIV ABMOV 34H,A ;A为十位MOV 35H,B ;B为个位MOV R0,#30H ;送显示缓冲首地址MOV R2,#01H ;送位选信号,从最低位开始亮LOOP3:MOV A,#0FFHMOV P1,A ;段选:送灭码MOV A,R2MOV P0,A ;送位选信号MOV A,@R0 ;送显示缓冲数据MOV DPTR,#TAB ;查表求字形码MOVC A,@A+DPTRMOV P0,A ;送段选ACALL DELAY1MS ;延时以保持稳定INC R0 ;取下一个数MOV A,R2JB ACC.5,EXIT ;判断位选是否送到最高位RL A ;左移选下一个位。
实验八键盘扫描显示实验
所需软硬件:
Keil
STC-ISP
MCS-51 89C52实验箱
程序清单:
基于汇编语言
//连线P0接8列(同时也是数码管的位选线)高电平选中某位。
P3低两位接行P1接数码管(段选线)低电平选中某段亮。
ORG 0000H
LJMP MAIN
MAIN:
MOV 30H,#00H
MOV 31H,#00H
MOV 32H,#00H
MOV 33H,#00H
MOV 34H,#00H
MOV 35H,#00H
BEGIN:
ACALL SCAN
ACALL CHECK
ACALL DISP
SJMP BEGIN
//子程序SCAN 全扫描2次扫描去抖
SCAN:;全扫描
MOV R0,#00H;去抖,扫描2次计数标志
MOV A,#00H
MOV P0,A;送列扫描码
LOOP:
MOV A,P3;回读行信号
ANL A,#03H;只取低两位
INC R0
CJNE A,#03H,K1
CLR F0;无键,置标志位为0
K1:
NOP
NOP
CJNE R0,#02H,LOOP;去抖,扫描2次
SETB F0;有键,置标志位为1
RET
//子程序CHECK 逐列扫描确定键码
CHECK:
MOV R1,#0FEH ;开始逐列扫描,从第0列开始
MOV R4,#00H;记录列号
MOV R5,#00H;记录行号
MOV A,R1
PUSH ACC;压栈保留第0列扫描码
LOOP1:
MOV P0,A;送列扫描码
MOV A,P3
ANL A,#03H
CJNE A,#03H,K2;有键转K2确定为哪一行
POP ACC;无键扫描下一列
RL A
INC R4
CJNE R4,#08H,LOOP1 ; 是否扫描进行到最后一列
RET
K2:
DEC SP;为保证堆栈平衡
CJNE A,#00H,K3;分支判断,看是否为第一行
SJMP OVER
K3:
MOV A, R5
ADD A,#08H
MOV R5,A;不是第一行,就是第二行,行码加8 OVER:
MOV A,R4
ADD A,R5;行码+列码=键码
PUSH ACC;键码入栈保护
NOP
NOP
LCALL SCAN;扫描看手是否松开
CJNE A,#03H,OVER ;A=03H,表示手未松开,继续扫描
POP ACC;手松开,键码出栈
RET
//子程序DISP 键码分离送数码管显示
DISP:
JNB F0,LOOP3;无键不分离键码
MOV B,#10;有键,要进行十位和个位的分离
DIV AB
MOV 34H,A;A为十位
MOV 35H,B;B为个位
MOV R0,#30H;送显示缓冲首地址
MOV R2,#01H;送位选信号,从最低位开始亮
LOOP3:
MOV A,#0FFH
MOV P1,A;段选:送灭码
MOV A,R2
MOV P0,A;送位选信号
MOV A,@R0;送显示缓冲数据
MOV DPTR,#TAB;查表求字形码
MOVC A,@A+DPTR
MOV P0,A;送段选
ACALL DELAY1MS;延时以保持稳定
INC R0;取下一个数
MOV A,R2
JB ACC.5,EXIT;判断位选是否送到最高位
RL A ;左移选下一个位。
MOV R2,A;
AJMP LOOP3
EXIT:
RET
//子程序DELAY1MS
DELAY1MS:
MOV R7,#0FFH
DJNZ R7,$
RET
TAB:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,88H,83H,0C6H,0AH,86H,8EH END。