andywpg
- 27th February 2013, 02:17
First of all, this may be a duplicate - I posted in the PBP 3 forum before I noticed that the three posts there were two years old! It also said that the post had to be moderated first - so, mods, could you delete that one?
Here's the problem: I am adding a feature to an existing project (I know, I know, leave well enough alone......)
I am trying to accomplish the following: When a switch is on (logic low) the LED is on steady. When the switch is off, I want the LED to be on for 250ms out of two seconds.
Originally when the switch was off, the program would nap the processor with GIE off, and the only thing that woke it up was the change of state on PORTB.0. There was no interrupt handler, the program just continued the main loop. Now I need the WDT to wake it up as well, and the interrupt handler to blink the LED based on a counter.
I have tried various ways to do this and have failed at every attempt. The LED is on when the switch is on, but it does not blink when the switch is off - it remains stubbornly dark. Almost like the interrupt handler is not even being entered.
I have pared the program down to just this feature for testing - and I'm pulling my hair out at this point. Every time I think I have it, I don't.
If anyone has any ideas what I'm doing wrong, I would appreciate the suggestions. I read a bunch of interrupt and WDT posts but didn't find anything that helped.
BTW, I have used interrupts when I was programming in assembler but never in PBP. And its a 16F886.
Thanks
#CONFIG
__config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _LVP_OFF & _CP_OFF
#ENDCONFIG
DEFINE OSC 8 'LETS PBP KNOW THE OSCILLATOR IS RUNNING AT 8MHz
OSCCON = %01110001 '8 MHz INTERNAL OSCILLATOR, INTERNAL OSCILLATOR IS USED FOR SYSTEM CLOCK
DISABLE DEBUG 'NO DEBUG
ANSEL = 0 'PORTA ALL DIGITAL
ANSELH = 0 'PORTB ALL DIGITAL
OPTION_REG = %10000000 'PORT B PULLUPS ENABLED, TMR0 PRESCALER IS *NOT* ASSIGNED TO WDT
WPUB = %01111111 'PULL UPS ENABLED ON PORTB 0-6
INTCON = %10001000 'GIE ENABLED, PORTB CHANGE OF STATE INTERRUPT ENABLED
IOCB = %00000001 'PORTB.0 INTERRUPT ON CHANGE ENABLED
WDTCON = %00010000 '1:8192 PRESCALER (272MS)
TRISA = 0 'PORTA ALL OUTPUTS
TRISB = %01111111 'B7 OUTPUT, ALL THE OTHERS INPUTS
TRISC = 0 'PORTC ALL OUTPUTS
SWITCH VAR PORTB.0
LED VAR PORTC.6
DEBOUNCE VAR BYTE
DUMMY VAR BYTE
BLINK_COUNT VAR BYTE
DEBOUNCE = 30 'MILLISECONDS
ON INTERRUPT GOTO MY_INT
BLINK_COUNT = 0
MAIN_LOOP:
DO 'ENDLESS LOOP
IF SWITCH = 0 THEN 'SWITCH ON
PAUSE DEBOUNCE 'DELAY TO DEBOUNCE
IF SWITCH = 0 THEN 'SWITCH STILL ON
DISABLE INTERRUPT
LED = 1 'TURN LED ON STEADY WHILE SWITCH IS OPERATED
DO WHILE SWITCH = 0
LOOP
PAUSE DEBOUNCE
LED = 0 'TURN OFF THE LED TO ALLOW THE INTERRUPT HANDLER TO BLINK IT
BLINK_COUNT = 0
GOTO DONE_LOOP
ENDIF
ENDIF
DONE_LOOP:
INTCON = %10001000 'TURN ON GIE AND INTERRUPTS FOR PORTB.0 CHANGE OF STATE AND CLEAR ANY FLAGS
WDTCON = %00010000 '1:8192 PRESCALER - 272MS (CLRWDT RESETS THIS TO 17MS)
ENABLE INTERRUPT
ASM
SLEEP 'SLEEP UNTIL WDT TIMES OUT OR PORTB.0 CHANGES STATE
NOP 'NOP BECAUSE THE PROCESSOR PREFETCHES PC+1 ON SLEEP
ENDASM
LOOP
DISABLE 'DISABLE INTERRUPTS BELOW THIS POINT
MY_INT:
DUMMY = PORTB 'READ PORTB TO CLEAR THE SWITCH MISMATCH IF THAT GENERATED THE INTERRUPT
IF BLINK_COUNT = 8 THEN BLINK_COUNT = 0
IF STATUS.4 = 0 THEN 'WDT TIME OUT OCCURRED
BLINK_COUNT = BLINK_COUNT + 1
IF BLINK_COUNT > 1 THEN
LED = 0
ELSE
LED = 1
ENDIF
ENDIF
INTCON = %10001000 'TURN ON GIE AND INTERRUPT PORTB.0 CHANGE OF STATE, AND CLEAR FLAGS
WDTCON = %00010000 '1:8192 PRESCALER - 272MS (CLRWDT RESETS THIS TO 17MS)
RESUME 'IF NO WDT TIME-OUT OCCURRED, THEN THE SWITCH WAS TURNED ON NO NEED TO DO ANYTHING
'AS THE SWITCH WILL BE CAUGHT BY THE MAIN LOOP
END
Here's the problem: I am adding a feature to an existing project (I know, I know, leave well enough alone......)
I am trying to accomplish the following: When a switch is on (logic low) the LED is on steady. When the switch is off, I want the LED to be on for 250ms out of two seconds.
Originally when the switch was off, the program would nap the processor with GIE off, and the only thing that woke it up was the change of state on PORTB.0. There was no interrupt handler, the program just continued the main loop. Now I need the WDT to wake it up as well, and the interrupt handler to blink the LED based on a counter.
I have tried various ways to do this and have failed at every attempt. The LED is on when the switch is on, but it does not blink when the switch is off - it remains stubbornly dark. Almost like the interrupt handler is not even being entered.
I have pared the program down to just this feature for testing - and I'm pulling my hair out at this point. Every time I think I have it, I don't.
If anyone has any ideas what I'm doing wrong, I would appreciate the suggestions. I read a bunch of interrupt and WDT posts but didn't find anything that helped.
BTW, I have used interrupts when I was programming in assembler but never in PBP. And its a 16F886.
Thanks
#CONFIG
__config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _LVP_OFF & _CP_OFF
#ENDCONFIG
DEFINE OSC 8 'LETS PBP KNOW THE OSCILLATOR IS RUNNING AT 8MHz
OSCCON = %01110001 '8 MHz INTERNAL OSCILLATOR, INTERNAL OSCILLATOR IS USED FOR SYSTEM CLOCK
DISABLE DEBUG 'NO DEBUG
ANSEL = 0 'PORTA ALL DIGITAL
ANSELH = 0 'PORTB ALL DIGITAL
OPTION_REG = %10000000 'PORT B PULLUPS ENABLED, TMR0 PRESCALER IS *NOT* ASSIGNED TO WDT
WPUB = %01111111 'PULL UPS ENABLED ON PORTB 0-6
INTCON = %10001000 'GIE ENABLED, PORTB CHANGE OF STATE INTERRUPT ENABLED
IOCB = %00000001 'PORTB.0 INTERRUPT ON CHANGE ENABLED
WDTCON = %00010000 '1:8192 PRESCALER (272MS)
TRISA = 0 'PORTA ALL OUTPUTS
TRISB = %01111111 'B7 OUTPUT, ALL THE OTHERS INPUTS
TRISC = 0 'PORTC ALL OUTPUTS
SWITCH VAR PORTB.0
LED VAR PORTC.6
DEBOUNCE VAR BYTE
DUMMY VAR BYTE
BLINK_COUNT VAR BYTE
DEBOUNCE = 30 'MILLISECONDS
ON INTERRUPT GOTO MY_INT
BLINK_COUNT = 0
MAIN_LOOP:
DO 'ENDLESS LOOP
IF SWITCH = 0 THEN 'SWITCH ON
PAUSE DEBOUNCE 'DELAY TO DEBOUNCE
IF SWITCH = 0 THEN 'SWITCH STILL ON
DISABLE INTERRUPT
LED = 1 'TURN LED ON STEADY WHILE SWITCH IS OPERATED
DO WHILE SWITCH = 0
LOOP
PAUSE DEBOUNCE
LED = 0 'TURN OFF THE LED TO ALLOW THE INTERRUPT HANDLER TO BLINK IT
BLINK_COUNT = 0
GOTO DONE_LOOP
ENDIF
ENDIF
DONE_LOOP:
INTCON = %10001000 'TURN ON GIE AND INTERRUPTS FOR PORTB.0 CHANGE OF STATE AND CLEAR ANY FLAGS
WDTCON = %00010000 '1:8192 PRESCALER - 272MS (CLRWDT RESETS THIS TO 17MS)
ENABLE INTERRUPT
ASM
SLEEP 'SLEEP UNTIL WDT TIMES OUT OR PORTB.0 CHANGES STATE
NOP 'NOP BECAUSE THE PROCESSOR PREFETCHES PC+1 ON SLEEP
ENDASM
LOOP
DISABLE 'DISABLE INTERRUPTS BELOW THIS POINT
MY_INT:
DUMMY = PORTB 'READ PORTB TO CLEAR THE SWITCH MISMATCH IF THAT GENERATED THE INTERRUPT
IF BLINK_COUNT = 8 THEN BLINK_COUNT = 0
IF STATUS.4 = 0 THEN 'WDT TIME OUT OCCURRED
BLINK_COUNT = BLINK_COUNT + 1
IF BLINK_COUNT > 1 THEN
LED = 0
ELSE
LED = 1
ENDIF
ENDIF
INTCON = %10001000 'TURN ON GIE AND INTERRUPT PORTB.0 CHANGE OF STATE, AND CLEAR FLAGS
WDTCON = %00010000 '1:8192 PRESCALER - 272MS (CLRWDT RESETS THIS TO 17MS)
RESUME 'IF NO WDT TIME-OUT OCCURRED, THEN THE SWITCH WAS TURNED ON NO NEED TO DO ANYTHING
'AS THE SWITCH WILL BE CAUGHT BY THE MAIN LOOP
END