Com port communication
Moderators:Administrator, Global Moderator
I'm working to interface Qbasic with several machines in the lab, and I was wondering if it would be possible for me to save or view signals that come through the Com port from an outside source. Any help would be appreciated.
- frankiebaby
- Global Moderator
- Posts:95
- Joined:Tue Apr 30, 2002 1:38 am
- Location:Pennsylvania
- Contact:
Re: Com port communication
yes, it is possible. I have created a unit that controls 8 AC outlets via parallel port for the purpose of controled lighting.
The statement your are looking for is:
OPEN "COMn: optlist1 optlist2" [FOR mode] AS [#]filenum [LEN=reclen]
_ n is either 1 or 2, and identifies the communications port to be opened
_ optlist1 has the following syntax
[speed][,[parity][,[data][,[stop]]]]
where the defaults are set for the transmission of text (rather than
numeric) data. See Details if you are transmitting numeric data.
this was taken from the basic online help. if the data you are recieveing is text, 1 bit per character (LEN = reclen = 1) for integers 2 bits and for doubles i believe is 4. if you are using mixed characters and numbers i would probably use characters. Its seems your purpose would be to save or display output, so 1 bit should do the trick. You use the com port just like a file ie:
INPUT #1, variable
The statement your are looking for is:
OPEN "COMn: optlist1 optlist2" [FOR mode] AS [#]filenum [LEN=reclen]
_ n is either 1 or 2, and identifies the communications port to be opened
_ optlist1 has the following syntax
[speed][,[parity][,[data][,[stop]]]]
where the defaults are set for the transmission of text (rather than
numeric) data. See Details if you are transmitting numeric data.
this was taken from the basic online help. if the data you are recieveing is text, 1 bit per character (LEN = reclen = 1) for integers 2 bits and for doubles i believe is 4. if you are using mixed characters and numbers i would probably use characters. Its seems your purpose would be to save or display output, so 1 bit should do the trick. You use the com port just like a file ie:
INPUT #1, variable
Re: Com port communication
I've tried what you're suggesting, but the program seems to stall on that INPUT command. You see, since the COM ports open up either as output, input, or random, I have to switch between them after I send the message that causes the hardware to respond. I don't know if that completely messes it up or what, but I'll try your suggestion again. Thanks for the tip!
Re: Com port communication
I have an A/D converter that has placed the following characters in Com Port #3: Voltage = 1.2, *
I am using the following QB64 code to read the serial data:
‘ ** Wipe out old messages
Z$ = ""
OPEN "Com3:9600,n,8,1,ds0,cs0,rs" FOR INPUT AS #2
_DELAY .25 ' Delay to let Com Port settle
PRINT "EOF="; EOF(2), "LOC="; LOC(2), "LOF="; LOF(2) ' Debug line showing why the following error; EOF=-1 LOF and LOC both =0 even though info is there
DO UNTIL INSTR(Z$, "*") > 0
Z$ = INPUT$(12, # 2) '-----------------ERROR INPUT PAST END OF FILE
PRINT "EOF(2)="; EOF(2)
LOOP
PRINT "instr="; INSTR(Z$, "*")' When I get the error I get a dialog box asking if I want to continue anyway I press YES and get instr= 9
PRINT "Z$="; Z$ ,” lenZ$= “; LEN(Z$) , I also get Z$=Vlae=12,* That is every other character in the buffer.
First question why do I get EOF=-1 as soon as I open the port? How can I change that or not show EOF for the INPUT statement?
I am using the following QB64 code to read the serial data:
‘ ** Wipe out old messages
Z$ = ""
OPEN "Com3:9600,n,8,1,ds0,cs0,rs" FOR INPUT AS #2
_DELAY .25 ' Delay to let Com Port settle
PRINT "EOF="; EOF(2), "LOC="; LOC(2), "LOF="; LOF(2) ' Debug line showing why the following error; EOF=-1 LOF and LOC both =0 even though info is there
DO UNTIL INSTR(Z$, "*") > 0
Z$ = INPUT$(12, # 2) '-----------------ERROR INPUT PAST END OF FILE
PRINT "EOF(2)="; EOF(2)
LOOP
PRINT "instr="; INSTR(Z$, "*")' When I get the error I get a dialog box asking if I want to continue anyway I press YES and get instr= 9
PRINT "Z$="; Z$ ,” lenZ$= “; LEN(Z$) , I also get Z$=Vlae=12,* That is every other character in the buffer.
First question why do I get EOF=-1 as soon as I open the port? How can I change that or not show EOF for the INPUT statement?
Re: Com port communication
I have since added the following lines after the _Delay .25 line.
getdata:
bytes% = LOC(2) ' Check receive buffer for data
IF bytes% = 0 THEN GOTO getdata ' After more than 300 thousand of getdata cycles it continues
Now EOF is still -1 but LOC is 17 and LOF still shows 0
How can LOF be 0 if there are 17 characters?
I tried changing to Open for Random and using Get #2, , Z$ but since LOF=0 it gives ERROR bad file length
When opening as random EOF =0 until the first Get statement, but LOF=0 still causes the above error.
HOW DO YOU READ A SERIAL BUFFER?
getdata:
bytes% = LOC(2) ' Check receive buffer for data
IF bytes% = 0 THEN GOTO getdata ' After more than 300 thousand of getdata cycles it continues
Now EOF is still -1 but LOC is 17 and LOF still shows 0
How can LOF be 0 if there are 17 characters?
I tried changing to Open for Random and using Get #2, , Z$ but since LOF=0 it gives ERROR bad file length
When opening as random EOF =0 until the first Get statement, but LOF=0 still causes the above error.
HOW DO YOU READ A SERIAL BUFFER?
Re: Com port communication
SOLUTIONS USED:
I used the OPEN FOR INPUT command and Z$=INPUT(LOC(2),#2) which I knew would result in an INPUT PAST END OF FILE error. I had to use LOC instead of LOF b/c LOF was always =0 and my routine returned LOC = a valid number. just before the Z$= INPUT command I added the line ON ERROR GOTO EHANDLER. Then at the end of the Code I added"
EHandler:
errfile$ = _INCLERRORFILE$
RESUME NEXT
The program steps over the error and keeps running.
As for the every other character in the buffer read error. I altered the output of my A/D sending code with spaces between the letters. I could then read the correct message with QB64 with the exception of the missing decimal in the voltage value. Then using LSTR$, RSTR$, and CVI commands I was able to get my voltage reading. of course it was wrong having no decimal, but knowing where it belonged I divided by 10,000 to put the decimal where it belonged. Seems like a nasty bunch of work arounds but I am continuing with my project now.
I used the OPEN FOR INPUT command and Z$=INPUT(LOC(2),#2) which I knew would result in an INPUT PAST END OF FILE error. I had to use LOC instead of LOF b/c LOF was always =0 and my routine returned LOC = a valid number. just before the Z$= INPUT command I added the line ON ERROR GOTO EHANDLER. Then at the end of the Code I added"
EHandler:
errfile$ = _INCLERRORFILE$
RESUME NEXT
The program steps over the error and keeps running.
As for the every other character in the buffer read error. I altered the output of my A/D sending code with spaces between the letters. I could then read the correct message with QB64 with the exception of the missing decimal in the voltage value. Then using LSTR$, RSTR$, and CVI commands I was able to get my voltage reading. of course it was wrong having no decimal, but knowing where it belonged I divided by 10,000 to put the decimal where it belonged. Seems like a nasty bunch of work arounds but I am continuing with my project now.
Re: Com port communication
This program reads a com port and plots a voltage reading sent to the com port via an A/D
QB64 always causes an Input Past End of File error when reading a com port but the included ON ERROR / Error handling sub takes care of it.
QB64 always causes an Input Past End of File error when reading a com port but the included ON ERROR / Error handling sub takes care of it.
Code: Select all
CLS
LOCATE 2, 20, , 0, 7
PRINT "COLLECTING DATA"
_DELAY 1
j = 0 ' Counter for counting samples to average
SCREEN 12 ' Set screen to Graph Mode
GOSUB AxisPrint
seconds1 = TIMER
again: ' This is where it starts again and again for each sample
CLOSE #2 ' Close COM ports
'_DELAY 1
OPEN "Com3:9600,n,8,1,ds0,cs0,cd0,rs" FOR RANDOM AS #1 ' Open COM port to output command
_DELAY 1.25 ' delay to let com settle
FIELD #1, 35 AS m$
' Form Message to send to External Device
Command = 2: pin = 4: argument = 0 ' Code to Get analog voltage reading(0-5Vdc)
msg$ = STR$(Command) + "," + STR$(pin) + "," + STR$(argument) + "*"
LSET m$ = msg$ ' Prepare message for sending code
PUT #1, , m$ ' Send message to the external device
_DELAY 1 ' Let it settle
CLOSE #1 ' Finish sending request
m$ = "": msg$ = "" ' Wipe out old messages
bytes% = 0: Z$ = ""
OPEN "Com3:9600,n,8,1,ds0,cs0,cd0,rs" FOR INPUT AS #2 ' Open to get Voltage reading
getdata: ' Loop until data present
_DELAY 2.5 ' Delay to let Com Port settle and data arrives
bytes% = LOC(2) ' Check receive buffer for data
IF bytes% < 2 THEN GOTO getdata 'DELAY above was increased until first pass has data: Loop if not ready
ON ERROR GOTO EHandler ' Input past end of file occurs in next line b/c LOF=0
Z$ = INPUT$(12, # 2) ' Error but gets data in buffer Goes to EHandler to clear Error Message
'
j = j + 1 ' Counts number to average
endofdata = INSTR(Z$, "*"): ' PRINT "EOD= "; endofdata: PRINT " len(Z$)= "; LEN(Z$)
Z$ = LEFT$(Z$, endofdata - 1) ' gets data left of End of File trash
Z$ = RIGHT$(Z$, 2) ' plucks voltage reading out of Buffer
V = VAL(Z$) ' Converts voltage text to number
V = V / 10 ' Decimal point not read restore decimal point
IF V > .01 THEN Vb = V ' If valid voltage reading save as Vb
Va = Va + Vb ' Add for average
IF j = 4 THEN Va = Va / 4 ELSE GOTO again ' Average this many samples or go get another sample
j = 0 ' Clear number to average counter
seconds2 = TIMER ' Get finish time
DeltaT = seconds2 - seconds1 ' Calculate time to end of average sample for plotting
IF DeltaT > 3500 THEN DeltaT = 1 ' Wrap data points on graph if X axis max is reached
' *******************Calculate and scale data TO GRAPH **********
X = DeltaT
X = 50 + DeltaT * 600 / 3600 ' SCALE TIME to X AXIS FOR the Time point
tmp$ = " ####,.## Seconds" ' Format for printing Time
PRINT ; USING tmp$; DeltaT
tmp$ = " #####.## Volts" ' Format for printing voltage
PRINT ; USING tmp$; Va
Va = 400 - (Va * 80) ' SCALE Va TO GRAPH Y for the voltage point
Y = Va
Va = 0 ' reset to zero for next round
AxisPrint: ' ********** Subroutine to draw graph axis and labels *********
LINE (50, 0)-(50, 400), 10 ' Draw Y axis
LINE (50, 400)-(600, 400), 10 ' DRAW X AXIS
LINE (350, 395)-(350, 405), 10 ' Draw X axis Tic
LOCATE 12, 3, , 0, 7 ' Y AXIS LABEL POSITION
PRINT "V" ' Y AXIS LABEL
LOCATE 27, 43, 1, 0, 7 ' X AXIS LABEL POSITION
PRINT "TIME" ' X AXIS LABEL
FOR i = 1 TO 390 STEP 20 ' Y AXIS TIC MARKS
LINE (45, i)-(55, i), 7
NEXT i
LOCATE 21, 4, , 7 ' Y AXIS LABEL POINT
PRINT "1"
FOR i = 50 TO 600 STEP 25: k = i + 5 ' Voltage line
LINE (i, 81)-(k, 81), 10
NEXT i
LOCATE 16, 4, , 10
PRINT "2"
FOR i = 50 TO 600 STEP 25: k = i + 5 ' Voltage line
LINE (i, 161)-(k, 161), 10
NEXT i
LOCATE 11, 4, , 10
PRINT "3"
FOR i = 50 TO 600 STEP 25: k = i + 5 ' Voltage line
LINE (i, 241)-(k, 241), 10
NEXT i
LOCATE 6, 4, 0, 10
PRINT "4"
FOR i = 50 TO 600 STEP 25: k = i + 5 ' Voltage line
LINE (i, 321)-(k, 321), 10
NEXT i
LOCATE 1, 4, 0, 10
PRINT "5"
FOR i = 50 TO 600 STEP 25: k = i + 5 ' Voltage line
LINE (i, 1)-(k, 1), 10
NEXT i
RETURN ' End of subroutine to print graph
CIRCLE (X, Y), 2%, 7 ' DRAW VOLTAGE POINT
GOTO again ' Go get next voltage reading
END
EHandler: ' ********* Subroutine to clear End of File error message ********
errfile$ = _INCLERRORFILE$
RESUME NEXT