Internet PLC Forum

General => Technical support => Topic started by: BC SYSTEMS on April 01, 2011, 10:56:15 AM

Title: Serial communications
Post 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

Title: Re:Serial communications
Post by: support on April 01, 2011, 12:00:36 PM
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$)



Title: Re:Serial communications
Post by: BC SYSTEMS on April 01, 2011, 12:54:28 PM
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
Title: Re:Serial communications
Post by: BC SYSTEMS on April 04, 2011, 04:26:23 AM
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




Title: Re:Serial communications
Post by: support on April 04, 2011, 06:20:00 AM
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?
Title: Re:Serial communications
Post by: BC SYSTEMS on April 04, 2011, 06:31:57 AM
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
Title: Re:Serial communications
Post by: support on April 04, 2011, 07:04:03 AM
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.
Title: Re:Serial communications
Post by: BC SYSTEMS on April 04, 2011, 10:51:35 AM
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
Title: Re:Serial communications
Post by: support on April 05, 2011, 08:00:47 AM
In your screen capture there isn't STX][STX][STX]*[ENQ] type of non-printable ASCII characters mentioned in your email.
Title: Re:Serial communications
Post by: BC SYSTEMS on April 05, 2011, 08:37:38 AM
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.
Title: Re:Serial communications
Post by: support on April 05, 2011, 10:55:55 AM
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.
Title: Re:Serial communications
Post by: BC SYSTEMS on April 11, 2011, 03:43:20 AM
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
Title: Re:Serial communications
Post by: BC SYSTEMS on April 12, 2011, 06:41:03 AM
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
Title: Re:Serial communications
Post by: garysdickinson on April 12, 2011, 01:07:20 PM
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.
 
Title: Re:Serial communications
Post by: support on April 12, 2011, 02:03:36 PM
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.
Title: Re:Serial communications
Post by: BC SYSTEMS on April 13, 2011, 02:38:59 AM
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
Title: Re:Serial communications
Post by: garysdickinson on April 13, 2011, 08:32:27 AM
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.
Title: Re:Serial communications
Post by: BC SYSTEMS on April 13, 2011, 08:53:19 AM
Thanks Gary,

I'm not sure why I can't compile that will carry on trying!

Title: Re:Serial communications
Post by: BC SYSTEMS on April 20, 2011, 04:30:39 PM
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.
Title: Re:Serial communications
Post by: garysdickinson on April 20, 2011, 08:49:06 PM
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
Title: Re:Serial communications
Post by: garysdickinson on April 20, 2011, 08:57:47 PM
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
Title: Re:Serial communications
Post by: BC SYSTEMS on April 21, 2011, 12:52:20 AM
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
Title: Re:Serial communications
Post by: garysdickinson on April 21, 2011, 07:54:14 AM
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

Title: Re:Serial communications
Post by: BC SYSTEMS on April 21, 2011, 09:51:04 AM
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
Title: Re:Serial communications
Post by: garysdickinson on April 21, 2011, 11:47:04 AM
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
Title: Re:Serial communications
Post by: BC SYSTEMS on April 21, 2011, 12:34:05 PM
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
Title: Re:Serial communications
Post by: support on April 21, 2011, 01:14:28 PM
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.

Title: Re:Serial communications
Post by: BC SYSTEMS on April 21, 2011, 02:21:56 PM
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.



Title: Re:Serial communications
Post by: garysdickinson on April 21, 2011, 02:59:42 PM
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.
Title: Re:Serial communications
Post by: BC SYSTEMS on April 21, 2011, 11:17:22 PM
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