Shop OBEX P1 Docs P2 Docs Learn Events
Read string from Serial Port and convert it to numbers — Parallax Forums

Read string from Serial Port and convert it to numbers

John AstralidisJohn Astralidis Posts: 28
edited 2006-01-10 23:36 in BASIC Stamp
· 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 ...[noparse][[/noparse]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.
«1

Comments

  • stamptrolstamptrol Posts: 1,731
    edited 2006-01-09 13:01
    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 .....[noparse][[/noparse]DEC3 num1,SKIP x,DEC3 num2] where x is the number of characters to ignore between the two good numbers.

    Cheers
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-09 13:59
    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 WilliamsJon Williams Posts: 6,491
    edited 2006-01-09 14:29
    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 AstralidisJohn Astralidis Posts: 28
    edited 2006-01-09 23:54
    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.
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 01:00
    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,[noparse][[/noparse]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.
  • NewzedNewzed Posts: 2,503
    edited 2006-01-10 01:06
    PJ, don't you have an extra· ("· in thereshakehead.gif

    Sid
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-01-10 01:06
    If you've got enough time between characters, this will should help:

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

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

    Get_Y:
    · DO
    ·· ·SERIN Sio, Baud, [noparse][[/noparse]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
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 01:07
    Newzed,

    Explain.· [noparse][[/noparse]I don't see anything amiss.]
  • NewzedNewzed Posts: 2,503
    edited 2006-01-10 01:13
    I was expecting WAIT("), but I see now.· Your WAIT character is· (· .

    Sid
  • John AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 03:04


    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 [noparse][[/noparse]500,999].

    Although, I try to A. get a string (like: 555666) ...
    **************************************
    test_string VAR Word(6)
    SERIN 16, 16468, [noparse][[/noparse]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, [noparse][[/noparse]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.
    823 x 988 - 135K
    812 x 978 - 188K
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 12:09
    I think that your line:·SERIN· 16, 16468, [noparse][[/noparse]DEC pulse1, DEC pulse2]

    should be re-written as: SERIN· 16, 16468, [noparse][[/noparse]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 AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 12:15
    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.
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 13:33
    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, [noparse][[/noparse]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 BatesBruce Bates Posts: 3,045
    edited 2006-01-10 13:43
    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, [noparse][[/noparse]WAIT("("),STR DIG1\1,STR DIG2\1,STR DIG3\1,STR DIG4\1,STR DIG5\1,STR DIG6\1]

    Regards,

    Bruce Bates
  • John AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 13:50
    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 AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 13:55
    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, [noparse][[/noparse]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.
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 13:59
    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.

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

    [noparse][[/noparse] I have edited the program, lest some innocent bystander get hold of it without reading this far.· smile.gif· ]

    Post Edited (PJ Allen) : 1/10/2006 2:43:30 PM GMT
  • John AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 14:13
    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.
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 14:30
    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 WilliamsJon Williams Posts: 6,491
    edited 2006-01-10 15:07
    ...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, [noparse][[/noparse]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 AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 16:42
    PJ,
    I tried "SERIN· 16, 16468, [noparse][[/noparse]WAIT("("), DEC3 pulse1, SKIP 1, DEC3 pulse2, WAIT(")")]", but there are still errors.
    Also, I tried your latest code with "SERIN 16, 16468, [noparse][[/noparse]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, [noparse][[/noparse]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,[noparse][[/noparse]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,[noparse][[/noparse]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 BatesBruce Bates Posts: 3,045
    edited 2006-01-10 17:01
    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
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 18:20
    I wonder if I could make any money selling a MAX232/233 plug-in board?
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-01-10 18:36
    Ask Al Williams, he's already selling one.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 21:00
    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 AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 21:30
    PJ, have you anything in mind how to get the following done ?

    We get a string via SERIN 16,16468, [noparse][[/noparse]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.
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-01-10 21:42
    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 [noparse][[/noparse] Deviation Kills ].

    OK?· Nothing but COMMunications: VARs,... SERIN..., STR,...·but get rid of everything else.·
  • John AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 21:42
    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 AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 21:49
    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 AstralidisJohn Astralidis Posts: 28
    edited 2006-01-10 23:09
    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
Sign In or Register to comment.