1. 程式人生 > >PIC微控制器實現氣泡排序演算法

PIC微控制器實現氣泡排序演算法

  • 編寫子程式paixu,實現1Byte數的順序排列。待排序的10個二進位制數(自定義資料大小)存放在記憶體空間內。
  • 編寫巨集定義實現大小比較和換位,入口引數為待比較的兩個資料地址。
  • 注意排序過程中需要使用間接定址方式,即利用FSR和INDF兩個特殊功能暫存器實現定址操作。
  • 編寫子程式,呼叫巨集定義,使用氣泡排序演算法實現排序。

1、氣泡排序演算法

氣泡排序是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。

氣泡排序演算法的運作如下:

  • 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
  • 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
  • 針對所有的元素重複以上的步驟,除了最後一個。
  • 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。

2、編寫巨集定義實現大小比較與換位

程式框圖PIC氣泡排序演算法-比較與交換

;*****************巨集定義*********************************************************
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、編寫子程式,呼叫巨集定義實現排序

子程式框圖:PIC氣泡排序

;*************************子程式************************** ********************
    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                              ; 程式結束