Serial in and pin sensing together help needed, please.

shoei600

New Member
Hi all,
I have been writing some code to switch outputs on and off using serial commands with feedback which I have done ok using interupt.
I really want to switch the same outputs on and off using the input pins too which will also provide the same serial feedback. Can anyone please give me some pointers? I have been trying to use several interupts and if I put the if pin6=1 routine in the main body the serial stops.

Also, what is wrong with this statement: if pin6=1 then let b0=$31? I have tried several variations of this using write or swapping the data value and the variable location, etc and it just does not compile.

Many thanks,
James.
 

hippy

Ex-Staff (retired)
The "IF pin6=1" causing seial to not work is probably a logic or design error with the code, but without the source code it is not going to be possible to guess what's going wrong.

Not being able to do "IF pin6=1 THEN LET b0=$31" is a limitation of the PICAXE programming language. The only thing which can appear after THEN is the name of a label to jump to, not another statement. You'll need to use something like ...

- IF pin6 <> 1 THEN NoAssignment
- LET b0=$31
- NoAssignment:

This will skip the "LET b0=$31" when pin6 isn't 1, and will execute the LET when it is.
 

hippy

Ex-Staff (retired)
It would be better if you could post the code to the forum or on a web site you can link to. That way problem solving gets shared, you'll hopefully get a more prompt solution or explanation of the problem, and other PICAXE users get to understand programming issues better.
 

shoei600

New Member
Hi Hippy,
I'm sure there's lots of things that could be optimised, which I hope to get to later. Perhaps branching using variables rather than seperate routines for each blink session? But the main issue is geting both serial in and pin statusus to call the same routines.
I added the Delay routine because I was having problems with the timing using pause and wait, and put it own to the serial influence.
Many thanks.

init:
setint %00000010,%00000010
setfreq m4

Symbol Byte=b3
Symbol Counter=b4
Symbol DelayCount=b5
MAIN:
serout 0,N4800,(" START ")
if pin7=1 then r3
goto main


interrupt:
serin 1,T4800,Byte
serout 0,N4800,("Received ",Byte)
setint %00000010,%00000010
let Counter=$31
serout 0,N4800,("Reset Count to ",Counter)
GoSub Parse
goto main

Parse:
if Byte=$31 then r1
if Byte=$32 then r2
if Byte=$33 then r3
if Byte=$34 then r4
serout 0,N4800,(" Parse ")
serout 0,N4800,(" Parsed ",Byte)
return
r1:
serout 0,N4800,(" Routine 1 ")
for Counter = 1 to 10
GoSub blink1
serout 0,N4800,(" Counting " )
next Counter
serout 0,N4800,(" Final Count ",#Counter,"Routine ",Byte)
wait 5
return
r2:
serout 0,N4800,(" Routine 2 ")
for Counter = 1 to 10
GoSub blink2
serout 0,N4800,(" Counting " )
next Counter
serout 0,N4800,(" Final Count ",#Counter,"Routine ",Byte)
wait 5
return
r3:
serout 0,N4800,(" Routine 3 ")
for Counter = 1 to 10
GoSub blink3
serout 0,N4800,(" Counting " )
next Counter
serout 0,N4800,(" Final Count ",#Counter,"Routine ",Byte)
wait 5
return
r4:
serout 0,N4800,(" Routine 4 ")
for Counter = 1 to 10
GoSub blink4
serout 0,N4800,(" Counting " )
next Counter
serout 0,N4800,(" Final Count ",#Counter,"Routine ",Byte)
wait 5
return

blink1:
high 1
GoSub Delay
low 1
GoSub Delay
return

blink2:
high 2
GoSub Delay
low 2
GoSub Delay
return

blink3:
high 3
GoSub Delay
low 3
GoSub Delay
return

blink4:
high 4
GoSub Delay
low 4
GoSub Delay
return

Delay:
for DelayCount = 1 to 200
next DelayCount
return
 

hippy

Ex-Staff (retired)
Okay, two problems to start with ...

The 'interrupt:' routine ends with "goto main". It should end with RETURN or interrupts will never be re-enabled.

The 'MAIN:' routine has "if pin7=1 then r3" The "r3" has to be changed to the name of the label of some code which is "GOSUB r3" followed by a "goto main". At present it jumps to "r3", eventually executes a RETURN and goes into oblivion because there was no previous GOSUB.

Example ...

- Main:
- SerOut 0,N4800,(" START ")
- If pin7=1 Then Call_r3
- Goto Main
-
- Call_r3:
- GoSub r3
- GoTo Main
-
- Interrupt:
- serin 1,T4800,Byte
- serout 0,N4800,("Received ",Byte)
- setint %00000010,%00000010
- let Counter=$31
- serout 0,N4800,("Reset Count to ",Counter)
- GoSub Parse
- Return
 

shoei600

New Member
Hi Hippy,
Thanks for this.
I can now start from a serial input one time only, then all other functions are from inputs only until a reset. It seems the interupt is not being set again. I tried the Setint in the main routine but that didn't help.
I also had to remove the Delay subroutine as I had exceed the 16 GoSub commands on the 18X. I guess I need to start looking into the Branch command to see if that will help me for that.

I'm trying some more ideas, and will be back shortly.
Kind regards.

Edited by - shoei600 on 22/05/2006 18:57:11
 

hippy

Ex-Staff (retired)
You can use View->Options in the Programming Editor to select 256 GOSUB's for the 18X.

No idea why the interrupts only work once.
 

shoei600

New Member
Hi Hippy,
I'm sure there's lots of mistakes in this. Currently it needs to see a serial to kick start it, then it is stuck in the MAIN loop and more serial commands do not work, but pin inputs do. Pin inputs do not work at startup.
Pleased to hear about the GoSubs. Many thanks.
James.

init:
setint %00000010,%00000010

Symbol Byte=b0
Symbol Counter=b1
Symbol DelayCount=b2

MAIN:
if pin6=0 then NoAssignment6
LET Byte=$31
NoAssignment6:
if pin7=0 then NoAssignment7
LET Byte=$32
GoSub Parse
NoAssignment7:
serout 0,N4800,("Pre serial is: ",Byte)
if Byte > $30 then Parse
GoTo Main

Interrupt:
serin 1,T4800,Byte
serout 0,N4800,("Byte received is: ",Byte)
setint %00000010,%00000010
if Byte > $30 then Parse
return

Parse:
if Byte=$31 then Call_r1
if Byte=$32 then Call_r2
if Byte=$33 then Call_r3
if Byte=$34 then Call_r4
serout 0,N4800,(" Parsed ",Byte)
return

Call_r1:
Gosub r1
GoTo Main

Call_r2:
Gosub r2
GoTo Main

Call_r3:
Gosub r3
GoTo Main

Call_r4:
Gosub r4
GoTo Main

r1:
serout 0,N4800,(" Routine 1 ")
for Counter = 1 to 10
GoSub blink1
serout 0,N4800,(" Counting",#Counter )
next Counter
LET Byte=$30
return


Edited by - shoei600 on 23/05/2006 09:16:39
 

hippy

Ex-Staff (retired)
You have similar problems as to those originally ...

In "main:" the "if Byte > $30 then Parse" is a jump into a subroutine, which ends with a RETURN which will screw things up.

In the "Parse:" routine, then "if Byte=$31 then Call_r1" were okay as "then r1" etc, and you've added "goto main" which should be returns.

Try this ...

MAIN:
if pin6=0 then NoAssignment6
LET Byte=$31
NoAssignment6:
if pin7=0 then NoAssignment7
LET Byte=$32
GoSub Parse
NoAssignment7:
serout 0,N4800,("Pre serial is: ",Byte)
if Byte > $30 then Call_Parse
GoTo Main

Call_Parse:
GoSub Parse
GoTo Main

Interrupt:
serin 1,T4800,Byte
serout 0,N4800,("Byte received is: ",Byte)
setint %00000010,%00000010
if Byte > $30 then Parse
return

Parse:
if Byte=$31 then r1
if Byte=$32 then r2
if Byte=$33 then r3
if Byte=$34 then r4
serout 0,N4800,(" Parsed ",Byte)
return

<i>Delete everything up to 'r1:' </i>
 

shoei600

New Member
Ok, serial in works ok apart from timing (minor issue) and the pins are ignored. I feel I may have to have a re-think on how to approach this because with two possible inputs controlling each output it may be better to flag and monitor a variable in each case such that if the serial has put on on, it will remain on until either input requires it off. Would peek and poke be best used for this? or would you recommend an alternative method?
James.

init:
setint %00000010,%00000010

Symbol Byte=b0
Symbol Counter=b1
Symbol DelayCount=b2
MAIN:
if pin6=0 then NoAssignment6
LET Byte=$31
NoAssignment6:
if pin7=0 then NoAssignment7
LET Byte=$32
NoAssignment7:
serout 0,N4800,(&quot;Pre serial is: &quot;,Byte)
if Byte &lt;&gt; $30 then Call_Parse
GoTo Main

Call_Parse:
GoSub Parse
GoTo Main

Interrupt:
serin 1,T4800,Byte
serout 0,N4800,(&quot;Byte received is: &quot;,Byte)
setint %00000010,%00000010
if Byte &gt; $30 then Parse
return

Parse:
if Byte=$31 then r1
if Byte=$32 then r2
if Byte=$33 then r3
if Byte=$34 then r4
serout 0,N4800,(&quot; Parsed &quot;,Byte)
return


Call_r1:
Gosub r1
GoTo Main

Call_r2:
Gosub r2
GoTo Main

Call_r3:
Gosub r3
GoTo Main

Call_r4:
Gosub r4
GoTo Main
 

hippy

Ex-Staff (retired)
The 'byte' variable is being used as a persistent variable during the whole life of the program, which could be causing problem.

There is also a major problem if the code is handling an event caused by one of the input pins, and then the Interrupt routine fires. This would overflow the subroutine stack and the code would be unpredictable when the interrupt completes. To solve this it is necessary to disable interrupts when handling a pin activation, and then interrupts must be re-enabled afterwards.

This is probably a better way to do what you are attempting ...

Symbol byte = b0
Symbol counter = b1
Symbol delayCount = b2

Init:
SetInt %00000010,%00000010

Main:
If pin6 = 1 Then Pin6Activated
If pin7 = 1 Then Pin7Activated
GoTo Main

Pin6Activated:
SetInt 0,0
byte = $31
GoSub Parse
GoTo Init

Pin7Activated:
SetInt 0,0
byte = $32
GoSub Parse
GoTo Init

Interrupt:
SerIn 1,T4800,byte
SerOut 0,N4800,(&quot;Byte received is: &quot;,byte)
SetInt %00000010,%00000010
If byte &gt; $30 Then Parse
Return

Parse:
SerOut 0,N4800,(&quot; Parsing &quot;,byte)
If byte = $31 Then r1
If byte = $32 Then r2
If byte = $33 Then r3
If byte = $34 Then r4
Return

Test the pin inputs without serial and see if they work, and if not try it with the SetInt in &quot;Init:&quot; commented out. It could be that the code is becoming stuck in the Interrupt routine.

If the interrupt condition is asserted ( Input Pin 1 high ) when the interrupt routine ( and subroutines called ) complete, the code will jump straight back into the interrupt routine and execute the SerIn there. The program will then 'stop working' until further serial data is received. This could give all sorts of apparently odd behaviour, and it could even appear to be working correctly when it actually isn't.

Interrupts are not the simplest of things to handle, and nor is shared code which can be called from a main program and from within an interrupt routine. Remember that subroutines can only be nested to a depth of four.

An alternative way of doing what you want might be ...

Symbol byte = b0
Symbol counter = b1
Symbol delayCount = b2

Init:
byte = 0
SetInt %00000010,%00000010

Main:
If pin6 &lt;&gt; 1 Then Pin6NotActivated
byte = $31
Pin6NotActivated:
If pin7 &lt;&gt; 1 Then Pin7NotActivated
byte = $32
Pin7NotActivated:
If byte = 0 Then Main

SetInt 0,0
GoSub Parse
GoTo Init

Interrupt:
SerIn 1,T4800,byte
SerOut 0,N4800,(&quot;Byte received is: &quot;,byte)
SetInt %00000010,%00000010
Return

Parse:
SerOut 0,N4800,(&quot; Parsing &quot;,byte)
If byte = $31 Then r1
If byte = $32 Then r2
If byte = $33 Then r3
If byte = $34 Then r4
Return

There are still situations where the 'byte' variable, set by an interrupt or pin activation will be over-ridden by the other, but sometimes not.

For both cases, interrupts are locked out for a considerable time, and there may be problems when the interrupts are re-enabled and a serial command is already part way through being sent. In any situation where serial and pin activation can both occur there will be a potential problem which can stop the program dead at unpredictable times.

To overcome this, it will be necessary to add some &quot;double-buffering&quot;. This has not been tested at all, but should work ...

Symbol byte = b0
Symbol counter = b1
Symbol delayCount = b2
Symbol rxByte = b3

Init:
SetInt %00000010,%00000010

Main:
byte = rxByte
rxByte = 0
If pin6 &lt;&gt; 1 Then Pin6NotActivated
byte = $31
Pin6NotActivated:
If pin7 &lt;&gt; 1 Then Pin7NotActivated
byte = $32
Pin7NotActivated:
If byte = 0 Then Main

GoSub Parse
GoTo Main

Interrupt:
SerIn 1,T4800,rxByte
SerOut 0,N4800,(&quot;Byte received is: &quot;,rxByte)
SetInt %00000010,%00000010
Return

Parse:
SerOut 0,N4800,(&quot; Parsing &quot;,byte)
If byte = $31 Then r1
If byte = $32 Then r2
If byte = $33 Then r3
If byte = $34 Then r4
Return


Edited by - hippy on 23/05/2006 11:57:50
 

shoei600

New Member
Hi Hippy,
Thank you for your detailed response and the lesson, I am taking it in. Unfortunatley the code left me without any input routines being called. Its seems to be stuck in the interrupt loop reporting back the command sent and ignoring the pins. I also tried rem'ing out the set int.
My feeling now is that I will use the pins to send a command to the pc, and commands from the pc to control the outputs only. In this way at least I can be sure that is is managed by the pc and the status will not change unless the pc knows about it.
Many thanks for your help, I will no doubt be in touch again soon.

Edited by - shoei600 on 23/05/2006 17:34:20
 
Top