My place...

'Type in your company slogan here'

2011-04-20 22:07






Your Link

Your Link

Your Link

Link / News Box

Mach3 Customzing

Your Link

Your Link

Your Link

Your Link

Your Link


Text Box

Use this box to type any specials, new updates or even gallery pics here.


Serial communication with Mach3


Out of the box Mach3 provides some limited ways of communicating with external devices over the serial port (not counting MODBUS). Under Config -> General Config you can select the baudrate and either 8-N-1 or 7-N-2. You can then use the macro-call SendSerial ("This is a test") to send a string of data.


As you can see this is quite straight forward but it's also quite limiting since you don't have full control over the port - you can't for example set the parity and you can't, to my knowlege, receive data from a device.


Fortunately the Cypress Enable scripting engine built into Mach3 allows you to access commands and functions in external .dll files and the intention with this page is to show an example of how that can be done to achive a more flexible way of doing serial communication.


The brute force method of doing this would be to access the Windows API directly in order to gain access to the serial ports but this is neither easy or straight forward and it is beyond my knowlege level when it comes programming. A rescent question on the Mach3 Yahoo user group sent me on a hunt for a .dll library that would provide an easier interface to the serial port than the Windows API method. Basically the .dll provides an interface between our application (the Mach3 macro/script) and the Windows API so that we don't have to worry about the low level stuff.


I stumbled across an old (2003) article i the electronics magazine ELEKTOR where they provided a .dll for serial communications. The .dll is available for download from their web-site but I'm not sure if I'm allowed to redistribute it so I'm going to provide you with a direct link to their Swedish site instead. You can also get it from Elektors english web-site but you need to create an account in order to access the file there (which I believe is free).


If you download the .zip file from the Swedish site the archive contains a bunch of files, the one we're specifically interested in here is the one called Serial.dll. If you download from the English site you'll get the .dll directly (


In order for Cypress Enable to find the file you need to place it in one of the following locations (I recommend the first):


1) Your Mach3 install folder (usually C:\Mach3)

2) Your macro folder

3) In the Windows folder


Before we can use the functions exported by the .dll we must tell Cypress Enable that we are intending to use functions located in an external library, what they are called and what type of data they expect and return. Since the example file provided in the .zip file is written in Delphi this took a bit of reverse engineering and trial error for me to get working in Cypress but I think I've got it now.

 You can download a copy of this file here.


I won't go into all of the available functions here but I'll try the cover the ones most likely to be used and I'll do it in the order you're likely to be calling them.



This function is used to check if a port with a certain number is available or not. This is done by passing in the number of the comport that we're interested in and the funtion will return 1 if the port exists and is free to use. It will return 0 if the port either doesn't exists or is already opened by another application (or can't be used for whatever reason).



e = COMPortExists(1)


This function opens the port with the number you pass to it and it returns that very same number if the port is opened successfully. It returns 0 if the port couldn't be opened.



e = OpenCOM(1)


This function sets the baudrate for the currently opened port. It returns TRUE if the operation is successful and FALSE if not. Any number may be passed in but not all ports will allow non standard baudrate.



e = BaudrateSet(115200)


This function is used to set the parity for the currently opened port. It returns TRUE if successful and FALSE if not. The number passed to the function corresponds to the various parity settings like this:

0 = No parity

1 = Odd parity

2 = Even parity

3 = Mark

4 = Space



e = ParitySet(0)


This function is used to set the number of databits (usually 7 or 8) but anything between 4 and 8 is allowed. It returns TRUE if successful and FALSE if not.



e = BitsPerByteSet(8)


This function is used to set the number of stopbits to use. Possible values are 0, 1 and 2 for 1, 1.5 and 2 stopbits respectively. The function returns TRUE if the operation was successful and FALSE if not. Note that not all ports allow 1.5 stopbits in which case the function will return FALSE.



e = StopBitsSet(0)


This function is used to send a character to the serial port and it returns 1 if successfull. The .dll expects the data you pass it to be of type Char but Cypress Enable doesn't have that datatype so we have to pass it the data as type Integer instead. Note that you can only pass one character at the time.



e = SendCharCOM(ASC("A"))   'Convert 'A' to an integer and pass it.


The .dll has its own buffer (or it might be using the system buffer) so even though you can only pass one character a time you can quickly loop thru a string passing each character as you itterate thru the string. (See the example file below for one possible way of doing it.)


This function is used to get (or read) a character from the receive buffer. You pass in the name of the integer variable (byRef) in which you want it to put the character and it returns TRUE if successfull and FALSE if not (if there's no data to read for example).



Dim RxChar as Integer

Dim RxString as String

RxString = ""                                 'Clear the string.

While ReadCharCOM(RxChar)            'Keep getting characters as long as there are any

  RxString = RxString & Chr(RxChar)   'Convert the numeric value to a char and append.



This function closes the port. The .dll can only handle one port so it closes whatever port is open and it always seems to return 0.



e = CloseCOM()

Apart from the above calls there are also calls to set and reset the control line outputs (RTS and DTR) and to get the status of the contol line inputs (CTS, DCD, DSR & RI). The .dll doesn't provide any flowcontrol so that has to be coded "manually" by using the above calls or XON/XOFF characters. This however isn't something that I've personally done as of this writing.


A couple of notes.

Each macro called in Mach3 is run as a separate instance. That means that one macro doesn't know what another macro does or have done. This means that you can not open the port with one macro and expect to send or receive data with another macro. Likewise if you open the port with a macro but forget to close it before the macro ends that port will be left "hanging" and the only way to regain access to it is to restart Mach3. For that reason I highly recommend implementing an error handler that at least closes the port if there's an unexpected error while the macro executes.

For the same reason as above this also means that this way of handling serial input and output doesn't provide a way to get data from a device which you don't have control over. You have to have the port opened in order to receive data from the from the device and you can't leave the port open when you're not executing the macro. So if you have a device which "randomly" spits out data and you can't afford to miss anything then this aproach won't work. The "best" devices to use with this aproach is "polled" devices, ie. devices that only sends data when you tell it to.


The .dll provides a way of passing Windows messages from the Windows API to the calling application when the status of the port changes (like events in any event driven language). Unfortunately there's no way, at least as far as I know, to receive these messages in Cypress Enable and for that reason I've left the declarations of this function out of this example. If someone knows how to do this please let me know.


You can download an example script that I used when working this out. I used a serial loopback plug so that anything going out the port was going right back in. The loopback plug is simply a female DB9 wired as shown to the left. The macro is pretty straight forward, it checks COM1-COM5 and builds up a string that is then shown as an InputBox asking the user to input a COM port to open. It opens the port, sends a lenghty string out and then immedately reads the receive buffer and displays whatever comes in.


Henrik Olsson 2011-04-16

henrik [at] henriksplace [dot] se


Copyright 2011 Henrik Olsson. All Rights Reserved.
Template downloaded from:
FrontPage Templates