51单片机学习之冒泡排序

目录

前言

一、本篇文章将使用的指令介绍

二、交换数值的实现

2.1 XCH 两个操作数的数值交换

2.2 XCHD 低4位交换

2.3 SWAP 交换高低次位

三、冒泡排序——汇编版本

3.1 小——>大的冒泡排序

3.2 大——>小的冒泡排序

总结


前言

在前面两篇文章中,对单片机有了初步的了解,下面将介绍利用汇编语言实现冒泡排序。


一、本篇文章将使用的指令介绍

MOV  传送字或字节
INC  加1,类比与C语言++
DEC  减1,类比与C语言--
JC   有进位/借位时转移,cy端为进位/借位标志位;当进位/借位时cy为1
CJNE 比较不等转移指令
DJNZ  减一不为0跳转指令
SJMP 短跳转指令
CLR  清零指令
JB   无符号小于则跳转
XCH  交换两个操作数的值指令
SETB 置1

二、交换数值的实现

2.1 XCH 两个操作数的数值交换

         交换两个操作数的值一般用XCH指令实现,下面是该指令是使用格式:

XCH的使用格式: XCH A,SRC(SRC为源操作数)

         观察格式发现第一个操作数只能是累加器A,那么如果要实现R0跟R7内是数值交换怎么做呢?由于第一个操作数被限定为A,那么就需要将R0/R7的其中一个数值给A,再与另外一个数进行交换;而给A数值的R7/R0需要再被A交换或者传数值,代码实现如下:

MOV R0,#5  ;XCH  function:exhange the vail between two number
	MOV R7,#45
	MOV A,R0
	XCH A,R7
	MOV R0,A  ;XCH A,R0
	END      ;结束标志符

        执行XCH指令后的结果为:

        此时可以发现仅仅A与R7的数值进行了交换,而R0几乎没变。这是因为仅仅对R0进行了传送数据的指令操作,而没有对R0进行另外的操作,所以在第五行需要对R0进行操作,如果执行第五行——MOV R0,A 的结果为:

         而如果执行——XCH A,R0,结果为:

         从结果来看,MOV R0,A或者XCH A,R0的最后目的都达到了,不同的区别点就是程序结束后,累加器A的数值不一样。在具体功能的实现下这两者需要加以区分。

        看完XCH的数值交换实现后,你可能会想如果不用XCH能不能实现两个操作数的数值交换呢?结果是肯定的。那么该如何实现呢,这其实与酱油,醋瓶的交换类似。设想一下,你面前由一个红色瓶装醋,一个蓝色瓶装酱油,如果要求将酱油装如红色瓶,醋装入蓝色瓶,该如何操作呢?

没错,就是在用一个空瓶作为中介,借助它实现酱油,醋瓶的交换。由此,可以实现30H单元与50H 单元的数值交换,以60H单元作为中介,代码如下:

MOV 30H,#30H  function:exhange the vail between two number
	MOV 50H,#20H
	MOV 60H,30H
	MOV 30H,50H
	MOV 50H,60H
	END

        结果如下:

        所以实现目的方法有多种,并非唯一的,选择适合自己的方法就行。 

2.2 XCHD 低4位交换

          交换两个操作数的值的低4位一般用XCHD指令实现,下面是该指令是使用格式:

XCHD   A,@Ri

        其中第一个操作数只能是累加器A,第二个操作数只能为寄存器间接寻址。下面实现33H与R7的低四位交换,代码如下:

MOV R0,#33H  
	MOV 33H,#66H
	MOV R7,#22H
	XCH A,R7
	;XCH R1,R0  
	XCHD A,@R0    
	MOV R7,A
	END

         因为指令格式的限定,需要进行传入数据MOV 的操作,初始下33H单元的数值位O*66H,寄存器R7的数值为O*22H,交换低4位后33H单元的数值位O*62H,寄存器R7的数值为O*26H,结果如图所示:

2.3 SWAP 交换高低次位

        交换高低次位的指令为SWAP,是应该单目操作符,下面是该指令是使用格式:

SWAP  A

        下面是实现交换30H单元数据的高低次伟,代码如下:

MOV 30H,#45H
	MOV A,30H  
	SWAP A
	MOV 30H,A
	END

结果由O*45H——>O*54H,如图所示:

三、冒泡排序——汇编版本

3.1 小——>大的冒泡排序

        小——>大的冒泡排序,将两个数进行比较,将大数放后,经过第一趟冒泡排序后,最大的数值便放在了最后,比较次数减一,直到所有所给的数据满足小——>大的顺序时,排序结束。简而言之就是,不断的把大数放后,直到只剩一个数时,排序完成。

        接下来就是具体细节的分析,

  • 交换两个数时使用XCH,需要用到累加器A,那么得把一个数值传入A,并且对操作数的操作能够直接影响原始数据,这里得用到寄存器间接寻址
  • 如何判断数据的排列顺序是否符合小——>大的顺序?这里得用标志位F0进行判断,如果前后两个数的顺序不符合小——>大的顺序,F0为1,即SETB  F0;前后两个数的顺序符合小——>大的顺序,F0为0,即CLR F0。
  • 比较次数如何设定?由原始数据的个数-1开始——第一个数不用比较,毕竟自己跟自己比无大小之分,比较无意义。在经历一趟冒泡排序后,次数继续减一。

这里是10个数的小——>大,冒泡排序,需要比较更多数的话修改41H的源操作数,但不能超过O*FFH,代码如下:

               ;小——>大冒泡排序
	MOV 41H,#10                ;41H存的为排序数字的个数
START:CLR F0                    ;F0作为顺序是否一致的标志位
	MOV R7,41H                 ;R7作为循环次数
	DEC R7                   ;第一个数不用比较,次数减一
	MOV R0,#30H               ;将30日的首地址给R0
	MOV 40H,@R0                ;将R0指向的地址元素给40H,40H作为前数
MAOP_1:INC R0                  ;将下一个元素送给R0
	MOV A,@R0                  ;A作为后数
	CJNE A,40H,NEXT            
	NEXT:JC EXC               ;有进位,说明前数比后数大,跳转EC交换程序
		 XCH A,40H	          ;否则,将后数给40H,作为前数
	     SJMP CONT    
EXC:SETB F0                  ;F0作为表示为,即顺序不满足,小->大
	XCH A,40H                  ;前数与后数交换,此时40H为小数,A为大数
	MOV @R0,A                  ;R0此时指向后数,将大数放后,小数提前,完成两数排序
		DEC R0                 ;R0指向前数
		XCH A,40H              ;保证40日单元始终为大数
		MOV @R0,A
		INC R0                 
CONT:CLR C
	DJNZ R7,MAOP_1             
	DEC 41H                    ;循环一次大数都放到最后,循环次数减一,减小遍历次数
	JB F0,START                ;检查F0顺序,即n个数是否满足小->大
	END

         初始数据的输入,keil的数据输入与vs的输入不同,vs可直接用scanf函数继续数据的输入,而keil得在memory窗口输入,如图所示:

        输入的初始10个数据为: 5  8  1   2  3  41  21  23  7  63。经过第一趟冒泡排序后,结果应为:5  1  2  3   8  21  23   7  41   63,运行程序观察第一趟冒泡排序结果为:

        经过第二趟冒泡排序后,结果应为:1 2  3  5  8  21   7   23   41   63,运行程序观察第二趟冒泡排序结果为:

  经过第三趟冒泡排序后,结果应为:1 2  3  5  8  7   21   23   41   63,运行程序观察第三趟冒泡排序结果为:

        经过第三趟冒泡排序后,结果应为:1 2  3  5  7   8  21   23   41   63,运行程序观察第三趟冒泡排序结果为:

         至此冒泡排序结束,且符合预期结果,说明程序的逻辑与功能实现符合预期,是可行的。

3.2 大——>小的冒泡排序

        下面介绍大——>小的冒泡排序。可以说大——>小的冒泡排序与小——>大的冒泡排序几乎相近,只不过往最后输送的数是大数还是小数。

  接下来就是具体细节的分析,

  • 交换两个数时使用XCH,需要用到累加器A,那么得把一个数值传入A,并且对操作数的操作能够直接影响原始数据,这里得用到寄存器间接寻址
  • 如何判断数据的排列顺序是否符合大——>小的顺序?这里得用标志位F0进行判断,如果前后两个数的顺序不符合大——>小的顺序,F0为1,即SETB  F0;前后两个数的顺序符合小——>大的顺序,F0为0,即CLR F0。
  • 比较次数如何设定?由原始数据的个数-1开始——第一个数不用比较,毕竟自己跟自己比无大小之分,比较无意义。在经历一趟冒泡排序后,次数继续减一。

        这里是10个数的大——>小,冒泡排序,代码如下: 

              ;大——>小
	MOV 41H,#10            ;41H存的为排序数字的个数
START:CLR F0               ;F0作为顺序是否一致的标志位
	MOV R7,41H             ;R7作为循环次数
	DEC R7                    ;第一个数不用比较,次数减一
	MOV R0,#30H                ;将30日的首地址给R0
	MOV 40H,@R0            ;将R0指向的地址元素给40日,40日作为前数
MAOP_1:INC R0                  ;将下一个元素送给R0
	MOV A,@R0                  ;A作为后数
	CJNE A,40H,NEXT            
	NEXT:JNC EXC                ;没有进位,说明前数比后数小,跳转EC交换程序
		 XCH A,40H	           ;否则,将后数给40日,作为前数
	     SJMP CONT    
EXC:SETB F0                    ;F0作为表示为,即顺序不满足,大->小
	XCH A,40H                  ;前数与后数交换,此时40H为大数,A为小数
	MOV @R0,A                  ;R0此时指向后数,将小数放后,大数放前,实现大->小
		DEC R0                ;R0指向前数
		XCH A,40H             ;保证40日单元始终为小数
		MOV @R0,A
		INC R0                 
CONT:CLR C
	DJNZ R7,MAOP_1             
	DEC 41H                     ;循环一次小数都放到最后,循环次数减一,减小遍历次数 
	JB F0,START                 ;检查F0顺序,即n个数是否满足大->小
	END

        这里继续用上面的10个数据: 5  8  1   2  3  41  21  23  7  63。这里不继续展示每趟冒泡排序的结果,直接贴最后结果,如图所示:

        至此大——>小的冒泡排序完成。 


总结

本文仅仅简单介绍了汇编的冒泡排序,对冒泡排序进行了粗略的分析,具体的细节需要自行感受体会。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值