实验-循环程序的设计(汇编语言与接口技术)
本次实验掌握了51单片机片内/片外存储器的数据存取操作。(1)通过实践,学会了在Keil中查看片外RAM(X:2000H)的方法,以及使用MOVX指令读写片外存储区的技巧。(2)在编程方面,理解了子程序的现场保护机制(PUSH/POP Acc和PSW)和RET返回指令的用法,同时认识到SJMP $指令的作用是让程序原地循环,常用于调试或维持系统状态。(3)实验还巩固了逆序拷贝等数据处理方法,加深了
目录
一、 实验要求
(1)向起始地址为SRC的片内存储中,顺序写入NUM个单字节数(数值不限),并以$字符(ASCII码)结尾。
(2)从SRC中,向起始地址为DEST的片外存储中,逆序拷贝之前存储的NUM个单字节数,并以$字符结尾。
(3)将上述两个操作写成两个子程序。
二、 实验设计
2.1 整体思路
(1)向起始地址为SRC的片内存储中,顺序写入NUM个单字节数(数值不限),并以$字符(ASCII码)结尾。
设定SRC的地址和NUM的地址,设定NUM的值(循环的次数)写入NUM地址中。设定A的初始值为1H。
首先我们需要判断NUM的值是否为0,如果为0,直接存入‘$’符号,如果不为0,则进入循环。
在循环中,将A中的值存入到SRC地址中,每循环一次,SRC的地址加一,A的值加一(可以替换为其他逻辑),循环次数减一。直到NUM循环次数为0时,表示存入完成。此时我们在当前的地址中存入‘$’符号,结束子程序。
(2)从SRC中,向起始地址为DEST的片外存储中,逆序拷贝之前存储的NUM个单字节数,并以$字符结尾。
因为需要逆序拷贝,所以我们需要寻找上面存入的最后一个数据,即地址值为(@SRC+NUM-1),将它赋值给以起始地址为DEST的片外存储中,每循环一次,(@SRC+NUM-1)地址值减一,以起始地址为DEST的片外存储地址值加一,循环次数减一。当循环次数为0时,在当前的地址中存入‘$’符号,结束拷贝子程序。
(3)将上述两个操作写成两个子程序。
将存入数据和拷贝数据写成两个子程序,在主程序中调用每一个子程序。每个子程序要注意现场保护(开头要将Acc和PSW进栈,结尾要把他们出栈)。子程序完成后要用RET返回。
2.2 流程图

2.3 主要模块设计思路及分析
(1)存入数据模块
使用寄存器R0作为指向片内存储地址的指针,初始化为SRC地址。
使用寄存器R1来控制循环次数,初始化为NUM,代表要写入的字节数。
将累加器A初始化为 1,作为第一个要写入的值。
首先我们需要判断NUM的值是否为0,如果为0,直接存入‘$’符号,如果不为0,则进入循环。
进入循环,每次循环将A的值写入R0指向的地址,然后更新地址指针R0和累加器A的值(+1),并减少循环次数R1(-1)。通过DJNZ R1, COPY_LOOP判断循环次数是否为 0,如果不为 0 则继续循环。
循环结束后,将‘$’字符写入当前地址,作为结尾标志。
(2)拷贝数据模块
首先设置源地址指针和目的地址指针以及循环控制变量。
将SRC地址加载到R0,作为源地址指针。
将NUM值加载到R1,作为循环控制变量,表示要拷贝的字节数。
通过计算NUM加上SRC地址再减一,得到源地址的末尾地址,并将其重新赋值给R0,这样R0就指向了源数据的最后一个字节。
将DEST地址加载到数据指针DPTR,作为目的地址指针。
进入循环进行数据拷贝。从源地址R0读取一个字节到累加器A。使用MOVX指令将A中的内容写入到目的地址DPTR。目的地址指针DPTR加一,源地址指针R0减一,实现逆序读取源数据,并减少循环次数R1(-1)。
通过DJNZ R1, COPY_LOOP判断循环次数是否为 0,如果不为 0 则继续循环。
循环结束后,将$字符写入目的地址的末尾。
(3)子程序模块
将存入数据和拷贝数据写成两个子程序,在主程序中调用每一个子程序。每个子程序要注意现场保护(开头要将Acc和PSW进栈,结尾要把他们出栈)。子程序完成后要用RET返回。
三、 实现效果
3.1 存入数据
(1)设置NUM的值:

如图可以看到:
将NUM的值设为10(0AH)存入NUM的地址20H中。
(2)循环存入数据:

如图可以看到:
将A的值循环存入以SRC为起始地址的源地址中。
(3)循环结束存入‘$’:

如图可以看到:
循环结束,将‘$’(24H)存入最后的地址中。
3.2拷贝数据
(1)逆序拷贝数据:

如图可以看到:
程序将以SRC为起始地址的数据逆序拷贝到以DEST为起始地址的存储区内。
(2)循环结束存入‘$’:

如图可以看到:
循环结束,将‘$’(24H)存入最后的地址中。
四、源代码
//1.向起始地址为SRC的片内存储中,顺序写入NUM个单字节数(数值不限),并以$字符(ASCII码)结尾。
//2.从SRC中,向起始地址为 DEST的片外存储中,逆序拷贝之前存储的NUM个单字节数,并以$字符结尾。
//3.将上述两个操作写成两个子程序。
ORG 0000H
LJMP MAIN
ORG 2000H
MAIN:
SRC DATA 30H
DEST DATA 2000H
NUM DATA 20H
MOV A, #0AH ; 将立即数0AH加载到累加器A中 ,为需要循环的次数
MOV R0, #NUM ; 将NUM(实际上是20H)加载到寄存器R0中
MOV @R0, A
ACALL WRITE_TO_SRC ; 调用写入子程序
ACALL COPY_TO_DEST ; 调用复制子程序
SJMP $
// 子程序:向SRC写入NUM个字节并以'$'字符结尾
WRITE_TO_SRC:
PUSH PSW
PUSH Acc
MOV R0, #SRC ; 将SRC地址加载到R0寄存器
MOV R1, NUM ; 将NUM值加载到R1寄存器 ,为需要循环的次数 ,10次
MOV A, #01H ;数值为1开始写入
WRITE_LOOP:
JZ WRITE_FINISH ; 如果NUM为0,则跳转到WRITE_FINISH
MOV @R0, A ;将A的值存入SRC地址中
INC R0 ;地址加一
INC A ; 示例:每次循环增加A的值(可以替换为其他逻辑)
DJNZ R1, WRITE_LOOP ; 减1并判断R1(循环次数)是否为0,不为0则继续循环
WRITE_FINISH:
MOV A, #'$'
MOV @R0, A ; 将'$'字符存储在最后
POP Acc
POP PSW
RET
// 子程序:将SRC中的数据逆序复制到DEST并以'$'字符结尾
COPY_TO_DEST:
PUSH PSW
PUSH Acc
MOV R0, #SRC ; 将SRC地址加载到R0寄存器
MOV R1, NUM ; 将NUM值加载到R1寄存器
MOV A, NUM
ADD A, R0
ADDC A, #-1
MOV R0, A
MOV DPTR, #DEST ; 将DEST地址加载到DPTR(用于片外数据存储器访问)
COPY_LOOP:
MOV A, @R0
MOVX @DPTR, A ; 将A的内容写入到DEST地址
INC DPTR ; DEST地址加1
DEC R0 ; SRC地址减1(逆序)
DJNZ R1, COPY_LOOP ; 减1并判断R1是否为0,不为0则继续循环
; 写入'$'字符到DEST的末尾
COPY_FINISH:
MOV A, #'$'
MOVX @DPTR, A
POP Acc
POP PSW
END
五、总结和思考
本次实验掌握了51单片机片内/片外存储器的数据存取操作。
(1)通过实践,学会了在Keil中查看片外RAM(X:2000H)的方法,以及使用MOVX指令读写片外存储区的技巧。
(2)在编程方面,理解了子程序的现场保护机制(PUSH/POP Acc和PSW)和RET返回指令的用法,同时认识到SJMP $指令的作用是让程序原地循环,常用于调试或维持系统状态。
(3)实验还巩固了逆序拷贝等数据处理方法,加深了对指针操作(R0、DPTR)和循环控制(DJNZ)的理解。
这些知识为后续嵌入式开发奠定了重要基础。
更多推荐



所有评论(0)