程序举例.docx
《程序举例.docx》由会员分享,可在线阅读,更多相关《程序举例.docx(17页珍藏版)》请在冰豆网上搜索。
程序举例
例1:
将内部RAM40~4FH的16个数据送到外部RAM2000~200FH,再将外部2000~200FH数据送到内部RAM50~5FH中。
例2:
有一变量存放在片内RAM的20H单元,其取值范围为:
00H~05H。
要求编制一段程序,根据变量值求其平方值,并存入片内RAM的21H单元。
在程序存储器的一片存储单元中建立起该变量的平方表。
用数据指针DPTR指向平方表的首址,则变量与数据指针之和的地址单元中的内容就是变量的平方值。
采用MOVCA,@A+PC指令也可以实现查表功能,且不破坏DPTR的内容,从而可以减少保护DPTR的内容所需的开销。
但表格只能存放在MOVCA,@A+PC指令后的256字节内,即表格存放的地点和空间有一定限制。
例3:
(双字节无符号数加法)设被加数存放在内部RAM的51H、50H单元,加数存放在内部RAM的61H、60H单元,相加的结果存放在内部RAM的51H、50H单元,进位存放在位寻址区的00H位中。
程序段如下:
MOVR0,#50H;被加数的低字节地址
MOVR1,#60H;加数的低字节地址
MOVA,@R0;取被加数低字节
ADDA,@R1;加上加数低字节
MOV@R0,A;保存低字节相加结果
INCR0;指向被加数高字节
INCR1;指向加数高字节
MOVA,@R0;取被加数高字节
ADDCA,@R1;加上加数高字节(带进位加)
MOV@R0,A;存高字节相加结果
MOV00H,C;保存进位。
例4:
双字节BCD数加法
例5:
将给定的一个字节二进制码转换十进制码
RESULTEQU30H
ORG00H
LJMPSTART
START:
MOVSP,#40H
MOVA,#123
LCALLBINTOBAC
SJMP$
BINTOBAC:
MOVB,#100
DIVAB;除以100得百位数
MOVRESULT,A
MOVA,B
MOVB,#10
DIVAB;余数除以10得十位数
MOVRESULT+1,A
MOVRESULT+2,B;余数为个位数
RET
END
例6:
多分支程序跳转
ORG00H
START:
MOVA,#0
CALLFUNCENTER
MOVA,#1
MOVA,#2
CALLFUNCENTER
MOVA,#3
CALLFUNCENTER
LJMP$
FUNCENTER:
ADDA,ACC;AJMP为二字节指令,地址偏移量*2
MOVDPTR,#FUNCTAB;设置基址
JMP@A+DPTR;跳转到目标地址
FUNCTAB:
AJMPFUNC0
AJMPFUNC1
AJMPFUNC2
AJMPFUNC3
FUNC0:
MOV30H,#0
RET
FUNC1:
MOV31H,#1
RET
FUNC2:
MOV32H,#2
RET
FUNC3:
MOV33H,#3
RET
END
例7:
多字节BCD取补
ORG00H
MOV30H,#12H
MOV31H,#44H
MOV32H,#89H
MOVR7,#03H;设置操作数的字节数
MOVR0,#30H;设置指针
NEG:
MOVA,R7
DECA;取字节数减1至R2中
MOVR2,A
MOVA,R0;保护指针
MOVR3,A
NEG0:
CLRC
MOVA,#99H
SUBBA,@R0;按字节十进制取补
MOV@R0,A;存回以@R0开始的连续单元
INCR0;调整数据指针
DJNZR2,NEG0
MOVA,#9AH;最低字节单独取补
SUBBA,@R0
MOV@R0,A
MOVA,R3;恢复指针
MOVR0,A
SJMP$
END
例8(无符号数排序程序)在片内RAM中,起始地址为30H的8个单元中存放有8个无符号数。
试对这些无符号数进行升序排序。
(先执行后判断)
数据排序常用的方法是冒泡排序法。
执行时从前向后进行相邻数的比较,如数据的大小次序与要求的顺序不符就将这两个数互换,否则不互换。
对于升序排序,通过这种相邻数的互换,使小数向前移动,大数向后移动。
从前向后进行一次冒泡(相邻数的互换),就会把最大的数换到最后。
再进行一次冒泡,就会把次大的数排在倒数第二的位置。
设R7为比较次数计数器,初始值为07H,位地址00H为数据互换标志位。
START:
CLR00H;互换标志清0
MOVR7,#07H;各次冒泡比较次数
MOVR0,#30H;数据区首址
LOOP:
MOVA,@R0;取前数
MOV2BH,A;暂存
INCR0
MOV2AH,@R0;取后数
CLRC
SUBBA,@R0;前数减后数
JCNEXT;前数小于后数,不互换
MOV@R0,2BH
DECR0
MOV@R0,2AH;两数交换
INCR0;准备下一次比较
SETB00H;置互换标志
NEXT:
DJNZR7,LOOP;进行下一次比较
JB00H,START;进行下一轮冒泡
SJMP$
例9:
将内部RAM中起始地址为data的数据串传送到外部RAM中起始地址为buffer的存储区域内,直到发现‘$’字符停止传送。
由于循环次数事先不知道,但循环条件可以测试到。
所以,采用先判断后执行的结构比较适宜。
(先判断后执行)
程序段如下:
MOVR0,#data
MOVDPTR,#buffer
LOOP0:
MOVA,@R0
CJNEA,#24H,LOOP1;判断是否为‘$’字符
SJMPLOOP2;是‘$’字符,转结束
LOOP1:
MOVX@DPTR,A;不是‘$’字符,执行传送
INCR0
INCDPTR
SJMPLOOP0;传送下一数据
LOOP2:
……
例10:
(利用累加器或寄存器)编写程序,实现c=a2+b2。
设a,b,c分别存于内部RAM的30H,31H,32H三个单元中。
程序段如下:
START:
MOVA,30H;取a
ACALLSQR;调用查平方表
MOVR1,A;a2暂存于R1中
MOVA,31H;取b
ACALLSQR;调用查平方表
ADDA,R1;a2+b2存于A中
MOV32H,A;存结果
SJMP$
SQR:
MOVDPTR,#TAB;子程序
MOVCA,@A+DPTR;
RET
TAB:
DB0,1,4,9,16,25,36,49,64,81
例11:
(利用存储器)将R0和R1指向的内部RAM中两个3字节无符号整数相加,结果送到由R0指向的内部RAM中。
入口时,R0和R1分别指向加数和被加数的低位字节;出口时,R0指向结果的高位字节。
低字节在高地址,高字节在低地址。
实现程序:
NADD:
MOVR7,#3;三字节加法
CLRC;
NADD1:
MOVA,@R0;取加数低字节
ADDCA,@R1;被加数低字节加A
MOV@R0,A;
DECR0
DECR1
DJNZR7,NADD1
INCR0
RET
例12:
(利用堆栈)把内部RAM中20H单元中的1个字节十六进制数转换为2位ASCII码,存放在R0指示的两个单元中。
MAIN:
MOVA,20H;
SWAPA
PUSHACC;参数入栈
ACALLHEASC
POPACC
MOV@R0,A;存高位十六进制数转换结果
INCR0;修改指针
PUSH20H;参数入栈
ACALLHEASC
POPACC
MOV@R0,A;存低位十六进制数转换结果
SJMP$
HEASC:
MOVR1,SP;借用R1为堆栈指针
DECR1
DECR1;R1指向被转换数据
XCHA,@R1;取被转换数据
ANLA,#0FH;取一位十六进制数
ADDA,#2;所加值为MOVC与DB间字节数
MOVCA,@A+PC;查表
XCHA,@R1;1字节指令,存结果于堆栈
RET;1字节指令
ASCTAB:
DB30H,31H,32H,33H,34H,35H,36H,37H
DB38H,39H,41H,42H,43H,44H,45H,46H
例13:
做单一的左移/右移,八个二极管接在P1端口上。
输出”0“时,发光二极管亮。
先从P1.0到P1.7,然后从P1.7到P1.0。
ORG00H
START:
MOVA,#0FEH;设置输出初值
SETBC;进位标志置1
S1:
MOVP1,A;输出A值
LCALLDELAY
RLCA;A带进位右移
JCS1;若移位次数达到8次,重设输出初值
MOVA,#7FH
SETBC
S2:
MOVP1,A;将新的A值输出
LCALLDELAY
RRCA
JCS2
LJMPSTART
DELAY:
MOVR5,#20;延时子程序
D1:
MOVR6,#20
D2:
MOVR7,#248
DJNZR7,$
DJNZR6,D2
DJNZR5,D1
RET
END
例14:
AT89C51单片机的P1.0到P1.3端口接四个发光二极管D1到D4,P1.4到P1.7端口接了四个开关,编程将开关的状态反映到发光二极管上.(每个开关相对应不同的发光二极管)
ORG00H
START:
MOVA,P1;读取P1口数据
SWAPA;交换A中高四位与低四位的位置
ORLA,#0F0H;与0F0H进行或运算
MOVP1,A;将开关状态送LED显示
SJMPSTART
END
例15:
AT89C51单片机的P3.2/INT0引脚接一个开关,模拟外部中断源,编写程序,当外部中断发生时,对其作出响应(以发光二极管的灯的状态来显示)
LEDBITP1.0
LEDBUFEQU30H
ORG00H
LJMPSTART
ORG03H;外部中断入口
LJMPINTERRUPT
START:
CLRLEDBUF
CLRLED
MOVTCON,#01H;外部中断0下降沿触发
MOVIE,#81H;打开外部中断允许围(EX0)及总中断允许位(EA)
LJMP$;等待中断
INTERRUPT:
PUSHPSW;保护现场
CPLLEDBUF;取反LED
MOVC,LEDBUF
MOVLED,C
POPPSW;恢复现场
RETI
END
例16:
定时/计数器可以用来实现定时,计数,频率测量,脉冲宽度测量,产生信号,等。
用AT89C51单片机定时/计数器0的定时功能可构成一简单的方波发生器,实现周期为400us的方波输出。
若改变定时/计数器0的初值可得到不同周期的方波输出。
ORG00H
SJMPSTAR
ORG0BH
SJMPT0F
STAR:
MOVTMOD,#0;T0工作方式0
MOVP3,#03FH
MOVTH0,#0F9H;赋初值高位
MOVTL0,#18H;赋初值低位
MOVIE,#0FFH;中断允许设置
SETBTR0;启动T0
SJMP$
T0F:
CPLP3.5;输出信号取反
CPLP3.7
MOVTH0,#0F9H;重装初值
MOVTL0,#18H
CPLP3.0
RETI
END
例17:
AT89C51的定时/计数器T0产生2s的定时。
每当2s定时到来时,更换指示灯闪亮。
每个指示灯闪亮时间位0.2s。
如此的循环下去。
0.2s的闪亮时间也由定时/计数器T0来完成。
COUNTEQU30H
FLASHEQU31H
ORG00H
SJMPSTART
ORG0BH;定时器0中断入口
LJMPINT_T0
START:
MOVCOUNT,#00H
MOVFLASH,#00H
MOVTMOD,#01H;定时器工作方式1
MOVTH0,#(65536-50000)/256;定时器初值
MOVTL0,#(65536-50000)MOD256
MOVIE,#82H;开中断
SETBTR0;启动定时器
SJMP$;等待中断
INT_T0:
MOVA,COUNT
CJNEA,#00H,I1;D1闪亮
CPLP1.0
INCFLASH
MOVA,FLASH
CJNEA,#40,RETUNE;达到2s?
MOVFLASH,#00H
INCCOUNT
LJMPRETUNE;D2闪亮
I1:
CJNEA,#01H,I2
CPLP1.1
INCFLASH
MOVA,FLASH
CJNEA,#40,RETUNE;达到2s?
MOVFLASH,#00H
INCCOUNT
LJMPRETUNE
I2:
CJNEA,#02H,I3;D3闪亮
CPLP1.2
INCFLASH
MOVA,FLASH
CJNEA,#40,RETUNE;达到2s?
MOVFLASH,#00H
INCCOUNT
LJMPRETUNE
I3:
;D4闪亮
CJNEA,#03H,RETUNE
CPLP1.3
INCFLASH
MOVA,FLASH
CJNEA,#40,RETUNE;达到2秒?
MOVFLASH,#00H
MOVCOUNT,#00H
LJMPRETUNE
RETUNE:
MOVTH0,#(65536-50000)/256
MOVTL0,#(65536-50000)MOD256
RETI
END
例18:
P2口接动态数码管的字形码笔端,P3.2和P3.3接动态数码管的数位选择端,P3.7接一个开关,编写程序,使得开关接低电平时,在两位数码管上滚动显示'12345'字样,开关接低电平时,在两位数码管滚动显示“HELLO”字样。
KEYBITP3.7;按键位
HBBITP3.2;数码管高位
LBBITP3.3;数码管低位
FLAGBIT00H:
;标志位
ORG00H
START:
JBKEY,S1;判断按键是高电平还是低电平
MOVDPTR,#TABLE1;如果是低电平,为'12345‘显示码首地址
CLRFLAG
LJMPS2
S1:
MOVDPTR,#TABLE2;如果是高电平,为“HELLO"显示码首地址
SETBFLAG
S2:
MOVR0,#00H;数码管偏移地址高位显示码
MOVR1,#01H;数码管偏移地址低位显示码
K1:
MOVR7,#100;延时常数
L1:
SETBLB
CLRHB
MOVA,R0
MOVCA,@A+DPTR;查高位段码
MOVP2,A
LCALLDELAY;数码管高位显示
SETBHB
CLRlB
MOVA,R1
MOVCA,@A+DPTR;查低位段码
MOVP2,A
LCALLDELAY;数码管低位显示
DJNZR7,L1
JBFLAG,J1;扫描一次后,判断按键电平是否变化
JBKEY,START
LJMPJ2
J1:
JNBKEY,START
J2:
INCR0
INCR1
CJNER0,#06H,K1;判断是否循环完一次
LJMPSTART
DELAY:
MOVR5,#5;延时
D1:
MOVR6,#250
DJNZR6,$
DJNZR5,D1
RET
TABLE1:
DB00H,06H,5BH,4FH,66H,6DH,00H
TABLE2:
DB00H,76H,79H,38H,38H,3FH,00H
END
例19:
采用74LS164驱动七段数码管,单片机串行移位的输出作为74LS164的输入,74LS164的输出作为段码驱动7段数码管。
编写程序,在2位独立的数码管上显示“51"字样。
DBUF0EQU30H;存储区首地址
TEMPEQU40H
DINBIT0B0H;串行口输出
CLKBIT0B1H;时钟输出口
ORG00H
MOV30H,#1H
MOV31H,#5H
DISP:
MOVR0,#DBUF0;存入显示数据
MOVR1,#TEMP
MOVR2,#2
DP10:
MOVDPTR,#SEGTAB;表头地址
MOVA,@R0
MOVCA,@A+DPTR;查表指令
MOV@R1,A
INCR1
INCR0
DJNZR2,DP10
MOVR0,#TEMP;段码地址指针
MOVR1,#2;段码字节数
DP12:
;输出子程序
MOVR2,#8
MOVA,@R0;取段码
DP13:
RLCA;段码左移
MOVDIN,C;输出一位段码
CLRCLK;发送移位脉冲
SETBCLK
DJNZR2,DP13
INCR0
DJNZR1,DP12
SJMP$
SEGTAB:
DB3FH,06H,5BH,4FH,66H;0,1,2,3,4
DB6DH,7DH,07H,7FH,6FH;5,6,7,8,9
DELAY:
;延时子程序
MOVR4,#03H
AA1:
MOVR5,#0FFH
AA:
DJNZR5,AA
DJNZR4,AA1
RET
END