PDA

View Full Version : Serial Timeout Strange Issues



Corbet
- 5th June 2011, 04:38
Hey all,
I am having a strange issue that has been driving me crazy for a couple weeks. Today I figured out how to recreate my problem.
I have 1 chip sending a serial signal and one receiving. The sender is a PIC16f684 and the receiver is the PIC16f84. I am using the serin2 and serout2. The serout2 works fine but when i have a timeout in the serin2 that is longer than the delay in the sender program, the program hangs up on the serin2 statement. What I mean by this is i had the sender chip counting and sending the result through serial to the receiver. The sender sends the serial and then i have a pause in an infinite loop. If the timeout length in serin2 is shorter than time between the serout2 commands then the serin2 hangs up.

The end goal is to have a chip refresh servos every 20 ms with angles received through serial. If the sender takes too long i want the sender to wait till the receiver is ready then send but I need the receiver to be able to timeout and refresh the servos.

Thanks,

mackrackit
- 6th June 2011, 12:50
Any noise on the line will cause the time out to be reset. Is this an RF project?

Corbet
- 6th June 2011, 16:39
No both chips are on the same board about 2 inches apart with a wire going through a 1k resistor to the other chip. How do I filter out the noise, if any, without filtering out the signal?

mackrackit
- 6th June 2011, 20:33
Noise should not be the problem then.

Post your code and we will see if there is anything there.

Archangel
- 7th June 2011, 07:31
I am guessing you are powering the pics from the same supply as the servo. A little electric motor like that can generate some serious voltage (back EMF) and distribute it back into the power supply. I would power them seperately and tie the grounds all at a single place.

Corbet
- 7th June 2011, 18:18
No the servos and chips have seperate power supplies with connected ground as I ran into that problem before :)
Here is my code

Receiver

Define osc 4
trisa = %000000
trisb = $00
low portb
t1pulse var byte[6]
t1pulse[0] = 90
t1pulse[1] = 90
t1pulse[2] = 90
t1pulse[3] = 90
t1pulse[4] = 90
t1pulse[5] = 90
porta.1 = 1
porta.2 = 0
trisa.3 = 1

Main:
porta.2 = 0 'turns on a transistor that brings pin on sender high
'to stop it from sending the serial

pulsout portb.3,t1pulse[0] + 60 'pulsout for servos
pulsout portb.2,t1pulse[1] + 60
pulsout portb.1,t1pulse[2] + 60
pulsout portb.4,240 - t1pulse[3]
pulsout portb.5,240 - t1pulse[4]
pulsout portb.6,240 - t1pulse[5]

porta.2 = 1 'turns transistor on to bring sender pin low to
'tell sender to send

Serin2 porta.3,84,15,Comfail,[wait ("@"), str t1pulse\6] 'if timeout length
' is longer than the time between the sends
'on the sender, this line hangs up and chip
'acts weird like turning porta.2 on but not
' sending the pulses or turn on servo pins
' and never turn off

porta.2 = 0 'tell sender to stop sending

goto main 'loop to main

Comfail: 'if sendin timesout, go here.
Porta.2 = 0 'tell sender to stop sending
goto main 'goto main

The sender does some calculations and sends an array of size 6 through a pin and doesn't do anything else with that pin, just serout2 and then continues on with the program. If the time it takes the sender to send is longer than the timeout the receiver doesn't work correctly.

Archangel
- 8th June 2011, 09:10
Here is a shot in the dark.
You have not posted any config fuses in your code so I am free to assume you are allowing your code to use the Default configs which are located in the 16F84.inc file found in your PBP root directory.
This is the default MPASM config:
__config _XT_OSC & _WDT_ON & _CP_OFF
and here is the PM default config:
device pic16F84, xt_osc, wdt_on, protect_off
it defaults to WDT_ON, I think your code is hanging waiting and the WDT resets and the follies begin. You should early in your PIC programming career learn how to set them in your code so there are no surprises.
It is explained in this thread:
http://www.picbasic.co.uk/forum/showthread.php?t=543

Corbet
- 9th June 2011, 02:10
I tried turning off the watchdog timer and it didn't change. Thanks for the sggestion.

Archangel
- 9th June 2011, 05:37
Ok, well different theory,
try using a pullup resistor and change mode from 84 to 32852, it is still 9600 True but with open collector instead of driven high.
Try adding
DEFINE CHAR_PACING 1000
in transmitter code.

Corbet
- 10th June 2011, 02:38
I added a 10k resistor between the +5 PIC source and the serial wire and changed the 84 to 32852 and it is getting more motion than before but not much more. the servos are all over the place for a biut but then they do what I want for a little. I have 3 serial wires going from the transmitter to 3 receiver chips that control the servos and they are all wired the same just going to different pins on the transmitter. Sometimes two out of three will do as described before but the third for some reason doesn't do anything. I verified on an oscope that the transmitter is sending data and for it to send that means the receiver is giving the signal to receive, it just isn't receiving because the servos are staying at their set default of 90 degrees which I programmed in to the receivers in case the transmitter stops.
To me it seems the receivers are sending the go ahead, the transmitter is sending, but the receivers aren't receiving.

Archangel
- 10th June 2011, 04:19
Tell us about the power supplies and what you have done to suppress any noise from the power supply going to the PIC. You should have (MUST ?) a bypass capacitor right between the PICs power pins, you should have the servos on their own supply and I would recommend a nice fat 10 µF or larger Cap to pick up Low Freq spikes as well, Make sure the pics are not browning out when they run, all serial wires should be at the very least twisted, shielded is better but probably overkill, be aware fluorescent lights can cause misbehavior too. If all else fails try setting things up at a slower baud rate and if that works increase it until it fails, other things to check are, how sure are you about the actual oscillator speeds, are you using crystals, resonators or just R/C oscillators?

EDIT; Oh and Dave pointed this out a while back from the data sheet . . .
Note: When using resonators with frequencies
above 3.5 MHz, the use of HS mode rather
than XT mode, is recommended. HS mode
may be used at any VDD for which the
controller is rated.

EDIT2: Define osc 4 MUST BE ALL UPPERCASE LETTERS . . . DEFINE OSC 4

Corbet
- 10th June 2011, 04:44
I'm using an old ciomputer power supply 5 volt 8 amp power supply for the servos running straight from the output 5 volt to the servos with no filter cap. I have a 5 volt 2 amp transformer used for like a phone charger running to the PICs with a .1uf cap between the +5 and GND. My serial lines are not twisted or shielded, I didn't think this was too critical being on the same board going such a short distance. I'm not picking up anything significant on the oscope either.

Archangel
- 10th June 2011, 04:50
It probably isn't but in search for the ant queen, you kill a lot of ants.
Make sure to change the OSC as shown above, are you using crystals, or what ?.
Do you get bizarre behavior when you get your fingers near the breadboard in the vicinity of the pic?

mackrackit
- 10th June 2011, 13:47
I think your problem may be in the position variable size.
Here are a couple examples.
http://www.picbasic.co.uk/forum/showthread.php?t=10692
http://www.picbasic.co.uk/forum/showthread.php?t=14149&page=1
And a nice tutorial
http://www.picbasic.co.uk/forum/showthread.php?t=544

Archangel
- 11th June 2011, 09:22
I think your problem may be in the position variable size.
Here are a couple examples.
http://www.picbasic.co.uk/forum/showthread.php?t=10692
http://www.picbasic.co.uk/forum/showthread.php?t=14149&page=1
And a nice tutorial
http://www.picbasic.co.uk/forum/showthread.php?t=544
Well now, we never saw the transmitter code did we? You think he is sending data bytes of size greater than 255-60 and overflowing the byte array's bytes?

mackrackit
- 11th June 2011, 12:53
After reading post #10,
the servos are all over the place for a biut but then they do what I want for a little. makes me think data is getting there, just not good data.

Yup, we need to see the code from both sides.

Archangel
- 12th June 2011, 04:33
I think it's a good call, I want to think I bumbled around and had the same overrun problem when I first wrote code for servos. Problem is I have to learn everything several times before I can remember it now days.

Corbet
- 14th June 2011, 15:27
This is the main routine that sends the data to the 3 receivers on 3 separate lines.


Clear
@ DEVICE pic16F684, WDT_OFF
adcon0 = 7
adcon1 = 7
ansel = 0



define OSC 4
trisc = %000111
define CHAR_PACING 1000
t1 var byte[6] 'angle of servo at body joint
t2 var byte[6] 'angle of servo at leg
t3 var byte[6] 'angle of servo at thigh
i var byte
start var byte
ender var byte
a var byte
k var byte
j var byte
l var word
rec var byte
control var byte
sta var byte
fin var byte
ste var byte

control = 0
speed var byte
rec = 0

Init:
For i = 0 to 5
t2[i] = 110
t3[i] = 110
t1[i] = 90
next i
Gosub Send

Main: 'Main makes the robot sit then stand then step forward 5 times
' and then turn 5 times and then backward 5 times then sit.
For l = 0 to 1
gosub sit
next l
for l = 0 to 1000
pauseus 1
next l
For l = 0 to 1
gosub stand
next l
for l = 0 to 1000
pauseus 1
next l

For l = 0 to 5
speed = 2
gosub forward2
next l
for l = 0 to 5
speed = 2
gosub turn
next l

for l = 0 to 5
speed = - 2
gosub Backward
next l
for l = 0 to 1
gosub sit
next l
while 0 = 0 'robot remains sitting indefinately

wend
goto main


Forward2: 'moves every leg individualy forward while the rest move backward slowly.
For i = 0 to 5 step 1
t2[i] = 130
t3[i] = 130
porta.3 = 0
for j = 0 to 5 step 1
For k = 0 to 50
pauseus 1
next k
select case i
case 0
t1[0] = t1[0] + 5 * speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
Case 1
t1[0] = t1[0] - speed
t1[1] = t1[1] + 5 * speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 2
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] + 5 * speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 3
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] + 5 * speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 4
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] + 5 * speed
t1[5] = t1[5] - speed
case 5
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] + 5 * speed
end select
Gosub Send 'goes to the serout2 routines sending the position of the legs (t1 t2 and t3)
next j
t2[i] = 110
t3[i] = 110
Gosub Send
next i
return

Backward: 'basically the same as forward but in reverse.
For i = 5 to 0 step - 1
t2[i] = 130
t3[i] = 130
porta.3 = 0
for j = 0 to 5 step 1
For k = 0 to 50
pauseus 1
next k
select case i
case 0
t1[0] = t1[0] + 5 * speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
Case 1
t1[0] = t1[0] - speed
t1[1] = t1[1] + 5 * speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 2
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] + 5 * speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 3
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] + 5 * speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 4
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] + 5 * speed
t1[5] = t1[5] - speed
case 5
t1[0] = t1[0] - speed
t1[1] = t1[1] - speed
t1[2] = t1[2] - speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] + 5 * speed
end select
Gosub Send
next j
t2[i] = 110
t3[i] = 110
Gosub Send
next i
return

Turn: 'similar to others but changes the direction of a side.
For i = 5 to 0 step - 1
t2[i] = 130
t3[i] = 130
porta.3 = 0
for j = 0 to 5 step 1
For k = 0 to 50
pauseus 1
next k
select case i
case 0
t1[0] = t1[0] - 5 * speed
t1[1] = t1[1] + speed
t1[2] = t1[2] + speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
Case 1
t1[0] = t1[0] + speed
t1[1] = t1[1] - 5 * speed
t1[2] = t1[2] + speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 2
t1[0] = t1[0] + speed
t1[1] = t1[1] + speed
t1[2] = t1[2] - 5 * speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 3
t1[0] = t1[0] + speed
t1[1] = t1[1] + speed
t1[2] = t1[2] + speed
t1[3] = t1[3] + 5 * speed
t1[4] = t1[4] - speed
t1[5] = t1[5] - speed
case 4
t1[0] = t1[0] + speed
t1[1] = t1[1] + speed
t1[2] = t1[2] + speed
t1[3] = t1[3] - speed
t1[4] = t1[4] + 5 * speed
t1[5] = t1[5] - speed
case 5
t1[0] = t1[0] + speed
t1[1] = t1[1] + speed
t1[2] = t1[2] + speed
t1[3] = t1[3] - speed
t1[4] = t1[4] - speed
t1[5] = t1[5] + 5 * speed
end select
Gosub Send
next j
t2[i] = 110
t3[i] = 110
Gosub Send
next i
return

sit: 'makes the legs go up to set the robot down.
while t3[0] < 175
t3[0] = t3[0] + 2
t2[0] = t2[0] + 1
t3[1] = t3[1] + 2
t2[1] = t2[1] + 1
t3[2] = t3[2] + 2
t2[2] = t2[2] + 1
t3[3] = t3[3] + 2
t2[3] = t2[3] + 1
t3[4] = t3[4] + 2
t2[4] = t2[4] + 1
t3[5] = t3[5] + 2
t2[5] = t2[5] + 1
Gosub Send
wend
return

Stand: 'makes legs go down to stand robot up
while t3[0] > 110
t3[0] = t3[0] - 2
t2[0] = t2[0] - 1
t3[1] = t3[1] - 2
t2[1] = t2[1] - 1
t3[2] = t3[2] - 2
t2[2] = t2[2] - 1
t3[3] = t3[3] - 2
t2[3] = t2[3] - 1
t3[4] = t3[4] - 2
t2[4] = t2[4] - 1
t3[5] = t3[5] - 2
t2[5] = t2[5] - 1
Gosub Send
wend
return

Send: 'the send routine sends t1,t2,and t3 to the 3 servo controllers.

While portc.0 = 1
wend
serout2 portc.3,32852,["@", STR t1\6]
While portc.2 = 1
wend
serout2 portc.4,32852,["@", STR t2\6]
while portc.1 = 1
wend
serout2 portc.5,32852,["@", STR t3\6]
Return

end
This is the receiver I am using. The three receivers all use the same code.



'************************************************* ***************
'* Name : Hexapod.BAS *
'* Author : Corbet Peters *
'* Notice : Copyright (c) 2011 *
'* : All Rights Reserved *
'* Date : 4/26/2011 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************
Clear
@ DEVICE pic16F84, WDT_OFF
define osc 4
trisa = %000000
trisb = $00
low portb
t1pulse var byte[6]
servos var portb
servos[0] = portb.1
servos[1] = portb.2
servos[2] = portb.3
servos[3] = portb.4
servos[4] = portb.5
servos[5] = portb.6
t1pulse[0] = 90
t1pulse[1] = 90
t1pulse[2] = 90
t1pulse[3] = 90
t1pulse[4] = 90
t1pulse[5] = 90
porta.1 = 1
porta.2 = 0
trisa.3 = 1
i var byte

Main:
porta.2 = 0 'turns on a transistor that brings pin on sender high
'to stop it from sending the serial

porta.2 = 1 'turns transistor on to bring sender pin low to
'tell sender to send
pulsout portb.3, t1pulse[0]+60
pulsout portb.2, t1pulse[1]+60
pulsout portb.1, t1pulse[2]+60
pulsout portb.4, 240 - t1pulse[3]
pulsout portb.5, 240 - t1pulse[4]
pulsout portb.6, 240 - t1pulse[5]
pulsout portb.7, 240 - t1pulse[5]



Serin2 porta.3,32852,10,comfail,[wait ("@"), str t1pulse\6] 'if timeout length
' is longer than the time between the sends
'on the sender, this line hangs up and chip
'acts weird like turning porta.2 on but not
' sending the pulses or turn on servo pins
' and never turn off
porta.2 = 0 'tell sender to stop sending

goto main 'loop to main
Comfail:
porta.2 = 0
goto main

Sorry for the delay, I have been busy and I wanted a chance to comment a little. Any questions please ask. Any suggestions please post!

Archangel
- 14th June 2011, 17:57
Just 1 question . . . Does it work now, or do you still have the same problem ?

Corbet
- 14th June 2011, 18:49
Sorry about the formatting. It doesn't work right now. The seperate movement routines work but the serial doesn't. I can make it work with a timer interrupt but it refreshes about every 25 to 30 ms which is too long and makes the servos weak. I want the servo controllers to wait for a signal from the main and if it does't get one in time then I want it to refresh using the same position.

Archangel
- 15th June 2011, 03:41
Hi Corbet, have you tried changing your byte values to word, just to see if you are overloading your bytes as Dave suggested ?
You could make redundant variables and store your current var value as a backup and then compare your new values to them and if out of range then restore from them. Something like:
psuedocode


serin . . . t1pulse
dummy1 = t1pulse
pulseout . . . t1pulse
serin . . . t1pulse
if t1pulse >255 then t1pulse = dummy1 ' restore previous value
pulseout . . .
If time critical serial is too slow then you should switch to HSERIN which will receive via hardware while loop does it's thing.
A nice buffer is featured in the Article about "Serial Backpack LCDs" This Thread was promoted to an article based upon one my early posts seeking help to make a serial LCD as I am TOO CHEAP to lay out 35 to 50 bucks a pop for them.
You could also Increase your clock speed to 20mhz and increase the baud rate WAY UP so as to execute the loops faster. It uses a little more power though. Bit Bang serial is a Time Hog, of them Debug seems the fastest, uses serout2 syntax too.