Matlab: Serial Communication with Pfeiffer MaxiGauge
Connect the MaxGauge to the PC using a simple (3-wire) cross-over serial cable.
The communication protocol (viewed from the PC) is roughly:
--> Mnemonic <CR>
<-- <ACK> <CR> <LF>
--> <ENQ>
<-- Data <CR> <LF>
The mnemonics are described in the user manual (page 85ff). CR (carriage return), ACK (acknowledge), LF (line-feed), ENQ (enquire) are standard ASCII control chararacters.
A simple script for first interactions (almost no error checks!):
maxigauge = serial('COM1');
fopen(maxigauge);
% ASCII control characters
ENQ = int8(5);
LF = int8(10);
CR = int8(13);
ACK = int8(6);
NAK = int8(21);
% Send command: I want to know the part number.
message = [int8('PNR'), CR];
fwrite(maxigauge, message)
% Device the "command received" answer from the device
answer = fscanf(maxigauge);
if all(answer == [ACK CR LF])
% disp('Command received by MaxiGauge')
else
error('Command not received correctly by MaxiGauge')
end
% Send the ENQ signal
fwrite(maxigauge, ENQ)
% Receive Answer
answer = fscanf(maxigauge);
disp(answer(1:end-2))
% End communication and cleanup
fclose(maxigauge);
delete(maxigauge)
clear maxigauge
Here is somewhat equivalent code as a Matlab class. I don’t do much OOP, so take it with a grain of salt.
classdef PfeifferMaxiGauge < handleAllHidden
properties (Hidden, SetAccess = immutable)
ENQ @ int8 scalar = 5; % Undocumented @ syntax: value is of type doulbe, a scalar, with initinal value = 0
LF @ int8 scalar = 10;
CR @ int8 scalar = 13;
ACK @ int8 scalar = 6;
NAK @ int8 scalar = 21;
com_port @ char vector;
end
properties (SetAccess = immutable)
serial_handle @ serial scalar;
end
methods (Hidden) % Low-level methods that the user should not (but can) call
function obj = PfeifferMaxiGauge(com_port) % constructor
obj.com_port = com_port;
obj.serial_handle = serial(obj.com_port);
fopen(obj.serial_handle);
end
function delete(obj) % destructor
fclose(obj.serial_handle);
end
function write(obj, str)
% Adds CR to str.
% Low-level function. Use send_command(), if appropriate.
message = [int8(str), obj.CR];
fwrite(obj.serial_handle, message)
end
function output = read(obj)
% Removes CR LF from output
output = fscanf(obj.serial_handle);
if output(end-1) ~= obj.CR || output(end) ~= obj.LF
error('MaxiGauge Read Operation: Unexpected data format - no CR LF at end!')
end
output = output(1:end-2);
end
end
methods % High-level methods that the user should use.
function send_command(obj, str)
obj.write(str)
ack_msg = obj.read();
if length(ack_msg) > 1 || ack_msg ~= obj.ACK;
error(['Command "' str '" not acknowledged by device'])
end
end
function output = query(obj, str)
if nargin > 1
obj.send_command(str)
end
fwrite(obj.serial_handle, obj.ENQ);
output = obj.read();
end
function pnr = get_pnr(obj)
pnr = obj.query('PNR');
end
end
end
This class derives from handleAllHidden, which is a trick to hide the standard methods when deriving from the handle class. I only implemented one helper method in my class (get_pnr), the rest will come later, as I need it.