Read string from Serial Port and convert it to numbers
John Astralidis
Posts: 28
·
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.
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.
Comments
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
· 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
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
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.
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 --
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.
Sid
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
Explain.· [noparse][[/noparse]I don't see anything amiss.]
Sid
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.
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?
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.
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:
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
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
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.
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.
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.· · ]
Post Edited (PJ Allen) : 1/10/2006 2:43:30 PM GMT
John.
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 "(".
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
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.
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
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax
Post Edited (PJ Allen) : 1/10/2006 9:23:00 PM GMT
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.
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.·
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.
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.
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