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