Hello,
Once again, I will need some clever advise.
I'm using interrupts triggered by changes on PORTA pins. I also need to increment a timer for a 5 minutes countdown while leaving the interrupts for PORTA and having my main loop being a @SLEEP.
My problem is that when the countdown begins and I get back to the main loop (where I skip the @SLEEP because it would freeze my timer and use a loop with a 15Us pause instead), it does not react to PORTA interrupts anymore.
There is an LCDOUT in my main loop and the display seems to be refreshed very quicly and at a given period of time it jumps to the right routine in my INT handler to display the countdown (it updates the counter state avery 30s).
Below is the code, maybe if you have a look you will see what I don't see, probably an obvious error... Thanks for any help.
Code:
'-------------------------------------------------------------------------------
a = PORTA 'clear any mismatch with latched values
LCDOUT $fe,1,"1st A=",#a 'output ascii value of variable a: 47, %00|101|111
PAUSE 3000
'MEMO: GIE is handled by PBP !!! Don't enable GIE bit manually or expect troubles!
'Contribution from Darrel Taylor, www.picbasic.co.uk/forum/
INTCON = %00001000 'val=8, enable porta interrupts on change, clear interrupt flags, datasheet p13
' flag (bit0) for portA INT must be cleared by software after int occurs
'All A port pins trigger an int
IOCA = %111111 'enable interrupts on change individually (RA5 is used for handshaking with gun unit, default is 0v)
IOCB = %0000
'If enabling INT for RA3 and no WPU is used, it triggers ints!!!
'Do not leave input (high impedance) pins floating
'-------------------------------------------------------------------------------
Code:
'-------------------------------------------------------------------------------
ON INTERRUPT GOTO in_sig 'when interrupt occurs on any portA pin
'-------------------------------------------------------------------------------
loop1: 'main program is a stupid loop waiting for a int on change triggered by an ir signal on sensors or input on supply port
'put MCU to sleep in low power mode until an int awakens it
LCDOUT $fe,1,"crit=",#critical
IF (critical == 1) THEN 'we can't use "@sleep" when using TMR0 because when at sleep, TMR0 is frozen
PAUSEUS 15 'minimum pause length at 8MHz
'waits for a int of TMR0 or any other int
ELSE
@ SLEEP
ENDIF
GOTO loop1
'###############################################################################
DISABLE 'disable individual interrupts while executing the interrupt routine (do not put check interrupts calls after each instruction)
in_sig:
a = porta
IF ((critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow
Code:
IF (damage >= 100) THEN '0-99% damage, player is alive, 100 and over means player is dead
IF (healed == 1) THEN 'if healed already, there will be no critical condition, player dies
dead = 1
WRITE dead_,dead
READ dead_,tempvar
IF (tempvar != dead) then
SOUND speaker,[100,200]
LCDOUT $fe,1,"RoR"
PAUSE 2000
ENDIF
ELSE 'if not already healed, player will enter critical condition for 5 minutes within which he can be patched and go back to 75% damage
LCDOUT $fe,1,"CritSts"
PAUSE 2000
critical = 1 'from now on, player will be in critical condition for 5min and can be patched and still be hit
countdown = 0 'clear the countdown timer
TMR0 = 98 'set the offset (for 10ms duration with 1:128 at 8MHz)
INTCON.2 = 0 'clear TMR0 overflow flag
INTCON.5 = 1 'enable TMR0 overflow INT (GIE will be set by PBP at the end of the int handler
HIGH speaker 'output sound on speaker or buzzer
'player won't send status back to gun, so if AC is enabled, gun cannot be operated
ENDIF
ENDIF
Code:
'--------------------------------------------------------------------------------------------------------------------------------------------
count_down:
'routine that increases the countdown when in critical condition
'the update/increment of the timer happen every 10ms
alert = (alert + 1)
IF (alert == 30000) THEN 'at every 30s
LCDOUT $fe,1,"countdown:"
LCDOUT $fe,$C0,#countdown
PAUSE 1000
countdown = (countdown + 1)
alert = 0
ENDIF
IF (countdown == 10) THEN 'if 30s elapsed, player dies
LCDOUT $fe,1,"CntDwnEND"
PAUSE 3000
INTCON.5 = 0 'disable TMR0 overflow int
TMR0 = 0 'stop tmr0
INTCON.2 = 0 'reset int flag
LOW speaker 'use a 5V piezzo buzzer, not a speaker
GOTO died
ENDIF
GOTO finish
Code:
finish:
a = porta 'mirror porta and clear the mismatch, refresh latches
INTCON.0 = 0
resume 'end int routine
enable 'REENABLING GIE, PBP lame instruction
END 'end of program
I read my code again and again and the following line just at the begining of my interrupts handler may cause a problem:
Code:
IF ((critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow
because when entering the interrupts handler, if the "critical" called variable is set and the flag for TMR0 overflow interrupt is set (what will probably be the case if I'm stupid enough not to clear it before leaving the int handler routine) then it will jump to the code that handles the interrupt that occured because of the TMR0 overflow, and I guess that if an int occurs because of a change on PORTA, it will be kinda ignored because the conditions are met for TMR0 overflow interrupt before it is even checked for PORTA change ??? ...
I should probably use:
Code:
IF ((INTCON.0 == 0) && (critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow
instead and check that I reset the flag for TMR0 overflow interrupt everytime this INT occurs
Code:
count_down:
'routine that increases the countdown when in critical condition
'the update/increment of the timer happen every 10ms
INTCON.2 = 0 'reset int flag <<<<<<--- Reset the flag for TMR0 overflow before leaving the INT handler
alert = (alert + 1)
IF (alert == 30000) THEN 'at every 30s
LCDOUT $fe,1,"countdown:"
LCDOUT $fe,$C0,#countdown
PAUSE 1000
countdown = (countdown + 1)
alert = 0
ENDIF
Bookmarks