Internet PLC Forum
General => Technical support => Topic started by: BC SYSTEMS on April 01, 2011, 10:56:15 AM
-
Hi,
I'm using the following print command to send a string out or comm port 1.
PRINT #1 "50002404000E00403A" + chr$(13)
A$ = INPUT$(1)
The data from the device is received at A$ no problem in the following format:
506125050E00400BB913
I'm only intrested in the last four bytes of data before the CS i.e 0BB9 when this is converted from hex to dec I get 3001.
I then want to put this value into a DM so my HMI can access the variable.
Not even sure where to start with this so any help appreciated.
Cheers
-
You can get the last four bytes of any string in A$ using the following:
IF LEN(A$) >= 4
B$ = MID$(A$, LEN(A$)-3, 4)
ENDIF
Since B$ is Hex data you convert into a number using the HEXVAL function:
DM[1] = HEXVAL(B$)
-
Thanks, I would have been ages on that!
I had to change it slightly as the above included the checksum to:
IF LEN(A$) >= 4
B$ = MID$(A$, LEN(A$)-5, 4) // -5
ENDIF
Since B$ is Hex data you convert into a number using the HEXVAL function:
DM[1] = HEXVAL(B$)
Many thanks
-
Hi Guys,
I'm seeing differnt results using the simulator and actual program in the PLC.
In SIM mode.
I'm using the following command:
PRINT #1 "50002404000E00027A"
I send back via the popup screen.
506125050E00400BB913
I then use the following to get the data I want
IF LEN(A$) >= 4????????????????????????' LOOK TO SEE IF RETURN STRING IS > 4
SETIO RX_LED????????????????????????' SET RX LED
B$ = MID$(A$, LEN(A$)-5, 4)???????????????' COPY LAST FOR BYTES (-5) AND NUMBER OF BYTES LONG
A = A + 1???????????????????????????' COUNTS DATA RECEIVED
CLRIO RX_LED ????????????????????????' CLR TX LED
ENDIF
DM[1] = HEXVAL(B$)????????????????????? 'CONVERT RECEIVED DATA FROM HEX TO DEC
The last four bytes are 0BB9, when converted and stored into DM[1] I Get 3001 - this works perfectly.
PLC Mode
When I monitor the PLC program with a serial program called Listern32, the string the plc sends out is
11:59:39:469 04-Apr-2011 Port 9 - 50002404000E00027A[CR]
50002[SP]A"[STX][STX][STX]*[ENQ][DC3]&[CAN]27A[CR]
50002404000E00027A[CR]
50002404[SP]A[STX]*[ENQ][DC3]&[CAN]27A[CR]
50002404000E00027A[CR]
50002404000[NUL]A[STX][STX][DC2]:[NL]Ux50002404000E00027A[CR]
0002404000E00027A[CR]
50002404000E00027A[CR]
50002404000E00027A[CR]
50002404000E00027A[CR]
50002404000E00027A[CR]
50002404000E00027A[CR]
5000240[SP]A[STX][STX]*[ENQ][DC3]&[CAN]27A[CR]
50002404000E00027A[CR]
as you can see the communication is garbled every now and then with some [STX][STX]*[ENQ][DC3]& characters??
when I send back
506125050E00400BB913[CR]
The PLC reads the data from A$, in B$ I read 1CL4 and the DM has 7508 insted of 3001
Any Ideas??
Cheers
-
Those non printable characters did not come from the PLC using PRINT #. So they must have come from your 3rd party device. Is this an RS485 port that you are monitoring the exchange between the PLC and the device using the U-485 adapter?
-
Hi,
I run the program in the PLC (TMD2424) and capture the data from the RS232 port using the Listen32 program. after a few strings I pause the PLC, stop the Listen program and go online with the PLC using the same port. No other hardware is present??
I tried watching with my U485 but i cannot get it to connect to the PLC?? (seperate issue!!)
Works a treat in simulation but not in real life??
Cheers
-
Your "real life" wasn't quite real-life after all as you are involving the PLC going online monitoring via the same COM port.
We would suggest you monitor the PLC via the RS485 port and you can use a HyperTerminal to send test strings to the PLC via the RS232 port.
-
Guy's
To clarify.
I'm not trying to capture the strings and monitor online via the same comm port. As below I send some strings from the PLC via a 1 sec pulse, I use the serial tool to capture the data and send some strings back.
I use the same tool onsite where the device is located without any additional characters appearing in the strings. See attached.
I will try to monitor online via the RS485 if i get the U485 working.....
Cheers
-
In your screen capture there isn't STX][STX][STX]*[ENQ] type of non-printable ASCII characters mentioned in your email.
-
Correct, this is captured from the serial tool connected to the actual device.
I dont get these additional characters which is why i thought maybe the PLC was generating them??
Will update when I get new data.
-
If executed correctly the PLC would not send out those non-printable characters. You should ensure that you only have function that execute PRINT # statement and not intermixed with other custom functions that could be sending binary characters using OUTCOMM.
-
Hi Guys,
It looks like my generic USB serial port was causing the errors?? I don't know whay as I cannot re-produce the errors but as a precaution have placed it in my box of bits for worring about later!
I have now got my U485 up and running and all looks great.
Thaks for the help.
Cheers
-
Hi guys,
Can you help as I'm pulling my hair out on this one.
I'm using a sequencer to step through my program, each step sends out a different string. the sequencer is advanced via relay NEXT_CALL. this sequencer just goes round in circles as long as the data is coming in. Each step has a fixed 1 second timer contact in series with the sequence step to re-call the custfn
Each call sends a string out of comm 1. If no data is received I increment B and return to the caller forever..... B counts the transmit attempts
If data is received, I convert the data from hex to dec and store in DM
when A >0 i want to move on to the next custfn for the next string etc.
This all works fine except after data has been received I want to move on and not re send the same string.
If you look at the attachement you will see I send the data out to my serial listerning tool a couple of times then I force a reply (highlighted in blue) at this point I want to move to the next custfn but I always send the original string before moving on to the next string and I cannot get rid of it!
I have tried only sending the string out of comm 1 if A = 0 but this doesnt stop this happening either..... i.e
IF
A = 0
PRINT #1 "50002402000E00027A"
ENDIF
***********ACTUAL CODE****************
CLRIO NEXT_CALL
SETIO TX_LED_RELAY ' SET TX LED
PRINT #1 "50002402000E00027A" ' ASK CCM FOR SPEED TIMING MAP 0 -255
A$ = INPUT$(1) ' CHECK FOR DATA ON COMM PORT 1
IF LEN(A$)= 0
SETLCD 0,0,chr$(1) ' 1 SENT TO LCD WILL CLEAR SCREEN
SETLCD 0,1,CHR$(12) ' NO CURSOR
SETLCD 1,1, "NO TIMING MAP DATA"
B = B + 1 ' COUNTS NO DATA RECEIVED
RETURN ' NO DATA HAS BEEN RECEIVED
ENDIF
IF LEN(A$) > 0 ' LOOK TO SEE IF RETURN STRING IS > 0
A = A + 1 ' COUNTS DATA RECEIVED
SETIO RX_LED_RELAY ' SET RX LED
B$ = MID$(A$, LEN(A$)-5, 4) ' COPY LAST FOUR BYTES (-5) AND NUMBER OF BYTES LONG
ENDIF
DM[1] = HEXVAL(B$) 'CONVERT RECEIVED DATA FROM HEX TO DEC
SETLCD 0,0,CHR$(1) ' 1 SENT TO LCD WILL CLEAR SCREEN
SETLCD 0,1,CHR$(12) ' NO CURSOR
SETLCD 1,1, "TIMING MAP = " +STR$(DM[1],2)
IF
A > 0 ' WHEN NUMBER OF REPLIES = 1 MOVE ON TO NEXT CALL
SETIO NEXT_CALL
B = 0
A = 0
ENDIF
-
I notice that you are using:
CLRIO NEXT_CALL <-- first line of custom function
SETIO NEXT_CALL <-- almost last line of custom function
Are you expecting that the RELAY NEXT_CALL will generate a pulse that will advance a COUNTER? If yes, then this will not work. The ladder logic is suspended until your custom function completes, so the ladder logic will only "see" the final state of NEXT_CALL
If you are going to advance a sequencer no more often than once per second you could do something like the following. In your custom function you could do a CLRIO NEXT_CALL to disable the sequencer from advancing.
-
One thing you should understand about the way the PLC handles outgoing string is that after the PRINT #1, the string is stored into an outgoing buffer and the operating system in the PLC employs a serial output interrupt service routine to send out the characters one-by-one until the last character has been sent and the system automatically disable the serial interrupts.
This means that the program execution does not wait for PRINT #1 to complete before it moves on to execute the next statement. This ensures minimum latency for the program execution but if your program has been resending out the same string if it does not receive a response from the device you connect to, could it be that the sequence of characters that was sent out was a result of a previous PRINT #? Maybe you can think along this line to see if that is the cause of the problem you encountered.
-
Hi Guys,
Thanks for your response (Gary and Tri). I have re arranged and modified the code a bit and now it works as required :)
******CODE******
CLRIO NEXT_CALL
A$ = INPUT$(1) ' CHECK FOR DATA ON COMM PORT 1
IF LEN(A$)= 0
SETLCD 0,0,chr$(1) ' 1 SENT TO LCD WILL CLEAR SCREEN
SETLCD 0,1,CHR$(12) ' NO CURSOR
SETLCD 1,1, "NO TIMING MAP DATA"
B = B + 1 ' COUNTS NO DATA RECEIVED
ENDIF
IF LEN(A$) > 0 ' LOOK TO SEE IF RETURN STRING IS > 0
A = A + 1 ' COUNTS DATA RECEIVED
SETIO RX_LED_RELAY ' SET RX LED
B$ = MID$(A$, LEN(A$)-5, 4) ' COPY LAST FOUR BYTES (-5) AND NUMBER OF BYTES LONG
ENDIF
DM[1] = HEXVAL(B$) 'CONVERT RECEIVED DATA FROM HEX TO DEC
SETLCD 0,0,CHR$(1) ' 1 SENT TO LCD WILL CLEAR SCREEN
SETLCD 0,1,CHR$(12) ' NO CURSOR
SETLCD 1,1, "TIMING MAP = " +STR$(DM[1],2)
IF A = 0
SETIO TX_LED_RELAY ' SET TX LED
PRINT #1 "50002402000E00027A" ' ASK CCM FOR SPEED TIMING MAP 0 -255
ENDIF
IF
A > 0 ' WHEN NUMBER OF REPLIES = 1 MOVE ON TO NEXT CALL
SETIO NEXT_CALL
B = 0
A = 0
ENDIF
*******************
On another note... the following will not compile. I have tried many different permutation with () and "" but cannot get it right!!
PRINT #1 "50003402000E000DFF" + STR$(C$) +"50"
the C$ contains a hex variable I want to add to the string (F).
The other the problem is calculating the new checksum. In this case "50" is the check sum of the whole message. I use =CheckSum(xx) in excel to calculate the whole message CS but was wondering if it can be calculated in the PLC before sending?
Otherwise I could use a load of IF statements i.e
IF
C$ = xx
Print #1 "A"
ENDIF
IF
C$ = xx
Print #1 "B"
ENDIF
etc
Cheers
-
Can't help with your PRINT statement. The isolated statement complies for me. I'm guessing that your have messed up the "(" or some other syntax junk in a previous line.
In regards to calculating a Checksum (sumcheck) it is pretty simple.
If you concatenate the strings that need the the sumcheck in A$, then call a custom function that appends the appropriate sumcheck value onto A$, then you can send A$ on it's way. Something like this is a good starting point:
' SumCheck
'
' On entry A$ holds ASCII string
'
' On exit A$ holds ASCII string with checksum appended
' Integer variable used: I,S,N
'
'
S = 0 'Starting point for SumCheck
N = LEN(A$)
FOR I = 1 TO N ' For each ASCII char in string
S = S + ASC(A$,I)
NEXT
S = S & &HFF ' Toss out everything but 8 bits
A$ = A$ + HEX$(S,2) ' Tack on sucmcheck
Since there are no absolute rules on how checksums are calculated, you may need to adjust the algorithm to fit the rules for your communication protocol.
Gary d.
-
Thanks Gary,
I'm not sure why I can't compile that will carry on trying!
-
Hello all.
Can the PLC receive HEX data on the serial port that doesn't have a carriage return terminator?
I looked at incomm but this is binary only?
cheers.
-
incomm() is your last resort.
If your incoming data is not delimitated by ASCII <cr> characters, then your only choice is to use incomm(). In these cases, your code will have to handle each character received from the external device and figure out what is data and what is chaff.
Yes this function does return an 8-bit integer value. If you need to convert the value returned by incomm() to an ASCII character, you can use chr$()
A$ = chr$(incomm(4)) 'poof a$ now contains a single ASCII character
Gary d
Gary d
-
In regards to your error in compilation
PRINT #1 "50003402000E000DFF" + STR$(C$) +"50"
This line should NOT compile. The problem is with str$(c$). Str$() expects an integer as an argument. C$ is a string!
Sorry for not catching this, earlier.
Gary d
-
Hi Gary,
Thanks for the info.
Regarding converting the data back to ascii, I see each ascii character in A$ but only one character at a time (8-bit integer value) how do I reconstruct the entire string? i.e copy each value from a$ to x$ in the right order? also the a$ returns a /FF at the end of the received string, I guess this is the PLC confirming job done!
Cheers
-
Concatenation.
if A$ +"A" and X$ = "B",
then concatenate:
A$ = A$+X$
A$ will now be "AB"
As for the /FF you are seeing returned from INCOMM() is probably one of 2 things:
1. It is actual data received from your external device
2. -- OR -- INCOMM() is documented to return a numeric -1 value
to indicate that NO character has been
received from the external device since the last time that
you called INCOMM().
Remember that a decimal -1 is a string of "f"s in hexadecimal.
Gary D
-
Hi Gary,
Thanks for that. I may have led you down the garden path with the x$.... The problem I have is that the the incomm string is converted into A$, each character appers one after the other for a short duration a bit like the message boards with the moving text! (I see this in the simulator). What I need to do is copy each individual value before it changes in to another string, B$ for example.
Thinking about it I guess I could use
If
B$ <> A$
B$ = B$ + A$
Endif
What do you think?
Cheers
-
I don't actually think that I can really help all that much.
Your description that strings change value with time is nonsensical. If a string variable changes, it is because your programming changed the string.
Sorry,
Gary d
-
Hi Gary,
Try it! I'm sendind a string like 001234567800 to comm port 1
Run a fm incomm on that port, convert to ascii and copy to A$ and you see 0 delay 0 delay 1 delay 2 delay etc
The delay is probably caused by me calling the fm via a 1 sec contact. I suspect this is because the data is being transferred from the serial buffer to the A$???
Cheers
-
Gary thanks for helping up with questions posted by BC System. I hope the following helps to clear up things a bit:
The PLC has a 256 bytes circular buffer that can keep incoming byte data. Each time you call the INCOMM command it removes one byte of data from the buffer and return to you. All data returned are positive number between 0 and 255. When it runs out of data (buffer empty) it returns a -1. That marks the end of the buffer.
You do have to know what is the delimiter to know how to assemble a series of data into a string if that's what you want to do. The delimiter is either a special character or a sequence of a few characters to mark the end of a packet, so your program need to check that in order to return a complete packet of data. The concatenation method that Gary mentioned will work to assemble incoming bytes and translate them into string characters, but it is really up to you to program when the delimiter has been received and end the string concatenation.
-
Guys,
Thanks for the pointers. I'm not trying to assemble two separate strings but make one complete string form the data received using the income fm.
If I send the following to port 1:
12345
Then use the following fn to convert to ASCII
A$ =chr$(incomm(1))
I get (looking @ online monitor) 1 delay 2 delay 3 delay etc
How can I reassemble the complete string and store in B$?
Cheers.
-
I'll give it one more try.
Let's say your did something like this:
1. Did something to request data from some external device.
2. Wait 1 second to ensure:
Request was sent to the external device
Request was processed by the external device
External device sent the requested data.
PLC has buffered up all received data bytes
3. Now, assuming everything went as planned, do something like the following to build a string in A$:
A$ = "" ' Empty string
D = INCOMM(1) ' get first data byte (if any)
WHILE(D <> -1) ' While data is available
A$ = A$ + CHR$(D) ' assemble string
D = INCOMM(1) ' get next data byte (if any)
ENDWHILE
' At this point, A$ contains any and all data received from the
' external device.
'
Gary D.
-
Thanks Gary,
I was going to re assemmble the string in a much more incumbent manor!
I'm sure this will get me going in the right direction.
Cheers