Serial communication (two-way) between VB '05 Express and BS
SeanT
Posts: 17
Hi, I've run into a problem where I can't have my PBASIC program make a decision on values higher than one digit. Here's what is happening: values are entered to the Stamp via a serial connection to a VB program, and I want the stamp to analyze those values and do a task that will eventually scale the values. This is a BS2 and PBASIC 2.5.
This is where the values come from, so from the VB program I send two numbers mushed together, and place them into separate bytes with PBASIC once received. So for X and Y values 10 or greater, would the byte array really·need to be of size 4? I figure if the stamp takes in a value of 1512 corresponding to X = 15 and Y = 12, I can take XY(0) and multiply that by 10 and add to it XY(1). This should give me for X the correct value I'm looking for, 15 (please comment and tell me if there is an easier way to do this or if this will actually work correctly).
Now for the strange part: when I go to the subroutine Analyze, for testing purposes I have this:
When I enter this in and try to·send to the stamp, the stamp editor tells me it is expecting a THEN right after the 1 from the 15. I can enter it as X = (15), but then the conditional doesn't work correctly and I get a Task1 incorrectly·if the value I send for X starts with a 1 at all, 10-19. Obviously, I want to avoid this. Perhaps there is some crucial syntax rule that I am missing?
I can also enter the conditional as X = 15 AND Y = 12, but I don't ever go to Task1, even if I send 1512 to the stamp, so it seems it doesn't recognize any of the data if there are no quotation marks (but perhaps this is my array math not working - but on second thought, I seem to remember it not working this way for single digits either, but it worked for the quotation marks).
If you see some simple error that I'm making, feel free to tell me. I'm having some trouble understanding why I can say my conditional requires X = 1, but the program says I've met that condition with an X value of 10. I'm also really confused as to why the program will allow only one digit between quotation marks. Please enlighten me.
Thanks,
Sean
Post Edited (SeanT) : 10/31/2006 5:40:52 PM GMT
GetInput: SERIN INPUT_PIN, BAUDMODE, [noparse][[/noparse]STR XY\4] X = XY(0)*10 + XY(1) Y = XY(2)*10 + XY(3) GOSUB Analyze RETURN
This is where the values come from, so from the VB program I send two numbers mushed together, and place them into separate bytes with PBASIC once received. So for X and Y values 10 or greater, would the byte array really·need to be of size 4? I figure if the stamp takes in a value of 1512 corresponding to X = 15 and Y = 12, I can take XY(0) and multiply that by 10 and add to it XY(1). This should give me for X the correct value I'm looking for, 15 (please comment and tell me if there is an easier way to do this or if this will actually work correctly).
Now for the strange part: when I go to the subroutine Analyze, for testing purposes I have this:
IF X = "15" AND Y = "12" THEN GOSUB Task1 RETURN ELSE GOSUB Task4 RETURN ENDIF
When I enter this in and try to·send to the stamp, the stamp editor tells me it is expecting a THEN right after the 1 from the 15. I can enter it as X = (15), but then the conditional doesn't work correctly and I get a Task1 incorrectly·if the value I send for X starts with a 1 at all, 10-19. Obviously, I want to avoid this. Perhaps there is some crucial syntax rule that I am missing?
I can also enter the conditional as X = 15 AND Y = 12, but I don't ever go to Task1, even if I send 1512 to the stamp, so it seems it doesn't recognize any of the data if there are no quotation marks (but perhaps this is my array math not working - but on second thought, I seem to remember it not working this way for single digits either, but it worked for the quotation marks).
If you see some simple error that I'm making, feel free to tell me. I'm having some trouble understanding why I can say my conditional requires X = 1, but the program says I've met that condition with an X value of 10. I'm also really confused as to why the program will allow only one digit between quotation marks. Please enlighten me.
Thanks,
Sean
Post Edited (SeanT) : 10/31/2006 5:40:52 PM GMT
Comments
··· RETURN
··· ELSE
··· GOSUB Task4
··· RETURN
· ENDIF
I think you need the parentheses.· If the X·AND Y conditions are not met then it will RETURN --·it'll never hit the ELSE.· Does the program branch to this IF...THEN as the result of a GOSUB?
Yes this IF...THEN is branched to through a GOSUB. I'll check on your syntax later, I didn't try it like that.·However, it looks like I'll still get an error from the editor due to what's inside the parentheses, because they are only allowing one digit between quotation marks. Maybe in the format you gave me it should work without the quotation marks?...I'll test that and post back later. Thanks for the tip though...
Sean
By accepting it as a string, you are trying to do math on ASCII values. "1" is a byte value of $31, "2" is $32. While you could do this with your string:
X = XY(0)-$30 * 10 + (XY(1)-$30)
Y = XY(2)- $30 * 10 + (XY(3)-$30)
then use
IF X = 15 AND Y = 12 THEN
....
But strings are hard to manipulate anyway, an easier method is to accept it back as DEC value:
You need to use the DEC modifier and not use strings though you may need a space between them to seperate values or other work arounds.
SERIN INPUT_PIN, BAUDMODE, [noparse][[/noparse]dec2 X, dec2 y]
** This code is in theory only, not tested.
-Martin
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Martin Hebel
StampPlot - Graphical Data Acquisition and Control
AppBee -·2.4GHz Wireless Adapters & transceivers·for the BASIC Stamp & Other controllers·
IF (X = 15) AND (Y = 12) THEN
is best to ensure precedence is met.
-Martin
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Martin Hebel
StampPlot - Graphical Data Acquisition and Control
AppBee -·2.4GHz Wireless Adapters & transceivers·for the BASIC Stamp & Other controllers·
So if I send 14 15 21 23 08 04·to the stamp (only 3 points), how can I not have the stamp send servo output after those points are sent?·Is it possible to·read the amount of points actually filled and use a Do While Loop?
Thanks,
Sean
Sorry the question is not making much sense. Please restate the question.
"Is it possible to read the amount of points actually filled and use a Do While Loop?"
1. What are your maximum X and Y values to accept as input
2. How many (X,Y) points do you want to accept as input? Fixed? or variable amount of points?
You could set up a loop to accept the X and Y values like this to accept a variable number of XY pairs and limit the total number of pairs to a maximum. Without more information on what your min/max values are I cant help with variable storage options.
Psudo code:
array_pointer=0
datainput:
get X and y
If x and y are 0 exit--- all done getting input
store x and y in array
increment array_pointer
if maximum number of points have been entered exit
goto datainput
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think outside the BOX!
1. The maximum X or Y values are realistically going to be about 20-30, but the important thing is that there must be two digits for each X or Y value (01, 06) or (15, 10) - each value is two digits.
2. The amount of points being sent is variable, not fixed.
3. I may actually want to send a (0, 0) point to send the unit to the origin, so I can't exit the loop if X and Y are zero (but maybe exiting the loop when X and Y are zero will turn out to be the only way I can actually accomplish what I want, so this one is not concrete).
get the input variables in pairs as the above loop and exit when the number of variables has been entered
Check the input for out of bounds numbers
show error of out of bounds if any and ask for reentry of data.
then display the input and ask if the data is correct and then process the data.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think outside the BOX!
If you want to compare 'X' to the STRING "15", then "15" consists of two bytes, and the IF won't compare that.
You COULD compare 'X' to the string "1" (which is one byte, I believe value is 49) which is why the compiler complains on the second character.
2. The usual way to address this problem is with a SERIN with the 'DEC' modifier.
X VAR BYTE ' Stores 0..255'
Y VAR BYTE '
SERIN 16, 16384, [noparse][[/noparse]DEC X, DEC Y]
So if you send "30, 15 <CR>" -- then X gets the value 30, and Y gets the value 15
Despite the fact that "you can do it", it's not very efficient, either in speed or memory. Note that the DEC formatter also accepts a character count like DEC2 which reads 2 digit characters and produces the binary equivalent and may be more the sort of thing you want.
VB - "I need to transfer X amount of points to you"
BS - "OK, I'm ready for X amount of points, bring it on."
VB - (send first point)
BS - (process first point) "Done with first point, send next point."
VB - (send second point)
BS - (process second point) "Done, send next."
et cetera
BS - (process last point)
So I tried to have the VB program send the data through a regular SerialPort.Write command and send everything at once for simplicity, because I could not get the Event command to recognize the stamp sending data over. Perhaps I was going about it the wrong way, but I'll check some more on MS forums for that.
Now a question: if I have a SERIN command on the stamp, will it wait at the command until there is some serial data transmitted, or will it have to be in a loop instead?
You can use the pseudo-pin '16' in a SEROUT and SERIN to talk/listen to the 'programming' port, if you dont' want to install a MAX232 chip for the RS-232 level shifting.
I would set it up like this:
BS waits for a byte
VB sends a command byte that gives BS all the information it needs to receive the following packet of data.
BS reads in all data
BS processes data
Loop
So for example use the following example
Command byte --
Use the high nibble for the command up to 15 commands
use the low nibble for the number of bytes to receive
Say our first command is a simple command that tells the BS to read in 6 bytes. We might use %1000 0110
The first nibble is the command %1000 BS knows that means "read bytes"
It then uses the lower nibble as the number of bytes to read in.
All the input stuff is handled by your VB program, input, data chacking, etc and it only sends valid data.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think outside the BOX!
Just remember when you're using Pin Port 16, all data sent through that port will be echoed back to the sender. There is no way to circumvent this so long as you are using Pin Port 16. This doen't happen when using any other Pin Port.
Regards,
Bruce Bates
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
<!--StartFragment -->
Edit: Metron, if I used that method, how would I get around the fact that VB will loop and send each piece of data faster than the stamp can process?
Would not the baud rate take care of that, i thought you were using serial communication.
I have Visual Studio, If you want to post the VB file I could have a look. I have not used VB for quite a few years though so don't expect much but I am interested in using VB to communicate with these devices so I would give it a go.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think outside the BOX!
BS2:
Note: the Max subroutines are not complete, I added the FREQOUTs for debugging. So far, I know that it accepts the N value from VB, but sending the OK password back to VB is where things get hairy.
Here is the relevant part of the VB program:
So the VB program sends the Count variable just fine (N in the PBASIC program). The program then freezes and none of the points actually get sent. This is VB 2005 Express Edition (I have Visual Studio 2003, but the combination of·much easier Serial communications and freeness led me to Express). Now, a few things in this block I'm not too confident about -
1. The SerialPort.Read command - So hopefully this is saying check the incoming data and read only byte 1 and store it in Check(0), but I'm not certain.
2. Do I need to use a DiscardBuffer command after each password arrives to ensure proper password approval and timing? Also, the MS literature on the DiscardBuffer command is very very limited, I could only find about a line of explanation, and it wasn't deep enough for me - I still don't get it.
3. The SerialPort.Write command for the list of points - Will this actually read the first item in the list, then loop and wait for the second password and continue, or will my list syntax in the parentheses not work?
If these questions are answerable, yay! This is my first time working with programming of any sort, so thanks for all the help.
Now I know why i quit using VB , I hate it, give me a fixed list of program statements with some low level access and I can get it done but this oop programming is not my cup of tea. No wonder windows is so dam buggy if they use this stuff to make programs. I have programs with thousands of lines of code that run every day for the last 15 years, no updates no fluff, no pretty colors or fancy artwork and they run flawlessly under DOS/Novell I am going to remove that darn program to free up some disk space.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think outside the BOX!
hope this helps
Jeff T.
Oh and metron, if you can get VB '05 Express to work, it can do some really amazing things (not that I would know yet, but I've been reading some books on it). I did read in several places that the serial commands in VB6 were pretty rotten and finicky. So far at least I know writing with '05 Express is pretty simple, I just need to find out how to do the reading properly.
Code at bottom for a VB form
Picture of serial output using the free serial port monitor
"Metron, if I used that method, how would I get around the fact that VB will loop and send each piece of data faster than the stamp can process?"
Ok I went back in, found the MSDN site that has information on VB commands, *My HELP not working because I erased MSDN gigantic mammoth help files from my hard drive, god one day these people are going to run out of names to call stuff I swear to god)
Here is the program I came up with, the user puts in 6 pairs of numbers and presses SEND
The program is set to 300 baud, the stamp can do a word serial in command and process the data
I would simply adjust the sleep time, (I have it set at 1000ms
Look at it like a MIDI interface, just send the stuff at a rate the stamp can handle using the first byte as a command byte
Like a MIDI if it misses it a not dosent get played and it just waits for command bytes to tell it what to do.
In your app i would guess when the person presses send, something happens on your device for feedback to the user so he knows it has been sent. You could use a display output on the stamp to show the 6 pairs of numbers
I used a "!!" for a command word and then just sent the data one variable at a time
You will have to process the string data back to numbers in the stamp
[noparse][[/noparse]/code]
Private Declare Sub Sleep Lib "kernel32" ( _
ByVal dwMilliseconds As Long)
Private Sub Form_Load()
Form1.Caption = "App1"
With MSComm1
.Handshaking = 2 - comRTS
.RThreshold = 1
.RTSEnable = True
.Settings = "300,n,8,1"
.SThreshold = 1
.PortOpen = True
' Leave all other settings as default values.
End With
Command1.Caption = "&Send"
End Sub
Private Sub Command1_Click()
MSComm1.Output = "!!"
MSComm1.Output = Text1.Text
Sleep 1000
MSComm1.Output = Text2.Text
Sleep 1000
MSComm1.Output = Text3.Text
Sleep 1000
MSComm1.Output = Text4.Text
Sleep 1000
MSComm1.Output = Text5.Text
Sleep 1000
MSComm1.Output = Text6.Text
End Sub
Private Sub Form_Unload(Cancel As Integer)
MSComm1.PortOpen = False
End Sub
[noparse][[/noparse]code]
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think outside the BOX!
Tried to port the code I I posted that runs on VB6 but no luck
Looks like the completely changed the interface/tools/commands/syntax/names/how everything works.
What's the point in learning a language that changes so drastically from version to version, its a nightmare.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Think outside the BOX!
Stamp code
VBdata VAR Byte
main:
SERIN 16,16468,[noparse][[/noparse]DEC Vbdata]
PAUSE 50
SEROUT 16,16468,[noparse][[/noparse]DEC 9,10]
GOTO main
VB code
Dim count As Int16
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
count = Val(TextBox1.Text)
SerialPort1.Open()
SerialPort1.Write(count & Chr(10))
Do While SerialPort1.BytesToRead < 2
'
wait here for the Stamp to echo back
Loop
If count > 1 Then
SerialPort1.DiscardInBuffer()
End If
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If count < 3 Then
TextBox2.Text = SerialPort1.ReadExisting
Else
TextBox2.Text = SerialPort1.ReadLine()
End If
SerialPort1.DiscardInBuffer()
SerialPort1.Close()
End Sub
Jeff T.
Here are the basic components you need:
First add a serial port to the form, it's in the toolbox under components or all windows forms. In these examples, I named my serial port SerialPort (nice eh?).·You can change all the properties of the serial port component in the form designer if you click on the port. It should not show up on the form, but rather at the bottom of the designer window all by itself.
Connect button:···
Disconnect button:
·Send button:
·
·
So just add a simple text box to enter data into, then in the Write command·parentheses type·txtBox.Text (if your text box was named txtBox) instead of yourdatahere.
I know the writing part works nice, but right now the read part is a guess, so don't expect it to work.