一、 实验要求
实验目的:
- 学习使用汇编语言实现算法设计
- 熟练掌握单片机外部存储空间的访问方法
实验内容:
- 用汇编实现冒泡排序算法。
- 在实验三的代码基础上,利用冒泡排序将DEST中数据从小到大重新排序 。
- 将冒泡排序算法写成子程序。
- 在主程序中,通过设置参数,使用同一个子程序实现从大到小,从小到大排序的自由选择。
二、 实验设计
1.整体思路
对一段数据进行排序,根据7AH寄存器的值决定是从小到大还是从大到小排序。代码主要分为两个子模块:STOB和BTOS。
2.流程图
3.主要模块设计思路及分析
(1)STOB子程序
- 初始化R2和R3为0,用于外层循环计数和内层循环计数。
- 设置R4为NUM,用作循环次数。
- 外层循环(Outer_STOB):通过R4计数,控制排序轮次。
- 内层循环(Inner_STOB):通过R5计数,控制每轮排序的比较次数。
- 从DPTR指向的内存中读取数据并进行比较。
- 如果当前字节小于上一个字节,进行交换。
- 继续内层循环直至完成当前轮次的比较。
- 继续外层循环直至完成所有轮次的比较。
(2)BTOS子程序
- 初始化R2和R3为0,用于外层循环计数和内层循环计数。
- 设置R4为NUM,用作循环次数。
- 外层循环(Outer_BTOS):通过R4计数,控制排序轮次。
- 内层循环(Inner_BTOS):通过R5计数,控制每轮排序的比较次数。
- 从DPTR指向的内存中读取数据并进行比较。
- 如果当前字节大于上一个字节,进行交换。
- 继续内层循环直至完成当前轮次的比较。
- 继续外层循环直至完成所有轮次的比较。
三、 实现效果
由大到小 |
由小到大 |
![]() |
![]() |
四、总结
1.在本次冒泡排序的实验中,参考了C语言的代码思路,采用内外循环的方法来实现内外循环。
2.在实验最开始思考如何进行两个数据大小的比较,发现汇编指令里有的指令无法再K4里执行,最后采用减法来判断两个数据的大小。
3.关于上一个实验程序,不知道是因为代码错误还是思路错误的原因,出现死循环,于是我在程序中添加了一行代码。当LOOP1与LOOP2执行完后,直接跳转到冒泡排序的子程序。
4.本次实验让我掌握了单片机外部存储空间的访问方法。
附录:
ORG 0000H
LJMP MAIN
ORG 2000H
MAIN:
SRC DATA 30H
DEST XDATA 2000H
NUM DATA 20H
MOV A, #01H ; 将值01H存储到A寄存器中
MOV R0, #SRC
MOV DPTR, #DEST
MOV R2, #NUM
MOV R3, #NUM
ACALL LOOP1
DEC R0 ; LOOP1 子程序中R0最后多加了一次,所以要减1
ACALL LOOP2
CHECK:
CJNE R2, #0, CHECK ; 检查R2是否为0,如果不为0则继续循环,避免成为死循环
LOOP1:
MOV @R0, A ; 将A寄存器的值存储到R0指向的地址
INC R0
ADD A, #01H
DJNZ R2, LOOP1 ; 如果R2不等于0,则跳转到LOOP1继续执行循环
RET
LOOP2:
MOV A, @R0 ; 将R0指向的地址的值存储到A寄存器
DEC R0
MOVX @DPTR, A
INC DPTR
DJNZ R3, LOOP2 ; 如果R3不等于0,则跳转到LOOP2继续执行循环
RET
NEXT: SJMP MAIN1 ; 跳入冒泡循环子程序
MAIN1:
CLR 7AH
ACALL ORDERS
SETB 7AH
ACALL ORDERS
SJMP $
ORDERS:
CLR C
JB 7AH, BTOS ; 如果 7AH 置位(非零),则进行从大到小排序
ACALL STOB ; 否则进行从小到大排序
SJMP ENG
STOB:
MOV R2, #0 ; R2 用于外层循环计数
MOV R3, #0 ; R3 用于内层循环计数
MOV R4, #NUM
Outer_STOB:
MOV A,R4
MOV R5, A
DEC R5 ; R5 存储当前轮次内循环次数
MOV R6, #0 ; R6 用于比较次数计数
Inner_STOB:
MOVX A, @DPTR
INC DPTR
MOV R7, A
MOVX A, @DPTR
SUBB A, R7 ; 与上一个字节的数据进行比较
JC Skip_STOB ; 如果 A < 上一个字节的数据,跳过交换
XCH A, R7
MOVX @DPTR, A
MOV A, R7
INC R6
Skip_STOB:
DJNZ R5, Inner_STOB
DJNZ R4, Outer_STOB
SJMP ENG
BTOS:
MOV R2, #0 ; R2 用于外层循环计数
MOV R3, #0 ; R3 用于内层循环计数
MOV R4, #NUM
Outer_BTOS:
MOV A,R4
MOV R5, A
DEC R5 ; R5 存储当前轮次内循环次数
MOV R6, #0 ; R6 用于比较次数计数
Inner_BTOS:
MOVX A, @DPTR
INC DPTR
MOV R7, A
MOVX A, @DPTR
SUBB A, R7 ; 与上一个字节的数据进行比较
JNC Skip_BTOS ; 如果 A > 上一个字节的数据,跳过交换
XCH A, R7
MOVX @DPTR, A
MOV A, R7
INC R6
Skip_BTOS:
DJNZ R5, Inner_BTOS
DJNZ R4, Outer_BTOS
ENG:
END