资源描述
2013
XuYue
微软中国
2013/11/30
单片机汇编程序
【例5-2】在89C51单片机的引脚外接脉冲信号,要求每送来一个脉冲,把30H单元值加1,若30H单元计满则进位31H单元。现利用中断编制脉冲计数程序。
主程序部分:
ORG 0000H
AJMP MAIN ;设置主程序入口地址
ORG 0003H ;中断入口地址
AJMP SUBG ;设置中断服务程序入口地址
ORG 0100H
MAIN: MOV A, #00H ;30H、31H两单元清零
MOV 30H,A
MOV 31H,A
MOV SP, #70H ;设置堆栈指针
SETB IT0 ;设为边沿触发
SETB EA ;开中断
SETB EX0 ;允许中断
AJMP $ ;等待中断
中断服务程序:
ORG 0200H ;设置中断服务子程序位置
SUBG: PUSH ACC ;保护现场
INC 30H ;中断后将脉冲计数值加1
MOV A, 30H
JNZ BACK
INC 31H
BACK: POP ACC ;恢复现场
RETI ;返回
【例5-3】设计一个比赛抢答器,电路如图5-9所示,P1.0~P1.3分别接按钮S1~S4,当其中任何一个按钮按下时,都能立即从P3.3发出铃声信号,并点亮相应的发光二极管。即S1点亮VL1,S2点亮VL2,S3点亮VL3,S4点亮VL4。电路连接如图5-8。
图5-8 例5-3电路图
主程序部分:初始化,等待中断
0RG 0000H
LJMP START
0RG 0003H
LJMP 0300H
ORG 0100H
START: MOV SP,#70H ;设置栈区
SETB IT0 ;脉冲触发方式
WAITOFF:CLR P3.3 ;响铃控制
SETB EA ;CPU中断允许
SETB EX0 ;中断允许
SJMP $
中断服务程序: 查按钮,有按钮按下时响铃
ORG 0300H ;中断服务程序
ZDP: MOV A,P1 ;查哪个按钮按下
ANL A,#0FH
SWAP A ;转换为点亮发光管信号
ORL A,#0FH
MOV P1,A
LCALL RING ;响铃
LCALL DELAY
RETI
延时子程序:
RING: MOV R5, #20H ; 时间常数
RIN0: MOV R6, #60H ; 时间常数
RIN1: MOV R7, #0F0H ; 时间常数
RIN2: DJNZ R7, RIN2
SETB P3.3
DJNZ R6, RIN1
DJNZ R5, RIN0
RET
DELAY: MOV R6, #0FFH
DE2: MOV R7, #0FFH
DE1: DJNZ R7, DE1
DJNZ R6, DE2
RET
【例5-4】设定时器T0工作在方式0,在P1.0引脚上输出周期为2ms的方波(定时时间为1ms),fosc=6MHZ。编程实现其定时功能。
解:当T0处于工作方式0时,加1计数器为13位。设T0的初值为X。(1机器周期=2µs)
1. 计算T0初值X
则:X=7692;转换为二进制数:1111000001100B;结果为(TH0)=F0H,(TL0)=0CH.
2. 初始化
选择T0并确定工作方式:(TMOD)=00H
装入初始值:(TH0)=0F0H (TL0)=0CH
选择数据传输方式:中断方式:允许T0中断
SETB EA
SETB ET0
查询方式:禁止T0中断
CLR ET0
3. 程序清单
将上述的分析过程用指令表示出来。
方法1:中断法。在定时器初始化时要开放对应的中断允许(ET0或ET1)和总允许EA,在启动后等待中断。当计数器溢出中断,CPU将程序转到中断服务程序入口,因此应在中断服务程序中安排相应的处理程序。
主程序:
ORG 1000H
PTOMD :MOV TMOD, #00H ;T0方式0
MOV TL0, #0CH ;送初值
MOV TH0, #0F0H
SETB EA ;CPU开中断
SETB ET0 ;开T0中断
SETB TR0 ;启动定时
SJMP $ ;等待中断
中断服务程序:
ORG 0120H
ITOP: MOV TL0, #0CH ;重新装入初值
MOV TH0, #0F0H
CPL P1.0 ;P1.0取反输出方波
RETI
方法2:查询法。在定时器初始化并启动后,在程序中安排指令查询TF0的状态。
MOV TMOD, #00H ;设置T0为模式0
MOV TL0, #0CH ;送初值
MOV TH0, #0F0H
CLR ET0 ;禁止T0中断
SETB TR0 ;启动T0
LOOP: JBC TF0, NEXT ;查询定时时间是否到?
SJMP LOOP
NEXT: MOV TL0, #0CH ;重装计数初值
MOV TH0, #0F0H
CPL P1.0 ;输出取反
SJMP LOOP ;重复循环
【例5-5】 用89C51单片机产生方波信号,晶振频率为6MHz,用T0定时,通过并行口P1.0输出频率为lKHz的方波的程序。用查询方式。
ORG 2000H
START: MOV TMOD,#01H ;T0工作于方式1
MOV TL0, #06H ;时间常数初值低8位
MOV TH0, #0FFH ;时间常数初值高8位
CLR ET0 ;禁止T0中断
SETB TR0 ;启动T0
LOOP: JBC TF0, DONE ;检查T0溢出否
SJMP LOOP ;未计满再查
DONE: MOV TL0, #06H ;计满重装时间常数初值
MOV TH0, #0FFH
CPL P1.0 ;将P1.0输出电平反相;
SJMP LOOP
【例5-6】利用定时器T1的模式2对外部信号计数。要求每计满100次,累加器A加1。
解:
计算T1的计数初值 :X=28-100=156D=9CH
因此,TL1的初值为9CH,重装初值寄存器TH1=9CH.
程序清单:
ORG 0000H
LJMP MAIN
ORG 001BH ;中断服务程序入口
LJMP INTT1
MAIN: MOV TMOD, #60H ;T1为模式2计数方式
MOV TL1, #9CH ;赋初值
MOV TH1, #9CH
MOV IE, #88H ;定时器T1开中断
SETB TR1 ;启动计数器
HERE: SJMP HERE ;等待中断
中断服务程序:
INTT1: CPL P1.0
RETI
【例5-7】用T0方式3,分别产生200μs和300μs的定时,并使P1.0和P1.1分别产生400μs和600μs的方波。(fosc=6MHz)
解:本题需要2个定时器TH0和TL0
计数初始值计算:(28-初始值)×2=200/300
TH0的初值=156=9CH ; TL0的初值=106=6AH
初始化:TMOD:03H且TR0=1和TR1=1
程序:
ORG 3000H
START: AJMP MAIN ;转主程序
ORG 000BH ;转TR0溢出中断
AJMP PIT0
ORG 001BH ;转TR1溢出中断
AJMP PIT1
MAIN: MOV TMOD, #03H
MOV TH0, #6AH
MOV TL0, #9CH
MOV IE, #8AH
MOV TCON, #50H
SJMP $
PIT0:MOV TH0, #6AH ;定时300us
CLP P1.0
RETI
PIT1:MOV TL0, #9CH ;定时200μs
CLP P1.1
RETI
【例5-8】用定时器/计数器T0监视一生产线,每生产100个工件,发出一包装命令,包装成一箱,并记录其箱数。硬件电路如图5-15所示。
图5-15 例5-8题图
用T0作计数器,T为光敏三极管。当有工件通过时,三极管输出高电平,即每通过一个工件,便会产生一个计数脉冲。
T0工作于计数器方式的方式2,方式控制字为TMOD:00000110B;计数初值为TH0=TL0=256-100=156=9CH;用P1.0启动包装机包装命令;用R5、R4作为箱数计数器。
程序如下:
ORG 0000H
LJMP MAIN ;主程序
ORG 000BH ;T0中断服务程序
LJMP COUNT
ORG 0030H
MAIN: MOV SP, #60H
CLR P1.0
MOV R5,#0 ;箱数计数器清“0”
MOV R4,#0
MOV TMOD,#06H ;置T0工作方式
MOV TH0, #9CH
MOV TL0, #9CH
SETB EA ;CPU开中断
SETB ET0
SETB TR0
SJMP $ ;模拟主程序
COUNT : MOV A, R4 ;箱数计数器加1
ADD A, #01H
MOV R4,A
MOV A, R5
ADDC A, #00H
MOV R5,A
SETB P1.0 ;启动包装
MOV R3,#100
DLY: NOP ;给外设一定时间
DJNZ R3,DLY
CLR P1.0
RETI ;中断返回
END
【例5-9】设系统时钟频率为12MHz,编程实现P1.1引脚上输出周期为1s,占空比为20%的脉冲信号。
分析:根据输出要求,脉冲信号在一个周期内高电平占0.2s,低电平占0.8s,超出了定时器的最大定时间隔,因此利用定时器0产生一个基准定时配合软件计数来实现。取10ms作为基准定时,采用工作方式1,这样整个周期需要100个基准定时,其中高电平占20个基准定时,低电平占80个基准定时。
程序代码如下:
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP T0INT
ORG 0030H
MAIN: MOV SP,#60H
MOV R7,#0
MOV TMOD,01H ;初始化
MOV TH0, #0D8H
MOV TL0, #0F0H
SETB EA
SETB ET0
SETB TR0
SJMP $
中断服务程序:
T0INT: MOV TH0,#0D8H ;重载初始值
MOV TL0,#0F0H
INC R7
CJNE R7,#20,LL1
CLR P1.1
SJMP LLEND
LL1: CJNE R7,#100,LLEND
SETB P1.1
MOV R7,#00H
LLEND: RETI
【例5-10】试编写利用T0产生1s定时的程序。使得由P1口控制的8个LED指示灯每隔一秒轮流闪亮(输出为低电平时亮),设fosc=6MHz。
解:
1) 定时器T0工作模式的确定
因定时时间较长,使用51单片机的定时器/计数器进行定时,即使按工作方式l,其最大定时时间也只能达到131 ms,离ls还差很远。为此,我们把秒计时用硬件定时和软件计数相结合的方法实现,
采用哪一种工作模式合适呢?可以算出:
模式0最长可定时16.384ms;
模式1最长可定时131.072ms;
模式2最长可定时512μs。
题中要求定时1s,可选模式1,每隔100ms中断一次,中断10次为1s。
初始值X(设fosc=6MHZ,振荡脉冲经12分频得到机器周期)
∵(216-X)
∴X=15536=3CB0H
因此,(TL0)=0B0H,(TH0)=3CH。
2) 实现方法
对于中断10次计数,可使T0工作在计数方式,也可用循环程序的方法实现。本例采用循环程序法。
3)程序设计:
ORG 0000H
LJMP MAIN ;上电,转向主程序
ORG 000BH ;T0的中断入口地址
AJMP DVT0 ;转向中断服务程序
ORG 2000H ;主程序
MAIN: MOV SP, #60H ;设堆栈指针
MOV R2, #0AH ;设循环次数
MOV TMOD, #01H ;设置T0工作于模式1
MOV TL0, #0B0H ;装入计数值低8位
MOV TH0, #3CH ;装入计数值高8位
SETB TR0 ;启动定时器T0
SETB ET0 ;允许T0中断
SETB EA ;允许CPU中断
SJMP $ ;等待中断
中断服务程序:
DVT0: MOV TH0,#3CH
MOV TL0,#0B0H
DJNZ R2,RTN
RL A ;左移一位
MOV P1,A
MOV R2,#20
RTN: RETI
【例5-11】门控位GATE的应用
利用定时/计数器T0的门控位GATE,测量引脚上出现的脉冲宽度,并将结果(机器周期数)存入内部RAM 30H和31H单元中。
解:
1)由题意分析,外部脉冲由引脚输入,可设T0工作于定时方式1,计数初值为0,在一个完整的外部脉冲宽度内对机器周期计数(定时方式),显然计数值乘上机器周期就是脉冲宽度。
2)设定GATE=1,当TR0置1时,由外部脉冲上升沿启动T0开始工作。加1计数器开始对机器周期计数;引脚变为低电平时,停止计数,这时读出TH0、TL0的值,该计数值即为被测信号的脉冲宽度对应的机器周期数。测试过程如5-16图所示.
图5-16 例5-11题图
3)工作方式字TMOD=00001001B
计数初值TH0=00H,TL0=00H
4)程序设计
ORG 0000H
LJMP MAIN
ORG 0030H
MAIN: MOV TMOD,#09H ;GATE=1
MOV TH0, #00H ;置计数初值
MOV TL0, #00H
MOV R0, #30H
WAIT1: JB P3.2,WAIT1 ;等待变低
SETB TR0 ;预启动T0
WAIT2: JNB P3.2,WAIT2 ;等待变高、启动计数
WAIT2: JB P3.2,WAIT3 ;等待再变低
CLR TR0 ;停止计数
MOV @R0,TL0 ;读取计数值,存入指定单元
INC R0,
MOV @R0,TH0
AJMP DATA ;转数据处理程序
【例6-1】利用串行口工作方式0扩展出8位并行I/O口,驱动共阳极LED数码管显示0~9。电路连接如图6-16。
把89C51串行口8位状态码串行移位输出后,TI置“l”,把Tl作为状态查询标志,则使用查询方法完成的串行口和CD4094驱动共阳极LED数码管(查表)显示0-9数字的参考子程序如下:
DSPLY:MOV DPTR, #TABLE
MOVC A, @A+DPTR
MOV SBUF, A
JNB TI, $
CLR TI
RET
TABLE:DB 0C0H,0F9H,0A4H 0B0H,99H
DB 92H,82H,0F8H,80H,90H
图6-16 共阳极LED与单片机的联接
图6-17 串行移位输入电路连接
用方式0加上并入一串出移位寄存器可扩展一个8位并行输入口。移位寄存器必须带有预置/移位的控制端,由单片机的一个输出端子加以控制,以实现先由8位输入口置数到移位寄存器,然后再串行移位从单片机的串行口输入到接收缓冲器,最后再读入到CPU中。
【例6-2】用51单片机串行口外加移位寄存器CD4014(或74LSl65,166)扩展8位输入口,输入数据由8个开关提供,另有一个开关K提供联络信号。当K=0时,表示要求输入数据,输入的8位为开关量,提供逻辑模拟子程序的输入信号。如图6-17所示。
解:串行口方式0的接收要用SCON寄存器中的REN位作为开关来控制。因此,初始化时,除了设置工作方式之外,还要使REN位为l,其余各位仍然为0。
对RI采用查询方式来编写程序,当然,先要查询开关K是否闭合。
参考程序:
START:MOV SCON,#10H ;串行口方式0初始化
JB P1.l,$ ;开关K未闭合,等待
SETB Pl.0 ;P/=1,并行置入数据
CLR Pl.0 ;P/=0,开始串行移位
JNB RI,$ ;查询RI
CLR RI ;查询结束,清RI
MOV A,SBUF ;读数据到累加器
ACALL LOGSIM ;进行逻辑模拟
SJMP START ;准备下一次模拟
甲机发送主程序:
ORG 0023H
AJMP ACINT
ORG 0030H
MOV TMOD,#20H ;设置定时器l工作方式2
MOV TLl,#0F3H ;定时器Tl数初值
MOV THl,#0F3H ;计数重装值
SETB EA ;中断总允许
CLR ES ;禁止串行中断
MOV PCON,#00H ;波特率不倍增
SETB TRl ;启动定时器l
MOV SCON,#50H ;设置串行口方式l,REN=1
MOV SBUF,#40H ;发送数据区首地址高位
SOUTl: JNB Tl,$ ;等待一帧发送完毕
CLR Tl ;清发送中断标志
MOV SBUF,#00H ;发送数据区首地址低位
SOUT2: JNB Tl,$ ;等待一帧发送完毕
CLR TI
MOV SBUF,#40H ;发送数据区末地址高位
SOUT3: JNB Tl,$ ;等待一帧发送完毕
CLR Tl ;清发送中断标志
MOV SBUF,#lFH ;发送数据区末地址
SOUT4: JNB Tl,$ ;等待一帧发送完毕
CLR TI
MOV DPTR,#4000H ;数据区地址指针
MOVX A,@DPTR ;读第一个数据
INC DPTR
MOV R7,#20H ;数据个数
SETB ES ;开放串行中断
MOV SBUF,A ;启动发送第一个数据
DEC R7
AHALT: AJMP $ ;等待中断
甲机中断服务程序:
ORG 0100H
ACINT: MOVX A,@DPTR ;读数据
CLR TI ;清发送中断
MOV C,P ;奇偶标志赋予
MOV ACC.7, C ;送ASCII码高位
MOV SBUF,A ;发送字符
DEC R7
CJNE R7,#00H,AEND2 ;没发送完转AEND2
CLR ES ;发送完禁止串行中断
CLR TRl ;定时器l停止计数
AJMP AENDl
AEND2: INC DPTR
AENDl: RETI ;中断返回
乙机接收主程序:
0RG 0023H
AJMP BCINT
ORG 0030H
MOV TMOD,#20H ;设置定时器l工作方式2
MOV THl,#0F3H ;定时器l计数初值
MOV TLl,#0F3H ;计数重装值
SETB EA ;中断总允许
CLR ES ;禁止串行中断
MOV PCON,#00H ;波特率不倍增
SETB TRl ;启动定时
MOV SCON,#50H ;设置串行口方式l,REN=1
MOV DPTR,#5000H ;数据存放首地址
MOV R7,#24H ;接收数据个数
SINl: JNB Rl,$ ;等待一帧接收完
CLR Rl ;清接收中断标志
DEC R7
MOV A,SBUF ;接收数据区首地址高位
MOVX @DPTR,A ;存首地址高位
INC DPTR ;地址指针增量
SIN2: JNB RI,$
CLR RI
DEC R7
MOV A,SBUF ;接收数据区首地址低位
MOVX @DPTR,A ;存首地址低位
INC DPTR
SIN3: JNB RI,$
CLR RI
DEC R7
MOV A,SBUF ;接收数据区未地址高位
MOVX @DPTR,A ;存本地址高位
INC DPTR
SIN4: JNB RI,$
CLR RI
DEC R7
MOV A,SBUF ;接收数据区未地址低位
MOVX @DPTR,A ;存末地址低位
INC DPTR
SETB ES ;开放串行中断
BHALT: AJMP $ ;等待中断
乙机中断服务程序:
ORG 0100H
BCINT: MOV A,SBUF ;接收数据
MOV C,P ;奇偶标志赋予C
JNC BEND3 ;C≠l为偶数转至BEND3
ANL A,#7FH ;为奇数删去校验位
BEND3: MOVX @DPTR,A ;存数据
CLR RI ;清接收中断标志
DEC R7
CJNE R7,#00H,BENDl;没接收完转BENDl
CLR ES ;接收完禁止串行中断
CLR TR1 ;定时器l停止计数
AJMP BEND2
BENDl: INC DPTR
BEND2: RETI ;中断返回
【例6-4】设计一个发送程序,将片内RAM 50H~5FH中的数据串行发送,串行口设定为方式2状态。TB8作奇偶校验位。在数据写入发送缓冲器之前,先将数据的奇偶位P写入TB8,这时第9位数据作奇偶校验用。
参考程序如下:
TRT: MOV SCON,#80H ;方式2设定
MOV PCON,#80H ;取波特率为fosc的1/32
MOV R0,#50H ;首地址50H送R0
MOV R7,#10H ;数据长度10H送R7
LOOP: MOV A,@R0 ;取数据送A
MOV C,PSW.0
MOV TB8,C ;P送TB8
MOV SBUF,A ;数据送SBUF启动发送
WALT: JBC TI,CONT ;判断发送中断标志
SJMP WALT
CONT: INC R0
DJNZ R7,LOOP
RET
【例6-5】设计一个接收程序,将接收的16个字节数据送入片内RAM 50H~5FH单元中。设串行口方式3状态工作,波特率为2400bps。定时钟数器Tl为工作波特率发生器时, SMOD=0,计数常数为F4H。
参考程序如下:
RVE: MOV TMOD,#20H ;Tl编程为方式2定时状态
MOV TH1,#0F4H ;计数常数送Tl
MOV TL1,#0F4H
SETB TRl ;启动Tl
MOV R0,#50H ;R0置初值
MOV R7,#10H ;数据长度10H送R7
MOV SCON,#0D0H ;串行El编程方式3接收
MOV PCON,#00H ;置SMOD=0
WAIT: JBC RI,PRI ;等待接收到数据
SJMP WAIT
PRI: MOV A,SBUF
JNB PSW.0,PNP ;奇偶校验判P=R1387
JNB RB8,PER ;出错转至PER结束
SJMP RIGHT
PNP: JB RB8,PER
RIGHT:MOV @R0,A ;数据送缓冲器
INC R0
DJNZ R7,WAIT ;判数据块接完否?
CLR PSW.5 ;正确接收完l6个字节置标志
PER:RET
【例8-1】对8255A各口作如下设置:A口方式0输入,B口方式1输出,C口高位部分为输出,低位部分为输入。设控制寄存器地址为003AH。
按各口的设置要求,工作方式控制字为10010101,即95H。初始化程序段应为:
MOV R0,#3AH
MOV A,#95H
MOVX @R0, A
【例8-2】若要求8255A工作在方式0,且A口作为输入口,B口、C口作为输出口,则8255A的初始化程序如下。
ORG 3000H
MOV A,#90H ;置方式控制字
MOV DPTR,#2503H ;控制寄存器地址
MOVX @DPTR,A ;写控制字
MOV DPTR,#2500H ;A口地址
MOVX A,@DPTR ;从A口读数据
INC DPTR ;B口地址
MOV A,#DATA1 ;需要输出的数据
MOVX @DPTR,A ;将数据送B口输出
INC DPTR ;C口地址
MOV A,#DATA2 ;需要输出的数据
MOVX @DPTR,A ;将数据送C口输出
(2)8255A的C口8位中的任意一位,都可用指令来置位或复位。
【例8-3】若想把C口的第5位PC4置1,相应的控制字为:00001001B=09H,程序如下。
MOV DPTR,#2500H ;设控制寄存器地址为2500H
MOV A,#09H ;控制字
MOVX @DPTR,A ;把控制子送到控制口
【例8-4】已知8255A的端口地址为02E1H~02E4H,请实现对端口C的PC2置位和PC4复位。
解: MOV DPTR,#02E4H ;大于8位的端口地址送DX
MOV A,#05H ;位操作控制字=0000 0101B
MOVX @DPTR,A ;置位PC2
MOV A,#08H ;位操作控制字=0000 1000B
MOVX @DPTR,A ;复位PC4
【例8-5】请在8255A端口C的PC7位输出一个正脉冲(设原来PC7=0)。
解:程序段如下
MOV A, #0FH ;置位PC7,操作控制字=00001111
MOV DPTR,#CTRL_PORT ;控制端口地址
MOVX @DPTR, A ;写入控制端口
CALL DELAY ;延时产生脉宽
MOV A, #0EH ;复位PC7,操作控制字= 00001110
展开阅读全文