单片机原理和开发应用(6) 第六讲 学习与实验(二)

🏠 首页 《无线电》杂志 1991年 🔗 第1期 🔗 第24页 分类:无线电技术自学经验交流 🔗 周振安 🔗

本讲我们将学习逻辑运算类指令,循环转移类指令的功能和用法,了解子程序和堆栈的概念和用法,以及了解I/O 口的简单操作方法。

逻辑运算和循环转移类指令

表1列出了18条逻辑运算指令、17条控制转移指令及6条循环指令的助记符、功能说明和指令周期数。下面我们仍以TD-Ⅰ型机为例进行了解指令功能利用法的实验,拥有TD-Ⅱ、Ⅲ型机的读者可参照文中程序编制方法,在TD-Ⅱ、Ⅲ型机上进行实验。

图1
图1 🔍原图 (976×1968)

[实验1] 逻辑“与”指令实验。

逻辑“与”操作的符号为“∧”。0∧0=0,0∧1(或1∧0)=0,1∧1=1。利用“与”指令可以实现对某存储单元清零或者对其中的某些位清零。例如ANL TH 0,#0 FH指令可将定时/计数器TH 0的高4位清零。

本实验进行FBH∧0 FH操作,列出竖式如下:

1111 1011 (FBH)

∧ 0000 1111 (0FH)

—————————————

0000 1011 (0BH)

实验子程序如下:

PRO:MOV A,#0 FBH;(A)←FBH

ANL A,#0 FH ;(A)←(A)∧0 FH

RET ; 返回

机器码为0100H:74 FB 54 OF 22。键入学习程序和上述实验子程序,执行后应显示0BH。

[实验 2] 逻辑“或”指令实验。

逻辑“或”指令操作的符号为“∨”。 0∨0=0,1∨0(或0∨1)=1,1∨1=1。利用“或”指令可以对某个字节的某些位同时置1而不破坏源操作数。请读者列出竖式计算05H∨33H的结果,然后做下面实验:

PRO: MOV P1,#05H;(P1)←05H

MOV A #33H;(A)←33H

ORL A, P1 ;(A)←(A)∨(P1)

RET ; 返回

机器码为0100H:75 90 05 74 33 45 90 22。结果应显示37H。把学习程序中的MOV P1,A指令去掉换成空操作NOP,即F5 90换成00 00。执行后显示05H,说明逻辑“或”操作并未影响P1中原有内容。

[实验 3] 逻辑“异或”指令实验。

逻辑“异或”操作的符号为“3。03ɑ13=0,14ɑ03=1。利用“异或”指令将某单元自身相“异或”可实现清零。请列出竖式计算55H3H,然后进行下面实验:

PRO:MOV A, #55H;(A)←55H

MOV 40H,#00H;(40H)←00H

XRL A, 40H;(A)←(A)340H)

RET ; 返回

机器码为0100H:74 55 75 40 00 65 40 22。执行结果应显示55H。将0104H单元中00H换成55H,结果应显示00H(V1~V8全灭)。

[实验4]利用左移指令实现乘2运算。

请用竖式计算29H×2(即29H+29H),然后做下面实验:

图2
图2 🔍原图 (797×162)

机器码为0100H:74 29 33 22。结果显示52H。

[实验 5] 利用循环移位指令实现累加器A中高半字节内容与低半字节内容互换。实验子程序如下:

PRO:MOV A,#38H;(A)←38H

RL A/RL A/RL A/RL A;移位4次

RET ;返回

机器码为0100H:74 38 23 23 23 23 22。结果显示83H。请改用RR A指令重新实验一下。

[实验 6]根据累加器内容进行跳转指令的实验。

这类指令有JZ、JNZ和CJNZ指令,它们分别判断(A)=0,(A)颍ˋ)≠nnH条件满足时进行跳转。表1指令中的地址偏移量rel用来指示跳转方向和长度。当rel>0时,表示向地址增加方向跳转;当rel<0时,表示向回跳转。rel>0时,其值rel=[目标地址]-{[跳转指令地址]+[该指令字节数]};rel<0时,则需用补码表示,即我们在上一讲中说的7D=1时该数表示带符号数的负数,这时,rel=FFH-{[跳转指令地址]+[该指令字节数]-[目标地址]}+01H。

下面的实验子程序为关键字搜索子程序。在片内RAM的20H、21H单元中存放着5FH、30H这两个数据,该程序用来查找这一段存储区中有无关键字30H。实验子程序如下:

图3
图3 🔍原图 (891×705)

机器码为0100H:75 20 5F 75 21 30 78 20 7A 02 B6 30 02 E8 22 08 1A BA 00 F6 74 00 22。其中标号LOOP1地址为010AH,标号LOOP2地址为010FH,标号A地址为0111H。从LOOP1跳转到LOOP 2的地址偏移量rel=010F-010A-3=02,从A处跳转到LOOP 1的地址偏移量rel=FF-0111-3+010A+01=F6。运行上述程序应显示关键字存放的地址值21H。

[实验 7] 循环转移指令实验。

这类指令助记符为DJNZ,它以工作寄存器Rn或片内RAM单元为循环计数器,每运行该指令一次,循环计数器内容减1并继续循环,直到循环计数器内客减至0才停止循环。下面实验子程序是利用循环转移指令对片外扩展RAM中的0220H~027FH单元进行清零的子程序。

PRO: MOV R 2,#60 H ;置循环计数器初值

MOV DPTR,#0220 H ;设存储区首地址

MOV A, #00 H ;(A)←00H

LOOP: MOVX @DPTR,A ;清零

INC DPTR ;地址加1

A:DJNZ R2,LOOP; ;全清完否?

RET ;清完则返回

机器码为0100 H:7 A 60 90 02 20 74 00 F0 A3 DA FC 22。读者可试着计算从A跳转到LOOP的 地址偏移量rel应为FCH。执行学习程序,待V1~V8全熄灭后,检查6116中0220H~027FH单元内容应全为00 H。把子程序中指令DJNZ R2, LOOP换成DEC R2及CJNE R2,#00H,LOOP指令再试,结果应一样。

[实验8] 利用无条件转移指令编制一个简易键盘监控程序。

在键盘监控程序中,通常将各个命令键的服务子程序(KEYn)的入口地址排成一个散转表(TABLE)。程序不断查询各个键,当有键按下后,程序将该命令键的键值送累加器A,根据A的内容跳转到散转表中相应的键服务子程序入口,再由该入口进入键服务子程序。程序如下:

图4
图4 🔍原图 (909×1063)

机器码为0100H:E5 90 54 0F B4 0F 03 02 01 00 64 0F 75 F0 03 A4 90 01 20 73/0120 H:02 01 40 02 01 43 02 01 49/0140 H:74 00 22 75 90 3F 02 01 00 75 90 CF 02 01 00。运行该程序后,用一个1~5 kΩ电阻串接一根导线,一端接地,另一端分别触碰8031单片机的0 P 1、1 P 1端,这时V1~V8应分别显示3 FH和CFH,即V3V4、V1V2交替发光。

[实验 9] 调用子程序实验

在程序设计中,常常出现多处都需要完成相同的处理功能。为了简化程序,可将这段被多处用到的程序分离出来,并赋予名称和返回命令(RET),我们称这样的程序为子程序。子程序除可被主程序调用(LCALL、ACALL)外,还可以被另一个子程序调用,这种情况被称为子程序嵌套。

下面我们编制一个延时1秒的延时子程序。

图5
图5 🔍原图 (886×438)

程序中R2、R3、R4分别放有小、中、大循环的循环初值da1、da2、da3。系统工作主频为f\(_{osc}\)=6MHz,工作周期为Tosc=1/f\(_{osc}\)。8031单片机1个机器周期为工作周期的12倍,即T=12Tosc=2μs。有

{[(3×T\(_{NOP}\)+TDJNZ)×da3+T\(_{DJNZ}\)+TMOV]×da2+

T\(_{DJNZ}\)+TMOV}×dal×T=1(秒)

设da3=100,da2=10,则解得dal=100。即有(R4)=64H、(R3)=0AH、(R2)=64H。

把这些值代入程序中,则有延时1秒的延时子程序机器码为0200H:7A 64 7B 0A 7C 64 00 00 00 DC FB DB F7 DA F3 22。

为了演示该子程序,我们编制1个轮流显示1秒钟0FH或F0H的程序如下:

PRO: MOV P1,#0FH; 0100H: 75 90 0F

LCALL DELAY: 0103H: 12 02 00

MOV P1,#F0H: 0106H: 75 90 F0

LCALL DELAY: 0109H: 12 02 00

LJMP PRO ; 010CH: 02 01 00

堆栈及其实验

当CPU中止执行主程序而转去执行子程序时,需要对断点(即主程序中调用子程序指令下一条指令的地址)加以保护,以便执行完子程序后能准确返回断点,继续执行主程序。为此8031单片机在片内RAM专门划出一段存储区用作断点和其它内容的保护区,这段存储区就是我们所要介绍的堆栈。堆栈的地址由片内RAM的81H单元(表示为SP,称作堆栈指针)的内容指示。8031单片机的堆栈是向上生长的,即栈底设在片内RAM地址较小的位置,每当压入堆栈一个数据时,堆栈指针SP内容自动加1;每当从堆栈弹出一个数据时,堆栈指针SP内容自动减1。单片机复位后,堆栈指针SP内容自动设为07H,即栈底在07H。片内RAM07H~7FH都可用作堆栈。堆栈区的大小可由指令指定,当需要重新设置堆栈时,例如栈底设在50H,则可用指令MOV SP,#50H来实现,此时片内RAM的50H~7FH都被设为堆栈区。

使用调用子程序指令时,只有断点被保护。如果同时要对“现场”进行保护(保护某些专用寄存器或地址单元内容),则应用PUSH指令将这些现场内容压入堆栈。如果有多项内容需要入栈保护,一定要注意“先入后出,后入先出”的栈入、栈出顺序。另外,执行PUSH或调用子程序指令时,SP内容先加1,然后再压入数据到堆栈,所以堆栈将从08H开始。

[实验10] 观察堆栈情况的实验

ORG 0000H

MAIN: MOV P1,#00H;送P1口00H

PUSH P1; 将P1内容00H压入堆栈

MOV 40H, #33H;(40H)←33H

PUSH 40H; 将40H内容33H压入堆栈

LCALL PRO; 调用子程序

断点: POP 40H; 将40H内容弹出堆栈

POP P1; 将P1内容弹出堆栈

STOP: LJMP STOP; 停止

ORG 0100H

PRO: MOV P1, #0FH;(P1)←0FH

MOV R 0 ,#07H ;送栈底地址

MOV DPTR, #0207H ;送外部RAM区首地址

MOV R2 ,#05H ;送堆栈长度

LOOP:MOV A ,@R0 ;堆栈内容送入A中

MOVX DPTR,A ;A中内容送外部RAM

INC R0 ;堆栈地址加1

INC DPTR ;外部RAM地址加1

DJNZ R2,LOOP ;堆栈内容全送完否?

MOV A ,81H ;完,把SP内容进入A中

MOV DPTR,#0200H ;指定外部RAM地址

MOVX@DPTR,A ;将SP内容送外部RAM

RET ;返回

上述程序有3处参与堆栈操作,先压入堆栈00H,又压入33H,调用子程序时断点000DH被压入堆栈(先压低位0DH,后压高位00H)。该程序机器码为0000H:75 90 00 C0 90 75 40 33 C0 40 12 01 00 D0 40 D0 90 02 00 11/0100 H: 75 90 0F 78 07 90 02 07 7A 05 E6 F0 08 A3 DA FA E5 81 90 02 00 F0 22。执行之,待V1~V8显示00H(全灭)后,检查0207H以后内容:从0208H起到020BH单元内容分别为00H、33H、0DH、00H,0200H中放入的堆栈指针SP内容为0BH。从程序执行结果看到,主程序赋予P1内容为00H,子程序将P1内容变为0FH,由于采用了入栈保护PUSHP1及出栈弹回POP P1,故P1内容未受影响。如果去掉POP P1(即把000FH:D0 90改为00 00),则显示内容变为0FH,P1原有内容受到影响。

I/O口简单实验

8031单片机一般只能提供给用户一个8位I/O口,即P1口。P0口每位的驱动能力为8个LSTTL(低功耗肖特基晶体管晶体管逻辑)负载,P1~P3口每位的驱动能力为4个LSTTL负载(10mA以下)。当8031单片机的P1口用来驱动外设时,需要根据外设负载大小选择不同的驱动电路。例如驱动15mA左右的LED发光二极管时,驱动器可选一般的反相器、缓冲器等;如果驱动多只LED或继电器时,则应选择驱动能力较大的元器件如SN75452(300mA)、MC1413(500 mA)或三极管9013、9012、8050及8550。

[实验11] 利用P1口做一个简单的应答电路。

图6
图6 🔍原图 (401×295)

该电路的电路图如图1所示。现在我们编制一个程序,使得开关S1每按下一次,VH1状态翻转(由亮→灭或由灭→亮)一次。程序如下:

图7
图7 🔍原图 (900×839)

机器码为0000H:02 01 00/010 0H:E5 90 54 01 70 FA 7A 02 12 02 02 E5 90 54 01 70 EF E5 90 54 01 60 FA B2 91 80 E5。

程序采取了消除开关接通或断开时产生的抖动的措施,这也是实用程序中常用到的。

电路的连接方法:为了锻练硬件电路设计能力,建议把图1电路单做在一块板上。由于从下一讲开始我们还要做诸如RAM扩展、I/O扩展等实验,这些实验中电路连线密度较大,一般单面电路板无法完成,所以这里推荐使用《无线电》1990年第12期介绍的“万次多用实验电路板”。该板使用寿命根长,IC及模拟器件可灵活安排,很适合本次讲座学习与实验及开发应用部分的需要。另外也可选用面包板进行实验,但面包板存在一个严重缺陷,就是使用几次后,接脚变松,易出现虚接现象。尤其对布线密度较大的电路,一旦出现这类问题,查找起来非常麻烦。从学习(开发)机中引出电源和各种信号线的方法是将一个40脚IC插座“趴伏”于8031单片机芯片之上(注意缺口方向应一致),使插脚与IC引脚一一对应并焊牢。VCC、地线、0P1、1P1以及以后用到的P1口其它引线、P2口、P3口、P0口等引线均可由此插座引出。低8位地址线0A~7A可用同样办法从地址锁存器74LS373上获得。为保证引出可靠方便,可再找一IC插座将需要引出信号焊线引出,使用时将这只IC插座插到8031上的IC插座即可,不用时可拔下。按上述方法连好图1电路后,键入本程序和实验9的延时程序,就可以运行实验了。(周振安)