PIC微控制器實現氣泡排序演算法
阿新 • • 發佈:2019-02-06
- 編寫子程式paixu,實現1Byte數的順序排列。待排序的10個二進位制數(自定義資料大小)存放在記憶體空間內。
- 編寫巨集定義實現大小比較和換位,入口引數為待比較的兩個資料地址。
- 注意排序過程中需要使用間接定址方式,即利用FSR和INDF兩個特殊功能暫存器實現定址操作。
- 編寫子程式,呼叫巨集定義,使用氣泡排序演算法實現排序。
1、氣泡排序演算法
氣泡排序是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。
氣泡排序演算法的運作如下:
- 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
- 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
- 針對所有的元素重複以上的步驟,除了最後一個。
- 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
2、編寫巨集定義實現大小比較與換位
程式框圖:
;*****************巨集定義*********************************************************
compare_swap macro DATAI,DATAJ,TEMP
BCF STATUS,C ; 標誌位清零
MOVF DATAJ,W
SUBWF DATAI,W ; 比較大小
BTFSC STATUS,C ; TEMP1>TEMP2?
GOTO NEXT1
GOTO NEXT2
NEXT1
swap DATAI,DATAJ,TEMP ; 是,則交換兩者的值
NEXT2
nop ; 否則,不做操作
endm
swap macro DATAI,DATAJ,TEMP
MOVF DATAI,W
MOVWF TEMP
MOVF DATAJ,W
MOVWF DATAI
MOVF TEMP,W
MOVWF DATAJ
endm
進行巨集指令巢狀時,要十分注意巨集指令呼叫與子程式呼叫的區別,否則很容易產生錯誤。例如下面這段程式碼:
BTFSC STATUS,C ; TEMP1>TEMP2?
GOTO NEXT1
GOTO NEXT2
NEXT1
swap DATAI,DATAJ,TEMP ; 是,則交換兩者的值
NEXT2
nop
如不慎寫作:
BTFSC STATUS,C ; TEMP1>TEMP2?
swap DATAI,DATAJ,TEMP ; 是,則交換兩者的值
nop ; 否則,不做操作
就會發生錯誤。
3、編寫子程式,呼叫巨集定義實現排序
子程式框圖:
;*************************子程式************************** ********************
ORG 0x0100
paixu
LOOP1
MOVLW 0x20
MOVWF FSR ; FSR=0x20,起始位置
CLRF COUNT2
LOOP2
MOVF INDF,W
MOVWF DATAI
INCF FSR,F
MOVF INDF,W
MOVWF DATAJ
compare_swap DATAI,DATAJ,TEMP
MOVF DATAJ,W ; 資料還原
MOVWF INDF
DECF FSR,F
MOVF DATAI,W
MOVWF INDF
INCF FSR,F
INCF COUNT2,F ; COUNT2++,COUNT2<9-COUNT1?
MOVF COUNT1,W
SUBWF SIZE,W
BSF STATUS,C
SUBWF COUNT2,W
BTFSS STATUS,C
GOTO LOOP2
INCF COUNT1,F ; COUNT1++,COUNT1<9?
BSF STATUS,C
MOVF SIZE,W
SUBWF COUNT1,W
BTFSS STATUS,C
GOTO LOOP1
NOP
RETURN
;*****************************************************************************
附
完整程式:
list p=16f877A ;標明所用的處理器型別
#include <p16f877A.inc> ;呼叫標頭檔案
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
;*****************巨集定義*********************************************************
compare_swap macro DATAI,DATAJ,TEMP
BCF STATUS,C ; 標誌位清零
MOVF DATAJ,W
SUBWF DATAI,W ; 比較大小
BTFSC STATUS,C ; TEMP1>TEMP2?
GOTO NEXT1
GOTO NEXT2
NEXT1
swap DATAI,DATAJ,TEMP ; 是,則交換兩者的值
NEXT2
nop ; 否則,不做操作
endm
swap macro DATAI,DATAJ,TEMP
MOVF DATAI,W
MOVWF TEMP
MOVF DATAJ,W
MOVWF DATAI
MOVF TEMP,W
MOVWF DATAJ
endm
;*****************變數定義*******************************************************
DATA1 EQU 0x20 ; 待排序的資料
DATA2 EQU 0x21
DATA3 EQU 0x22
DATA4 EQU 0x23
DATA5 EQU 0x24
DATA6 EQU 0x25
DATA7 EQU 0x26
DATA8 EQU 0x27
DATA9 EQU 0x28
DATA10 EQU 0x29
SIZE EQU 0x30 ; 待排序資料個數-1
COUNT1 EQU 0x31 ; 迴圈變數
COUNT2 EQU 0x32
TEMP EQU 0x33 ; 臨時變數
DATAI EQU 0x34
DATAJ EQU 0x35
;*******************************************************************************
ORG 0x0000 ; 復位入口地址
nop ; 相容ICD除錯工具,必須加nop
goto Main ; 跳轉至Main函式
;*************************Main 函式的程式碼***************************************
Main
MOVLW 0x34 ; 資料初始化
MOVWF DATA1
MOVLW 0x53
MOVWF DATA2
MOVLW 0xb5
MOVWF DATA3
MOVLW 0x33
MOVWF DATA4
MOVLW 0xA1
MOVWF DATA5
MOVLW 0x42
MOVWF DATA6
MOVLW 0x11
MOVWF DATA7
MOVLW 0x86
MOVWF DATA8
MOVLW 0x65
MOVWF DATA9
MOVLW 0x76
MOVWF DATA10
MOVLW .9
MOVWF SIZE
CLRF COUNT1 ; 初始化迴圈變數
CLRF COUNT2
CLRF TEMP ; 初始化臨時變數
CLRF DATAI
CLRF DATAJ
CALL paixu ; 呼叫子程式排序
nop
goto $ ; 停機
;*************************子程式************************** ********************
ORG 0x0100
paixu
LOOP1
MOVLW 0x20
MOVWF FSR ; FSR=0x20,起始位置
CLRF COUNT2
LOOP2
MOVF INDF,W
MOVWF DATAI
INCF FSR,F
MOVF INDF,W
MOVWF DATAJ
compare_swap DATAI,DATAJ,TEMP
MOVF DATAJ,W ; 資料還原
MOVWF INDF
DECF FSR,F
MOVF DATAI,W
MOVWF INDF
INCF FSR,F
INCF COUNT2,F ; COUNT2++,COUNT2<9-COUNT1?
MOVF COUNT1,W
SUBWF SIZE,W
BSF STATUS,C
SUBWF COUNT2,W
BTFSS STATUS,C
GOTO LOOP2
INCF COUNT1,F ; COUNT1++,COUNT1<9?
BSF STATUS,C
MOVF SIZE,W
SUBWF COUNT1,W
BTFSS STATUS,C
GOTO LOOP1
NOP
RETURN
;*****************************************************************************
END ; 程式結束