PDA

View Full Version : Problems controlling multiple pics



gandora
- 26th May 2007, 04:03
I am currently in the process of designing a servo controller. I have already been able to make a pic that can take a message from a pc serial port and command 11 servos position, and speed.

Now I am having a very hard time taking the messages from a computer, and distributing them to multiple controllers.

For now I am attempting to just control one servo controller, with one master pic interfaced to the pc.

master pic


define OSC 8
OSCCON = %1111110 ' sets internal osc to run at 8MHZ

'----------turn analog on porta off, and use as digital input/output '----------this is used to allow serial input on the A bus.
CMCON = 7 'Comparators OFF
ANSEL = 0 'A/D OFF -- Port pins all digital
'----------

'---**Pins
rsoutpin var porta.0
rsinpin var porta.1

picinpin var portb.4
picoutpin var portb.5

'---vars
'-------- transfer vars
message var byte
'--------





'---main program
main:

gosub pcin
gosub picout

goto main

'----- retrieve next set of commands from pc.
pcin:

'----send serial request, and get user input, timeout 70 ms
serout2 rsoutpin, 16468, ["ready set go!"] 'call for data
'----
serin2 rsinpin, 16468, 70, main, [message]
'-----end serial request
return

'---- picout procedure waits for high on picinpin and then transmits data

picout:
input picinpin

'--- wait until pic is ready to recieve
while picinpin = 0
pause 1
wend

'-transmit message to pic.
serout2 picoutpin, 16468, [donecommanding]
return






slave pic


define OSC 8
OSCCON = %1111110 ' sets internal osc to run at 8MHZ

'----------turn analog on porta off, and use as digital input/output '----------this is used to allow serial input on the A bus.
CMCON = 7 'Comparators OFF
ANSEL = 0 'A/D OFF -- Port pins all digital
'----------

'---**Pins
picinpin var porta.1
picoutpin var porta.0

ledpin var portb.4



'---**Variables


'---processing vars
ledstat var byte

'------**main program



main:

gosub recieve
gosub driveled

goto main 'loop forever



recieve:

'----send ready signal and wait for message with timeout 150.
high picoutpin ' ready to recieve
'----
serin2 picinpin, 16468, 150, driveled,[ledstat]
low picoutpin 'not ready to recieve data.
'-----end serial request



return 'return to main routine

driveled:
low picoutpin 'not ready to recieve data.

if ledstat = "O" then

high ledpin 'turn on led

else

low ledpin 'turn off led

endif

return


end



Now this code actually works when I send "O" the light turns on, when I send something else it turns off.

My problem is I have to be able to transfer data that looks like this "03|005|225|y".

DEC2 servonumber "|" DEC3 rate "|" DEC3 position "|" finalcommand (single byte "y"/"n")

I have been unable to transmit this kind of data, and in addition to that I will need to have the master look at the servonumber and send the message to the appropriate slave with the correct servonumber (as all the slaves will be numbered the same internally)

Please let me know if you have any suggestions, or insight into how to achieve this. I have made multiple attempts, but apparently my brain is not working.

mister_e
- 26th May 2007, 19:09
Different method to do that, i'll suggest to have a look at the following link

How to make your own PIC network
http://www.picbasic.co.uk/forum/showthread.php?t=1192

This could give you some pointers.

HTH

PS: most here, including myself, don't recommend to use the internal OSC for serial communication for reliability reasons. If your PIC have a USART, you should use it. HSERIN/HSEROUT. I'll also suggest you to read the available Modifier list. WAIT will be handy in your case.

gandora
- 27th May 2007, 00:24
I am using 16f88 which does have an internal AUSART. But what is the difference between serin2 and hserin. I am a little confused about it.

Sergeant
- 27th May 2007, 01:01
Serin2 & HSerin share modifiers you can use, but to use HSerin you must set the config bits in the PIC to specify you are using a hardware communication option instead of "bit banging" the serial comms using Serin2 (or Serin, for that matter).

Sorry, but you'll have to spend some more time in both the manual and the datasheet for your PIC to get it set up properly. Do a search in the Archives here in the forum, and with Google if you need more help. I've just about finished getting my comms working as I need, using these same procedures.

Good luck!
Brad

mister_e
- 27th May 2007, 01:53
I am using 16f88 which does have an internal AUSART. But what is the difference between serin2 and hserin. I am a little confused about it.

HSEROUT or HSERIN use the PIC Hardware USART, while SERIN/SERIN2/DEBUGIN use a software Serial communication solution.

The only restriction when you're using HSERIN/HSEROUT is the I/O and the amount of serial port. With HSERIN/HSEROUT, you MUST use the PIC dedicated i/o (RX/TX) while any other software solution (SERIN.. ) allow you to choose any i/o.

Using the PIC USART give you for free at very least, a 2 Bytes receiver buffer, and interrupt trigger sources.

gandora
- 28th May 2007, 08:22
Now thankyou all for your feedback, I still don't know exactly how to use hserin yet, but I will most certainly use it later. However I was able to come up with a way of getting my method to work.

Now the biggest problem is that using the internal clocks on both the master and the slave makes errors pop up, but I came up with a way to check for errors and continue to retransmit, or request data until it is error free. And I came up with the solution to the original problem which was that I just needed to use STR message\12. What I was doing in the original code was converting multiple bytes into single bytes, and then attempting to transfer them in that form, which changed the data format causing it to be unreadable by the driver.

the simplest method to solve that problem is:

message VAR byte[12]

serin2 pcinpin, 16468, [STR message\12]

and then

serout2 picoutpin, 16468, [STR message\12]

the problem with the above code is the fact that during the process of recieving and transmitting twice its almost guarenteed you will get bad data at some point.

my solution :master code:



define OSC 8
OSCCON = %1111110 ' sets internal osc to run at 8MHZ

'----------turn analog on porta off, and use as digital input/output
'----------this is used to allow serial input on the A bus.
CMCON = 7 'Comparators OFF
ANSEL = 0 'A/D OFF -- Port pins all digital
'----------

'---**Pins
rsoutpin var porta.0
rsinpin var porta.1

picinpin var portb.4
picoutpin var portb.5

porta=0
portb=0

'---vars
'-------- transfer vars
'servonum var byte: rate var word:position var word:donecommanding var byte
'--------

message var byte[12]
message2 var byte[12]


'---main program
goto pcin
'----- retrieve next set of commands from pc.
pcin:

'----send serial request
serout2 rsoutpin, 16468, ["waiting!"] 'call for data
'----
serin2 rsinpin, 16468, [str message\12,str message2\12]

'compare both arrays
if message[0]=message2[0] and message[1]=message2[1] and _
message[2]=message2[2] and message[3]=message2[3] and _
message[4]=message2[4] and message[5]=message2[5] and _
message[6]=message2[6] and message[7]=message2[7] and _
message[8]=message2[8] and message[9]=message2[9] and _
message[10]=message2[10] and message[11]=message2[11] then
'arrays equal eachother then
serout2 rsoutpin, 16468, [str message\12]
goto picout
endif




serout2 rsoutpin, 16468, ["bad data!"]
goto pcin

'---- picout procedure waits for high on picinpin and then transmits data

picout:
input picinpin

while picinpin = 0
pause 1
wend
serout2 picoutpin, 16468, [str message\12,str message\12]
pause 6

if picinpin = 1 then 'checks if data was recieved
goto picout 're-send until recieved
endif
serout2 rsoutpin, 16468, ["|transmission succesful|"] 'tell computer
goto pcin

end




Here is the code for the slaves recieve portion:




recieve:

'----send high pic request, and get user input for motor drive

high picoutpin

'----
'--by using skip 1 rather then wait ("|") losing data is
'--prevented when wait is used if the data goes through
'--wrong the command is lost altogether.

serin2 picinpin, 16468,15,drivemotor, [dec2 servonum,skip 1,_
dec3 rate,skip 1,dec3 position,skip 1,donecommanding,_
dec2 servonum2,skip 1,dec3 rate2,skip 1,dec3 position2,skip 1,_
donecommanding2]

'---verify that the data matches
if servonum!=servonum2 or rate!=rate2 or position!=position2 or _
donecommanding!=donecommanding2 then
'data is bad recieve again
goto recieve 'try again
endif

low picoutpin
'-----end serial request

gosub setupservo

goto drivemotor 'return to main routine






I have one question, would using a lower baud rate decrease the frequency of errors? If you have any suggestions to improve this code, please feel free to through in your two cents. Thanks again!

skimask
- 28th May 2007, 08:46
Now the biggest problem is that using the internal clocks on both the master and the slave makes errors pop up.........
I have one question, would using a lower baud rate decrease the frequency of errors? If you have any suggestions to improve this code, please feel free to through in your two cents. Thanks again!

You aren't going to be able to get away from serial transmission/reception errors when using the internal oscillator. If you were using the hardware UART, you might be able to tweak the baud by using the overrun and framing error bits in the UART itself (overrun generally too slow baud, framing generally too fast baud rate). But overall, if you're not tweaking OSCTUN for each 'F88, it's a crapshoot as to whether or not you oscillator is running near it's spec'd frequency or not, thereby, your SERIAL commands are off by the same amount.
And a lower baud rate might help, but it's certainly not a fix.



'compare both arrays -- easier to read method I think....
for temp = 0 to 11 : if message[temp] <> message2[temp] then goto baddataout
next temp
serout2 rsoutpin, 16468, [str message\12] 'arrays equal each other
goto picout

baddataout:
serout2 rsoutpin, 16468, ["bad data!"]
goto pcin

gandora
- 28th May 2007, 14:28
Awesome coding suggestions. I was able to get rid of 4 pages of code using similar thinking after you showed me that. (guess my brain just finally started working) ^^

also, I tried something just as a blind guess at a way to fix the problem, or help a little, and it worked really well. I put a 470 ohm resistor to the ground from the picin pin on the slave. seems to have gotten rid of noise that was causing it to think it was recieving data when it wasn't, and it lowered the number of errors in general pretty significantly.

Maybe thats standard practice? Or was it really insanity to genius. Anyways hopefully that fixed it. ^^

Archangel
- 29th May 2007, 05:08
Awesome coding suggestions. I was able to get rid of 4 pages of code using similar thinking after you showed me that. (guess my brain just finally started working) ^^

also, I tried something just as a blind guess at a way to fix the problem, or help a little, and it worked really well. I put a 470 ohm resistor to the ground from the picin pin on the slave. seems to have gotten rid of noise that was causing it to think it was recieving data when it wasn't, and it lowered the number of errors in general pretty significantly.

Maybe thats standard practice? Or was it really insanity to genius. Anyways hopefully that fixed it. ^^
Hmmmm, What it does is short out the hi impeadence noise, since the noise doesn't have the amperage to carry through, but the signal does.

gandora
- 29th May 2007, 06:01
Hmmmm, What it does is short out the hi impeadence noise, since the noise doesn't have the amperage to carry through, but the signal does.

Thats what I thought it was doing, I did the same thing with the line in from the pc and I haven't had any errors since, but I still have the double buffer system that will make sure i know when i get one.

Now I can move on to the next challenge. Which is, having multiple commands qued to be executed at once.

I will get to work on that task and post my results when I get somewhere with it.

gandora
- 29th May 2007, 08:27
I have now given the master an 8 command buffer. And finnally life is good ^^.

I think I am going to up the buffer to 16, but that will require that I use 2 buffer arrays. For now, heres the master code, feel free to make any suggestions, and just let me know if you use it in any projects.

:MSmaster:



'************************************************* ***************
'* Name : MSERVMASTER.BAS *
'* Author : Joseph Dattilo *
'* Notice : Copyright (c) 2007 Joseph Dattilo *
'* : All Rights Reserved *
'* Date : 5/25/2007 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************

define OSC 8
OSCCON = %1111110 ' sets internal osc to run at 8MHZ

'----------turn analog on porta off, and use as digital input/output
'----------this is used to allow serial input on the A bus.
CMCON = 7 'Comparators OFF
ANSEL = 0 'A/D OFF -- Port pins all digital
'----------

'---**Pins
rsoutpin var porta.0
rsinpin var porta.1

picinpin var portb.4
picoutpin var portb.5

porta=0
portb=0

'---vars

temp var byte
qued var byte
outqued var byte

message var byte[24]

'-up to 8 commands can be buffered in que array.
que var byte[96]
'---------------


qued = 0 'set number in que to 0
goto pcin

'############################## pc recieve ################################
'que up messages from pc
'################################################# #########################

pcin:

'---- let pc know we are ready to recieve message.
serout2 rsoutpin, 16468, ["waiting!"] 'call for data
'---- ready to recieve message
serin2 rsinpin, 16468, [str message\24]

'------------------------------------------------------------------------
'compare both arrays checking for bad data if data bad request it again.
for temp = 0 to 11 : if message[temp] <> message[temp+12] then goto baddata
next temp
'------------------------------------------------------------------------


serout2 rsoutpin, 16468, [str message\12] 'send confirmation of reciept.

'------------------inque-----------------
for temp = 0 to 11:que[(12*qued)+temp]=message[temp]:next temp
serout2 rsoutpin, 16468, ["Qued:",str que\(12*qued+12)] 'display all in que


'----------------------------------------

if message[11] = "n" then
serout2 rsoutpin, 16468, ["still more commands!?"] 'debug statement

qued=qued+1 'go to next position in que

goto pcin 'request the data for the next item.

else

outqued = 0 'set picout que start position to 0 (first item in que first)

goto picout 'we are ready to command the servo controller.

endif



'-------------------------
'where bad data takes you.
baddata:
serout2 rsoutpin, 16468, ["bad data!"]
goto pcin
'-------------------------



'############################## pic transmit #############################
'---- picout procedure waits for high on picinpin and then transmits data
'################################################# ########################

picout:

'---------------------unque next item into message array
for temp = 0 to 11:message[temp]=que[(12*outqued)+temp]
message[temp+12]=que[(12*outqued)+temp]:next temp
'-------------------------------------------------------

input picinpin

while picinpin = 0
pause 1
wend


serout2 picoutpin, 16468, [str message\24]
pause 7

if picinpin = 1 then 'checks if data was recieved
goto picout 're-send until recieved
endif

serout2 rsoutpin, 16468, ["SUCCESS|",str message\12,"|"] 'tell computer

if outqued < qued then

outqued = outqued +1 'move to next qued item
goto picout 'proceed to transmit it.
else
serout2 rsoutpin, 16468, ["|ALL",DEC (qued+1),"items transmitted succesfully|"]
qued=0
goto pcin
endif


end




It is important that you attribute for the pause 7 in the master in the slaves procedure to prevent the master from constantly retransmitting the first message in the que.

This is the modified recieve part of the function which allows the mserv slave to recieve any number of messages in a row.
:MSslave:



'############################SLAVE RECIEVE################################

'################################################# #####################

recieve:

'----send serial request, and get user input for motor drive timeout 70 ms

high picoutpin

'----

serin2 picinpin, 16468,20,drivemotor, [dec2 servonum[0],skip 1,_
dec3 rate[0],skip 1,dec3 position[0],skip 1,donecommanding[0],_
dec2 servonum[1],skip 1,dec3 rate[1],skip 1,dec3 position[1],skip 1,_
donecommanding[1]]

if servonum[0]!=servonum[1] or rate[0]!=rate[1] or _
position[0]!=position[1] or donecommanding[0]!=donecommanding[1] then
'data is bad recieve again
goto recieve 'try again
endif

low picoutpin
'-----

'setup the servo chosen
goalarray[servonum-1]=position[0] 'set servo goal
ratearray[servonum-1]=rate[0] 'set servo rate
'
'allow for multiple commands.
if donecommanding[0] = "n" then
pause 7 'pause long enough to make sure master does not attempt retrans.
goto recieve
endif



goto drivemotor

gandora
- 29th May 2007, 08:59
Okay so that wasn't too hard.

The master transmitter now uses pretty much all of the ram available on the 16F88 as a buffer. Allowing 16 commands to be stored and transmitted from 2 seperate buffers.

I am pretty sure I will not be needing more then that for this project and so here it is.

:MSmaster:



'************************************************* ***************
'* Name : MSERVMASTER.BAS *
'* Author : Joseph Dattilo *
'* Notice : Copyright (c) 2007 Joseph Dattilo *
'* : All Rights Reserved *
'* Date : 5/25/2007 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************

define OSC 8
OSCCON = %1111110 ' sets internal osc to run at 8MHZ

'----------turn analog on porta off, and use as digital input/output
'----------this is used to allow serial input on the A bus.
CMCON = 7 'Comparators OFF
ANSEL = 0 'A/D OFF -- Port pins all digital
'----------

'---**Pins
rsoutpin var porta.0
rsinpin var porta.1

picinpin var portb.4
picoutpin var portb.5

porta=0
portb=0

'---vars

temp var byte
qued var byte
outqued var byte

message var byte[24]

'-up to 8 commands can be buffered in each que array adding up to 16 altogether.
que var byte[96]
que2 var byte[96]
'---------------


qued = 0 'set number in que to 0
goto pcin

'############################## pc recieve ################################
'que up messages from pc
'################################################# #########################

pcin:

'---- let pc know we are ready to recieve message.
serout2 rsoutpin, 16468, ["waiting!"] 'call for data
'---- ready to recieve message
serin2 rsinpin, 16468, [str message\24]

'------------------------------------------------------------------------
'compare both arrays checking for bad data if data bad request it again.
for temp = 0 to 11 : if message[temp] <> message[temp+12] then goto baddata
next temp
'------------------------------------------------------------------------


serout2 rsoutpin, 16468, [str message\12] 'send confirmation of reciept.

'------------------inque-----------------

for temp = 0 to 11
if qued<8 then 'add to first que
que[(12*qued)+temp]=message[temp]
else 'add to second que
que2[(12*(qued-8))+temp]=message[temp]
endif
next temp

if qued>7 then
serout2 rsoutpin, 16468, ["Que 1:",str que\96, _
"Que 2:",str que2\(12*(qued-8)+12)]

else

serout2 rsoutpin, 16468, ["Que 1:",str que\(12*qued+12)] 'display all in que

endif
'----------------------------------------

if message[11] = "n" and qued<15 then

serout2 rsoutpin, 16468, ["still more commands!?"] 'debug statement

qued=qued+1 'go to next position in que

goto pcin 'request the data for the next item.

else

outqued = 0 'set picout que start position to 0 (first item in que first)

goto picout 'we are ready to command the servo controller.

endif



'-------------------------
'where bad data takes you.
baddata:
serout2 rsoutpin, 16468, ["bad data!"]
goto pcin
'-------------------------



'############################## pic transmit #############################
'---- picout procedure waits for high on picinpin and then transmits data
'################################################# ########################

picout:

'---------------------unque next item into message array
for temp = 0 to 11



if outqued<8 then 'add to first que
message[temp]=que[(12*outqued)+temp]
message[temp+12]=que[(12*outqued)+temp]
else 'add to second que
message[temp]=que2[(12*(outqued-8))+temp]
message[temp+12]=que2[(12*(outqued-8))+temp]
endif

next temp
'-------------------------------------------------------

input picinpin

while picinpin = 0
pause 1
wend


serout2 picoutpin, 16468, [str message\24]
pause 7

if picinpin = 1 then 'checks if data was recieved
goto picout 're-send until recieved
endif

serout2 rsoutpin, 16468, ["SUCCESS|",str message\12,"|"] 'tell computer

if outqued < qued then

outqued = outqued +1 'move to next qued item
goto picout 'proceed to transmit it.
else
serout2 rsoutpin, 16468, ["|ALL",DEC (qued+1),"items transmitted succesfully|"]
qued=0
goto pcin
endif


end




As a note no changes need be made to the slave from last version for cross compatability.