Using MATLAB with the ADU2xx USB Relay I/O Products (Windows)

A: Introduction

Communicating with USB devices in MATLAB, or virtually any application software, involves a few simple steps.  Unlike RS232 based devices which are connected to physical COM ports, USB devices are assigned a logical handle by operating systems when they are first plugged in. This process is known as enumeration. Once a USB device has been enumerated, it is ready for use by the host computer software. For the host application software to communicate with the USB device, it must first obtain the handle assigned to the USB device during the enumeration process. The handle can be obtained using an open function along with some specific information about the USB device. Information that can be used to obtain a handle to a USB device include, serial number, product ID, or vendor ID. Once the handle is obtained, it is used to allow the application to read and write information, to and from, the USB device.  Once the application has finished with all communication with the USB device, the handle is closed. The handle is generally closed when the application terminates.

The AduHid DLL provides all the functions to open a handle, read and write data, and close the handle of ADU USB devices. The ADUHID dll can be used directly from a MATLAB application. The MATLAB data Acquisition ToolKit is not required to communicate with ADU interfaces.

For this tutorial we will use MATLAB to communicate with an ADU258 USB Solid State Relay I/O  Interface. The application will open the ADU258, send comands and receive data using various ADU comands to operate the interface, and then close the ADU258.  Although we are using an ADU258 in this tutorial, the code can be modified to suit any of the ADU Data Acquisition and Control Products.

ADU258 USB Solid-State Relay I/O InterfaceFigure 1: ADU258 USB Solid-State Relay I/O Interface

Before we dissect the code, the full MATLAB .m file is listed here, followed by the Command Window Output. (Download entire project at bottom of page)

% USB Relay MATLAB Example
%( ADU200, ADU208, ADU218, ADU228, ADU258, ADU222, ADU252)

% 1) set up variables and pointers to be used by function calls
ptrResult=libpointer('int8Ptr',zeros(1,8));
ProductID = 258; % ADU258 USB Solid-State Relay I/O Interface, 8 Channel, 5 Amp
vp = libpointer('voidPtr',zeros(1,1));

% 2) Load libraries
if not(libisloaded('AduHid64'))
    loadlibrary('AduHid64','AduHidMatlab.h'); %Will need MinGW-w64 add-on
end

% 3) Obtain Handle to ADU Device
device_handle = calllib('AduHid64','OpenAduDevice',1000); %if only one ADU is connected
%device_handle = calllib('AduHid64','OpenAduDeviceBySerialNumber','V00235',1000); %to connect by Serial Number
%device_handle = calllib('AduHid64','OpenAduDeviceByProductId',ProductID,1000);%to connect by Product ID

% 4a) Set Relay K0
% Write "sk0" to ADU to set (close contact) Relay K0
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('sk0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
    pause (2)

 % 4b) Reset Relay K0
% Write "rk0" to ADU to reset (open contact)relay K0
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('rk0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
    pause (2);

 % 4c) Turn on all relays.
% Write "MK255" to ADU
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('mk255') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
    pause (2);

% 4d) Turn off all relays.
% Write "MK0" to ADU
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('mk0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end

 % 4e) Read back value of PORT A in decimal
% Write "PA" to ADU to read PORT A in decimal format
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('PA') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
% Read data from ADU
result = calllib('AduHid64','ReadAduDevice',device_handle,ptrResult,8,vp,500);
    if result == 0
    fprintf('\nError During ADU Read\n');
    end
% Convert returned string to number
    x=char(ptrResult.value);
    reading=str2num(x);
% Print the Reading to the Command Window
    fprintf('\nDecimal value of PORT A is %i \n', reading);

% 4f) Read PORT A in Binary Format
% Write "RPA" to ADU to read PORT A in decimal format
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('RPA') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
% Read data from ADU
result = calllib('AduHid64','ReadAduDevice',device_handle,ptrResult,8,vp,500);
    if result == 0
    fprintf('\nError During ADU Read\n');
    end
    x=char(ptrResult.value);
% Print the Reading to the Command Window
    fprintf('\nPORTA value in binary is %s \n',x);

% 4g) Read Event Counter 0(PA0) in Decimal Format
% Write "RE0" to ADU to read Event Counter 0 in decimal format
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('RE0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
% Read data from ADU
result = calllib('AduHid64','ReadAduDevice',device_handle,ptrResult,8,vp,500);
    if result == 0
    fprintf('\nError During ADU Read\n');
    end
% Convert returned string to number
    x=char(ptrResult.value);
    reading=str2num(x);
% Print the Reading to the Command Window
    fprintf('\nEvent Counter 0 value is %i \n',reading);

% 5) Before terminating program, clear variables, release ADU handle
% and unload the library(s)
clear vp ptrResult reading;
calllib('AduHid64','CloseAduDevice',device_handle);
unloadlibrary('AduHid64');

 

 

 When run, the code displays the following in the Command Window.

Figure 2: Command Window Output


B: Lets have a look at the code......

1. Set up variables and pointers to be used by function calls.

The ADU products use NULL terminated ASCII strings to communicate, with the longest string being 8 bytes.  Here we initiate a pointer to create a 8 byte array to store the received data.  We then set the variable ProductID to 258 and then the vp pointer is initalized as a single byte. This variable is used to store bytes received and bytes sent by the function calls.

 
% 1) set up variables and pointers to be used by function calls
ptrResult=libpointer('int8Ptr',zeros(1,8));
ProductID = 258; % ADU258 USB Solid-State Relay I/O Interface, 8 Channel, 5 Amp
vp = libpointer('voidPtr',zeros(1,1));

2. Load Libraries.

To allow function calls to the ADU258 within MATLAB we must load the libraries including the AduHid64.dll and AduHidMatlab.h files. It is important to use the AduHidMatlab.h header file and NOT the AduHid.h file normally included with our dll. This is because MATLAB does not recognize the BOOL format used in the original Windows header. The AduHidMatlab.h file was created only for use in MATLAB.

% 2) Load libraries
if not(libisloaded('AduHid64'))
    loadlibrary('AduHid64','AduHidMatlab.h'); %Will need MinGW-w64 add-on
end

3. Obtain handle to ADU Device.

To communicate with the ADU258 we must first open a handle to it.  This can be done in one three types of calls. For this example we open a handle to the first ADU device detected.  This should only be used if there is only one ADU connected to the host computer. If more than one ADU is connected you can either open the handle by SerialNumber or ProductID.


% 3) Obtain Handle to ADU Device
device_handle = calllib('AduHid64','OpenAduDevice',1000); %if only one ADU is connected
%device_handle = calllib('AduHid64','OpenAduDeviceBySerialNumber','V00235',1000); %to connect by Serial Number
%device_handle = calllib('AduHid64','OpenAduDeviceByProductId',ProductID,1000);%to connect by Product ID

4. Send/Receive commands and data from the ADU258.

The ADU258 features 8 Solid-State relays ( K0 to K7), and 8 digital inputs divided into two 4-bit ports ( PA0-PA3, PB0-PB3).  Each of the digital input lines has a 16-bit event counter associated with it.  The command format the ADU258, and all ADU2xx products, uses is very intuative and consists of Null terminated ASCII strings. Here we will perform some random tasks to demonstrate how to send commands and receive data from the ADU258.

In section 4a we send the SK0 command to turn on relay K0, and then wait for 2 seconds

In section 4b, we send the RK0 command to open relay K0, and then wait for 2 seconds

In section 4c, we send the MK255 command to turn on all 8 relays, and then wait for two seconds

In section 4d, we send the MK0 command to turn off all eight relays.

To read data from any ADU device a read command must be sent (PA, for example). This is done using a WriteAduDevice function call. Note that the PA command is sent with  [int8('PA') 0 0]  which produces the ASCII string "PA" followed by two NULLs ( recommended). To retrieve the data, a ReadAduDevice function call is implemented. For details on all ADU function calls see: ADUHid Functions.

The returned data for the PA command is in the format of 2 ASCII characters ranging from 00 to 15 and it should be converted to an actual number to allow use of the data in calculations, plotting, etc. This is accomplished with the x=char(ptrResult.value); and
reading=str2num(x); statements.

In section 4e, we send the PA command to read PORTA in decimal format.  We then read the data, which is in the format of a null terminated ASCII string, and convert it to a number using the str2num function. the number is then output to the command window.

In section 4f, we send the RPA command to read PORTA in binary format.  We then read the data, which is in the format of a null terminated ASCII string, and output it to the command window.

In section 4f, we send the RE0 command to read the event counter on PA0 in decimal format.  We then read the data, which is in the format of a null terminated ASCII string,  and convert it to a number using the str2num function. The number is then output to the command window.

 

% 4a) Set Relay K0
% Write "sk0" to ADU to set (close contact) Relay K0
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('sk0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
    pause (2)

 % 4b) Reset Relay K0
% Write "rk0" to ADU to reset (open contact)relay K0
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('rk0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
    pause (2);

 % 4c) Turn on all relays.
% Write "MK255" to ADU
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('mk255') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
    pause (2);

% 4d) Turn off all relays.
% Write "MK0" to ADU
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('mk0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end

 % 4e) Read back value of PORT A in decimal
% Write "PA" to ADU to read PORT A in decimal format
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('PA') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
% Read data from ADU
result = calllib('AduHid64','ReadAduDevice',device_handle,ptrResult,8,vp,500);
    if result == 0
    fprintf('\nError During ADU Read\n');
    end
% Convert returned string to number
    x=char(ptrResult.value);
    reading=str2num(x);
% Print the Reading to the Command Window
    fprintf('\nDecimal value of PORT A is %i \n', reading);

% 4f) Read PORT A in Binary Format
% Write "RPA" to ADU to read PORT A in decimal format
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('RPA') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
% Read data from ADU
result = calllib('AduHid64','ReadAduDevice',device_handle,ptrResult,8,vp,500);
    if result == 0
    fprintf('\nError During ADU Read\n');
    end
    x=char(ptrResult.value);
% Print the Reading to the Command Window
    fprintf('\nPORTA value in binary is %s \n',x);

% 4g) Read Event Counter 0(PA0) in Decimal Format
% Write "RE0" to ADU to read Event Counter 0 in decimal format
result = calllib('AduHid64','WriteAduDevice',device_handle,libpointer('voidPtr',[int8('RE0') 0 0]),8,vp,500);
    if result == 0
    fprintf('\nError During ADU Write\n');
    end
% Read data from ADU
result = calllib('AduHid64','ReadAduDevice',device_handle,ptrResult,8,vp,500);
    if result == 0
    fprintf('\nError During ADU Read\n');
    end
% Convert returned string to number
    x=char(ptrResult.value);
    reading=str2num(x);
% Print the Reading to the Command Window
    fprintf('\nEvent Counter 0 value is %i \n',reading);

5. Before terminating program, clear variables, release ADU258 Handle and unload the library.

Before exiting the program the variables are cleared, the ADU258 handle is released, and the libraries are unloaded.

It is important that the handle for an ADU device is opened when the application opens, and closed only when the application terminates. DO NOT open and close the handle for each read or write as Windows may put the ADU258 into suspend mode causing a loss of configuration data.

% 5) Before terminating program, clear variables, release ADU handle
% and unload the library(s)
clear vp ptrResult reading;
calllib('AduHid64','CloseAduDevice',device_handle);
unloadlibrary('AduHid64');

Download the tutorial and associated libraries here:

MATLAB ADU2xx Tutorial ( Windows 64-Bit) ZIP

Authored by Tom Fortin, April 2021