PDA

View Full Version : Read string from Serial Port and convert it to numbers



John Astralidis
01-09-2006, 03:27 PM
· http://forums.parallax.com/images/smilies/hop.gif

Hi all !

I have the BoeBot with Board of Education Rev.C and I want to know if there is a way to read a String (format: xxx,yyy.) from serial port with SERIN command and to convert the first 3 characters (xxx) to a decimal number (e.c. 755) and the last three (yyy) to another.
I don't want to use the command
"SERIN ...[DEC num1, DEC num2], as there is a problem to correctly interpret the whole string given by the serial port (at once, non char-by-char) to Microcontroller.

Thank you, in advance.
John Astralidis.

stamptrol
01-09-2006, 08:01 PM
John,

Without knowing what the string looks like, this is just a guess. More information is always better than less information!

You should be able to use this idea: "Serin .....[DEC3 num1,SKIP x,DEC3 num2] where x is the number of characters to ignore between the two good numbers.

Cheers

PJ Allen
01-09-2006, 08:59 PM
John A. said...
to convert the first 3 characters (xxx) to a decimal number (e.c. 755) and the last three (yyy) to another.

· Is (xxx) BCD?· I'm not clear on what their form is.

· I think what you want (?) to do is structure the SERIN formatter so that you take in, as it were, each digit and place it in a variable using STR (see SERIN for more info).· Then you can take those variables and do your conversions.


Post Edited (PJ Allen) : 1/9/2006 2:04:32 PM GMT

Jon Williams
01-09-2006, 09:29 PM
John,

So long as the baud rate is 9600 or less (this gives the BASIC Stamp enough time during the stop bit to work on the incoming data), the DEC modifier works fine. Just make sure that your output variable is big enough to hold the value that will be coming in (you'll need a Word for values greater than 255).

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

John Astralidis
01-10-2006, 06:54 AM
OK, I will try to be more specific.

I have written a Java Joystick-Interface Program that polls joystick's·axis positions·every 30ms. Then, I convert these positions into two decimal numbers from 500 to 999, as to instruct both Standard servos to rotate clockwise or counterclockwise, accordingly and I put them in a 9-character string like: "(670,978)" (I put the left, right parenthesis and comma, in order to Basic Stamp interpret the string into two decimal numbers with the SERIN command). Finally, I transmit that string over a wireless network through a TCP port.

Then with a C program, compiled for a MIPS Linux Box (my Linksys WRT54GS Router), I receive that string and send it char-by-char to serial port (BoeBot), with usleep(30000) interval between each character.

Finally, it's up to Basic Stamp to interpret that string into the decimal numbers 670 for servo1 and 978 for servo2.

My problem is that the Basic Stamp does not interpret correctly the strings many times, because of the low interval (and not in a network transmission packet error, as I checked). And what I really want is as low as possible interval without faulty interpretions.

I also tried to send once a time the whole string, but nothing changed. Then, I read·an example in Basic Stamp Language Manual in SERIN command, saying·that·a flow pin is needed to control the serial connection between two Basic Stamps, because without it only the first byte of a string is read correctly, the rest are gone. But, I do not connect two Basic Stamps. So, I can't use the flow pin.·Can I?

My last thought is to read the 9-character string from serial port in format like: "(670,978)" and firstly interpret it into 9-character string STR /9 and then with Maths or other tricky way to convert the part 3-characters string "670" into decimal number 670 and the other part 3-characters string "978" into another decimal number 978. With this way, there will be no interpretion errors, as I checked that Basic Stamp interprets correctly STRINGS into Strings when are transmitted at once.

I hope I made clear what I'm trying to do and what my problem is.
Thank U all for the immediate support. I look forward hearing from U again.

John Astralidis.
---------------------------------------------------------------------------------------------------------------------------------------------

PJ Allen
01-10-2006, 08:00 AM
Resolved --
The STAMP is to receive this ASCII transmission: (670,978); furthermore,·LEFTVAL will be the decimal value of 670 and RIGHTVAL will be the decimal value 978.

In this example, I'm set up for 4800, 8N1 --


' {$STAMP BS2}
' {$PBASIC 2.5}

LEFTVAL VAR Word
RIGHTVAL VAR Word
SERIN 9,188,[WAIT("("),DEC LEFTVAL,DEC RIGHTVAL]

Is this like what you've tried?
It's cued by the first parenthesis.· The decimal formatter waits for the comma (first non-numeric char) as a marker for LEFTVAL and then the terminal parenthesis as a marker for RIGHTVAL.
Does it not work?
If not, please send along what you've done to aid discussion.

Newzed
01-10-2006, 08:06 AM
PJ, don't you have an extra· ("· in therehttp://forums.parallax.com/images/smilies/shakehead.gif

Sid

Jon Williams
01-10-2006, 08:06 AM
If you've got enough time between characters, this will should help:

Get_Values:
· SERIN Sio, Baud, [char]
· IF (char <> "(") THEN Get_Values
· xVal = 0
· yVal = 0

Get_X:
· DO
··· SERIN Sio, Baud, [char]
·· ·IF (char = ",") THEN·EXIT
·· ·xVal = xVal * 10 + (char - "0")
· LOOP

Get_Y:
· DO
·· ·SERIN Sio, Baud, [char]
·· ·IF (char = ")") THEN·EXIT
·· ·yVal = yVal * 10 + (char - "0")
· LOOP

· RETURN

Note that this code does not deal with spaces -- it is counting on your string to look like: (xxx,yyy) -- though PJ's solution is what I would use if this is my project.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

PJ Allen
01-10-2006, 08:07 AM
Newzed,

Explain.· [I don't see anything amiss.]

Newzed
01-10-2006, 08:13 AM
I was expecting WAIT("), but I see now.· Your WAIT character is· (· .

Sid

John Astralidis
01-10-2006, 10:04 AM
---------------------------------------------------------------------------------------------------------------------------------------------
SORRY FOR BEING LATE TO REPLY. PROBLEMS WITH GREEK DIAL-UP! ARGHHH!!!
---------------------------------------------------------------------------------------------------------------------------------------------
Jon,
I really appreciate the code-help. But how could I use it in my code listed below (at the end) ?

I checked more carefully the output results in my linux shell and I think that the real problem is that even though it gets apart the numbers from the whole string, it mixes up the numbers. For example, if the correct numbers were 670 and 978 they may become something like ?70 and 9&8. Below, I wrote down the .bs2 code. I made some modifications and I instruct Basic Stamp to ignore numbers out of the scale of [500,999].

Although, I try to A. get a string (like: 555666) ...
**************************************
test_string VAR Word(6)
SERIN 16, 16468, [STR test_string\6]
**************************************
... B. extract each character to a variable...
**************************************
char0 var Word
char1 var Word
char2 var Word
char3 var Word
char4 var Word
char5 var Word
**************************************
...C. convert char0...5 to seperate numbers , like character "6" ·to number 6 and so on...
************************************************** *********************
?????????????????????????????????????????????????? ?????????????????????????????????????????
************************************************** *********************
...D. multiply char0 100 times,
·········· //······· ·char1·· 10 times,
·········· //······· ·char2···· 1 times
··· and sum them together, so I get the 1st decimal number through the received string and with the same way for char3...5
··· to get the other decimal number.
************************************************** *************************************************
?????????????????????????????????????????????????? ?????????????????????????????????????????????????? ???????????????????????????
************************************************** *************************************************

If you have any ideas on how to implement steps C. and D. I would be very grateful !!!
Here is my modified code that is currently running on my BoeBot. Also, I attached·2 sshots of my linux shell with the output results.

THE CODE....
################################################## #################################################
'{$STAMP BS2}
'{$PBASIC 2.5}

servo1· CON 12
servo2· CON 13
pulse1· VAR Word
pulse2· VAR Word
p1······· VAR Word
p2······· VAR Word
counter VAR Byte

'Sign program start or battery low
FREQOUT 4, 300, 3000
p1 = 0
p2 = 0

'Center servos
FOR counter = 1 TO 20
·· PULSOUT servo1, 750
·· PULSOUT servo2, 750
·· PAUSE 20
NEXT

'Enter main loop to read incoming data (bytes)
loop1:
·· SERIN· 16, 16468, [DEC pulse1, DEC pulse2]
·· IF (pulse1 >= 500) AND (pulse1 <= 999) THEN
····· p1 = pulse1
····· PULSOUT servo1, p1
·· ELSE
····· DEBUG "(Wrong pulse1)"
·· ENDIF
·· IF (pulse2 >= 500) AND (pulse2 <= 999) THEN
····· p2 = pulse2
····· PULSOUT servo2, p2
·· ELSE
····· DEBUG "(Wrong pulse2)"
·· ENDIF
·· IF (p1 <> 0) AND (p2 <> 0) THEN
····· DEBUG· "(", DEC p1, ",", DEC p2, ")"
·· ENDIF
GOTO loop1
################################################## #################################################

THE RESULTS: 1ST SSHOT (WRONG.JPG) SENDING THE STRING (670,978) TO SERIAL PORT 70 TIMES WITH 15MS INTERVAL BETWEEN EACH
··················· CHARACTER.
···················· 2ND SSHOT(ALMOST_CORRECT.JPG) SENDING THE STRING (670,978) TO SERIAL PORT 70 TIMES WITH 35MS INTERVAL BETWEEN
··················· EACH CHARACTER.

(I hope the sshots attached correctly ... As I can't see them anywhere attached. )

Thank U all in advance, for UR time.

Hope hearing from U soon.

Regards,
John Astralidis.

PJ Allen
01-10-2006, 07:09 PM
I think that your line:·SERIN· 16, 16468, [DEC pulse1, DEC pulse2]

should be re-written as: SERIN· 16, 16468, [WAIT("("),DEC pulse1, DEC pulse2]

You really need to have it WAIT for the "(", otherwise, I think,·it jumps right in and takes whatever is being sent, right in the middle of things, regardless.

Have you tried this, yet?

John Astralidis
01-10-2006, 07:15 PM
Hi, PJ.

No, I haven't yet. I'll try it and let you know.

Also, could you please let me know if there is a way to implement steps C. and D. that I mentioned in my previous post ?
I would be very grateful!

Thank U.

John.

PJ Allen
01-10-2006, 08:33 PM
Regarding C. --
The ASCII codes for the numbers 0-9 are: $30, $31, $32, $33, $34, $35, $36, $37, $38, $39.· So, you see, the least significant digit turns out to be equal to the number itself.
If you received a series of ASCII characters "(123456)", you would take them in as a series of bytes/VARiables:


' {$STAMP BS2}
' {$PBASIC 2.5}

DIG1 VAR Byte
DIG2 VAR Byte
DIG3 VAR Byte
DIG4 VAR Byte
DIG5 VAR Byte
DIG6 VAR Byte

SERIN 16, 16468, [WAIT("("),STR DIG1\1,STR DIG2\1,STR DIG3\1,STR DIG4\1,STR DIG5\1,STR DIG6\1]

DIG1 = DIG1 & $0F 'truncates the MSD, VAL = LSD
DIG2 = DIG2 & $0F 'truncates the MSD, VAL = LSD
DIG3 = DIG3 & $0F 'truncates the MSD, VAL = LSD
DIG4 = DIG4 & $0F 'truncates the MSD, VAL = LSD
DIG5 = DIG5 & $0F 'truncates the MSD, VAL = LSD
DIG6 = DIG6 & $0F 'truncates the MSD, VAL = LSD

The above assumes the data will be sent in six-digit format.
You could shorten this up, of course, but I think it's most apparent (understandable at first sight)·this way.
I think you can then manage to multiply and add the resulting VALues, as you require for D.



Post Edited (PJ Allen) : 1/10/2006 2:42:03 PM GMT

Bruce Bates
01-10-2006, 08:43 PM
PJ -

I think there's a typo in the part of SERIN which fields DIG2. I suspect it's supposed to read as follows:

SERIN 16, 16468, [WAIT("("),STR DIG1\1,STR DIG2\1,STR DIG3\1,STR DIG4\1,STR DIG5\1,STR DIG6\1]

Regards,

Bruce Bates

John Astralidis
01-10-2006, 08:50 PM
Allen,

GREAT! I couldn't find this alone! Is it anywhere in BS manual to take a close look?

Also, I think that "SERIN 16, 16468, .... STR DIG2\2..." is a mistake and should be "SERIN 16, 16468, .... STR DIG2\1...", like the rest. Am I right?

Thank U very much.

John.

John Astralidis
01-10-2006, 08:55 PM
Thanks Bruce.

Also, I would like to ask if I should add a right parenthesis in the end of SERIN command like:

SERIN 16, 16468, [WAIT("("),STR DIG1\1,STR DIG2\1,STR DIG3\1,STR DIG4\1,STR DIG5\1,STR DIG6\1,WAIT(")")]

so as to be kind of an end character of the whole string.

What do U think? Is it necessary?

John.

PJ Allen
01-10-2006, 08:59 PM
Whoops -- sorry about that DIG2 \2 -- yes, it should be \1

I don't think you need any mention of ")" -- it's like a "don't care" at that point.

The SERIN/SEROUT (almost the same) in HELP present a LOT of information.· The HELP has all the tools, you just have to read and think about how to use them.· Sometimes I use a wrench like it was a hammer.

**************

[ I have edited the program, lest some innocent bystander get hold of it without reading this far.· http://forums.parallax.com/images/smilies/smile.gif· ]

Post Edited (PJ Allen) : 1/10/2006 2:43:30 PM GMT

John Astralidis
01-10-2006, 09:13 PM
So, what the need for the left parenthesis "(" if I send a six-byte string like: 567807 and take the first 3 bytes·for my first decimal 3-digit number (567) and the rest for the second one (807)? Could be any kind of problem? I run the program and all seemed to be OK. Am I missing something?

John.

PJ Allen
01-10-2006, 09:30 PM
When you WAIT for the "(", that's the sign that you are at the START instead of in the middle (it's like "(" = 'something good is going to happen!).·
If you send (123) and (456) then you don't know which number is for what (do you?).· You could send "L123" and "R456" and have it WAIT for an L or an R, if you want to receive/send the values independently (L is for Left servo, R is for Right servo, or whatever).· If you need the VALues as Pairs, then stick with WAITing for "(".

Jon Williams
01-10-2006, 10:07 PM
...and add a non-numeric delimiter in between. In the end, with this string: (111,222), PJ presented the cleanest solution several posts ago:

SERIN Sio, Baud, [WAIT("("), DEC xVal, DEC yVal]

You could always add a timeout to the call if that is needed by your program.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

John Astralidis
01-10-2006, 11:42 PM
PJ,
I tried "SERIN· 16, 16468, [WAIT("("), DEC3 pulse1, SKIP 1, DEC3 pulse2, WAIT(")")]", but there are still errors.
Also, I tried your latest code with "SERIN 16, 16468, [WAIT("("),STR DIG1\1,STR DIG2\2,STR DIG3\1,STR DIG4\1,STR DIG5\1,STR DIG6\1]" command.

I figured out that the problem is that Basic Stamp gets confused when it has to read single bytes or characters or strings or any other variables once at atime with low interval between each byte read. I mean that if I use the above command: "SERIN 16, 16468, [WAIT("("),STR DIG1\1,STR DIG2\1,STR DIG3\1,STR DIG4\1,STR DIG5\1,STR DIG6\1]", Basic Stamp board has to recognise 6 different bytes between "()" parenthesises. And here come the recognition errors.

You can try this, by making a macro in Basic Stamp's console program as to auto-insert the bytes "123456". Try this and you won't see the string "123456" you entered but something like "5σ1".

The problem fixed when I replaced the above SERIN command with this one : "SERIN 16,16468,[STR pulses\6]". Then, with the above macro, when I press the key combination Ctrl+Shift+A the string "123456" is written to serial port and immediately displayed in the debug (blue) screen, without errors. And that's, because (this time) Basic Stamp had to read ONLY ONE variable.

This is the code...
-------------------------------------------------------------------------
'{$STAMP BS2}
'{$PBASIC 2.5}

pulses VAR Word
d1···· VAR Byte ' for future use to put pulses 1st byte in
d2···· VAR Byte ' for future use to put pulses 2nd byte in
d3···· VAR Byte ' for future use to put pulses 3rd byte in
d4···· VAR Byte ' for future use to put pulses 4th byte in
d5···· VAR Byte ' for future use to put pulses 5th byte in
d6···· VAR Byte ' for future use to put pulses 6th byte in

Main:
SERIN 16,16468,[STR pulses\6]
DEBUG· STR pulses
GOTO Main
-------------------------------------------------------------------------

Now, I want to put into these 6 variables d1...6 each byte of the received
string "123456".· Like d1 = "1"
··························· ·d2 = "2"
···························· d3 = "3"
···························· d4 = "4"
·························· · d5 = "5"
·························· · d6 = "6"
·······································
·Is that possible ???

I believe this is the last problem of my project and if solved then I could
go on.

Please, any kind of help/idea would be highly appreciated.

Regards,
John Astralidis.

Bruce Bates
01-11-2006, 12:01 AM
John -

Try using a pin port other than pin port 16 and see if things don't change for the better. Pin port 16 is actually the DEBUG port.

Regards,

Bruce Bates

PJ Allen
01-11-2006, 01:20 AM
I wonder if I could make any money selling a MAX232/233 plug-in board?

Jon Williams
01-11-2006, 01:36 AM
Ask Al Williams, he's already selling one.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

PJ Allen
01-11-2006, 04:00 AM
Well --·a lot of people need one. Should Astralidis's program work through SERIN 16 or not?· I always use RS232 through P0-15 and don't have any troubles, leaving "SIN" & "SOUT" for programming purposes only.

Post Edited (PJ Allen) : 1/10/2006 9:23:00 PM GMT

John Astralidis
01-11-2006, 04:30 AM
PJ, have you anything in mind how to get the following done ?

We get a string via SERIN 16,16468, [STR serstring\6]
and then we want to extract each character of the string to seperate variables.
As I mentioned in previous post. Just like this...

serstring = "123456"
ch1 = "1"
ch2 = "2"
ch3 = "3"
ch4 = "4"
ch5 = "5"
ch6 = "6'

If anyone have an idea please let me know.

John.

PJ Allen
01-11-2006, 04:42 AM
John,
Are you an electronics person?
Can you make up a RS232-TTL converter (using a MAX-232)?

Can you slow your data speed to the STAMP from 9600 to 4800?· I've used STRs with a GPS at 4800 and it works great and I have to take in a lot more data/VARiables than you are here.· I don't use the STAMP programming ports (SIN/SOUT) for COMM.· I always use P0-P15 with a MAX-232.

If not,·I'd like you to make a stripped down program that's nothing but receiving data and tell me exactly what the data form is.· I say, let's have it be transmitted always (######) -- it always starts with a parenthesis and that's always followed by 6 numbers.· This way we won't have so much change [ Deviation Kills ].

OK?· Nothing but COMMunications: VARs,... SERIN..., STR,...·but get rid of everything else.·

John Astralidis
01-11-2006, 04:42 AM
Paul Baker,

Thanks for the advice. I'll give it a try. Do I have to change anything in my Basic Stamp hardware or anything else except from a simple pin number in code?

Also, do you have in mind anything particular about the pervious post-message (about the string extraction)?

John.

John Astralidis
01-11-2006, 04:49 AM
Allen,

no I am not an electronics person. I am a Master Degree college student in Computing & Telecommunications Enginnering Department of University of Thesally (Greece).
I really have to say that I do not understand your last post. But, if you could help me with the string-extraction-to-seperate-variables ("123456") matter I posted above I would be very grateful.

Thank U.

John.

John Astralidis
01-11-2006, 06:09 AM
Allen,

I did not quite understand what you'd like me to make (about the program). Could you please say again?
Also, did you have any idea about the string-extraction-to-different-variables matter?

Thanks

John

PJ Allen
01-11-2006, 06:09 AM
I have found that the STAMP has trouble with decimal formatting at 9600 baud (bps).
The HELP for SERIN/SEROUT states that this is likely.

Anyway, I say this because I have downloaded the following program and verified my statement.
It would not work at 9600, but it works great at 4800 bps.

It is practically the same program that I first sent.· However, it is using SERIN 16 like you want.·
I have an LED on P0 and another on P1 that turn on to verify the outputs·in accordance with·valid/desired SERIN,·they confirm LEFTVAL and RIGHTVAL correctness.

I send data·to the STAMP using the first format, that is,·with the parentheses and the comma in·the middle: (###,###).

My Conclusion --
I think that you need to slow down your Linux or whatever is sending data to the STAMP to 4800 bps.·
Hopefully this will not be·impossible.

Try it, you'll like it.


' {$STAMP BS2}
' {$PBASIC 2.5}
' {$PORT COM1}

LEFTVAL VAR Word
RIGHTVAL VAR Word

Prelims:
DIRS = $0F 'MSB INs, LSB OUTs
OUTL = %00000000 'preset OUTs
INH = %00000000

LEFTVAL = 0
RIGHTVAL = 0

GetData:
SERIN 16, 16572,[WAIT("("),DEC LEFTVAL,DEC RIGHTVAL]
IF LEFTVAL = 100 THEN GOSUB LED1ON
IF RIGHTVAL = 200 THEN GOSUB LED2ON
PAUSE 5000
GOTO LEDSOFF

LED1ON:
OUT0 = 1
RETURN

LED2ON:
OUT1 = 1
RETURN

LEDSOFF:
OUTL = %00000000
LEFTVAL = 0
RIGHTVAL = 0
GOTO GetData



... and That's The Way It Is.



Post Edited (PJ Allen) : 1/10/2006 11:12:05 PM GMT

John Astralidis
01-11-2006, 06:19 AM
Allen Thank I 'll try .

Could you please remind me what the proper number for 4800 8n1 connection to write in my code? I mean like 16468 is for 9600 8n1. What s for 4800 8n1?

John.

PJ Allen
01-11-2006, 06:20 AM
It is 16572 -- it's right there in the program, John.· C'mon.

Ryan Clarke
01-11-2006, 06:32 AM
On a side note,

PJ, I have had SERINs not work when I looked for an early termination char (the \L {\E} )- but *did* work when I omitted the specified end character. (At certain speeds, namely 9600.) Just confirming your statements.

Ryan

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Ryan Clarke
Parallax Tech Support

RClarke@Parallax.com (mailto:RClarke@Parallax.com)

John Astralidis
01-11-2006, 06:32 AM
Ok, sorry.

I have only 1 serial port in my PC sharing both modem Internet Connection and Communication with BoeBot. So, each time I want to test a program I have to disconnect.
It's really irritating! If I use a usb-to-serial adapter do U think I will solve this problem? I mean, the Basic Stamp will be successfully recognised by the program editor?

John.

[I'll try your code now...]

PJ Allen
01-11-2006, 06:36 AM
It would not hurt to try, John.· Make sure that they are on different COM #.· We're all waiting, buddy.

Post Edited (PJ Allen) : 1/10/2006 11:40:25 PM GMT