function result=watlow96(command,value) global w96_s; %This function controls the watlow 96 controller on the Cincinnati Sub-zero %temperature chamber. One must configure the following lines: serial_id='COM1'; serial_baud=19200; %This devices speaks something called MODBUS. Modbus has the following format: % % The funtion and data fields can vary in length. The slave address is an % 8 bit number of value 1-247; however, our Watlow 96 has an address of 1. % % from the document: Modbus_Application_Protocol_V1_1b.pdf if found that % the function fields are as follow: % 0x01 read coils % 0x02 read discrete inputs % 0x03 read holding register % 0x04 read input register % 0x05 write single coil % 0x06 write single register % 0x07 serial exception status % 0x08 serial diagnostics % In matlab, the format for this becomes quirky, for instance: % [1 3 00 100 0 1] would mean: to address 1, read, register number 100 (as % 0+100), 1 (this seems to denote 1 decimal place, I sent 0 but it balked, % but 1 works ). The controller will then return the temperature. if (nargin < 2) || isempty(value) value='none'; end if (nargin < 1) || isempty(command) command='none'; end switch command case 'init' switch value case 'close' if ~isempty(w96_s) fprintf('free serial port\n'); fclose(w96_s); w96_s=[]; result=0; else fprintf('I could not free the serial resource because it was not allocated.\n'); result=-1; end otherwise %connect if we shouldn't discoonect if isempty(w96_s) w96_s=serial(serial_id, 'BaudRate', serial_baud); %w96_s=serial('COM1', 'BaudRate', 19200); fopen(w96_s); else fprintf('The serial device was already initialized... Type watlow96(''init'',''close'') to disconnect.\n'); end result = 0; end case 'read' if(isempty(w96_s)) fprintf('Device is not open. Type watlow96(''init'',''open'') to create the serial device. \n'); end message=[1 3 00 100 0 1]; crc=generateCRC(message); fwrite(w96_s,[message crc]); result = fread(w96_s,7); result=convert2dec(result(4:5))/10; fprintf('current temperature: %.2f C\n',result); case 'set' if strcmpi(value,'none') result = -1; fprintf('no temperature value given?\n'); else setpoint=round(value*10); setpoint=convert2bytes(setpoint); message = [1 6 1 44 setpoint]; %register 300 crc=generateCRC(message); fwrite(w96_s,[message crc]); %now that we wrote, we need to see what the response was. result=fread(w96_s,8); if(result(2)==6) % result result=convert2dec(result(5:6))/10; fprintf('setpoint read back as: %.2f C\n',result); else fprintf('unexpected result in sending command, packet:'); result end end otherwise fprintf('unknown command, valid commands are:\nwatlow96(''init'',''open'') -- open the serial port\nwatlow96(''init'',''close'') -- close the serial port\nwatlow96(''read'') -- read current chamber temperature\nwatlow96(''set'',) -- set temperature\n') fprintf('an example would be:\nwatlow96(''set'',34.1) to set the chamber to 34.1C\n'); end return %utility functions. function retval = convert2bytes(value) if value < 0 ndnum=bitcmp(abs(value),16); value=ndnum+1; end bytes=dec2hex(value); if length(bytes) > 2 byte1=bytes(1:length(bytes)-2); byte2=bytes(length(bytes)-1:length(bytes)); else byte1=0; byte2=bytes; end retval=[hex2dec(byte1) hex2dec(byte2)]; return function retval = convert2dec(value) %make the return decimals. Make a signed 16-bit number and return it. cmd=[]; sp=dec2bin(value,8); %convert the arrya numreg=size(sp); for i=1:numreg(1) cmd=[cmd sprintf('sp(%d,1:8) ',i)]; end bnum=eval(['[' cmd ']']); dnum=bin2dec(bnum); % negative? if bitget(dnum,8*numreg(1))==1 ndnum=bitcmp(dnum,8*numreg(1)); dnum=-1*(ndnum+1); end retval=dnum; return function crc = generateCRC(message) %this generates the checksum as described by the MODBUS docuemnt if ~isnumeric(message) message=hex2dec(message); end pad=hex2dec('A001'); xd=hex2dec('FFFF'); for i=1:length(message) xd=bitxor(message(i),xd); for j=1:8 if bitand(xd,1) xd=bitshift(xd,-1); xd=bitxor(xd,pad); else xd=bitshift(xd,-1); end end end xdb=dec2bin(xd,16); crc(1)=bin2dec(xdb(9:16)); crc(2)=bin2dec(xdb(1:8)); return