分支与循环程序设计实验 (第二次实验)

第一篇文章,将自己的微机原理课程实验报告放在这里,给有需要的人参考

一、任务要求

1. 设有8bits符号数X存于外部RAM单元,按以下方式计算后的结果Y也存于外部RAM单元,请按要求编写程序。

2. 利用51系列单片机设计一个24小时制电子时钟,电子时钟的时、分、秒数值分别通过P0、P1、P2端口输出(以压缩BCD码的形式)。P3.0为低电平时开始计时,为高电平时停止计时。设计1s延时子程序(延时误差小于10us,晶振频率12MHz)。

提高部分(选做):

a. 实现4位十进制加、减1计数,千位、百位由P1口输出;十位、个位由P2口输出。利用P3.7状态选择加、减计数方式。

    b. 利用P3口低四位状态控制开始和停止计数,控制方式自定。

二、设计思路

1.用不断比较大小的方式实现三分支结构。首先通过MOVX指令将片外RAM数据传送到累加器A中,并将结果备份到寄存器R0中。根据A的最高位是正还是负,进行第一次跳转,若A为负,则直接执行取反的程序,若A为正,再通过用A减去40后,若Cy位为零,则执行第一个分支程序,若Cy位为1,则跳转到SWL程序。在SML程序中,再判断X与20的大小,从而执行相应的处理程序。通过几次比较,便得到了A属于哪个范围区间并执行相应程序。最后再将存储在A、B中的程序转移到片外RAM中。

2.程序的编写分为主程序和子程序,主程序用于实现正确的时分秒的输出,子程序用于实现一秒延时。首先通过对P3.0高低电平的判断进行计时或停止,当进行计时,先调用一秒延时子程序,再进入输出时分秒的程序,然后回到对P3.0高低电平判断的程序。在一秒延时子程序中,利用三重循环结构,采用了软件方法来进行延时。在时分秒输出的部分中,延时一秒后对秒数进行加一,然后进行BCD码转换,之后再判断是否满60秒,若满60秒,则对秒数清零,然后分钟数加一,再判断是否满60分钟;若不满60秒,则返回主程序之初。从分钟数到时钟数的进位以此类推。

3.(提高题)程序采用P3端口的低四位和第七位作为控制信号,当P3端口低四位全为零时开始计数,否则等待暂停。首先通过循环等待程序判断P3端口低四位是否全为零,若全为零,则再根据P3.7的高低电平来进入不同的程序。P3.7为1则加法计数,为0则减法计数。对于加一计数,先对个位进行加一,BCD码转换后,通过CY将十位的进位加到百位中;对于减一计数,首先判断P2是否为零(个十位是否为零),若不为零则加99H再BCD码来实现减一运算,若P2为零,则直接赋值99H;然后通过P1对百千位进行判断,若不为零则通过和前面同样方法置为零,若为零则直接加99H。

三、资源分配

1.需要用到DPTR来做寄存器间接寻址,用A,B存放中间运算结果,用Cy位来判断,用R0备份X。片外RAM的0000H单元中存放X,片外0001H和0002H单元存放运算结果。

2.用R0存放小时数,用R1存放分钟数,用R2存放秒钟数。用P0端口输出小时数,用P1端口输出分钟数,用P2端口输出秒数,用P3端口的零号位来控制计时或停止的操作。用R5、R6、R7来实现三重循环结构从而实现延时一秒的要求。

3.需要用到P3端口的低四位和第七位来作为控制信号,需要用到P2来输出个十位,用P1来输出百千位。

四、流程图

1.8位符号数分段计算

2.时分秒时钟程序

3.P1、P2端口计数程序

五、源代码 (含文件头说明、语句行注释)

1.      ;signed.asm

        ;有符号数散转程序,实现分段函数运算

MAIN:   MOV DPTR, #0000H

        MOVX A, @DPTR  

        MOV R0, A       ;备份数到R0寄存器中

        JB ACC.7, QFN   ;A为负数则跳到QFN

        CLR C

        SUBB A, #28H    ;A与40相减,通过CY判断大小

        JC SML          ;Cy为负,说明A小于40,则跳到AML

        CLR C          

        MOV A, R0

        MOV B, A

        MUL AB          ;第一种情况求X平方,积的高八位在A,低八位在B

        JIAOHUAN:MOV R1, A

        MOV A, B

        MOV B, R1       ;交换A,B中的数,使得最终积的高八位在DPTR的低地址,低八位在高地址

        LJMP CUN

QFN:    CPL A           ;取反后跳到CUN程序

        LJMP CUN

SML:    CLR C           ;对X小于40时的处理

        MOV A, #14H

        SUBB A, R0

        MOV A, R0  

        JNC QFN     ;X小于20,跳到QFN程序取反

        CLR C              

        MOV B, #2H

        DIV AB          ;X在20到40之间,进入第二分支程序

CUN:    INC DPTR        ;把算出来的值存储到外部RAM中的程序

        MOVX @DPTR, A

        INC DPTR

        MOV A, B

        MOVX @DPTR, A

        SJMP $

        END

2.      ;CLK.asm

        ;用汇编实现时钟计数

        ORG 0000H

        LJMP MAIN

        ORG 2000H

MAIN:   MOV SP, #30H        ;初始化

        MOV R0, #00H        ;存时寄存器

        MOV R1, #00H        ;存分寄存器

        MOV R2, #00H        ;存秒寄存器

        MOV P0, #00H

        MOV P1, #00H

        MOV P2, #00H

WAIT:   JB P3.0, BREAK      ;若P3.0为高电平,则一直停留在此处

BEGIN:  LCALL DELIS         ;若为低电平进入一秒延时子程序

        LJMP LOOP

BREAK:  SJMP WAIT

LOOP:   MOV A, R2               ;秒数计时

        ADD A, #01H

        DA A

        MOV P2, A

        MOV R2, A

LOOP1:  CJNE R2,#60H,LOOP4  ;计满60秒向分钟数进一

        MOV R2, #00H

        MOV A, R1

        ADD A, #01H

        DA A

        MOV P1,A

        MOV R1,A

LOOP2:  CJNE R1, #60H, LOOP4    ;计满60分向时钟数进一

        MOV R1, #00H

        MOV A, R0

        ADD A, #01H

        DA A

        MOV P0, A

        MOV R0, A

LOOP3:  CJNE R0,#24H,LOOP4  ;计满24时

        MOV R0, #00H

LOOP4:  LJMP WAIT              ;判断完是否时分秒数是否有进位后回到等待程序

DELIS:  MOV R7, #46         ;延时子程序

        DE:MOV R6, #88      ;1

        DE1:MOV R5, #122    ;1

        DE2:DJNZ R5, DE2    ;2

        DJNZ R6, DE1        ;2

        DJNZ R7, DE         ;2

        RET                ;3+

        END

3.      ;test.asm

        ;四位十进制数加减计数

        ORG 0000H

        LJMP MAIN

        ORG 2000H

       

MAIN:   MOV A, P3

        ANL A, #0FH

        CJNE A, #0, MAIN    ;判断P3的低四位是否为零

        JNB P3.7, SUBER     ;P3.7为零则执行减法,否则执行加法

ADDER:  CLR C              

        MOV A, P2          

        ADD A, #1           ;个位加一

        DA A                ;将二进制调整为十进制

        MOV P2, A          

        MOV A, P1          

        ADDC A, #0          ;十位有进位则百位加一

        DA A       

        MOV P1, A

        LJMP MAIN

SUBER:  CLR C

        MOV A, P2

        CJNE A, #0, SUBER1  ;个十位为零则执行下去,否则跳到SUBER1

        MOV P2, #99H        ;个十位为零,直接置99H,同时向百位借一

        MOV A, P1          

        CJNE A, #0, SUBER2  ;判断百千位是否为零

        MOV P1, #99H        ;百千位为零,直接置99H

        LJMP MAIN

SUBER1: ADD A, #99H         ;个位减一

        DA A                ;二进制转为十进制

        MOV P2, A

        LJMP MAIN

SUBER2: ADD A, #99H         ;百位减一

        DA A                ;二进制转为十进制

        MOV P1, A

        LJMP MAIN

        END

六、程序测试方法与结果

1.对程序编译后进入调试界面,通过Register窗口观察DPTR、A、B及R0的变化。在Memory 1窗口中输入x:0000H,通过鼠标直接点击内存单元0000H对应的值,即可修改片外RAM的值,分别输入不同区间的值进行运算,运算结果符合预期要求。

2.对程序编译并将晶振频率修改为12MHz后,进入调试界面,打开Peripherals窗口的四个Port窗口,此时发现四个端口均输出高电平。将程序全速运行,可以看到P0-P2窗口均清零了,暂停程序,此时程序停留在WAIT中。继续将程序全速运行,点击P3.0将其置零,P2开始变化,并且计满60后P1变为1,说明程序设计思路正确。将P3.0置高电平,P2端口暂停变化,再暂停程序,此时程序停留在WAIT中,符合预期。最后在子程序的RET处设置断点,将P3.0置低电平,全速运行程序,当程序运行到第一个时间断点后将时间t1复位,

,再将程序全速运行,此时t1为

,误差为12微秒,比要求的10微秒以内多了至少2微秒。这是因为用软件延时1s并不能做到很准确,且由于三重循环结构,使得循环次数的计算也麻烦了起来,只能大致地通过估算和调试确定最接近的数值。

3. 对程序编译后进入调试界面,通过Peripherals窗口将P1-P3的状态显示出来,控制P3端口的低四位和第七位作为控制信号。先将程序全速运行,此时P1与P2无变化,将P3的低四位置零,可以发现P1与P2开始快速变化;改变P3的第七位,转换计数模式,P1与P2仍在快速变化,通过逻辑分析仪来分析P2端口是递增计数还是递减计数。

将P3.7置一为加一计数模式,由波形窗口可以看到P2的波形如下:

将P3.7置零为减一计数模式,P2波形如下:

由测试结果可知,本实验结果符合预期要求

七、实验问题分析与对策

实验问题分析:在第二个实验的延时一秒子程序中采用了软件延时,但精度不高,存在12us的误差。

对策:采用硬件延时,使用单片机里的定时器外设,能更大地提高定时的精度。

思考题

    1.实现多分支结构程序的主要方法有哪些?举例说明。

1.方法一:采用分支地址表:

        MOV DPTR, #BRATAB       ;取表首地址

        MOV A, R3

        ADD A, R3               ;A<-R3*2

        JNC NADD

        INC DPH

NADD:   MOV R4,A               ;暂存A

        MOVC A, @A+DPTR     ;取分支地址高8位

        XCH A, R4

        INC A

        MOVC A, @A+DPTR     ;取分支地址低8位

        MOV DPL, A              ;分支地址低8位送DPL

        MOV DPH, R4         ;分支地址高8位送DPH

        CLR A

        JMP @A+DPTR         ;转相应分支程序

BRATAB:DW SUBR0            ;分支地址表

        DW SUBR1

        ……

        DW SUBR7

方法二:采用转移指令表

        MOV DPTR, #JMPTAB       ;取表首地址

        MOV A,R3

        MOV A,R3

        JNC NADD

        INC DPH             ;有进位加到DPH

NADD:   JMP @A+DPTR         ;转相应分支程序

JMPTAB:AJMP SUBR0              ;转移指令表

        AJMP SUBR1

        ……

        AJMP SUBR7

方法三:采用地址偏移量表:

        MOV DPTR, #DISTAB          ;取表首地址

        MOV A,R3                   :表的序号数送A

        MOVC A, @A+DPTR         ;查表

        JMP @A+DPTR            ;转相应分支程序

DISATAB:DB SUBR0-DISTAB        ;地址偏移表

        DB SUBR1-DISTAB

        ……

        DB SUBR79-DISTAB

        ……

SUBR0:      ……  

SUBR1:     ……

2.在编程上,十进制加1计数器与十六进制加1计数器的区别是什么?怎样用十进制加法指令实现减1计数?

答:由于数据在单片机中以二进制的形式保存,所以数据在单片机中只能完成十六进制加1计数器,用INC指令即可实现。而十进制加1计数器,则需低位满10进1,在编程上,需要用ADD A, #01H和DA A两条指令来实现。若要用十进制加法指令实现减一计数,可用ADD A, #99H和DA A指令进行进制调整实现。

  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值