PDA

View Full Version : Loop issues



jmgelba
- 23rd September 2021, 17:34
I have a very simple test loop that only partly functions and I cannot figure out why.


main:
if PortB.0 = 0 then
if PortB.1 = 1 then
if PortB.4 = 1 then
runtime = 60
endif
endif
endif

if PortB.0 = 1 then
if PortB.1 = 1 then
if PortB.4 = 1 then
runtime = 90
endif
endif
endif

if PortB.0 = 1 then
if PortB.1 = 0 then
if PortB.4 = 0 then
runtime = 120
endif
endif
endif

pause 1
write 0, runtime.highbyte
write 1, runtime.lowbyte

if SSW = 1 then
redport = 1
pause 200
redport = 0
pause 200
goto main
endif

if SSW = 0 then
redport = 1
goto main1
endif

ended = 0
goto main


main1:
redport = 0
blueport = 1
pause 500
redport = 0
blueport = 0

goto main1


The problem is that this portion of code..

if SSW = 0 then
redport = 1
goto main1
endif


It does turn on the LED at redport, and keeps it on while SSW = 0 but does not jump to main1, and I have no idea why.
If SSW remains at 1 it sits in its loop and flashes the LED perfectly and detects the change to 0 every time. I'm baffled by this!

mpgmike
- 23rd September 2021, 21:43
Just for diagnostics, try putting "goto main1" as the very first line in your "main:" If it goes there, then we need to look at something else. If not, there's something wrong with main1:.

CuriousOne
- 24th September 2021, 05:11
Side question - these nesting of IF-THEN are used to avoid usage of AND/OR operators?

richard
- 24th September 2021, 07:32
Side question - these nesting of IF-THEN are used to avoid usage of AND/OR operators?


or even a little binary arithmetic


if PortB.0 = 0 then
if PortB.1 = 1 then
if PortB.4 = 1 then
runtime = 60
endif
endif
endif


if PortB.0 = 1 then
if PortB.1 = 1 then
if PortB.4 = 1 then
runtime = 90
endif
endif
endif


if PortB.0 = 1 then
if PortB.1 = 0 then
if PortB.4 = 0 then
runtime = 120
endif
endif
endif


shrinks to


if PortB&19 == 18 then
runtime = 60
elseif PortB&19 == 19 then
runtime = 90
elseif PortB&19 == 1 then
runtime = 120
endif



with regard to the loop

if SSW = 1 then ???????????? what is ssw

snippets are a total failure as usual

could be the pin if its a pin is still set to analog

Ioannis
- 25th September 2021, 20:38
main1:
redport = 0
blueport = 1
pause 500
redport = 0
blueport = 0

goto main1


The problem is that this portion of code..

if SSW = 0 then
redport = 1
goto main1
endif


in this part of the code, if SSW=0, the redport will be on for a very narrow time frame. I doubt that you will be able to see it. And then it will loop for ever in the main1.

Ioannis

richard
- 26th September 2021, 00:58
in this part of the code, if SSW=0, the redport will be on for a very narrow time frame. I doubt that you will be able to see it. And then it will loop for ever in the main1.




whatever redport is , might be a bit var that could never be seen

the snippet is useless , so many things undefined

jmgelba
- 28th September 2021, 01:07
Here's the entire code.
Redport = 0 was a typo and should have been = 1. The loop worked once I disabled the external oscillator requirements for timer1.
18F1320 using internal 8MHz oscillator (because I have hundreds of them from a past project! :-) )

So this code is almost there functionally but has a couple of problems.

The project is to run some high power LED's for either 60, 90, 120 seconds. There is a lid that has to be closed (SSW=1) before it will allow the LED's to be turned on. If the lid is open, it will just sit there and flash redport until the lid is closed. At this point with lid closed, the redport indicator led will be on solid and it'll move into main1.
The main LED's get turned on with a momentary push button switch by the user. The timer should start, count up until Runtime is reached, switch off the LED's (enable1 and enable2 = 0) turn on greenport which is a green "done" indicator LED, and it should sit there until the lid is opened again.
On lid open it should return to the first loop and flash redport until the lid is closed again. While the timer is counting and the main LED's are on it has to monitor for the lid being opened and shut off the main LED's and return to the first loop with the counter ready to start at Runtime.

So that said here is what works:
It sets up correctly, will load either 60, 90 or 120 in to Runtime, will sit and flash redport with the lid open.
It will go in to main1 with a solid redport and wait for the pushbutton input (Startswitch)
It will turn on the timer, count and when done will turn off the main LED's and turn on greenport and sit there until the lid is lifted (SSW=1)

What isn't working is:
Its not counting to the correct number in Runtime. I use greenport in the timer loop to basically have a pulse to look at on the scope showing that the timer is indeed running, and it is. The pulses are approx 1ms apart but they are only running 50% of the time. So say 100 pulses 1ms apart (I haven't counted the actual number yet) then nothing for 100ms then 100 pulses 1ms apart etc etc.
Currently it runs for about 630ms if Runtime = 60, about 900ms if Runtime = 90 and never turns off if Runtime = 120. I added the thousandths to see if I could increase the on time and it doesn't respond, staying on all the time. When the lid is lifted it does interesting things and gives a wonderful flashing combination of the red green and blue indicator LED's. Clearly I'm setting up the timer wrong but I'm not sure what I'm doing wrong at this point and could use some fresh eyes.

jmgelba
- 28th September 2021, 01:21
OSCCON = %01110011
DEFINE OSC 8
DEFINE WRITE_INT 1
Include "modedefs.bas"

SSW var PortA.7
redport var PortB.5
blueport var PortB.7
greenport var PortB.6
enable1 var PortB.2
enable2 var PortB.3
runtime var word
RunningFlag var BIT
Startswitch var PortA.3
ended var bit
Thousandths var word
Hundredths var word
Seconds var word
comp var bit


adcon0.0 = 0
adcon1.3 = 1
adcon1.4 = 1
adcon1.5 = 1
adcon1.6 = 1
TRISA = %11111000
TRISB = %00010011
PortB.5 = 0
PortB.2 = 0
T1CON = %00000100

comp = 0
redport = 0
greenport = 0
blueport = 0
enable1 = 0
enable2 = 0
ended = 0
runningflag = 0
thousandths = 0
Hundredths = 0
Seconds = 0

Gosub SetTimer

blueport = 1 'testing outputs
pause 2000
blueport = 0
greenport = 1
pause 2000
greenport = 0

On Interrupt goto Starttimer
PIE1.0=1 ' Enable TMR1 Interrupts
INTCON.6=1 ' Enable all unmasked Interrupts
INTCON.7=1 ' Enable Global Interrupts



main:

if PortB.0 = 0 then
if PortB.1 = 1 then
if PortB.4 = 1 then
runtime = 60
endif
endif
endif

if PortB.0 = 1 then
if PortB.1 = 1 then
if PortB.4 = 1 then
runtime = 90
endif
endif
endif

if PortB.0 = 1 then
if PortB.1 = 0 then
if PortB.4 = 0 then
runtime = 120
endif
endif
endif

write 5, runtime

if SSW = 1 then
redport = 1
pause 200
redport = 0
pause 200
goto main
endif

if SSW = 0 then
redport = 1
goto main1
endif

goto main

'main code loop

Enable
main1:

if ssw = 1 then 'checks to see if lid is closed, if not,
goto main 'go back to first loop and wait
endif 'if lid is closed, continue on to next requirement

if SSW = 0 and startswitch = 1 then 'starts the first run of the timer if lid
ended = 0 'is closed and push button has been pressed
runningflag = 1 'and sets a flag to show timer is running
GOSUB StartTimer
endif

if runningflag = 1 then 'checks to see if timer was started and
gosub starttimer 'if true loops for next cycle
endif

goto main1
disable




completed:
T1CON.0=0
enable1 = 0
enable2 = 0
greenport = 1
redport = 0
blueport = 0
runningflag = 0
comp = 1
if ssw = 1 then
greenport = 0
goto main
endif
goto completed
return

'
' Subroutine Loads TMR1 values
' ============================
SetTimer:
T1CON.0=0 ' Stop the Clock
TMR1H=$B1
TMR1L=$e7
PIR1.0=0 ' Reset TMR1's Interupt Flag
Return

' Subroutine to stop the timer, reset, and shutoff outputs
Stoptimer:
T1CON.0=0
TMR1H=$B1
TMR1L=$E7
PIR1.0=0
enable1 = 0
enable2 = 0
thousandths = 0
Hundredths = 0
Seconds = 0
redport = 0
blueport = 0
greenport = 1
runningflag = 0
ended = 1
'gosub settimer
Pause 1000
return


Starttimer:
redport = 1 'output to show timer is running
blueport = 1
greenport = 0 'provides a pulse to measure for diagnostics to check timer is actually running
greenport= 1
greenport = 0
enable1 = 1 'turns on both LED channels
enable2 = 1
Gosub SetTimer ' Set the Timer for next Interrupt
If RunningFlag=1 then ' If timing actually enabled then continue
thousandths=thousandths+1
if thousandths>999 then
thousandths=0
Hundredths=Hundredths+1
If Hundredths>99 then
Hundredths=0
Seconds=Seconds+1
write 10, seconds 'just to see if it turns off at runtime seconds
' Increment the Seconds

if seconds = runtime then
gosub stoptimer
goto completed
endif
endif
endif
endif

if ssw = 1 then
gosub stoptimer
goto main
endif

Resume

End

Ioannis
- 28th September 2021, 10:30
1. RMW issue here:

greenport = 0 'provides a pulse to measure for diagnostics to check timer is actually running
greenport= 1
greenport = 0

I think you will not see the greenport change because of RMW issue. It depends on the capacitive load of the port though.

2. SetTimer turns off the timer.

So the rest of the commands after this line

Gosub SetTimer ' Set the Timer for next Interrupt

I guess are not executed.

The Interrupt routine should be less loaded also.

If time allows I will try to see more on your code.

Ioannis

jmgelba
- 28th September 2021, 10:41
Ioannis, thank you for your reply. I do actually see a pulse and have been using it to measure changes I've been making, although it is always fairly constant at about 1ms pulse to pulse. I'll assume this is because I'm turning off the timer rather than letting it run. Interestingly though, it does stop when seconds = runtime. Its just that seconds aren't 1000ms long :-D Uff just checked, 68uS between pulses, not 1ms as previously stated.

richard
- 28th September 2021, 10:46
There are many issues



starting here
1.

disable ; missing
Starttimer:
redport = 1 'output to show timer is running
blueport = 1
greenport = 0 'provides a pulse to measure for diagnostics to check timer is actually running
greenport= 1
greenport = 0
enable1 = 1 'turns on both LED channels
enable2 = 1
Gosub SetTimer ' Set the Timer for next Interrupt ; never a good look in a isr
If RunningFlag=1 then ' If timing actually enabled then continue
thousandths=thousandths+1 ;//// the isr is set to 10mS wtf
if thousandths>999 then
thousandths=0
Hundredths=Hundredths+1
If Hundredths>99 then ; what how
Hundredths=0
Seconds=Seconds+1
write 10, seconds 'just to see if it turns off at runtime seconds
' Increment the Seconds


if seconds = runtime then
gosub stoptimer
goto completed
endif
endif
endif
endif


if ssw = 1 then
gosub stoptimer
goto main you should never do this in an interrupt
endif


Resume
enable ;lmissing






you cannot call a isr as a subroutine . there is no return
2.

if SSW = 0 and startswitch = 1 then 'starts the first run of the timer if lid
ended = 0 'is closed and push button has been pressed
runningflag = 1 'and sets a flag to show timer is running
GOSUB StartTimer
endif


3.
the timer timer 1 is never turned on

4.
'INTCON.7=1 ' Enable Global Interrupts no do not do this

this works

#CONFIG CONFIG OSC=INTIO1, FSCM=ON, IESO=ON, PWRT=OFF, BOR=ON, BORV=27, WDT=ON
CONFIG WDTPS=512, MCLRE=ON, STVR=ON, LVP=OFF, DEBUG=OFF, CP0=OFF, CP1=OFF
CONFIG CPB=OFF, CPD=OFF, WRT0=OFF, WRT1=OFF, WRTC=OFF, WRTB=OFF, WRTD=OFF
CONFIG EBTR0=OFF, EBTR1=OFF, EBTRB=OFF
#ENDCONFIG
OSCCON = 110011
DEFINE OSC 8
DEFINE WRITE_INT 1
'Include "modedefs.bas"
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0 ; if not used for pwr
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
pause 2000
Debug "Start",13 ,10


SSW var PortA.7
redport var PortB.5
blueport var PortB.7
greenport var PortB.6
enable1 var PortB.2
enable2 var PortB.3
runtime var word
RunningFlag var BIT
Startswitch var PortA.3
ended var bit
Thousandths var word


Seconds var word
comp var bit


adcon1=$7f
'adcon0.0 = 0
'adcon1.3 = 1
'adcon1.4 = 1
'adcon1.5 = 1
'adcon1.6 = 1
TRISA = 111000
TRISB = 010011
PortB.5 = 0
PortB.2 = 0
T1CON=0
TMR1H=$B1 ;10mS
TMR1L=$e7
lata.0=0 ;debug


pause 1000
Debug "Start",13 ,10
comp = 0
redport = 0
greenport = 0
blueport = 0
enable1 = 0
enable2 = 0
'ended = 0
runningflag = 0
thousandths = 0


Seconds = 0






blueport = 1 'testing outputs
pause 200
blueport = 0
greenport = 1
pause 200
greenport = 0


T1CON.0=0
On Interrupt goto Starttimer
PIE1.0=1 ' Enable TMR1 Interrupts
INTCON.6=1 ' Enable all unmasked Interrupts
'INTCON.7=1 ' Enable Global Interrupts






main:
if (PortB&19) == 18 then
runtime = 10
elseif (PortB&19) == 19 then
runtime = 90
elseif (PortB&19) == 1 then
runtime = 120
endif


'Debug "runtime ",dec runtime," ",dec portb,13 ,10
''write 5, runtime
'pause 2000
if SSW = 1 then
redport = 1
pause 200
redport = 0
pause 200
goto main
endif


if SSW = 0 then
redport = 1
goto main1
endif


goto main


'main code loop


Enable
main1:
Debug "main1",dec runtime,13 ,10
if ssw = 1 then 'checks to see if lid is closed, if not,
goto main 'go back to first loop and wait
endif 'if lid is closed, continue on to next requirement
if (SSW = 0 )and (startswitch = 1) then 'starts the first run of the timer if lid
' Debug "start",dec runtime,13 ,10
runningflag = 1 'and sets a flag to show timer is running
T1CON.0=1 ; timer on
enable1 = 1
enable2 = 1
blueport = 1
comp = 0
while runningflag: wend
enable1 = 0
enable2 = 0
greenport = 1
blueport = 0
comp = 1
redport = 0
endif
if comp==1 then
WHILE SSW = 0 : wend
greenport = 0
Debug "DUNN",dec runtime,13 ,10
ENDIF
goto main

goto main1


end


disable
Starttimer:
lata.1=1 ;debug to clock time
T1CON.0=0
TMR1H=$B1+TMR1H ;10mS
TMR1L=$e7 +TMR1L
if STATUS.0 THEN TMR1H =TMR1H +1
PIR1.0=0 ' Reset TMR1's Interupt Flag
T1CON.0=1
thousandths=thousandths+10
if thousandths>999 then
thousandths=0
Seconds=Seconds+1
endif
if (seconds = runtime) || (ssw = 1) then
runningflag = 0
T1CON.0=0
endif
lata.1=0;debug to clock time
Resume
enable
End



my view of schematic
9082

jmgelba
- 28th September 2021, 14:37
Wow Richard, thanks for that! I guess I was way off. I used Melanie's Olympic Timer as the basis for my code and she included some of the things that you have advised against such as adding the SetTimer subroutine call in the Starttimer routine and INTCON.7=1.

I tried your code and needed to change a few things.

OSCCON = 110011
TRISA = 111000
TRISB = 010011

became

OSCCON = %01110011
TRISA = %11111000
TRISB = %00010011

in order to compile.

If you open the lid while its running and close it again, then push the start button, it doesn't turn on the outputs and start timing again. It does jump back to main, it will jump in to main1 and put the red led on solid, but doesn't run main1.
If the switch is in the 60 second run position it runs for about 10 seconds - which I saw you had runtime = 10 so I changed that.
In the 90 second position it runs for 90 seconds - perfect.
In the 120 second position it ends almost instantly. I noticed this would happen sometimes in my code too. 100 and less and it works each time. I don't know what this phenomena is.

richard
- 29th September 2021, 01:13
we are still in a covid lockdown [no 5 i think ] hence i'm bored shitless and will do anything that takes my interest

yes the forum has the ability to eat % symbols


If the switch is in the 60 second run position it runs for about 10 seconds - which I saw you had runtime = 10 so I changed that.
60 seconds is too long to wait while testing


In the 120 second position it ends almost instantly. I noticed this would happen sometimes in my code too. 100 and less and it works each time. I don't know what this phenomena is.
not on the simulator , works ok at all settings




if you want to be able to run code repeatedly then seconds and comp need to be reset to zero before a rerun
like this

#CONFIG CONFIG OSC=INTIO1, FSCM=ON, IESO=ON, PWRT=OFF, BOR=ON, BORV=27, WDT=ON
CONFIG WDTPS=512, MCLRE=ON, STVR=ON, LVP=OFF, DEBUG=OFF, CP0=OFF, CP1=OFF
CONFIG CPB=OFF, CPD=OFF, WRT0=OFF, WRT1=OFF, WRTC=OFF, WRTB=OFF, WRTD=OFF
CONFIG EBTR0=OFF, EBTR1=OFF, EBTRB=OFF
#ENDCONFIG
OSCCON = % 01110011
DEFINE OSC 8


DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
pause 2000
Debug "Start",13 ,10


SSW var PortA.7
redport var PortB.5
blueport var PortB.7
greenport var PortB.6
enable1 var PortB.2
enable2 var PortB.3
runtime var word
RunningFlag var BIT
Startswitch var PortA.3
ended var bit
Thousandths var word
Seconds var word
comp var bit


adcon1=$7f
TRISA = % 11111000
TRISB = % 00010011
PortB.5 = 0
PortB.2 = 0
T1CON=0
TMR1H=$B1 ;10mS
TMR1L=$e7
lata.0=0 ;debug


pause 1000
Debug 13 ,10 ,"ready",13 ,10
comp = 0
redport = 0
greenport = 0
blueport = 0
enable1 = 0
enable2 = 0
runningflag = 0
thousandths = 0
Seconds = 0




blueport = 1 'testing outputs
pause 200
blueport = 0
greenport = 1
pause 200
greenport = 0


T1CON.0=0
On Interrupt goto Starttimer
PIE1.0=1 ' Enable TMR1 Interrupts
INTCON.6=1 ' Enable all unmasked Interrupts




main:
if (PortB&19) == 18 then
runtime = 10
elseif (PortB&19) == 19 then
runtime = 90
elseif (PortB&19) == 1 then
runtime = 120
endif
if SSW = 1 then
redport = 1
pause 200
redport = 0
pause 200
goto main
endif
if SSW = 0 then
redport = 1
comp=0
goto main1
endif
goto main


'main code loop


Enable
main1:
' Debug "main1 loop ",dec runtime,13 ,10
if ssw = 1 then 'checks to see if lid is closed, if not,
goto main 'go back to first loop and wait
endif 'if lid is closed, continue on to next requirement
if (SSW = 0 )and (startswitch = 1) then 'starts the first run of the timer if lid
' Debug "start",dec runtime,13 ,10
runningflag = 1 'and sets a flag to show timer is running
T1CON.0=1
enable1 = 1
enable2 = 1
blueport = 1
comp = 0
while runningflag: wend
enable1 = 0
enable2 = 0
greenport = 1
blueport = 0
comp = 1
redport = 0
endif
if comp==1 then
Debug "DUNN",dec runtime,13 ,10
WHILE SSW = 0 : wend
greenport = 0
ENDIF
goto main
goto main1


end




disable
Starttimer:
lata.1=1
T1CON.0=0
TMR1H=$B1+TMR1H ;10mS
TMR1L=$e7 +TMR1L
if STATUS.0 THEN TMR1H =TMR1H +1
PIR1.0=0 ' Reset TMR1's Interupt Flag
T1CON.0=1
thousandths=thousandths+10
if thousandths>999 then
thousandths=0
Seconds=Seconds+1
endif
if (seconds = runtime) || (ssw = 1) then
seconds = 0
runningflag = 0
T1CON.0=0
endif
lata.1=0
Resume
enable
End

richard
- 29th September 2021, 02:23
a state machine approach simplifies the logic enormously , has a much more predictable result
and is vastly simpler to debug


#CONFIG CONFIG OSC=INTIO1, FSCM=ON, IESO=ON, PWRT=OFF, BOR=ON, BORV=27, WDT=ON
CONFIG WDTPS=512, MCLRE=ON, STVR=ON, LVP=OFF, DEBUG=OFF, CP0=OFF, CP1=OFF
CONFIG CPB=OFF, CPD=OFF, WRT0=OFF, WRT1=OFF, WRTC=OFF, WRTB=OFF, WRTD=OFF
CONFIG EBTR0=OFF, EBTR1=OFF, EBTRB=OFF
#ENDCONFIG
OSCCON = %01110000
DEFINE OSC 8


DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0



SSW var PortA.7
redport var latB.5
blueport var latB.7
greenport var PortB.6
enable1 var PortB.2
enable2 var PortB.3
runtime var word
RunningFlag var BIT
comp var bit
Startswitch var PortA.3
ended var bit
Thousandths var word
Seconds var word
now var word
machine_state var byte ; [ 0 lid up 1 waiting to start 2 running 3 ended]
old_state var byte
timer1_reload con 45543 ;10mS
DEFINE INTHAND timer ;COMMENT OUT IF DT_INTS USED
goto overasm
asm
timer ;tmr1 isr
MOVE?CT 0, T1CON, TMR1ON ; 1 stop timer
MOVLW LOW(_timer1_reload) ; 1 Add TimerReload to the
ADDWF TMR1L,F ; 1 value in Timer1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVLW HIGH(_timer1_reload) ; 1
ADDWF TMR1H,F ; 1
MOVE?CT 1, T1CON, TMR1ON ; 1 start timer
banksel _Thousandths
INCF _Thousandths
BTFSC STATUS,C
INCF _Thousandths+1
BANKSEL PIR1 ;COMMENT OUT IF DT_INTS USED
BCF PIR1 ,0 ;COMMENT OUT IF DT_INTS USED
RETFIE ;COMMENT OUT IF DT_INTS USED
endasm
overasm:

adcon1=$7f
TRISA = %11111000
TRISB = %00010011
PortB = 0
T1CON=0
TMR1H=$B1 ;10mS
TMR1L=$e7
PIE1.0=1 ' Enable TMR1 Interrupts
INTCON.6=1 ' Enable all unmasked Interrupts'
lata.0=1 ;debug
pause 1000
Debug "Start",13 ,10
clear
'post
latB = 32
pause 200
latB =64
pause 200
latB =128
pause 200
latB =0
T1CON=1
INTCON.7=1

main:
T1CON=0
now = thousandths
T1CON=1
if SSW then machine_state = 0
if old_state != machine_state then
Debug 13 ,10 , "new state "
select case machine_state
case 0
latB = latB & ~204 ; blue,green,ena,enb all off
Debug dec 0
case 1
if (PortB&19) == 18 then
runtime = 1000
elseif (PortB&19) == 19 then
runtime = 9000
elseif (PortB&19) == 1 then
runtime = 12000
endif
redport = 1
Debug dec 1,"rt ",dec runtime
case 2
latB = latB | 12 ;ena,enb on
Seconds = now
blueport = 1
redport = 0
Debug dec 2
case 3
latB = latB & ~12 ;ena,enb off
blueport = 0
greenport = 1
redport = 0
Debug dec 3
end select
old_state = machine_state
endif
select case machine_state
case 0
if now//20=0 then redport = !redport
if ssw==0 then machine_state =1
case 1
if startswitch == 1 then machine_state =2
case 2
if now - Seconds > runtime then machine_state=3
end select
pause 10
goto main


end

richard
- 29th September 2021, 06:03
new cleaned up version with comments

just to emphasize the versality of state machine approach
debounce of start button added
validation of runtime selection added





'************************************************* ***************'
* Name : UNTITLED.BAS *
'* Author : richard *
'* Notice : Copyright (c) 2021 caveat emptor *
'* : All Rights Reserved *
'* Date : 28/09/2021 *
'* Version : 1.0 *
'* Notes : 18f1320 *
'* : *
'************************************************* ***************
#CONFIG
CONFIG OSC=INTIO1, FSCM=ON, IESO=ON, PWRT=OFF, BOR=ON, BORV=27, WDT=ON
CONFIG WDTPS=512, MCLRE=ON, STVR=ON, LVP=OFF, DEBUG=OFF, CP0=OFF, CP1=OFF
CONFIG CPB=OFF, CPD=OFF, WRT0=OFF, WRT1=OFF, WRTC=OFF, WRTB=OFF, WRTD=OFF
CONFIG EBTR0=OFF, EBTR1=OFF, EBTRB=OFF
#ENDCONFIG


DEFINE OSC 8




DEFINE DEBUG_REG PORTA ;debug
DEFINE DEBUG_BIT 0
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0


SSW var PortA.7
red var latB.5 ;use lat to avoid rmw
blue var latB.7
green var latB.6
enable1 var latB.2
enable2 var latB.3
Startswitch var PortA.3


runtime var word
Thousandths var word ; can measure upto 655 seconds in 10mS quanta
Seconds var word
now var word
machine_state var byte ; possible states [ 0 lid up, 1 waiting for start button, 2 running, 3 ended]
old_state var byte
start var byte
timer1_reload con 45543 ;10mS


DEFINE INTHAND ticker
goto overasm
asm
ticker ;tmr1 isr
MOVE?CT 0, T1CON, TMR1ON ; 1 stop timer
MOVLW LOW(_timer1_reload) ; 1 Add TimerReload to the
ADDWF TMR1L,F ; 1 value in Timer1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVLW HIGH(_timer1_reload) ; 1
ADDWF TMR1H,F ; 1
MOVE?CT 1, T1CON, TMR1ON ; 1 start timer
banksel _Thousandths
INCF _Thousandths
BTFSC STATUS,C
INCF _Thousandths+1
BANKSEL PIR1
BCF PIR1 ,0
RETFIE
endasm
overasm:


OSCCON = %01110000
adcon1=$7f
TRISA = %11111000
TRISB = %00010011
PortB = 0
T1CON=0
TMR1H=$B1 ;10mS
TMR1L=$e7
PIE1.0=1 ' Enable TMR1 Interrupts
INTCON.6=1 ' Enable all unmasked Interrupts'
lata.0=1 ;debug
clear


pause 1000 ;debug
Debug "Start",13 ,10 ;debug


'post
latB = 32
pause 200
latB =64
pause 200
latB =128
pause 200
latB =0


;isr begin
T1CON=1 ;timer on
INTCON.7=1

main:
T1CON=0
now = thousandths ; get current time
T1CON=1
start=start<<1 + startswitch ;debounce startswitch
if SSW then machine_state = 0 ; lid up emergency stop ??
if old_state != machine_state then ; manage changes of state
Debug 13 ,10 , "new state " ;debug
select case machine_state ; the new state
case 0 ;lid up ,all stop
latB = latB & ~204 ; blue,green,ena,enb all off
Debug dec 0 ;debug
case 1 ;lid down read runtime then we are good to go
runtime = 0 ; default if incorrect sw setting ie 0 2 3 16 17
if (PortB&19) == 18 then ;runtime is sec * 100 read from dipsw on b0,1,4
runtime = 500 '5
elseif (PortB&19) == 19 then
runtime = 9000 '90
elseif (PortB&19) == 1 then
runtime = 12000 '120
endif ; validate that rt sw setting is valid 1 18 or 19 as not all posdibilites have a result
if runtime == 0 then machine_state = 0 ; abort invalid runtime red slow flash
if machine_state then red = 1 ;red on solid
Debug dec 1,"rt = ",dec runtime ;debug
case 2 ; start button pressed
latB = 140 ;ena,enb,blue on red off
Seconds = now ;note starting time
Debug dec 2
case 3 ;time up
latB = 64 ;ena,enb,blue,red off green on
Debug dec 3 ;debug
end select
old_state = machine_state
endif
select case machine_state ; manage current state
case 0 ;monitor lid sw rapid flash red led
if now//20==0 then red = !red
if ssw==0 then machine_state =1
case 1 ;lid down monitor start button
if start == 255 then machine_state = 2
case 2 ; running is time up ?
if now - Seconds > runtime then machine_state = 3 '[the beauty of unsigned subtraction}
end select
pause 10
goto main


end

Ioannis
- 29th September 2021, 14:32
Richard, this is a case study programming example!

Ioannis

Aussie Barry
- 30th September 2021, 00:49
Ioannis, more a "select case" study programming example :D

Cheers
Barry

richard
- 30th September 2021, 01:04
there are three ways to design a program for a single core chip
1 cooperative task sharing
2 state machine
3 spaghetti

two are predictable , reliable and easy to debug. both will unravel yards of spaghetti every time

a ticker is a very useful tool for any process that needs time supervision

put it all together and the world is your oyster


if you have a goto in your code as a logical flow control device you are well on the way to spaghetti
goto is the first warning sign

richard
- 30th September 2021, 01:42
I used Melanie's Olympic Timer as the basis for my code and she included some of the things that you have advised against such as adding the SetTimer subroutine call in the Starttimer routine and INTCON.7=1.



i should address some of these issues when using on interrupt


subroutine call in isr
pbp code is not re-entrant if the isr is called while the foreground task is running the same routine the result will be unpredictable
subroutines in an isr are bad practice mostly

INTCON.7=1
pbp on interrupt is not a real interrupt , the int flag is simply checked on completion of every command with flow diverted if flag set
if you actually enable interrupts where does the int vector point ? not good not needed