專注差異化嵌入式產(chǎn)品解決方案 給智能產(chǎn)品定制注入靈魂給予生命
提供開發(fā)工具、應(yīng)用測試 完善的開發(fā)代碼案例庫分享
從全面的產(chǎn)品導(dǎo)入到強(qiáng)大技術(shù)支援服務(wù) 全程貼心伴隨服務(wù),創(chuàng)造無限潛能!
PIC12F509 - 繞過堆棧限制
12C5系列PIC只有一個兩級堆棧,它將嵌套子程序調(diào)用的數(shù)量限制為兩個。這可能是一個非常嚴(yán)重的限制。
(16C84有一個八級堆棧,它允許嵌套的子程序達(dá)到八個深度。我無法想象一個程序,這是不夠的)。
在以下程序中,提供了另一個用戶堆棧,它為程序員提供了替代的“調(diào)用”和“返回”功能。
請注意,使用最高數(shù)據(jù)地址實(shí)現(xiàn)用戶堆棧。這個想法是用戶堆棧從1FH開始增長,而用戶變量從07H及以上分配。因此,使用這種方法允許的嵌套程度是完全變量空間(25)減去在程序中用作變量的字節(jié)數(shù)。
這種方法還有兩個局限性;
1.只有程序計數(shù)器的低字節(jié)保存在用戶堆棧中。因此,這限制了所有函數(shù)的調(diào)用以及函數(shù)的實(shí)現(xiàn)到同一頁面。
但是,這并不妨礙人們將程序分成幾頁并在每頁上實(shí)現(xiàn)每個被調(diào)用的函數(shù)。當(dāng)然,不同頁面上相同的函數(shù)實(shí)現(xiàn)必須具有不同的名稱。也就是說,一定要小心并思考。但是,隨著12C5XX的價格下降到僅僅1.00美元,我們需要思考!
這種分離程序的方法在另一個涉及I2C總線的討論中顯示。
請參考程序STACK_1.ASM,它會持續(xù)閃爍LED指示燈。請注意,主調(diào)用例程SUB1,DELAY,SUB2和DELAY然后循環(huán)返回以重復(fù)該過程。
FSR寄存器初始化為最高數(shù)據(jù)位置01FH。
每個“呼叫”包含以下說明。
MOVF PCL,W; 將PCL提取到W ADDWF OFFSET,W; 加4 MOVWF INDF; 保存到FSR DECF FSR 指向的位置,F(xiàn); 用于下一個子程序GOTO SUB1; 打開LED
RET_POINT1:; …程序的繼續(xù)
在上文中,請注意,獲取程序計數(shù)器的低字節(jié)的當(dāng)前內(nèi)容。要返回的地址(RET_POINT1)通過添加4來計算,并將其保存到用戶堆棧指針指向的位置。然后遞減堆棧指針以容納下一個返回地址。最后,執(zhí)行跳轉(zhuǎn)到該函數(shù)。
在子例程中,首先執(zhí)行任務(wù)。然后使用以下代碼實(shí)現(xiàn)“返回”。
; 任務(wù)執(zhí)行INCF FSR,F(xiàn); 返回MOVF INDF,W MOVWF PCL
在上文中,用戶堆棧指針遞增以便指向包含存儲在調(diào)用例程中的程序計數(shù)器的值的位置。這被取出并放在程序計數(shù)器的低字節(jié)中。因此,執(zhí)行在調(diào)用例程的返回點(diǎn)繼續(xù)。
; STACK_1.ASM(12F509); ; 說明如何使用用戶堆棧來實(shí)現(xiàn)“調(diào)用”和“返回”。; 這在12F509上尤為重要,因為疊加限于; 兩個級別。; ; 閃爍GPIO0上的LED,250 ms開啟和250 ms關(guān)閉。
列表p = 12F509
include __CONFIG 1AH
LOOP1 EQU 07H; 用于定時環(huán)路LOOP2 EQU 08H OFFSET EQU 09H
ORG 000H
MOVLW 1FH; 初始化FSR以指向“堆疊” MOVWF FSR的頂部
MOVLW .4 MOVWF OFFSET; 偏移初始化為4
MOVLW 1EH; 最小符號位是輸出TRIS GPIO TOP : ; 保存堆棧上的返回地址MOVF PCL,W; 獲取PCL,添加4并保存在ADDWF OFFSET,W 位置; FSR MOVWF INDF DECF FSR 指出,F(xiàn); dec堆棧指針用于下一個子程序GOTO SUB1; 打開LED
MOVF PCL,W ADDWF OFFSET,W MOVWF INDF DECF FSR,F(xiàn) GOTO DELAY; 250毫秒延遲
MOVF PCL,W ADDWF OFFSET,W MOVWF INDF DECF FSR,F(xiàn) GOTO SUB2; 關(guān)閉LED
MOVF PCL,W ADDWF OFFSET,W MOVWF INDF DECF FSR,F(xiàn) GOTO DELAY; 250毫秒延遲
GOTO TOP
SUB1:BCF GPIO,0; 邏輯零點(diǎn)亮LED
; 這三行是返回INCF FSR,F(xiàn)的等價物; 增量FSR MOVF INDF,W; 獲得返回地址MOVWF PCL; 并放入程序計數(shù)器
SUB2:BSF GPIO,0; 邏輯1關(guān)閉LED INCF FSR,F(xiàn); 返回MOVF INDF,W MOVWF PCL
延遲:; 運(yùn)行時將LOOP1設(shè)置為.250,將LOOP2設(shè)置為.110。; 這將導(dǎo)致250毫秒的延遲。MOVLW .250 MOVWF LOOP1 OUTTER:MOVLW .110; 當(dāng)設(shè)置為.110 MOVWF LOOP2 INNER:NOP NOP DECFSZ LOOP2,F(xiàn) 時接近1.0毫秒延遲; 減量和離開結(jié)果為LOOP2 ; 如果為零則跳過下一個語句
GOTO INNER DECFSZ LOOP1,F(xiàn) GOTO OUTTER
INCF FSR,F(xiàn); 返回MOVF INDF,W MOVWF PCL
結(jié)束
在程序STACK_2.ASM中,“調(diào)用”和“返回”是使用已標(biāo)記為GOSUB和RET的宏實(shí)現(xiàn)的。請注意,宏使程序更容易理解。
; STACK_2.ASM。; ; 與STACK_1.ASM相同,但使用宏實(shí)現(xiàn)。; ; 版權(quán)所有,Peter H. Anderson,MSU,1997年6月1日
列表p = 12F509 #include __CONFIG 1AH
; 宏定義了GOSUB MACRO arg1; 使用用戶定義的堆棧保存返回地址MOVF PCL,W; 并跳轉(zhuǎn)到指定的例程。ADDWF OFFSET,W MOVWF INDF DECF FSR,F(xiàn) GOTO arg1
ENDM
RET MACRO; 從堆棧INCF FSR,F(xiàn) MOVF INDF,W MOVWF PCL 獲取返回地址
ENDM
LOOP1 EQU 0CH; 用于定時環(huán)路LOOP2 EQU 0DH OFFSET EQU 0EH
ORG 000H
MOVLW 1FH; 初始化FSR以指向“堆疊” MOVWF FSR的頂部
MOVLW .4 MOVWF OFFSET; 將OFFSET初始化為4
MOVLW 1EH TRIS GPIO; 最小符號位定義為輸出TOP:GOSUB SUB1 GOSUB DELAY GOSUB SUB2 GOSUB DELAY GOTO TOP
SUB1:BCF GPIO,0 RET SUB2:BSF GPIO,0 RET DELAY :; 運(yùn)行時將LOOP1設(shè)置為.250,將LOOP2設(shè)置為.110。; 這將導(dǎo)致250毫秒的延遲。MOVLW .250 MOVWF LOOP1 OUTTER:MOVLW .110; 當(dāng)設(shè)置為.110 MOVWF LOOP2 INNER:NOP NOP DECFSZ LOOP2,F(xiàn) 時接近1.0毫秒延遲; 減量和離開結(jié)果為LOOP2 ; 如果零GOTO INNER DECFSZ LOOP1,F(xiàn) GOTO OUTTER ,則跳過下一個語句
RET
結(jié)束