diff --git a/@MyLakeshore336/MyLakeshore336.m b/@MyLakeshore336/MyLakeshore336.m index 1b62f91..2fa09d9 100644 --- a/@MyLakeshore336/MyLakeshore336.m +++ b/@MyLakeshore336/MyLakeshore336.m @@ -1,107 +1,130 @@ % Class communication with Lakeshore Model 336 temperature controller. classdef MyLakeshore336 < MyScpiInstrument & MyCommCont properties (SetAccess = protected, GetAccess = public) % Temperature unit, K or C. This variable should be set % before the command list is created. temp_unit = 'K' end properties (Constant = true) % Correspondence lists for numeric codes in parameter values. % Indexing starts from 0. These lists are for information only. % Values for the output mode, out_mode_n(1). out_mode_list = {'Off', 'Closed loop PID', 'Zone', ... 'Open loop', 'Monitor out', 'Warmup supply'}; % Control input, out_mode_n(2). control_input_list = {'None', 'A', 'B', 'C', 'D'}; % Heater ranges heater12_range_list = {'Off','Low','Medium','High'}; heater34_range_list = {'Off','On'}; end methods (Access = public) function this = MyLakeshore336(varargin) this@MyCommCont(varargin{:}); createCommandList(this); end + + % Create temperature logger + function Lg = createLogger(this, varargin) + function temp = readTemperature() + sync(this); + temp = [this.temp_a,this.temp_b,this.temp_c,this.temp_d]; + end + + Lg = MyLogger(varargin{:}, 'MeasFcn', @readTemperature); + + % Make column headers + inp_ch = {'A', 'B', 'C', 'D'}; + headers = cell(1, 4); + for i = 1:length(inp_ch) + sens_name = sprintf('sens_name_%s', lower(inp_ch{i})); + headers{i} = sprintf('T ch %s %s (%s)', inp_ch{i}, ... + sens_name, this.temp_unit); + end + + if isempty(Lg.Record.data_headers) + Lg.Record.data_headers = headers; + end + end end methods (Access = protected) function createCommandList(this) % Commands for the input channels inp_ch = {'A', 'B', 'C', 'D'}; for i = 1:4 nch = inp_ch{i}; addCommand(this, ['sens_name_' lower(nch)], 'INNAME', ... 'read_ending', ['? ' nch], ... 'write_ending', [' ' nch ',%s'], ... 'info', ['Sensor name channel ' nch]); info = sprintf('Reading channel %s (%s)', nch, ... this.temp_unit); addCommand(this, ['temp_' lower(nch)], ... [this.temp_unit 'RDG'], ... 'format', '%e', ... 'access', 'r', ... 'read_ending', ['? ' nch], ... 'info', info); end % Commands for the output channels for i = 1:4 nch = num2str(i); addCommand(this, ['setp_' nch], 'SETP', ... 'read_ending', ['? ' nch], ... 'write_ending', [' ' nch ',%e'], ... 'info', ['Output ' nch ' PID setpoint in ' ... 'preferred units of the sensor']); addCommand(this, ['out_mode_' nch], 'OUTMODE', ... 'read_ending', ['? ' nch], ... 'write_ending', [' ' nch ',%i,%i,%i'], ... 'info', ['Output ' nch ' settings: ' ... '[mode, cntl_input, powerup_enable]'], ... 'default', [0, 0, 0]); if i==1 || i==2 % Outputs 1 and 2 have finer range control than than 3 % and 4 addCommand(this, ['range_' nch], 'RANGE', ... 'read_ending', ['? ' nch], ... 'write_ending', [' ' nch ',%i'], ... 'info', ['Output ' nch ' range ' ... '0/1/2/3 -> off/low/medium/high'], ... 'value_list', {0, 1, 2, 3}); else addCommand(this, ['range_' nch], 'RANGE', ... 'read_ending', ['? ' nch], ... 'write_ending', [' ' nch ',%i'], ... 'info', ['Output ' nch ' range ' ... '0/1 -> off/on'], ... 'value_list', {0, 1}); end end end end methods function set.temp_unit(this, val) assert(strcmpi(val,'K') || strcmpi(val,'C'), ... 'Temperature unit must be K or C.') this.temp_unit = upper(val); end end end diff --git a/@MyTpg/MyTpg.m b/@MyTpg/MyTpg.m index af37e7a..f3d0d5c 100644 --- a/@MyTpg/MyTpg.m +++ b/@MyTpg/MyTpg.m @@ -1,174 +1,174 @@ % Class for communication with Pfeiffer TPG single and dual pressure gauge % controllers. % Use 'serial' communication objects instead of 'visa' with this instrument % Tested with TPG 262 and 362. classdef MyTpg < MyInstrument & MyCommCont properties (Constant = true, Access = protected) % Named constants for communication ETX = char(3); % end of text CR = char(13); % carriage return \r LF = char(10); %#ok line feed \n ENQ = char(5); % enquiry ACK = char(6); % acknowledge NAK = char(21); % negative acknowledge end properties (SetAccess = protected, GetAccess = public, ... SetObservable = true) % Last measurement status gauge_stat = {'', ''}; end methods (Access = public) function this = MyTpg(varargin) this@MyCommCont(varargin{:}); createCommandList(this); end % read pressure from a single channel or both channels at a time function p_arr = readPressure(this) queryString(this, ['PRX', this.CR, this.LF]); str = queryString(this, this.ENQ); % Extract pressure and gauge status from reading. arr = sscanf(str,'%i,%e,%i,%e'); p_arr = transpose(arr(2:2:end)); % Status codes: % 0 –> Measurement data okay % 1 –> Underrange % 2 –> Overrange % 3 –> Sensor error % 4 –> Sensor off (IKR, PKR, IMR, PBR) % 5 –> No sensor (output: 5,2.0000E-2 [hPa]) % 6 –> Identification error this.gauge_stat{1} = gaugeStatusFromCode(this, arr(1)); this.gauge_stat{2} = gaugeStatusFromCode(this, arr(3)); end function pu = readPressureUnit(this) queryString(this, ['UNI',this.CR,this.LF]); str = queryString(this, this.ENQ); % Pressure units correspondence table: % 0 –> mbar/bar % 1 –> Torr % 2 –> Pascal % 3 –> Micron % 4 –> hPascal (default) % 5 –> Volt pu_code = sscanf(str,'%i'); pu = pressureUnitFromCode(this, pu_code); end function id_list = readGaugeId(this) queryString(this, ['TID',this.CR,this.LF]); str = queryString(this, this.ENQ); id_list = deblank(strsplit(str,{','})); end function code_list = turnGauge(this) queryString(this, ['SEN',char(1,1),this.CR,this.LF]); str = queryString(this, this.ENQ); code_list = deblank(strsplit(str,{','})); end % Attempt communication and identification of the device function [str, msg] = idn(this) try queryString(['AYT', this.CR, this.LF]); str = queryString(this.ENQ); catch ME str = ''; msg = ME.message; end this.idn_str = toSingleLine(str); end % Create pressure logger function Lg = createLogger(this, varargin) - Lg = MyLogger('MeasFcn', @this.readPressure, varargin{:}); + Lg = MyLogger(varargin{:}, 'MeasFcn', @this.readPressure); pu = this.pressure_unit; if isempty(Lg.Record.data_headers) && ~isempty(pu) - this.Lg.Record.data_headers = ... + Lg.Record.data_headers = ... {['P ch1 (' pu ')'], ['P ch2 (' pu ')']}; end end end methods (Access = protected) function createCommandList(this) addCommand(this, 'pressure', ... 'readFcn', @this.readPressure, ... 'default', [0, 0]); addCommand(this, 'pressure_unit', ... 'readFcn', @this.readPressureUnit, ... 'default', 'mBar'); addCommand(this, 'gauge_id', ... 'readFcn', @this.readGaugeId, ... 'default', {'', ''}); end function createMetadata(this) createMetadata@MyInstrument(this); addObjProp(this.Metadata, this, 'gauge_stat', ... 'comment', 'Last measurement status'); end % Convert numerical code for gauge status to a string function str = gaugeStatusFromCode(~, code) switch int8(code) case 0 str = 'Measurement data ok'; case 1 str = 'Underrange'; case 2 str = 'Overrange'; case 3 str = 'Sensor error'; case 4 str = 'Sensor off'; case 5 str = 'No sensor'; case 6 str = 'Identification error'; otherwise str = ''; warning('Unknown gauge status code %i', code); end end % Convert numerical code for pressure unit to a string function str = pressureUnitFromCode(~, code) switch int8(code) case 0 str = 'mBar'; case 1 str = 'Torr'; case 2 str = 'Pa'; case 3 str = 'Micron'; case 4 str = 'hPa'; case 5 str = 'Volt'; otherwise str = ''; warning('unknown pressure unit, code=%i',pu_num) end end end end diff --git a/GUIs/GuiLakeshore.mlapp b/GUIs/GuiLakeshore.mlapp index 038c922..b1841f9 100644 Binary files a/GUIs/GuiLakeshore.mlapp and b/GUIs/GuiLakeshore.mlapp differ