版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
PIC單片機最常用的幾種指令介紹PIC單片機最常用的幾種指令介紹源程序的編寫主要就是用這些基本的指令實現(xiàn)你的控制任務。但為了增加源程序的可讀性和可維護性,我們引入了偽指令的概念。偽指令本身不會產生可執(zhí)行的匯編指令,但它們可以幫組“管理”你編寫的程序,其實用性和必要性絕不亞于35條正真的匯編指令。我們在此著重介紹最常用的幾種偽指令。#include或include#include偽指令的作用是把另外一個文件的內容全部包含復制到本偽指令所在的位置。被包含復制的文件可以是任何形式的文本文件,當然文件中的內容和語法結構必須是MPASM能夠識別的。最經常被“include”的是針對PIC單片機內部特殊功能寄存器定義的包含頭文件,在MPLAB安裝后它們全部放在路徑“C:\ProgramFiles\MPLABIDE\MCHIP_Tools”下,每一個型號的PIC單片機都有一個對應的預定義包含頭文件,擴展名是“.inc”。除了一些符號預定義文件,你也可以把現(xiàn)有的其它程序文件作為一個代碼模塊直接“包含”進來作為自己程序的一部分。見例3-01。#include;把預定義的PIC16F877A寄存器符號包含到此處#include”math.asm”;把現(xiàn)有的程序文件包含進來作為自己代碼的一部分例3-01請注意被包含文件的引用方式。一種是<>尖括號引用,這種引用意味著讓編譯器去默認的路徑下尋找該文件,MPASM默認的寄存器預定義文件存放路徑即為上面提及的MPLAB安裝后的目錄;另一種是””雙引號引用,這種引用方式的意思是指示編譯器從引號中指定的全程文件路徑下尋找該文件。例3-01中”math.asm”沒有指定路徑,即意味著在當前項目路徑下尋找math.asm文件。如果編譯器找不到被包含的文件,將會有錯誤信息告知。請在你的源程序中盡量用MPLAB標準頭文件定義的寄存器符號。一來這些被定義的寄存器符號和芯片數(shù)據(jù)手冊上的描述一一對應,理解起來即直觀又容易;二來如果用你自己定義符號就缺乏一個大家能一起交流的標準平臺,其他人要解讀你的代碼時將費時費力。故例3-01中的首行#include包含引用偽指令可以說是PIC單片機程序編寫時的標準必備。listlist偽指令可以設定程序編譯時的一些信息,例如所選單片機的型號,編譯時選擇的缺省數(shù)制等。例如:listp=16f877a,r=DEC;單片機型號為PIC16F877A,無特別指明的數(shù)字為十進制數(shù)例3-02如果程序開發(fā)時使用項目管理的模式,則所有l(wèi)ist偽指令可以描述的參數(shù)項都可以在項目的設定選項中通過對話框的形式設定并保存。在此只需對list偽指令稍作了解即可。__config此偽指令的重要作用是把芯片的配置字設定在源程序中,請參閱2.5節(jié)的詳細說明。建議大家盡量用此偽指令把芯片的配置字寫在程序中。__idlocsPIC單片機中有一處非常特殊的標記單元。它獨立于任何其它存儲器,唯一的作用就是作為一個標記。此標記值無法用軟件讀到,讀取和寫入的方法只有通過編程器實現(xiàn)。此標記值沒有讀保護,你可以利用它存放程序的版本或日期等信息。如果需要,則可以用偽指令__idloc在程序中定義具體的值。__idloc0x1234;設定芯片的標記值為0x1234,注意前面有兩個下劃線符例3-03和__config偽指令定義的配置字一樣,用__idloc定義的芯片標記值在最后也會存放在HEX文件中,這就要求編程器能夠解析它。errorlevelerrorlevel的用途是控制編譯信息的輸出顯示。編譯器在編譯你的源程序時會提供很多信息,有些信息是你必須要處理的,例如錯誤信息(Error),只要有錯誤信息存在,你的程序將永遠無法完成編譯;有些可能只需要關注,例如警告信息(Warning);也有一些可能你根本就不感興趣,它們只是一些提示信息(Message)而已。注意出現(xiàn)警告和提示信息時將不會中止編譯器的編譯工作,你的程序將被編譯并最終產生HEX文件。圖3-14中顯示了一個程序編譯后的各種信息實例,其中既有錯誤信息,也有警告和提示信息。我們可以用errorlevel偽指令來控制輸出信息的級別,或刻意關閉/打開一些提示信息。圖3-14編譯信息的輸出顯示級別有三種,分別是0、1和2。級別0代表顯示所有信息,包括各種錯誤、警告和提示信息,如圖3-14所示;級別1代表顯示錯誤和警告信息,忽略提示信息;級別3代表只顯示錯誤信息而忽略警告和提示信息。在任何一個大的級別上還可以對某些信息單獨設定顯示或關閉。每個信息都有一個識別標號,見圖3-14中信息項“[]”中的數(shù)字,打開或關閉某類信息只需在errorlevel偽指令中引用信息識別標號,并在其前面用“+”或“-”號,即代表打開或關閉這一類信息,例如:errorlevel0,-302,-305;顯示所有信息,但不需要302和305這兩類提示信息errorlevel1,+305;顯示錯誤和警告信息,但同時還要關注305類的提示信息#define/#undefine例3-04#define的作用是定義常數(shù)符號,即用一個符號變量替換另一個符號串或變量。被替換的可以是任意字母數(shù)字組成的符號但替換者本身不能是一個純數(shù)字。例如:#defineDELAY_TIME1000;定義常數(shù)符號,即用DELAY_TIME符號代替1000#defineKEY1PORTB,7;用KEY1符號代替端口PORTB的第7引腳例3-05用#define偽指令定義符號后,可使程序中的變量或指令變得更具實際意義,也使程序變得更易維護。指令“btfssPORTB,7”和“btfssKEY1”在事先用了例3-05中的#define后編譯的結果是一樣的,但明顯地后者看起來更容易理解,一看就知道這是在測試編號為KEY1的一個按鍵。而且如果你的硬件設計改動了KEY1所接的單片機引腳,只要改動這一處#define重新定義引腳位置,程序的其它部分無需任何修改,再編譯一次即可得到更新后的軟件代碼。一個好的編程習慣是事先把一些代表實際意義的變量、單片機的輸入輸出引腳在硬件電路中的實際功能等用#define偽指令定義成簡單直觀的符號名字,然后在程序中直接用其符號名字而不用簡單機械的數(shù)字形式。替換的工作由編譯器在編譯時自動完成。它會先掃描你的源程序代碼,把事先#define的符號名改回成被替換的字符串,然后再繼續(xù)編譯生產機器碼。equequ顧名思義是“等于”的意思,其作用和#define偽指令有點類似,也是用一個符號名字替換其它數(shù)字變量,但它只能替換立即數(shù)。如果要替換一個符號名字,則此符號名必須事先用#define或equ偽指令已經定義替換了一個立即數(shù)。例如:#defineMyCount0x70;定義MyCount符號替換立即數(shù)0x70w_tempequ0x20;符號名w_temp等于0x20count1equMyCount;符號名count1等同于MyCount;如果MyCount沒有事先定義則會產生一個錯誤例3-06在絕對定位的編程模式中equ被經常用于定義用戶自己的變量,即用一個符號名代替一個固定的存儲單元地址,上例3-06中的w_temp定義即屬于此類。用equ方式定義的符號在匯編后可以生成相關的調試信息,可以通過各種變量觀察的方式顯示此符號所代表的內存地址處的數(shù)據(jù)內容,但用#define方式定義的符號則不能產生調試信息。要注意equ偽指令本身并沒有限定所定義的一定是一個變量地址,它只是一個簡單的符號和數(shù)字替換而已,其意義必須和具體的指令結合才能確定,如下例3-07中對符號w_temp的理解。w_tempequ0x20;符號名w_temp等于0x20movlwmovwfmovfmovwfmovlwmovwf0x55w_tempw_temp,wFSRw_tempFSR;W=0x55;把W的值送給變量w_temp,(0x20單元內容=0x55);把w_temp單元內容送W,(W=0x55);把W的內容送FSR,(FSR=0x55);把w_temp所代表的立即數(shù)即地址值送給W,(W=0x20);讓FSR指針指向w_temp,(FSR=0x20而不是0x55)例3-07cblock/endc用equ偽指令可以給一個符號變量分配一個地址。但在一個程序設計過程中往往需要定義很多變量,你當然可以給每一個變量逐個用equ的方法分配一個地址空間。但如果變量很多,這樣做就顯得非常麻煩,你必須自己安排每個變量的地址,小心不能出現(xiàn)地址重疊;若要在已定義分配好的變量間插入新的變量,那就必須重新逐個安排隨后變量的地址等等。cblock/endc偽指令可以輕松解決有很多變量定義的場合出現(xiàn)的這些問題,我們把它叫作變量塊連續(xù)定義。具體用法如下:cblock偽指令聲明變量塊的起始地址,endc偽指令聲明變量塊定義結束,cblock/endc中間可以插入任意多的變量聲明。其地址編排由編譯器自動計算:第一個變量地址分配從起始地址開始,然后按所聲明變量保留的字節(jié)數(shù)自動分配后面變量的地址,變量所需保留的字節(jié)數(shù)用“:”加后面的數(shù)字表示,如果只有一個字節(jié)“:1”可以省略不寫。以例3-08來說明:cblock0x20變量定義起始地址為0x20w_tempstatus_tempbuffer:8var1var2endc;w_temp地址為0x20,占一個字節(jié);status_temp地址為0x21,占一個字節(jié);buffer的起始地址為0x22,并保留8個字節(jié)單元;var1的地址為0x2a,占一個字節(jié);var2的地址為0x2b,占一個字節(jié);結束變量連續(xù)定義例3-08用cblock方式定義的變量和用equ方式定義的變量一樣在匯編后可以生成相關的調試信息,可以通過各種變量觀察的方式顯示此符號所代表的內存地址和其中的數(shù)據(jù)內容,所以實際編程時一般無需關心計算每個變量的具體地址。程序員要注意的用這種方式連續(xù)定義很多變量時不要讓變量塊跨越所處bank的邊界。你可以在cblock中隨意插入新定義的變量,或通過改變起始地址的方式使變量塊整個挪到其它內存地址處,地址的更新由編譯器代勞。orgorg用以定義程序代碼的起始地址,通過此偽指令你可以把程序定位到任何可用的程序空間,它實現(xiàn)的是程序代碼絕對定位,如例3-09:Sub1orggotoorgmovwf;...orgreturn0x0000main0x0004w_temp0x0800;定義復位入口地址,以下指令從地址0x0000開始;定義中斷入口地址,以下指令從地址0x0004開始;保存w;其它中斷服務代碼;定義page1的起始地址,以下指令代碼放在page1例3-09只要你認為代碼需要確定放在某一特定地址處,在程序的任何地方都可以用org偽指令重新定義存放的起始地址,且地址順序可以任意編排。但要注意的是若干個確定起始地址的代碼塊不能相互重疊,否則編譯器會報錯,無法得到正確結果。若用可重定位方式開發(fā)指令代碼時一般不能用org偽指令絕對定位代碼。dtdt的作用是定義表格數(shù)據(jù)。在第一章介紹基本匯編指令時已經提到,PIC單片機實現(xiàn)表格定義的最基本指令是“retlwxx”,表格中的每一個字節(jié)數(shù)據(jù)都以指令“retlw”的形式出現(xiàn)。若表格較大,就需要很多“retlw”指令,比較麻煩,可讀性也差。這時我們可以用此“dt”偽指令替代“retlw”實現(xiàn)很多數(shù)據(jù)的表格定義。如例3-10:TabledeaddwfdtdtdtPCL,f01,2,’3’”ABC”;PC相對尋址查表;retlw0;retlw1;retlw2;retlw0x33(’3’的ASCII碼);retlw’A’;retlw’B’;retlw’C’例3-10
de偽指令可以讓你在源程序中定義片內EEPROM的初值。毫無疑問,該條偽指令只適用于那些內含EEPROM數(shù)據(jù)存儲器的單片機,例如:PIC16F87x、PIC16F62x等等。在中檔PIC單片機中,除了PIC16F7x系列外,其它Flash型的單片機都有片上EEPROM,只是字節(jié)數(shù)多少的問題。你可以編寫代碼在程序運行時來設定片內EEPROM數(shù)據(jù)區(qū)的初值,但此EEPROM區(qū)還可以在芯片編程燒寫時通過編程器對其設定初值。對編程器而言EEPROM數(shù)據(jù)區(qū)是程序空間的延伸,它有個特別的編程起始地址0x2100。基于這一前提,我們可以在源程序中利用“org”和“de”偽指令定義片內EEPROM數(shù)據(jù)的初值,這樣最后得到的HEX文件被燒入到單片機內后,EEPROM區(qū)就同時被特定數(shù)據(jù)所初始化??蠢?-11的實例orgdede0x21000,1,2,3”ABCD”;特殊的程序空間起始地址;編程器能識別此地址作為EEPROM數(shù)據(jù)區(qū)的起始地址;EEPROM地址單元[0]=0,[1]=1,[2]=2,[3]=3;[4]=0x41,[5]=0x42,[6]=0x43,[7]=0x44例3-11按例3-11所示的定義,芯片完成編程燒入后,其內部EEPROM區(qū)從0x00單元開始被分別初始化成0x00、0x01、0x02、0x03、0x41、0x42、0x43、0x44。其它未被初始化的EEPROM單元全部是0xff。要注意并不是所有的編程工具都能支持此法定義的EEPROM初始值燒入。能直接掛接在MPLAB環(huán)境下的Microchip原廠或兼容的編程工具都可以支持“de”偽指令定義的EEPROM初值燒入,但其它第三方生產的編程工具就不一定,使用前請咨詢編程器的生產廠商。fillfill偽指令可以實現(xiàn)對程序空間連續(xù)自動填充某一特定的指令數(shù)據(jù),被填充的可以是一個立即數(shù)(實際肯定代表某一條指令),也可以是一條形象的匯編指令?;旧显谝粋€設計中都有一些程序空間沒有寫上具體的指令編碼(空白處),在單片機正常運行時這些地方的指令是不會被執(zhí)行到的。但在有干擾的情況下程序跑飛正好落在這些非法指令處時,就有必要設置軟件陷阱捕捉這些非法跳轉,讓程序恢復正常運行。如果要程序員一個一個地址去分析哪里有空的指令單元然后又用特殊指令一條一條填入,這是根本行不通的。fill偽指令在這時就派上用場了。fill0x0000,5;從當前地址處連續(xù)5個程序字填成0x0000(NOP指令)fillorgNEXT_BLOCK(goto$),NEXT_BLOCK-$;從當前地址開始到標號NEXT_BLOCK前所有程序空間填上;goto$(死循環(huán))指令0x0800例3-12請大家特別注意上例3-12中第二行fill偽指令的用法。在你自己的程序中也可以用同樣的方法把所有未用到的程序空間填上“goto$”這樣一條死循環(huán)的指令。一旦單片機執(zhí)行過程中非法跳到這些指令處時指令運行就將被“俘獲”,停在那里直到看門狗復位,然后程序從頭開始。這是軟件陷阱的最基本處理方法。若填充指令“goto0x0000”直接跳轉到復位地址處可能會有問題,因為goto指令執(zhí)行時必須和PCLATH寄存器配合(跨頁跳轉的問題),若PCLATH[4:3]不為00就不能跳到復位地址0x0000處。在程序跑飛非法跳轉到設定的陷阱處時你又怎能保證PCLATH中的頁面設定為正好指向第0頁?endend偽指令告訴匯編編譯器編譯工作到此為止,end后面所有的信息,不管正確與否,一概不管。絕大多數(shù)情形下你的程序的最后一行應該是“end”。無論如何,end必須出現(xiàn)在程序中,不然編譯器會報錯,無法進行編譯工作。3.2.4MPASM內的直接運算符為了使所編的程序理解更直觀,維護更方便,MPASM匯編器允許你在程序的編寫過程中直接以數(shù)學表達式的形式在指令中實現(xiàn)一些數(shù)字運算的功能。千萬不要誤解成MPASM可以替你生成數(shù)學運算的指令,那可是其它編譯器(例如C編譯器)才能完成的工作。這里講的數(shù)字運算前提是所有參與運算的操作數(shù)全部是明明白白的立即數(shù),如果是符號名字則必須事先用#define或equ偽指令明確定義了的。整個運算過程是由編譯器在掃描你的源程序時進行的,運算結果也只能是一個確定的立即數(shù)。我們將在這里介紹幾種非常有用的運算符。取當前指令的地址值:$你可以在寫程序時給一條指令前加上一個標號,然后直接引用該標而得到此程序字的地址。如果你的程序經常需要用到指令的當前地址或附近的地址值,這樣的標號就需要寫很多且不能重復。用“$”運算符讓匯編器替你計算當前指令所處的位置將有效地減輕你的這份工作量。見例3-12和3-13。;用語句標號得到指令地址HeregotoHere;跳轉到當前地址,程序進入死循環(huán)Delaydecfszcount,fgotoDelay;計數(shù)器減1并判0;跳轉到上一行重復循環(huán);用$運算符得到指令地址而無需定義任何語句標號goto$;跳轉到當前地址,程序進入死循環(huán)decfszcount,f;計數(shù)器減1并判0goto$-1;跳轉到(當前地址-1)處,即上一行,重復循環(huán)例3-13取16位立即數(shù)的高低字節(jié):high和low一個16位的立即數(shù)在8位單片機中必須被拆解成高8位一個字節(jié)(高字節(jié))和低8位一個字節(jié)(低字節(jié))才能用指令一條條處理,類似的處理在對兩字節(jié)變量賦立即數(shù)初值和基于PC相對跳轉查表前設定PCLATH寄存器時經常碰到。MPASM提供了high和low兩個運算符分別計算一個立即數(shù)的高字節(jié)和低字節(jié)。我們看例3-14的代碼實例:;兩字節(jié)變量賦立即數(shù)初值#defineDELAY_TIME.1000;定義一個常數(shù)立即數(shù)movlwlow(DELAY_TIME);取立即數(shù)的低字節(jié)值,經編譯器計算將得到0xe8movwfcount;賦給變量的低字節(jié)movlwhigh(DELAY_TIME);取立即數(shù)的高字節(jié)值,經編譯器計算將得到0x03movwfcount+1;賦給變量的高字節(jié);查表前設定PCLATH寄存器。關于PC相對跳轉的概念詳見1.5.2節(jié)movlwmovwfmovfcallhigh(Table)PCLATHindex,wTable;取查找表入口地址的高字節(jié)值;設定PCLATH寄存器;取查表索引值;調用查表子程序例3-14加減乘除:+-*/實際上前面的很多代碼范例中都已經說明了“+”、“-”運算符的使用方法。“*”和“/”的運算也類似??聪旅胬?-15計算異步串行通訊波特率常數(shù)的方法。;高速異步通信波特率BPS=Fosc/(16*(X+1));故,波特率常數(shù)X=Fosc/(BPS*16)–1#defineBPS#defineFosc;...movlwmovwf.9600.4000000Fosc/(BPS*.16)–1SPBRG;定義工作波特率;定義單片機工作振蕩頻率4MHz;其它代碼;編譯器計算得到.25(10進制25);設定波特率定時寄存器例3-15程序中用了統(tǒng)一的計算公式后,在調試時只要簡單地改變前面的#define語句定義新的波特率或振蕩頻率值,然后重新編譯一次程序即實現(xiàn)了波特率設定代碼的更新,非常方便。移位運算:>>和<<“>>”運算符把一個立即數(shù)算術右移若干位(高位補0),“<<”運算符把一個立即數(shù)算術左移若干位(低位補0)。#definexxxmovlw0x55xxx>>1;W=0x2amovlwmovlwxxx<<21<<7;W=0x54;W=0x80例3-16立即數(shù)邏輯運算:&|^“&”運算符把一個立即數(shù)和另外一個立即數(shù)相“與”;“|”運算符把一個立即數(shù)和另外一個立即數(shù)相“或”;“^”運算符把一個立即數(shù)和另外一個立即數(shù)相“異或”。例3-17的代碼利用異或運算符“^”實現(xiàn)類似于C語言“switch-case”功能的匯編代碼指令,注意例中的VAL1、VAL2、VAL3等判別值都是事先已經定義的立即數(shù)而不是RAM中的變量。;利用異或運算實現(xiàn)類似于C語言的switch-case語句movfswitchVal,w;取分支判斷值.switch(W)xorlwbtfscgotoxorlwbtfscgotoxorlwbtfscgoto;...VAL1STATUS,ZCase_VAL1VAL1^VAL2STATUS,ZCase_VAL2VAL2^VAL3STATUS,ZCase_VAL3;W=W^VAL1;判0標志;caseVAL1:(原始W=VAL1);W=(W^VAL1)^(VAL1^VAL2)=W^VAL2;判0標志;caseVAL2:(原始W=VAL2);W=(W^VAL2)^(VAL2^VAL3)=W^VAL3;判0標志;caseVAL3:(原始W=VAL3);其它case情況判別例3-173.2.5MPASM的宏指令引入宏指令的目的也是為了增強程序的可讀性和易維護性。bankselbanksel和下面的pagesel宏指令可以說是所有宏指令中最好用最有用的了。banksel可以幫助你非常方便地實現(xiàn)寄存器bank的設定。你只需在banksel后給它一個變量名或地址,編譯器會自動按照變量地址所在的bank,自動生成設定STATUS寄存器RP1:RP0位的指令。更聰明的是,編譯器知道你所選的芯片最多有幾個bank,它將用最少的指令完成bank設定。例如:;芯片選擇PIC16F874A,RAM共有2個bankbankselTRISC;編譯后的機器碼bsfSTATUS,RP0;設定TRISC所在的bank(TRISC在bank1);只生成1條匯編代碼;芯片選擇PIC16F877A,RAM共有4個bankbankselTRISC;編譯后的機器碼;設定TRISC所在的bank(TRISC在bank1)bsfSTATUS,RP0bcfSTATUS,RP1;生成2條匯編代碼例3-18同樣的一條“bankselTRISC”指令,針對不同的芯片編譯器生成的匯編代碼可能不同。兩個bank的芯片只要用到RP0一位即可實現(xiàn)bank選擇,banksel宏指令會轉換成一條匯編指令;四個bank的芯片則必須用RP1:RP0兩位一起實現(xiàn)bank選擇,故一條banksel宏指令將轉換成兩條匯編指令。用banksel的好處是顯而易見的,你無需太多關心你準備操作的寄存器落在哪個bank內,編譯器會知道這個寄存器的實際地址,然后替你生成相關的匯編代碼以正確設定bank位;需要時你可以隨意移動變量的定義地址而無需修改其它代碼,只需重新編譯一次即可;另外,如果你用代碼可重定位方式進行軟件開發(fā)時,在寫指令之時根本就無法知道自己定義的變量最后會落在哪個bank中,想自己設定具體的bank都不行。此時,只有用banksel宏指令讓編譯器連接器一起在連接定位后再“自動填入”相關的bank位設定指令。bankisel和banksel類似,不過它對付的是用于寄存器相對尋址的STATUS寄存器中的IRP位。它也會用最少的代碼實現(xiàn)IRP位的設定。如果是只有兩個bank的芯片,用bankisel將不產生任何指令!在代碼可重定位開發(fā)方式下,對可重定位的變量作相對尋址需要設定IRP位時,也只能用bankisel交由編譯器連接器來替你實現(xiàn)。;芯片選擇PIC16F877A,RAM共有4個bankbuffer:8cblockendc0x120;從地址0x120起定義8字節(jié)的數(shù)據(jù)區(qū)bankiselbuffer;用bankisel自動設定IRP位movlwlow(buffer);取buffer的地址(只有低8位)movwfFSR;送給FSR;編譯后的機器碼bsfSTATUS,7movlw0x20movwfFSRpagesel;真正的設定IRP的匯編代碼例3-19pagesel可以幫助你設定程序的頁面。使用方式和banksel相似,只是它改變的是PCLATH[4:3]兩位。該宏指令也同樣將用最少的代碼實現(xiàn)程序頁面設定:程序空間不超過2K字(只有1頁)的將不產生任何匯編代碼;程序空間不超過4K字(最多2頁)的芯片將只生成一條設定PCLATH[3]的匯編代碼;只有超過4K字(最多4頁)的芯片才會生成兩條代碼。同樣,pagesel在代碼可重定位的開發(fā)模式下也是不可或缺的。;芯片選擇PIC16F877A,RAM共有4個頁面org0x0100;在第0頁內mainsub1pageselsub1callsub1pagesel$gotomainorg0x0800return;編譯后的機器碼(main部分);用宏指令設定被調用子程序的頁面;隨后調用該子程序;用宏指令設定當前地址的頁面;循環(huán);第1頁起始;子程序返回mainbsfbcfcallbcfbcfgotoPCLATH,3PCLATH,4sub1PCLATH,3PCLATH,4main;設定sub1所在的頁面;設定當前指令所在的頁面例3-20clrc/setcclrc/setc針對的是狀態(tài)寄存器STATUS中的進位標志位。clrc等同于bcfSTATUS,C;C=0setc等同于bsfSTATUS,C;C=1clrz/setzclrz/setz針對的是狀態(tài)寄存器STATUS中的零標志位。clrz等同于bcfSTATUS,Z;Z=0setz等同于bsfSTATUS,Z;Z=1clrdc/setdcclrdc/setdc針對的是狀態(tài)寄存器STATUS中的半字節(jié)進位標志位。clrdc等同于bcfSTATUS,DC;DC=0setdc等同于bsfSTATUS,DC;DC=1skpc/skpncskpc/skpnc是判狀態(tài)寄存器STATUS中的進位標志位,若條件滿足則程序跳過下一條指令。skpc等同于btfssSTATUS,C;若C=1則程序跳過下一條指令skpnc等同于btfscSTATUS,C;若C=0則程序跳過下一條指令skpz/skpnzskpz/skpnz是判狀態(tài)寄存器STATUS中的零標志位,若條件滿足則程序跳過下一條指令。skpz等同于btfssSTATUS,Z;若Z=1則程序跳過下一條指令skpnz等同于btfscSTATUS,Z;若Z=0則程序跳過下一條指令skpdc/skpndcskpdc/skpndc是判狀態(tài)寄存器STATUS中的半字節(jié)進位標志位,若條件滿足則程序跳過下一條指令。skpdc等同于btfssSTATUS,DC;若DC=1則程序跳過下一條指令skpndc等同于btfscSTATUS,DC;若DC=0則程序跳過下一條指令bc/bncbc/bnc宏指令的作用有點象51單片機的“jc/jnc”指令。它判別狀態(tài)寄存器STATUS中的進位標志位,按進位標志實現(xiàn)程序的分支跳轉。如例3-21。Carry1movlwaddwfbcnop;...nopbc等同于btfscgotobnc等同于btfssgoto0x31sum,fCarry1XXXSTATUS,CXXXYYYSTATUS,CYYY;W=0x31;sum=sum+W;如果發(fā)生進位就跳轉到Carry1處執(zhí)行;如果沒有進位則繼續(xù)執(zhí)行bc的下一條指令;如果C=1就跳轉到標號XXX,否則程序執(zhí)行bc的下一條;如果C=0就跳轉到標號YYY,否則程序執(zhí)行bnc的下一條例3-21請不要被bc/bnc這樣“一條”指令所迷惑,它實際上是由兩條匯編指令組成,且用到了“goto”實現(xiàn)跳轉,故在用此宏指令前注意頁面的設定。bz/bnz同bc/bnc一樣,只不過判別的是狀態(tài)寄存器STATUS中的零標志位。Matchmovlwxorwfbznop;...nop0x55flag,wMatch;W=0x55;flag=0x55?;Z=1,flag=0x55,跳轉到Match處執(zhí)行;Z=0,繼續(xù)執(zhí)行bz的下一條指令bz等同于btfscgotobnz等同于btfssgotobdc/bndcXXXSTATUS,ZXXXYYYSTATUS,ZYYY;如果Z=1就跳轉到標號XXX,否則程序執(zhí)行bz的下一條;如果Z=0就跳轉到標號YYY,否則程序執(zhí)行bnz的下一條例3-22同上,判別的是狀態(tài)寄存器STATUS中的半字節(jié)進位標志位。bdc等同于btfscgotobndc等同于btfssgotoXXXSTATUS,DCXXXYYYSTATUS,DCYYY;如果DC=1就跳轉到標號XXX,否則程序執(zhí)行bdc的下一條;如果DC=0就跳轉到標號YYY,否則程序執(zhí)行bndc的下一條例3-用戶自定義宏除了MPASM內帶的宏指令外,按實際開發(fā)的需要和個人的習慣,程序員可以自己定義任意形式的宏指令。大量使用定義合理的宏指令可以使程序的可讀性大大提高,也更容易移植。自己定義宏指令時須遵循一些語法規(guī)則。宏指令的定義由“宏指令名“開始,后跟關鍵詞“macro”,其后可以帶若干宏參數(shù),也可以不跟任何宏參數(shù);然后從下一行起開始寫基本的匯編指令或已被認可的其它宏指令(宏嵌套);指令可以是任意多行,最后以關鍵詞“endm”結束整個宏定義,例如:;定義宏指令實現(xiàn)一個字(兩字節(jié)數(shù))加1的功能IncWordmacroincfskpnzincfendmwordValwordVal,fwordVal+1,f;IncWord是宏指令名,wordVal是宏參數(shù);下面為宏的實體(實際的匯編指令);對字的低字節(jié)加1,如果結果為0則為字節(jié)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 四川省綿陽市梓潼縣2026屆九年級上學期1月期末考試物理試卷答案
- 衛(wèi)生檢查題目及答案
- 網(wǎng)格員考試題及答案
- 六年級樂趣作文300字4篇
- 二十屆四中全會考試測試卷及答案
- 電纜敷設施工技術要領
- 2026屆山東省淄博市高三上學期期末考試(摸底質量檢測)歷史試題(含答案)
- 社群運營管理實操考試題及答案
- 社會實踐考試試題及答案
- 青霉素過敏考試題及答案
- 2025南航機械復試試題及答案
- 急性胰腺炎診療指南解讀2025
- 遼寧省建筑施工安全生產標準化考評實施細則
- 電站火災事故應急預案
- GJB827B--2020軍事設施建設費用定額
- 娃娃菜栽培技術
- 工業(yè)鍋爐司爐課件
- 數(shù)字營銷專業(yè)人才培養(yǎng)方案
- 新疆概算管理辦法
- 女性中醫(yī)健康養(yǎng)生講座
- 《養(yǎng)老服務政策法規(guī)與標準》智慧健康養(yǎng)老服務專業(yè)全套教學課件
評論
0/150
提交評論