To interrupt or not to interrupt? [PIC12F629]

Status
Not open for further replies.

Gnome

New Member
So right now with the previous help my program is working properly. Now comes on of the larger debates that I have read about. Should interrupts be used for button detection or should I just use code. Now there is a part in my program were the PIC will goto sleep and wait for the WDT to awaken it, however I would like a button press to awaken the PIC early, to trigger an event, if need be. From what I understand only an interrupt can accomplish this.

Should I use code to detect a button press and the interrupt or just use the interrupt?

-Ken
 
While you generally need an interrupt "event" to wake up from sleep, you don't necessarily need to implement interrupts. For example, use IOC (interrupt on change) to detect a push-button state change and wake up from sleep but then poll and debounce the switch normally (don't enable global interrupts).

Regards, Mike

Code:
;
;  Copyright © 2010, Mike McLaren, Micro Application Consultants
;
suspend
        movf    GPIO,W          ; clear IOC mismatch condition    |B0
        bcf     INTCON,GPIF     ; clear IOC interrupt flag bit    |B0
        sleep                   ; sleep, wait for IOC interrupt   |B0
        nop                     ;                                 |B0
dbounce
        DelayCy(16*msecs)       ; 16-msec debounce interval       |B0
        comf    GPIO,W          ; sample active-lo switches       |B0
        andlw   b'00011000'     ; on GP4 and GP3 pins             |B0
        xorwf   swold,W         ; changes, press or release       |B0
        xorwf   swold,F         ; update switch state latch       |B0
        andwf   swold,W         ; filter out "new release" bits   |B0
        skpnz                   ; a "new press"? yes, skip, else  |B0
        goto    suspend         ; branch (sleep)                  |B0
        movwf   swnew           ; save "new press" bits           |B0

sw3
        btfss   swnew,3         ; sw3 press?  yes, skip, else     |B0
        goto    sw4             ; branch                          |B0
        nop                     ; perform "sw3" code here         |B0

sw4
        btfss   swnew,4         ; sw4 press?  yes, skip, else     |B0
        goto    swxit           ; branch                          |B0
        nop                     ; perform "sw4" code here         |B0

swxit
        goto    suspend         ; debounce release after sleep    |B0
;       goto    debounce        ; debounce release before sleep   |B0
 
Last edited:
It seems the software that I'm using doesn't simulate sleep, I'll have to wait until my PIC programmer comes in.

I did have a question about debouncing, why not just use the GPIF and btfsc to execute the button press code?

psuedo-code:
interrupt vector
delay of 24ms
btfsc GPIO, pin_3
goto action
bcf INTCON,0
retie

Wouldn't that allow the button to settle and then detect if it was still being pressed? Granted this is for non-simultaneous button presses.
 
I replaced the RBIF label with the correct GPIF label. Sorry.

I'm sorry, I don't understand what you're trying to do. Why would you want to execute a "goto" instruction or a 24-msec delay routine within an interrupt service routine?
 
I replaced the RBIF label with the correct GPIF label. Sorry.

I'm sorry, I don't understand what you're trying to do. Why would you want to execute a "goto" instruction or a 24-msec delay routine within an interrupt service routine?

As a note "goto" might have confused things, I just typed it as pseudo-code. I would call in the normal code. Is it bad to use a call in an interrupt? I thought that interrupts were used to call new functions.
 
As a note "goto" might have confused things, I just typed it as pseudo-code. I would call in the normal code. Is it bad to use a call in an interrupt? I thought that interrupts were used to call new functions.

Interrupts should be as short and fast as possible - and you certainly shouldn't call delay routines in one - in fact try and avoid subroutines in ISR's if you can, as stack space is VERY limited.

If you want an interrupt triggered delay, use the ISR to set a flag, and monitor the flag in the main program loop.
 
Well here is my code. Basically the PIC outputs a code and goes to sleep, wakes and repeats. If a button is pressed a modified code is output instead.

Code:
;First test run
;Microcontroller model: PIC12F629
;Clock Frequency 4.0 MHz
;Configuration Word: 31E9h
;
;*****[ Variables ]*****
	MOD_1	equ 0x55
	MOD_2	equ 0x56
	CODE	equ 0xAA
	Pin_7	equ 0
	Pin_6	equ 1
	Pin_5	equ 2
	fileA	equ 26h
	fileB	equ 27h
	fileC	equ 28h
	count	equ 29h
	Button1	equ 30h
	Button2	equ 31h
;
;===========================================================================
	org	0x0000		; 	Program Origin at mem location 0
	bcf	PCLATH,3
	bcf	PCLATH,4
	goto	L0001
	org	0x0004		;	Interrupt Location
	btfsc	GPIO,Pin_6	;	Checks if button one was pressed
	call	L0004
	btfsc	GPIO,Pin_5	;	Checks if button two was pressed
	call	L0005
;L0000:
;Continue Interrupt by initializing
	bcf	INTCON,0	;	Clears interrupt
	movlw	8		;	resets original loop counter
	movwf	count		;	and stores, then resets original
	movlw	CODE		;	CODE back into fileC
	movwf	fileC
	retfie
;---------------------------------------------------------------------------
L0001:				
;Initialization
	clrw
	bcf	STATUS,RP0	;	Bank 0
	clrf	TMR0		;	Clear Timer 0
;
;Set GPIO
;
;
	clrf	GPIO		;	Init GPIO
	movlw	07h		;	Set GP<2:0> to
	movwf	CMCON		;	digital IO
	bsf	STATUS,RP0	;	Bank 1
	movlw	06h		;	Set GP<2:1> as inputs
	movwf	TRISIO		;	and set GP<5:3, 0>
				;	as outputs
	movlw	8Fh		;	Turn off T0CKI,
	movwf	OPTION_REG	;	prescaler for WDT = 1:128
;
;Set Interrupts
;
	movlw	06h		;	Set IOC<2:1> to
	movwf	IOC		;	interrupt on change
				;	for button presses
;
	movlw	88h		;	Set INTCON<7,3> to
	movwf	INTCON		;	trigger interrupts
	bcf	STATUS,RP0	;	Bank 0
;
;===========================================================================
L0002:
;Main Program Start
	movlw	CODE		;	Stores the code in register W
	movwf	fileC		;	Moves CODE to file A
	bcf	INTCON,7	;	Disables GIE interrupt
	call	L0003
	bsf	INTCON,7	;	Enables GIE interrupt
	call	L0010
	goto	L0002		;	Repeat forever
;
;---------------------------------------------------------------------------
L0003:
;Serial Code output
	bcf	STATUS,0	;	Clears the carry bit
	movlw	8
	movwf	count
SLoop	btfss	fileC,0
	bcf	GPIO,Pin_7
	btfsc	fileC,0
	bsf	GPIO,Pin_7
	rrf	fileC,1
	call	L0006
	decfsz	count,1
	goto	SLoop
	bcf	GPIO,Pin_7
	call   	L0006
	return
;
;---------------------------------------------------------------------------
L0004:
;Button One Pressed
	bsf	Button1,0	;	Troubleshooting viewable change
;	call	L0006
	movlw	CODE
	addlw	MOD_1
	movwf	fileC
	call	L0003
	bcf	Button1,0	;	Troubleshooting viewable change
	return
;
;---------------------------------------------------------------------------
L0005:
;Button Two Pressed
	bsf	Button2,0	;	Troubleshooting viewable change
;	call	L0006
	movlw	CODE
	addlw	MOD_2
	movwf	fileC
	call	L0003
	bcf	Button2,0	;	Troubleshooting viewable change
	return
;
;---------------------------------------------------------------------------
L0006:
;Delay Function 200ms
	movlw	01h		;	Change to 9Eh after testing
	movwf	fileB
DelB	movlw	01h		;	Change to FDh
	movwf	fileA	 
DelA	decfsz  fileA,1 
	goto	DelA 
	decfsz  fileB,1 
	goto    DelB
	return
;
;---------------------------------------------------------------------------
L0007:
;Debouncer
	
;
;---------------------------------------------------------------------------
L0010:
;SLEEP function
	movf	GPIO,w		;	Stores GPIO in w so
				;	changes can be compared
	bcf	INTCON,0	;	Clears GPIF
;	sleep
	return
;
;---------------------------------------------------------------------------


	END

So should I redo the interrupt portion to remove the call instructions?
 
It depends on how many stack levels your main program uses. The 12F629 has a 8 level deep stack. The interrupt itself uses 1 level and your call's from within the interrupt uses another - so that's 2 stack levels for the Interrupt service routine. Since a interrupt can occur at any time this means you can only nest your main program 6 levels deep. If that is enough for your purposes, then it's fine the way it is.
 
Alright, I made sure to keep things tidy. The program should only go 6 levels at the max. during the interrupt and 2 during normal operation.
 
Alright, I made sure to keep things tidy. The program should only go 6 levels at the max. during the interrupt and 2 during normal operation.

So that's 8, out of a possible maximum of 8 - not leaving much in reserve is it?
 
The interrupt includes the other two, so I have two levels left. But even if I used all 8 my program should take that into account ( If I am a good programmer ) and not overflow. Also any of you have a PIC programmer? I still have yet to test it on a real PIC. Yay for waiting on a package....
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…