如何在89C51/52下,将片外RAM中的一段内容,无损移动到片外RAM中的任意地方
最近学校里单片机课程做了个实验,如下:实验指导书上给的代码:
不得不说这个loop看得头有点晕,不过好在大概明白是怎么跑的了,而且还发现一个潜在的bug,如果目的区域和源区域没有重合,当然没问题,但是一旦有重合区域,源内容就会失真,演示图如下:
我本来想如果重合了,就不处理了,后来想了想,如果从后往前传呢?于是更好的办法就有了:
这样不管是向前还是向后传送,都能无损移动了,关键是选对移动的方法(向前:从后往前移动;向后:从前往后移动)
改进代码如下:
;说明:
; 此程序将89C51/89C52单片机的片外RAM中的一段字符串,
; 整体移动至片外RAM的任意地方,源字符串所在位置将被清零。
;R2、R3存【源字符串的首地址】(16BIT,R2高R3低)
;R4、R5存【写入目标的首地址】(16BIT,R4高R5低)
;R6、R7存【字符串长度】,也就是字符串中字符的总个数(为16位无符号正整数)
;运行前,请在仿真软件中手动给上述寄存器赋值
ORG 0000H
LJMP MAIN
ORG 0033H
MAIN:
;安排额外的缓存地址
CACHE_0 EQU 30H
CACHE_1 EQU 31H
;记录寄存器地址,方便PUSH和POP(堆栈操作只能跟direct)
DR2 EQU 02H
DR3 EQU 03H
DR4 EQU 04H
DR5 EQU 05H
DR6 EQU 06H
DR7 EQU 07H
;A=E0H
DRA EQU 0E0H
;运行前先保存参数
PUSH DR6
PUSH DR7
PUSH DR2
PUSH DR3
PUSH DR4
PUSH DR5
;SJMP ICP1
;=================================================================
ICP1: ;INITIAL_CHECK_POINT_1,初始检查点1
;如果R6、R7均为0(传送个数为0),直接结束
;只要有一个不为0,就跳转至初始检查点2,否则结束程序
CJNE R7,#00H,ICP2
CJNE R6,#00H,ICP2
LJMP FINISH
;=================================================================
ICP2: ;INITIAL_CHECK_POINT_2,初始检查点2
;比较【源】和【目的】两个首地址的大小,并安排传送的策略方法
P2H_1: ;P2H_1:先比较高位
MOV A,R4
MOV CACHE_0,R2
CJNE A,CACHE_0,P2H_2
;高位相等,还得判断低位,跳“P2L_1”
SJMP P2L_1
P2H_2: ;P2H_2:高位不等
;
;【目的】高位大于【源】,即【目的】>【源】
;选择方法2(从后往前传送),先跳转至准备工作“RST_H”
JNC RST_H
;
;【目的】高位小于【源】,即【目的】<【源】
;选择方法1(从前往后传送),由于首地址已在寄存器中准备好,
;于是直接跳转至方法1(从前往后传送)
SJMP SG_T_1
P2L_1: ;P2L_1:高位相等,比较低位
MOV A,R5
MOV CACHE_0,R3
CJNE A,CACHE_0,P2L_2
;低位也相等⇩⇩⇩
;高低位均相等,只要传送个数大于零(上面“初始检查点1”已保证),
;也是合法的,效果是字符串保持不变;
;放行,下面直接选择方法1。
SJMP SG_T_1
P2L_2: ;P2L_2:低位不等(高位相等)
;
;【目的】低位大于【源】(高位相等),即【目的】>【源】
;选择方法2(从后往前传送),先跳转至准备工作“RST_H”
JNC RST_H
;
;【目的】低位小于【源】(高位相等),即【目的】<【源】
;选择方法1(从前往后传送),由于首地址已在寄存器中准备好,
;于是直接跳转至方法1(从前往后传送)
SJMP SG_T_1
;=================================================================
RST_H: ;RESET_TO_HIGH_ADDRESS
;将【源】和【目的】的地址重设为最后面的地址,准备从后往前传送
;
;个数-1得Δ(Δ的高位存CACHE_0,低位存CACHE_1)
CLR CY
MOV A,R7
SUBB A,#1
MOV CACHE_1,A
MOV A,R6
SUBB A,#00H
MOV CACHE_0,A
;源首地址 + Δ = 源末地址, 覆盖源 首地址R2、R3
CLR CY
MOV A,CACHE_1
ADDC A,R3
MOV R3,A
MOV A,CACHE_0
ADDC A,R2
MOV R2,A
;目的首地址 + Δ = 目的末地址,覆盖目的首地址R4、R5
CLR CY
MOV A,CACHE_1
ADDC A,R5
MOV R5,A
MOV A,CACHE_0
ADDC A,R4
MOV R4,A
;
;准备工作完成,跳“方法2”,从后往前传送
SJMP SG_T_2
;=================================================================
SG_T_1: ;SINGLE_TRANSPORT_METHOD_1,方法1,从前往后传送
;=================================
;(1)取数:
MOV DPL,R3
MOV DPH,R2
MOVX A,@DPTR
;===================
PUSH DRA
;【源】清零
CLR A
MOVX @DPTR,A
;===================
;【源】数据指针+1,指向下一个单元
INC DPTR
;保存即将【读取】的下一个单元的数据指针
MOV R3,DPL
MOV R2,DPH
;
;=================================
;(2)传送:
MOV DPL,R5
MOV DPH,R4
POP DRA
MOVX @DPTR,A
;
;【目标】数据指针+1,指向下一个单元
INC DPTR
;保存即将【写入】的下一个单元的数据指针
MOV R5,DPL
MOV R4,DPH
;=================================
;跳转至方法1对应的剩余个数检查点
SJMP NUM_CK_1
SG_T_2: ;SINGLE_TRANSPORT_METHOD_2,方法2,从后往前传送
;=================================
;(1)取数:
MOV DPL,R3
MOV DPH,R2
MOVX A,@DPTR
;===================
PUSH DRA
;【源】清零
CLR A
MOVX @DPTR,A
;===================
;【源】数据指针-1,指向下一个单元
ACALL DEC_DPTR
;保存即将【读取】的下一个单元的数据指针
MOV R3,DPL
MOV R2,DPH
;
;===================
;(2)传送:
MOV DPL,R5
MOV DPH,R4
POP DRA
MOVX @DPTR,A
;
;【目标】数据指针-1,指向下一个单元
ACALL DEC_DPTR
;保存即将【写入】的下一个单元的数据指针
MOV R5,DPL
MOV R4,DPH
;===================
;跳转至方法2对应的剩余个数检查点
SJMP NUM_CK_2
NUM_CK_1: ;NUMBER_CHECK_1
;操作前是当前数字对应的编号,操作后是下一个数对应的编号
ACALL DEC_NUM
;比较减一后是否为零
;如不为零,说明还没有移动完,进行下一次循环
CJNE R7,#00H,SG_T_1
CJNE R6,#00H,SG_T_1
;如为零,说明结束了
SJMP FINISH
NUM_CK_2: ;NUMBER_CHECK_2
;操作前是当前数字对应的编号,操作后是下一个数对应的编号
ACALL DEC_NUM
;比较减一后是否为零
;如不为零,说明还没有移动完,进行下一次循环
CJNE R7,#00H,SG_T_2
CJNE R6,#00H,SG_T_2
;如为零,说明结束了
SJMP FINISH
DEC_DPTR: ;DPTR自减1函数
CLR CY
;低8位减法,并保存
MOV A,DPL
SUBB A,#1
MOV DPL,A
;高8位减法,并保存
MOV A,DPH
SUBB A,#00H
MOV DPH,A
;返回
RET
DEC_NUM: ;剩余个数(编号)自减1函数
CLR CY
;低8位减法,并保存
MOV A,R7
SUBB A,#1
MOV R7,A
;高8位减法,并保存
MOV A,R6
SUBB A,#00H
MOV R6,A
;返回
RET
FINISH:
;恢复输入的参数
;交换【源】和【目标】的地址,
;软件中复位CPU后,下一次模拟运行时字符串就能移回原位
POP DR3 ;R5-->R3
POP DR2 ;R4-->R2
POP DR5 ;R3-->R5
POP DR4 ;R2-->R4
;个数保持不变
POP DR7 ;R7-->R7
POP DR6 ;R6-->R6
;
MOV PCON,#01H ;待机
;
NOP ;多一行NOP,防止模拟执行时在程序末尾报“access violation”错误
END
本人单片机刚刚入门,抱着玩一玩的想法分享这段内容,各位就当看看热闹好了,大佬轻喷:lol 汇编大佬!牛的 兄弟,过来人给你个忠告,别学汇编,玩单片机就学C,Python,我大学也学的汇编,找工作都不用汇编,汇编过时了,但是有一个好处,节省空间 汇编是基础,可以学习,了解一下就可以了。
工作还得用C nohao8024 发表于 2023-5-11 08:51
兄弟,过来人给你个忠告,别学汇编,玩单片机就学C,Python,我大学也学的汇编,找工作都不用汇编,汇编过时 ...
确实,不过学校的单片机期末考试还得应付一下:lol AWGemini 发表于 2023-5-11 08:04
汇编大佬!牛的
哪里哪里,刚刚入门:rggrg
页:
[1]