Code covered by the BSD License  

Highlights from
Pico Technology TC-08 USB data acquisition

Pico Technology TC-08 USB data acquisition



20 May 2013 (Updated )

Files to connect, query, and disconnect from the Pico Technology USB TC-08, using DLL's.

usbtc08query(handle, bufferSize, units)
function [recentData, allData, overflowFlag] = usbtc08query(handle, bufferSize, units)
% USBTC08QUERY gets information from Pico Technology TC-08 data loggers
% [recentData, allData, overflowFlag] = usbtc08query(handle) returns the
% most recent values (as an 8-element numeric column vector).
% usbtc08connect must be run first to configure the USB TC-08 and to obtain
% tc08Handle.  If allData is specified as a second argument, then all the
% data in the buffer is supplied as a cell array the same size as the
% number of channels, with temperature-time data.  If no data is in the
% buffer, all the temperatures are NaN's.  BufferSize is optional, and
% defaults to the maximum possible value (600, as according to the header
% file) to retain as much data as possible.  The overflowFlag is a vector
% the same size as the channels, which gives a 1 if at any point a
% measurement on that channel overflowed - it is not possible to determine
% exactly which measurement failed.

% e.g. recentData = usbtc08query(handle) returns all the temperature(s)
% and/or voltage(s) from all the channels from the USB TC-08 attached first
% (EXcluding the cold junction) - note that this is different behaviour to
% usbtc08queryslow, which does return the cold junction.

% number of arguments error check
error(nargchk(1, 3, nargin))

if nargin >= 2 && isempty(bufferSize)
    % ignore it, and set to the default bufferSize
    bufferSize = 600;

if nargin >= 3 && isempty(units)
    % ignore it, and set it to the default
    units = 0;

% defines the library
tc08LibraryName = 'usbtc08';

% define a buffer size of one wasn't specified
if nargin < 2
    % the maximum possible as described in the header file
    bufferSize = 600;

% define the units if some weren't specified
if nargin < 3
    % set to Celsius (not worrying about the datatype - we'll fix that
    % later
    units = 0;

% error handling
if ~isvalidtc08handle(handle)
    % errors
    error('handle must be a uint16 from 1-65535 generated by usbtc08connect')
% checks the library is loaded
elseif ~libisloaded(tc08LibraryName)
    % errors
    error('dll is not loaded - run usbtc08connect first to configure TC-08')

% checks the bufferSize - quite relaxed - this would let integers through,
% but this won't matter because we're going to change the datatype later
% anyway
elseif nargin >= 2 && (~isscalar(bufferSize) || ~isnumeric(bufferSize) || isnan(bufferSize) || bufferSize < 1 || bufferSize > 600)
    % errors
    error('bufferSize must be anything from 1 up to 600.')
% check the units (but not worrying about the datatype - fix that later
elseif nargin >= 3 && (~isscalar(units) || ~isnumeric(units) || ~ismember(units, [0, 1, 2, 3]))
    % units must be valid if specified
    error('Units must be set to 0 (Celsius), 1 (Fahrenheit), 2 (Kelvin) or 3 (Rankine) only.')

% unfortunately "long" depends on what platform we're on - if its windows
% its int32, but in Linux is int64
if ispc
    % use that
    bufferSize = int32(bufferSize);
    % assume its linux (not sure what happens on macs - not documented)
    bufferSize = int64(bufferSize);

% initialises the things to contain the data in
dataPointer = libpointer('singlePtr', NaN(bufferSize, 1));
timesPointer = libpointer('longPtr', NaN(bufferSize, 1));
overflowPointer = libpointer('int16Ptr', 0);

% the times data is the number of milliseconds since the first
% measurement (which starts at 0 ms)

% get_temp on channel 0 (the CJC) will return 0 - if you need it you need
% to use get_temp_single - so we start collecting data from channel 1
% (which fits better with MATLAB's handling of indexing anyway)

% converts units
units = int16(units);

% and we want the missing values to be filled with NaN - this doesn't
% actually seem to work - can guide this behaviour by initialising the
% data/timesPointers with NaN's
fillMissingValuesWithNaN = int16(0);

% assume we're going to scan all the channels...even if they're not
% connected - we can pull out the data we don't need later anyway
channels = 8;

% reading from channel 0 *should* give the cold junction temperature, but
% doesn't - it just gives NaN's - this behaviour is different to
% get_temp_single, as implemented in usbtc08queryslow

% if more than one channel isn't configured, then it will give a
% temperature that is the same as the last *configured* channel i.e. if
% there is only one unconnected channel, you will always see a pair of
% channels with exactly the same number - although this is an unlikely
% situation for real temperatures, it will fail for calculated parameters

% assume the maximum amount of data will be retrieved - not possible to
% predict the number of temperatures that will be obtained - set values to
% infinite so we know which ones to ignore
%allData = inf(channels, 3, 600); %DEBUG ME

% the most recent data is a vector of the number of channels
recentData = NaN(channels, 1);
readResponse = zeros(channels, 1);
allData = cell(channels, 1);
overflowFlag = zeros(channels, 1);

% get temperature - the buffer is FIFO behaviour - i.e. the buffer will
% back up if you don't keep reading data out, at which point the oldest
% data will be overwritten
for m = int16(1:channels)

    % get temperature - format is...
    %readSuccess = usb_tc_08_get_temp(handleInt16, tempBuffer(float),
    %times_ms_buffer(long,opt), bufferSize(long), overflow(short),
    %channel(short), units(short), fill_missing(short)
    % preallocate answer - first column is temperature data, second column
    % is the time (in ms) since the start, and third column is the
    % overflowFlag
    allData{m} = NaN(600, 2);
    % retrieves data into pointers
    readResponse(m) = calllib(tc08LibraryName, 'usb_tc08_get_temp', handle, dataPointer, timesPointer, bufferSize, overflowPointer, m, units, fillMissingValuesWithNaN);
    % stores pointer data in the right place
    allData{m}(:, 1) = get(dataPointer, 'Value');
    allData{m}(:, 2) = get(timesPointer, 'Value');
    overflowFlag(m) = get(overflowPointer, 'Value');
    % the most recent data is the largest index row in the first column,
    % that isn't a NaN - can't use find(..., 'first') for this
    temperatureData = allData{m}(:, 1);
    goodTemperatureData = temperatureData(~isnan(temperatureData));
    % edge case where all the data isnan...
    if ~isempty(goodTemperatureData)
        % set it - otherwise it will be just left as a NaN
        recentData(m) = goodTemperatureData(end);
    % check the data
    if ~readResponse
        % do something
        warning('Could not retrieve data from channel %d.', m)

Contact us