单片机原理与应用第2版源代码10.docx
《单片机原理与应用第2版源代码10.docx》由会员分享,可在线阅读,更多相关《单片机原理与应用第2版源代码10.docx(25页珍藏版)》请在冰豆网上搜索。
单片机原理与应用第2版源代码10
中断法查键处理程序设计如下:
ORG0000
LJMPMAIN
ORG0013H
LJMPKPINT1
MAIN:
MOVSP,#6FH
SETBIT1;选择边沿触发方式
SETBEX1
SETBEA
…
SJMP$
KPINT1:
PUSHPSW;中断服务子程序入口
PUSHACC
MOVA,P1
CPLA
JZEXIT;(A)=0,退出转EXIT
LCALLDEL10MS
MOVA,P1
CPLA
JZEXIT;(A)=0,退出转EXIT
KEY1:
CJNEA,#01H,KEY2
LJMPKEYK1;是K1键,转入K1键处理子程序KEYK1
KEY2:
CJNEA,#02H,KEY3
LJMPKEYK2;是K2键,转入K2键处理子程序KEYK2
KEY3:
CJNEA,#04H,KEY4
LJMPKEYK3;是K3键,转入K3键处理子程序KEYK3
KEY4:
CJNEA,#08H,KEY5
LJMPKEYK4;是K4键,转入K4键处理子程序KEYK4
KEY5:
CJNEA,#10H,KEY6
LJMPKEYK5;是K5键,转入K5键处理子程序KEYK5
KEY6:
CJNEA,#12H,KEY7
LJMPKEYK6;是K6键,转入K6键处理子程序KEYK6
KEY7:
CJNEA,#14H,KEY8
LJMPKEYK7;是K7键,转入K7键处理子程序KEYK7
KEY8:
CJNEA,#18H,EXIT
LJMPKEYK8;是K8键,转入K8键处理子程序KEYK8
EXIT:
RETI
DEL10MS:
MOV60H,#10;延时10ms子程序,晶振6MHz
LP1:
MOV61H,#250
DJNZ61H,$
DJNZ60H,LP1
RET
…
END
针对图10-5编程时,要求只处理单一按键,如有两个或多个按键同时按下视为无效,不予以处理,单片机应定时查询数据总线P0端口,按键采用延时去抖。
按键处理程序设计如下:
KEY_IN:
MOVDPTR,#7FFFH
MOVXA,@DPTR;读按键值
ANLA,#1FH;屏蔽高3位
CJNEA,#1FH,KEYQD;判断是否有键按下
LJMPEXIT;无键按下,退出键盘扫描
KEYQD:
LCALLDEL10MS;有键按下,延时10ms去抖
MOVXA,@DPTR;再读按键值
ANLA,#1FH
CJNEA,#1FH,KEY1
LJMPEXIT
KEY1:
CJNEA,#1EH,KEY2
LJMPKEYK1;是K1键,转入K1键处理子程序KEYK1
KEY2:
CJNEA,#1DH,KEY3
LJMPKEYK2;是K2键,转入K2键处理子程序KEYK2
KEY3:
CJNEA,#1BH,KEY4
LJMPKEYK3;是K3键,转入K3键处理子程序KEYK3
KEY4:
CJNEA,#17H,KEY5
LJMPKEYK4;是K4键,转入K4键处理子程序KEYK4
KEY5:
CJNEA,#0FH,EXIT
LJMPKEYK5;是K5键,转入K5键处理子程序KEYK5
EXIT:
RET
DEL10MS:
MOV60H,#10;延时10ms子程序,晶振为6MHz
LP1:
MOV61H,#250
DJNZ61H,$
DJNZ60H,LP1
RET
…
在行扫描法中,将所有行线作为输出端口,并逐行输出低电平,将所有列线作为输入端口,得到行、列线值后,也可以不采用查表的方式查找键码。
下面这个行扫描法查键程序,采用了非查表法,比较巧妙地找到按键键码,查键处理程序设计如下:
KEY_IN:
MOVP1,#0F0H;P1端口低4位全部输出0电平
MOVA,P1;从P1端口高4位读入列信号
ORLA,#0FH;屏蔽低4位
CPLA;取反
JZKPEXT;没有按键,即若A=0,Z=1,跳转到KPEXT
MOVR4,#0;键值初始化
MOVR2,#0FEH;行扫描码初始化
MOVR7,#4;扫描次数(行线数)
KP1:
MOVP1,R2;从P1端口低4位输出扫描码
MOVA,P1;从P1端口高4位读入列信息
ORLA,#0FH;屏蔽低4位
CPLA;取反
JNZKP2;本行有按键被按下否?
若有键,跳转到KP2
MOVA,R4;计算下一行键的起始键值
ADDA,#4
MOVR4,A
MOVA,R2;计算下一行的扫描码
RLA
MOVR2,A
DJNZR7,KP1;全部扫描结束否
SJMPKPEXT;无按键操作
KP2:
JBACC.4,KP3;是否第一列(若ACC.4=1,即为第一列有键)
RRA;调整到下一列
INCR4;调整键码
SJMPKP2;继续判断
KP3:
MOVA,R4;取键码,即键值
RET;返回键码
KPEXT:
MOVA,#0FFH;没有按键操作,返回0FFH
RET
线反转法查键及键码转换处理程序设计如下:
KEY_IN:
MOVP1,#0F0H;行线低4位输出低电平
MOVA,P1;从高4位读取列线值
ANLA,#0F0H;屏蔽低4位获得列线值
MOVB,A;暂存列线值→B
MOVP1,#0FH;列线高4位输出低电平
MOVA,P1;从低4位读取行线值
ANLA,#0FH;屏蔽高4位获得行线值
ORLA,B;行、列值合并,得到按键特征码
CJNEA,#0FFH,KPIN1;判断有按键否
AJMPEXIT;与0FFH相等,无按键,返回
KPIN1:
MOVB,A;有按键,把特征码暂存→B
MOVDPTR,#TABKP;DPTR指向键码表首地址
MOVR3,#0;顺序码初始化
KPIN2:
MOVA,R3;按顺序码查表
MOVCA,@A+DPTR;按顺序码查表
CJNEA,B,KPIN3;按键特征码与查表特征码比较
MOVA,R3;相等,顺序码有效,得到键码→A
AJMPEXIT;返回对应的键码(A)
KPIN3:
INCR3;不相等,调整顺序码,准备查下一个
CJNEA,#0FFH,KPIN2;是否为表格结束标志
EXIT:
RET;查到表格末尾仍未找到,以无按键处理
TABKP:
DB0EEH,0DEH,0BEH,7EH;K0到K3的特征码
DB0EDH,0DDH,0BDH,7DH;K4到K7的特征码
DB0EBH,0DBH,0BBH,7BH;K8到KB的特征码
DB0E7H,0D7H,0B7H,77H;KC到KF的特征码
DB67H,0FFH;KC+KF的特征码和表格结束标志
下面是静态显示3位50H~52H中的数的子程序:
DISP:
MOVR2,#03
MOVR0,#50H
LP0:
MOVA,@R0
ADDA,#0BH
MOVCA,@A+PC
MOVSBUF,A
LP1:
JNBTI,LP1
CLRTI
INCR0
DJNZR2,LP0
RET
TAB:
DB03H,9FH,25H,0DH,99H,49H;笔形码表0~9
DB41H,1FH,01H,09H,0FFH,0FFH
动态显示程序设计如下:
DISP:
MOVR3,#00;显示初值为0
MOVR4,#0E8H;循环显示次数
MOVDPTR,#TAB;置笔形码表首地址
LP0:
MOVA,R3
MOVCA,@A+DPTR
MOVP1,A;送显示段选码
SETBP2.2;控制输出锁存
CLRP2.2;保存输出
DELAY:
ACALLDISP1
DJNZR4,DELAY
INCR3
CJNER3,#0AH,LP0;控制显示一遍0~9数字
AJMPEXQ
DISP1:
MOVR1,#04
MOVR5,#00
DISP2:
MOVA,R5
MOVP2,A;送位选码
ACALLDEL1;每位显示1ms
INCR5;指向下一个LED
DJNZR1,DISP2;未显示完4位继续
RET
DEL1:
MOVR6,#250;延时1ms(6MHz晶振)
LP2:
DJNZR6,LP2
EXQ:
RET
TAB:
DB0C0H,0F9H,0A4H,0B0H,99H;0~9数字共阳笔形码
DB92H,82H,0F8H,80H,90H
按照图10-17电路,编写显示参考程序段如下:
ENEQUP1.2
CLKEQUP1.0
DINEQUP1.1
DISP:
CLRCLK
CLREN
MOVR7,#60
DEL:
DJNZR7,DEL;延时
MOVR7,#04;控制写入4位
MOVA,#4FH;小数点送A(高4位),即点亮第2位的小数点
ACALLWRD
MOVA,@R0;读取显示的BCD码→A
MOVR7,#08;控制写入8位
ACALLWRD
DECR0
MOVA,@R0
MOVR7,#08
ACALLWRD
SETBEN
RET
WRD:
SETBCLK;写入n个二进制位子程序
RLCA
MOVDIN,C
CLRCLK
DJNZR7,WRD
RET
单片机与MAX7219的通信程序设计如下:
DINEQUP1.0;定义数据线
LOADEQUP1.1;定义装载线
CLKEQUP1.2;定义时钟线
ORG0000
LJMPMAIN
ORG0030H
MAIN:
ACALLINIT
DISP:
MOVR0,#30H;置显示缓冲区起始地址(存储显示数BCD码)
MOVR1,#01
MOVR3,#08
LOOP3:
MOVA,@R0
MOVR4,A
MOVA,R1
ACALLWRITE;调用写8位数据子程序
INCR0
INCR1
DJNZR3,LOOP3
LJMPDISP
WRITE:
MOVR2,#08
CLRLOAD;LOAD引脚置低
SETBLOAD;LOAD引脚置高
LOOP1:
CLRCLK;CLK引脚置低
RLCA;移位传送位控数据
MOVDIN,C
CLRCLK
SETBCLK
DJNZR2,LOOP1
MOVA,R4
MOVR2,#08
LOOP2:
CLRCLK
RLCA;移位传送段码数据
MOVDIN,C
CLRCLK
SETBCLK
DJNZR2,LOOP2
CLRLOAD
SETBLOAD
RET
以下是MAX7219控制寄存器初始化子程序:
INIT:
MOVA,#09H;置译码方式
MOVR4,#0FFH
ACALLWRITE
MOVA,#0AH;置亮度控制
MOVR4,#08
ACALLWRITE
MOVA,#0BH;置扫描界线
MOVR4,#07
ACALLWRITE
MOVA,#0CH;置掉电控制
MOVR4,#01
ACALLWRITE
RET
DELAY:
MOVR7,#0;延时程序
AA:
NOP
NOP
DJNZR7,AA
RET
假设需要显示的数据已经分离出并存储在30H~35H单元,则程序段如下:
P1.0bitCLK
P1.1bitSKY1
P1.2bitSKY2
P1.3bitSKY3
DISP:
SETBCLK;CLK=1,允许TXD引脚同步移位脉冲输出显示
MOVR7,#06H;循环次数控制
MOVR0,#30H;R0作为显示数据指针
DSP1:
MOVA,@R0;取显示数送A
ADDA,#0DH;加偏移量
MOVCA,@A+PC;查表取笔形码
MOVSBUF,A;将段码送SBUF
JNBTI,$;输出段码,查询TI状态,1字节的段码输出完否
CLRTI;1字节的段码输出完,清TI标志
INCR0;指向下一个显示数据单元
DJNZR7,DSP1;段码个数计数器R7是否为0,若不为0,转DSP1继续
CLRCLK;CLK=0,禁止TXD输出同步移位脉冲到显示器
RET
TAB1:
DB03H,9FH,25H,0DH,99H,;共阳极段码表,对应0,1,2,3,4
DB49H,41H,1FH,01H,09H;5,6,7,8,9
DB11H,0C1H,63H,85H,61H;A,B,C,D,E
DB71H,0FDH,31H,0FFH,0FFH;F,-,P,暗
以下是键盘扫描子程序段:
KEY_IN:
CLRCLK;清CLK=0,禁止串口移位输出显示
MOVA,#00H;准备逐列扫描判键
MOVSBUF,A;向74LS164(7)输出00H,使所有列线为低电平
JNBTI,$
CLRTI
KNO:
JNBSKY1,KDY;判第1行是否有按键,如有按键跳转KDY
JNBSKY2,KDY;判第2行是否有按键,如有按键跳转KDY
JBSKY3,KNO;判第3行是否有按键,无按键跳转KNO
KDY:
ACALLDELY;软件去抖,调用延时10ms子程序
JNBSKY1,KIN1;判断是否抖动引起的
JNBSKY2,KIN1
JBSKY3,KNO
KIN1:
MOVR7,#08H;逐列扫描次数
MOVR6,#0FEH;先扫描第1列(列代码FEH),使QA=0
MOVR3,#00H;R3为列号寄存器
MOVA,R6
KIN3:
MOVSBUF,A;从串行口输出列代码
JNBTI,$
CLRTI
JNBSKY1,KIN2;判第1行是否有按键,如有按键跳转KIN2
JNBSKY2,KIN5;判第2行是否有按键,如有按键跳转KIN5
JBSKY3,NEXT;判第3行是否有按键,如无按键跳转NEXT
MOVR4,#10H;第3行行首键号10H送入R4
AJMPPK3
KIN5:
MOVR4,#08H;第2行行首键号08H送入R4
AJMPPK3
KIN2:
MOVR4,#00H;第1行行首键号00H送入R4
PK3:
MOVSBUF,#00H;等待松键,发送00H使所有列线为低电平
JNBTI,$
CLRTI
KIN4:
JNBSKY1,KIN4;判行线状态
JNBSKY2,KIN4
JNBSKY3,KIN4
MOVA,R4;两行线均为高电平,表示键已松开
ADDA,R3;行号+列号可得到键码→A
RET;找到键码,返回
NEXT:
MOVA,R6;列扫描码左移一位,判断下列键
RLA
MOVR6,A;记列扫描码于R6中
INCR3;列号加1
DJNZR7,KIN3;判断是否扫描完8列
RET;8列已扫描完毕返回
DELY:
MOVR7,#0AH;延时10ms子程序(晶振6MHz)
DL1:
MOVR6,#250
DJNZR6,$
DJNZR7,DL1
RET
按照图10-22电路连接编程,将扫描得到的按键值送出显示。
程序设计如下:
SDABITP1.0;I2C总线定义
SCLBITP1.1
ACKBIT00H;应答信号标志位
MTDDATA30H;发送缓冲区(30H~37H)
MRDDATA38H;接收缓冲区(38H~3FH)
SLADATA40H;器件从地址
SUBADATA41H;器件子地址
NUMBYTEDATA42H;数据传输字节数
DISP_BUFDATA43H;存储显示数据的缓冲区首地址(43H~4AH)
DISP_NUMDATA4BH;数码显示个数
CMD0DATA4CH;命令1
CMD1DATA4DH;命令2
ADDRDATA4EH;ZLG7290内部寄存器地址
DATA0DATA4FH;写入ZLG7290内部寄存器的数据存储单元
BUFDATA50H;显示缓冲区的指针
ZLG7290EQU70H;ZLG7290的器件地址
SUBCMDEQU07H;ZLG7290的命令缓冲区地址
SUBKEYEQU01H;ZLG7290的键值寄存器地址
ORG0000H;主程序
LJMPMAIN
MAIN:
MOVSP,#60H
MOVDISP_BUF,#01
MOVDISP_BUF+1,#02
MOVDISP_BUF+2,#03
MOVDISP_BUF+3,#04
MOVDISP_NUM,#04
LCALLDISPLY
LOOP:
LCALLGET_KEY
MOVA,MRD
JZLOOP
MOVB,#10H
DIVAB
MOVDISP_BUF,A
MOVDISP_BUF+1,B
MOVDISP_NUM,#02
LCALLDISPLY
LJMPLOOP
DISPLY:
MOVBUF,#DISP_BUF;ZLG7290送显示命令子程序
MOVR7,DISP_NUM
MOVCMD0,#60H;显示命令字(从0位置开始显示)
DISP1:
MOVR0,BUF
MOVCMD1,@R0;读取显示数据
LCALLSEND_CMD
INCBUF
INCCMD0
DJNZR7,DISP1
RET
WR_RGE:
MOVSLA,#ZLG7290;ZLG7290写寄存器子程序
MOVSUBA,ADDR
MOVMTD,DATA0
MOVNUMBYTE,#01
LCALLIWRNBYTE;调用数据写入子程序
LCALLDEL10MS
RET
SEND_CMD:
MOVSLA,#ZLG7290;ZLG7290发送控制命令子程序
MOVSUBA,#SUBCMD
MOVMTD,CMD0
MOVMTD+1,CMD1
MOVNUMBYTE,#02
LCALLIWRNBYTE;调用数据写入子程序
LCALLDEL10MS
RET
GET_KEY:
MOVSLA,#ZLG7290;ZLG7290读键值子程序
MOVSUBA,#SUBKEY
MOVNUMBYTE,#01
LCALLIRDNBYTE;调用数据读出子程序
DEL10MS:
MOV51H,#4
DEL_B:
MOV52H,#123
DJNZ52H,$
DJNZ51H,DEL_B
RET
IWRNBYTE:
MOVA,NUMBYTE;向器件指定子地址写入N字节子程序
MOVR3,A
LCALLSTART;启动总线,见9.5.4节的I2C总线常用子程序
MOVA,SLA
LCALLWRBYTE;发送器件从地址(参考I2C