;********************************************************************** ; File WK_PCHG.asm * ; Purpose : 展示如何使用 PIC 的 Wake-Up from "Pin Change" 的功能 * ; 1. PIC MCU 在 Mid-Range (PIC16C6XX & PIC16C7XX) 或更高階的產品皆俱* ; 備此一功能 * ; 2. PIC 可於 SLEEP MODE 時被致能的中斷來喚醒 * ; 3. 可省下因使用 Watchdog Timer 喚醒而增加的耗電流 * ; 4. 若善加規劃(將I/O Pin 設定為已知電位並且讓外部的負載不耗費電流) * ; 的話, 耗電流往往只有 1 ~ 2 uA 左右 * ; 5. 使用中斷源來喚醒 CPU 需注意其在 SLEEP 時是否尚可動作 * ; (SLEEP 時 CLOCK 已停止, 故需用到內部 Fosc 的周邊亦無法用來做為 * ; 喚醒的來源, 如使用 Fosc/4 的 Timer0,1,2 及內部 Fosc 的 AD , 但* ; 若 AD 使用內部 RC 為 ADCLK 或用外部的 CLOCK 為 Timer0 及 * ; Timer1 的 CLOCK 來源則無此限制) * ; 6. RB4 .. RB7 的 Pin Change 中斷為一理想的喚醒來源, 因 PORTB 有內 * ; 建的提昇電阻, 可有效率地支援按鍵掃瞄的功能 * ; * ; 7. WK_PCHG 使用 MPLAB-ICD 所附送的 DEMO BOARD 為基礎, 並於 RB4,RB5* ; 各加上一對 GND 動作的按鍵來測試 Wake-up from Pin Change 的動作 * ; 8. RB6 & RB7 因保留給 ICD 除錯用, 故在此不予使用 * ; 9. 用 MPLAB-ICD 直接模擬, 但注意不要在 PIC SLEEP 時下達任何 Debug * ; 的 COMMAND ! 可利用程式執行中下 COMMAND 或設定 Break Point 來做* ; 必要的除錯動作 * ; * ; 10.程式的動作大致如下 : * ; a. RESET 後設定 PORTB , PORTC 的輸出/輸入模式 * ; b. 將旗號 FLAG_INC 設為 "1" * ; c. 將 PORTC 清為 "0" * ; d. 主程式以 FLAG_INC & FLAG_DEC 的值來決定進入遞增或遞減的迴圈 * ; e. 迴圈中不斷將 PORTC 遞增或遞減後, 延遲 50 ms 後判斷是否為 "0"* ; f. 若 PORTC 不為 0 則繼續做迴圈, 否則跳出後準備進入 SLEEP * ; g. PIC 將 RBIE 設為 1 , RBIF 清為 0 , 再對 PORTB 做一次假讀取 * ; h. 因為 RB4..RB7 有 D 型正反器來記錄讀取時的狀態以便與往後的隨 * ; 機狀態比較, 故要於進 SLEEP 以前做一次讀取動作 * ; i. 一切就續後以 "SLEEP" 指令直接進入 POWER DOWN (SLEEP) Mode * ; j. 因 PIC 支援指令的預提取功能, 故在 SLEEP 後加一個 NOP 指令 * ; K. 中斷服務程式中, 先延遲約 10ms 以避免按鍵的彈跳. * ; l. 依照 RB4,RB5 的狀態來設定 FLAG_INC 或 FLAG_DEC * ; m. 注意 ! Pin Change 發生後要再讀一次 PORTB 才能解除此狀態 * ; n. 中斷服務程式在跳離前將 RBIF 及 RBIE 皆清除, 是為了減化程式 * ; User 可依需要自行修改 ! 但要注意 RB4..RB7 與其資料 Latch * ; 的一致性問題, 否則在按鍵未穩定前將一直有中斷發生 * ; * ; 進一步的使用資訊請參考 PICmicro Mid-Range MCU Family Reference * ; Manual 的以下章節 * ; 9.3 PORTB and the TRISB Register * ; 5.7 OPTION_REG Register * ; 8 Interrupts * ;********************************************************************** ; * ; Filename: WK_PCHG.asm * ; Date: Mar/13/2001 * ; File Version: 1.0 * ; * ; Author: Calvin Ho calvin.ho@microchip.com * ; Company: Microchip Technology Taiwan * ; * ; * ;********************************************************************** ; * ; Files required: Only WK_PCHG.ASM * ; * ; Notice : 本程式為 DEMO 之用 , 其中有許多判斷點並不夠周嚴, 主要為 * ; 簡短程式並增加其可讀性. 讀者請自行依需求將必要的判斷加入* ; * ;********************************************************************** list p=16f870 ; 宣告使用的 CPU 型號 #include ; ; __CONFIG _CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _RC_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF FLAG EQU 0x20 Var1 EQU 0x21 Var2 EQU 0x22 INT_Var1 EQU 0x30 ; 中斷程式用來延遲時間的變數 INT_Var2 EQU 0x31 W_Temp EQU 0x72 ; 中斷中儲存 W,STATUS,FSR 的暫存器 STATUS_Temp EQU 0x73 FSR_Temp EQU 0x74 #define VAL_1MS .248 #define FLAG_INC 0 ; 宣告旗標的所在位元 #define FLAG_DEC 1 org 0x00 ; RESET 的位址為 0x000 nop ; 使用 MPLAB-ICD 的第一個指令必須為 NOP clrf PCLATH goto Main org 0x004 ; 0x004 = 中斷向量 INT_ISRs ;*************************************************************** ;**** 將執行中的 W,STATUS,FSR 記下以便還原 ;**** 正常情形下中斷會在不可預期的執行點發生,故不破壞主程式也 ;**** 將用到的暫存器是 ISR 的義務 ;*************************************************************** movwf W_Temp ; save off current W register contents movf STATUS,W ; move status register into W register bcf STATUS,RP0 ; ensure file register bank set to 0 movwf STATUS_Temp ; save off contents of STATUS register movf FSR,W movwf FSR_Temp BANKSEL PORTB movf PORTB,W ; 清除 Mismatch 的狀態 bcf INTCON,RBIF ; RBIF 要由軟體清除 bcf INTCON,RBIE ; 將 RBIE Disable call Bounce_Delay ; 延遲 10 ms 後再讀 PORTB 以避免彈跳現象 ; ; 任何鍵被按下後其連接的輸入點會讀到 "0" btfsc PORTB,4 ; 檢查 RB4 是否被按下 goto Check_DEC_KEY bsf FLAG,FLAG_INC ; 是 RB4 則設定 FLAG_INC 為 1 goto Exit_ISRs Check_DEC_KEY btfss PORTB,5 ; 若是 RB5被按下則將 FLAG_DEC 設為 1 bsf FLAG,FLAG_DEC Exit_ISRs movf FSR_Temp,W movwf FSR bcf STATUS,RP0 ; ensure file register bank set to 0 movf STATUS_Temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf W_Temp,F swapf W_Temp,W ; restore pre-isr W register contents retfie ; return from interrupt ;****************************************************************************** ;**** Delay 10 ms 的 副程式 ;****************************************************************************** Bounce_Delay movlw .10 movwf INT_Var1 Bounce_Loop1 movlw .248 movwf INT_Var2 Bounce_Loop2 nop decfsz INT_Var2,F goto Bounce_Loop2 decfsz INT_Var1,F goto Bounce_Loop1 return ;***************************************************************************** ;**** 主程式由此開始 !! ;***************************************************************************** Main BANKSEL TRISB movlw B'11110000' movwf TRISB ; RB4..RB7 為輸入腳 clrf TRISC ; PORTC 都為輸出 movlw B'00000000' ; Enable PORTB 的 Pull UP movwf OPTION_REG BANKSEL PORTB movlw B'11111111' movwf PORTB clrf PORTC bsf INTCON,GIE clrf FLAG ; 先清除旗標暫存器 bsf FLAG,FLAG_INC ; 預設的動做為遞增 Prog_Loop btfss FLAG,FLAG_INC ; 是否要執行遞增的迴圈 ?? goto Dec_Process ; 否! 則至 Dec_Process 來執行遞減迴圈 Inc_Process call Delay_50ms incfsz PORTC,F ; 將 PORTC 遞增 goto Inc_Process goto SLEEP_Process Dec_Process call Delay_50ms decfsz PORTC,F ; 將 PORTC 遞減 goto Dec_Process SLEEP_Process ; 開始準備進入 SLEEP Mode clrf PORTC clrf FLAG ; 先清除所有旗標, 待喚醒後由按鍵再設定 movf PORTB,W ; 對 PORTB 做一次假讀取 bcf INTCON,RBIF ; 先清一次 RBIF , 確保喚醒的條件是發生在此之後 bsf INTCON,RBIE ; Enable PORTB Change 的中斷 SLEEP ; 進入 SLEEP Mode nop ; SLEEP 後最好加個 NOP nop goto Prog_Loop ; 再回到主迴圈 !! ;**************************************************************************** ;**** Delay 50ms 的副程式 ;**************************************************************************** Delay_50ms movlw .50 movwf Var2 Delay_200ms_Loop call Delay_1ms ; 執行 50 次 Delay_1ms decfsz Var2,F goto Delay_200ms_Loop return ;**************************************************************************** ;**** Delay 1ms 的副程式 ;**************************************************************************** Delay_1ms nop nop nop movlw VAL_1MS movwf Var1 Delay_1ms_Loop nop decfsz Var1,F goto Delay_1ms_Loop return END ; 程式到此結束 !!! Bye Bye !! ; 待續 ......................