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:
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 ??? ...Code:IF ((critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow
I should probably use:
instead and check that I reset the flag for TMR0 overflow interrupt everytime this INT occursCode:IF ((INTCON.0 == 0) && (critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow
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