子程式是什麼?
實際程式設計過程中,為減輕程式**的量,將一些經常用到的指令集稱之為子程式;這裡可以模擬一下c語言中的延時函式delay()等等;
功能:為了解決同一組程式**被反覆使用的麻煩操作,每次要用到的時候呼叫一下就好了;
子程式被調執行特點:
1. 被其他程式呼叫;
2. 執行完後又需要把執行流程返回到該子程式的主程式;
~一條華麗的分割線
~~~以上說的內容過於簡單,相信學過一點其他語言的同志都可以深刻理解了,這裡我們主要是針對組合語言進行的講解;來闡述我們經常用高階語言卻習慣性忽視的細節(細節也即是高階語言直接優化,而不被看到的功能)
重點來了!
子程式呼叫時要注意的兩點:
1. 現場的保護和恢復;
2. 主程式與子程式引數的傳遞
現場的保護和恢復
來想乙個場景:
在呼叫子程式之前,微控制器的某個通用單元裡(累加器a)儲存了乙個等子程式執行完畢後繼續用的有價值的資料;但是由於這個通用單元在執行子程式的時候被用了;出子程式後發現那個值已經不復存在了;gg了;
好吧,給予這種情況下,我們有了保護和恢復的說法;
通用單元有:r0~r7,累加器a,資料指標dptr,標誌和狀態等;
引數傳遞
利用累加器傳送引數
這種方式可以直接 「將計就計」,反正值已經在累加器a中了,在子函式中直接用就好了,子程式返回值得時候也是直接返回值給累加器a就好;
舉個栗子:
/*假設記憶體位址30h,31h,32h,33h,分別用來存放a,b,c,d的數值,現在要求除d=a平方+b平方+c平方*/
org 0000h ;設定程式起始儲存位址
start: mov a,30h ;將位址30h中的資料取出來送給累加器a
acall sqr ;呼叫查平方表 (平方表就是db定義的陣列)
mov r1,a ;a平方暫放在r1中
mov a,31h ;將位址30h中的b的值取出來送給累加器a
acall sqr ;呼叫子程式`這裡寫**片`
add a,r1 ;a=a方+b方
mov r1,a ;r1 = a
mov a,32h
acall sqr
addc a,r1
mov 33h,a
sjmp $
;子程式
sqr: mov dptr,#tab ;將平方表的首元素位址給dptr資料指標
movc a,@a+dptr ;將tab平方表中的相應資料值賦予給累加器a
ret ;子程式返回指令,執行後,棧頂的兩個內容彈出送到pc中,sp(棧頂指標)減2;然後將16位位址放入pc中;
tab: db 0,1,4,9,6,25,36,49,64,81 ;db為定義位元組指令,後面的每個資料都佔乙個位元組;
end
利用堆疊傳送引數
這裡補充乙個堆疊概念:
堆疊是什麼:儲存區域;記憶體ram中開闢的一塊儲存區域;
堆疊作用:專門用來暫時存放資料或存放返回位址;
堆疊傳送引數是什麼:
利用堆疊傳遞引數常用於子程式巢狀中長採用的一種方法;
怎樣傳遞引數:
在呼叫子程式之前,用push指令將子程式中所需資料壓入堆疊,
執行子程式時,再用pop指令從堆疊中彈出資料;
舉個栗子:
/*問題:
編寫0!+1!+2!+3!+4!的子程式。
20h單元存放要進行階乘的數,30h單元存放每次呼叫子程式計算後的階乘
遇到的問題在程式的第30行和第31行
*/ org 0000h
mov sp,#60h ;初始化sp=60h;注意,這裡的60h是位址而不是整數;
mov 20h,#0h ;存放要進行階乘的數;
mov r2,#04h ;迴圈次數
mov a,#0h
start: push 20h ;sp=sp+1,將整數20h給位址為61h的堆疊區暫存器
push acc ;sp=sp+1,這裡將acc內儲存的整數值賦予到位址為62h的暫存器單元,這裡不應該是a而是acc
acall mu ;呼叫mu處的子程式,sp=sp+2,將此處pc的位址送給sp
pop acc
pop 30h
add a,30h
inc 20h
djnz r2,start
sjmp $
mu: mov r1,sp ;借用r1為堆疊指標
dec r1 ;程式時要保護現場
dec r1 ;程式時要保護現場
dec r1
dec r1 ;r1指向要進行階乘的數
mov a,@r1 ;取出要進行階乘的數
add a,#02h ; ?為什麼a要加2?是不是和第31行的程式有關?
movc a,@a+pc ;查表 ?cp怎樣從自上而下執行程式的狀態轉變成查表狀態的
xch a,@r1 ;整位元組交換
ret ;返回主程式的位址
tab: db 0,1,2,6,24,120
end
知識補充:
在以上程式**的時候出現過這麼乙個問題:
push a
pop a
報錯:表示式不匹配
push acc
pop acc
不報錯;
錯誤原因:
雖然a和acc是乙個東西;但是……push和pop指令後面一定是直接位址,然而a被編譯成累加器a(非位址),編譯器編譯時a被認為是暫存器,acc被認為是特殊功能暫存器(位址);所以報錯;
基於MCS 51核心的彙編學習筆記
資料傳送類指令 算術運算類指令 只能是8位 add 不帶進製相加 addc 帶進製相加 inc 加1指令 subb 減法指令,運算元 源運算元 cy dec 減1指令 daa 十進位制調整指令 mul 乘法指令 div 除法指令 算術標誌指令將會影響進製標誌cy,輔助進製標誌ac,溢位標誌ov 運算...
基於MCS 51核心的彙編操作符筆記
資料傳送類指令 算術運算類指令 只能是8位 add 不帶進製相加 addc 帶進製相加 inc 加1指令 subb 減法指令,運算元 源運算元 cy dec 減1指令 daa 十進位制調整指令 mul 乘法指令 div 除法指令 算術標誌指令將會影響進製標誌cy,輔助進製標誌ac,溢位標誌ov 運算...
MCS 51和8051的區別
0 本文引自 嵌入式和微控制器系統 mcs是intel公司微控制器的系列符號。intel推出有mcs 48 mcs 51 mcs 96系列微控制器。mcs 51系列即包括三個基本型80c31 8051 8751,以及對應的低功耗型號80c31 8051 87c51,因而mcs 51特指intel的這...