3 July 2017

Цифровой датчик температуры TSic: адреса, пароли, явки

Блог компании ЭФО corporate blogIndustrial ProgrammingRobotics developmentProgramming microcontrollersDevelopment for IOT
Продолжаем серию материалов об особенностях применения различных датчиков и чувствительных элементов.

Герой сегодняшней статьи, на первый взгляд, не представляет собой ничего особенного — мало ли мы видели цифровых датчиков температуры. Однако у серии TSic есть два необычных свойства: действительно высокая точность (до ±0.07°C у старшей модели) и малоизвестный однопроводной интерфейс ZACwire.

Под катом подробно описываем номенклатуру стандартных датчиков TSic и кастомные решения, разбираемся в особенностях коммуникационного протокола, смотрим примеры программ для МК. Словом, делаем всё чтобы убедить уважаемого читателя в том что датчики TSic стоят своих денег.

TSic — это серия цифровых датчиков температуры, которые в прошлом выпускались под брендом ZMDI, а сейчас принадлежат швейцарской компании IST AG.

Чувствительным элементом датчика служит высокоточный источник опорного напряжения с выходом, пропорциональным температуре (bandgap reference with a PTAT (proportional-to-absolute-temperature). Как и другие интегральные датчики температуры, TSic также содержит АЦП, схему обработки сигнала, EEPROM с данными для калибровки и выходной интерфейс.

Между собой стандартные модели датчиков TSic различаются рабочим диапазоном температур, точностью, типом выходного сигнала и корпусом.



Рабочий диапазон температур и точность


Датчики TSic 20x и TSic 30x имеют рабочий диапазон температур от -50 до +150°C и три «зоны точности». На графике показана максимальная погрешность датчиков на различных диапазонах температуры.



Датчики TSic 50x предназначены для более узкого диапазона температур — от -10 до +60°C. На участке повышенной точности шириной 40 градусов датчики TSic 50x обеспечивают точность ±0.1°C, на остальном диапазоне — ±0.2°C.



Самый дорогой высокоточный датчик TSic — это модель TSic 716. На узком 20-градусном участке этот элемент обеспечивает ±0.07°C.



Отличием датчика TSic 716 также является более высокая разрядность (разрешение). Если в датчиках TSic 206, TSic 306 и TSic 506 встроен 11-битный АЦП, то TSic 716 оснащен 14-разрнядным преобразователем.
Таким образом, разрешение датчиков TSic 206 и TSic 306 составляет $\frac{(50 + 150)[°C]}{2^{11}} ≈ 0.1[°C]$,
разрешение TSic 506 составляет $ \frac{(10 + 50)[°C]}{2^{11}} ≈ 0.034[°C]$,
разрешение TSic 716 составляет $ \frac{(10 + 50)[°C]}{2^{14}} ≈ 0.004[°C]$.

Кастомная калибровка


Выше описаны стандартные исполнения датчиков TSic, однако диапазон повышенной точности любого из датчиков TSic может быть «сдвинут» при производстве элемента. Так, например, под заказ доступны датчики TSic 50x с повышенной точностью на участке от -10 до 30°C или от 13 до 53°C. Аналогично для других моделей TSic.



Корпус


Датчики серии TSic выпускаются в корпусах SOP-8 и TO92, распиновка доступна в документации.



Кроме того, существует возможность поставки датчиков TSic в нестандартных корпусах, с разного рода кабелями, коннекторами, контактными площадками и так далее. Тут всё обсуждается индивидуально, но сразу скажу, что для использования этой возможности совершенно не обязательно иметь проект на сотни датчиков в год.



Подключение датчика


Для подключения любой модели TSic понадобятся соединения по питанию и земле, а также одна сигнальная линия.



Рабочее напряжение датчика — от 3 до 5.5В. Часто датчик удобнее запитать от одного из GPIO управляющего контроллера. Во-первых, это позволяет свести к нулю энергопотребление датчика вне цикла измерений, а во-вторых, упрощается детектирование начала посылки, если используется датчик TSic с цифровым выходом.

В случае питания датчика от ножки контроллера производитель рекомендует позаботиться об исключении влияния шумов и добавить на линию питания RC-цепочку.

Выходной сигнал


Датчики TSic 20x, TSic 30x и TSic 50x могут иметь аналоговый, ратиометрический или цифровой выход. В первом случае напряжение на выходе изменяется от 0 до 1 В пропорционально температуре среды, во втором случае — от 10 до 90% от напряжения питания. Датчики с цифровым выходом используют протокол ZACWire, о котором мы подробно поговорим чуть ниже.

Во всех трёх случаях выходной сигнал пропорционален температуре, т.е. для расчета температуры используются простые формулы.

Для датчиков TSic с аналоговым выходом:

$T = Vвых * (Th - Tl) + Tl$


Для датчиков TSic с ратиометрическим выходом:

$T = \frac{\frac{Vвых}{V^+}- 0.1}{0.8}* (Th - Tl) + Tl$


Для датчиков TSic с цифровым выходом:

$T = \frac{DS}{2^{11}}* (Th - Tl) + Tl $

или

$T = \frac{DS}{2^{14}}* (Th - Tl) + Tl$


где
  • $T$ — температура, °C
  • $Vвых$ — выходное напряжение датчика, В
  • $V^+$ — напряжение питания, В
  • $DS$ — выходной цифровой сигнал
  • $Th$ — верхняя граница диапазона рабочих температур, °C
    $Th$ = +150°C для TSic 20x и TSic 30x, $Th$ = +60°C для TSic 50xF и TSic 716
  • $Tl$ — нижняя граница диапазона рабочих температур, °C
    $Tl$= -50°C для TSic 20x и TSic 30x, $Th$ = -10°C для TSic 50xF и TSic 716


Примеры сигналов на выходе датчиков TSic приведены в таблице.
Для датчиков TSic 20x / TSic 30x
Измеряемая температура, °C Аналоговый выход Ратиометрический выход Цифровой выход
-50 0.000В 10% V+
(0.5В при V+=5В)
0x000
-10 0.200В 26% V+
(1.3В при V+=5В)
0x199
0 0.250В 30% V+
(1.5В при V+=5В)
0x200
+25 0.375В 40% V+
(2.0В при V+=5В)
0x2FF
+60 0.550В 54% V+
(2.7В при V+=5В)
0x465
+125 0.875В 80% V+
(4.0В при V+=5В)
0x6FE
+150 1.000В 90% V+
(4.5В при V+=5В)
0x7FF
Для датчиков TSic 50xF / TSic 716
  11-бит
(TSic 506F)
14-бит
(TSic 716)
-10 0.000В 10% V+
(0.5В при V+=5В)
0x000  0x0000
0 0.143В 21.4% V+
(1.07В при V+=5В)
0x124  0x0924
+25 0.500В 50% V+
(2.5В при V+=5В)
0x3FF  0x01FF
+60 1.000В 90% V+
(4.5В при V+=5В)
0x7FF  0x3FFF

Чаще всего, впрочем, выбирают датчики с цифровым выходом, это позволяет не задумываться о влиянии схем обработки аналогового сигнала на точность измерений. При этом цифровой датчик TSic использует столько же ножек МК, сколько и аналоговый датчик, плюс он немножко дешевле.

Очевидный минус датчика TSic с цифровым выходом — нестандартный интерфейс, для которого на ваш МК ещё нет готовой библиотеки. Очевидный плюс — этот интерфейс очень простой.

Протокол ZACWire


ZACWire — однопроводной протокол, использующий кодировку, напоминающую Манчестерскую.

Датчик с заранее определенной частотой передаёт данные о температуре — два восьмибитных пакета данных. Каждый из пакетов начинается стартовым битом и заканчивается битом чётности. В зависимости от модели датчика, в каждой посылке либо 11, либо 14 значащих разрядов, первым идет старший бит.



Пассивным состоянием лини данных является высокий уровень. Каждый бит посылки TSic начинается со спада сигнала и занимает 125 микросекунд. Состояние линии данных фиксируется на середине этого интервала — если по прошествии 62.5 мксек со спада сигнала на линии высокий уровень, то записываем логическую «1», если низкий, то логический «0». Коэффицент заполнения в первом случае равняется 75%, в втором — 25%.



Коммуникационный интерфейс ZACWire не использует отдельного тактового сигнала, поэтому отсчёт тактов производится на стороне микроконтроллера.

Стартовый бит также начинается со спада сигнала, но имеет коэффициент заполнения 50%. Стартовый бит может использоваться как для детектирования начала посылки, так и для измерения длительности такта, если она не известна заранее: временной период между спадом и фронтом стартового бита равен Tstrobe — времени, по истечении которого нужно проверять состояние линии при чтении очередного бита.

С другой стороны, для стандартных датчиков TSic значение Tstrobeизвестно заранее
и равно 125 / 2 = 62.5 мксек, поэтому на практике стартовый бит просто детектируют и пропускают.



Биты чётности декодируются так же, как и биты данных. В отсутствии внешних помех и небольшой длине соединения (до 2 метров) контроль целостности, как правило, не требуется. Между окончанием первого пакета и вторым стартовым битом на линии установлен высокий уровень.

Чтобы внести окончательную ясность, рассмотрим осциллограмму пакета данных датчика TSic 306.



Посылка начинается со стартового бита, далее идут незначащие биты данных, которые всегда равны «0», далее идут старшие биты данных — «011», далее бит чётности, соответственно равный «0». Второй пакет начинается через один период (Tstrobe * 2) и содержит стартовый бит, восемь младших бит данных «00011000» и бит чётности, соответственно равный «0».



В результате получаем на выходе 01100011000bin = 792dec и по приведенной выше формуле вычисляем значение температуры.

$T = \frac{DS}{2^{11}}* (Th - Tl) + Tl= \frac{792}{2^{11}}* (150 - (-50)) + (-50) = 27.3°C$

Если говорить о частоте, с которой датчик TSic передаёт такие посылки с данными, то она устанавливается при производстве компонента и не может быть изменена по ходу использования датчика. Для моделей TSic 206, TSic 306, TSic 506 частота равляется 10 Гц, для TSic 716 — 1 Гц. Под заказ доступны датчики с нестандартной частотой измерений — 250, 10, 1 и 0.1 Гц.

Если задача не предполагает опроса датчика с максимально возможной частотой и на микроконтроллере есть свободная линия, то имеет смысл использовать эту линию для питания датчика. Таким образом, каждый раз когда требуется получить данные с датчика, можно подать питание на датчик и ожидать спада на линии данных — стартового бита первого пакета. Между подачей питания на TSic и передачей посылки пройдет менее 85 микросекунд, а после приёма двух пакетов данных питание датчика можно отключить.

Именно такой способ подключения датчика использовался вашей покорной слугой.

В порядке эксперимента я подключаю две стандартные модели TSic 306 TO92 и TSic 506 TO92 к отладочной плате EFM32ZG-STK3200. По нажатию на кнопку на датчик подаётся питание, принимается одна посылка с данными о температуре, данные обрабатываются, результат выводится на установленный на плату LCD дисплей, после чего датчик от питания отключается.

Отладочная плата EFM32ZG-STK3200 выпускается компанией Silicon Labs (SiLabs)
для работы с микроконтроллерами EFM32 Zero Gecko.

EFM32 Zero Gecko — младшая серия семейства EFM32. Эти микроконтроллеры построены на базе ядра ARM Cortex-M0+, имеют стандартный набор встроенный периферии и разные интересные модули для снижения энергопотребления контроллера. Мы уже публиковали на хабре подробную статью об особенностях этой платформы и средствах отладки для EFM32 Zero Gecko.

Сегодня мы вообще не будем касаться специфических программных и аппаратных компонентов EFM32, предназначенных для контроля и снижения энергопотребления. Вместо этого будем использовать самые базовые компоненты и режимы их работы, чтобы полученный алгоритм было проще перенести на богомерзкий STM портировать на другие микроконтроллерные платформы.

Итак, от МК нам понадобятся
  • Три GPIO: подключенный к кнопке PC9 и свободные PC0 и PC1 для линий питания и данных TSic
  • Таймер для тактирования линии данных TSic
  • SPI для работы со встроенным дисплеем. SPI я упоминаю просто для порядка, т.к. вся работа с выводом данных проводится с помощью SiLabs-овской библиотеки glib, содержимое которой мне не очень интересно


На отладочной плате, соответственно, мы используем
  • Микроконтроллер EFM32ZG222F32
  • USB-отладчик SEGGER J-Link USB
  • Механическую кнопку PB1
  • Разъем expansion header, на котором доступны нужные GPIO и земля
  • Дисплей 128x128 пикселей — исключительно симпатичный LCD




Итак, по прерыванию от кнопки подаём на датчик питание, принимаем посылку и отключаем питание. Если при приёме данных возникла ошибка — выдаём соответствующее сообщение, иначе вычисляем температуру в градусах Цельсия и показываем результат на LCD.

void ReceiveTempAndShowIt(void) {
	GPIO_PinOutSet(TSIC_VDD_PORT, TSIC_VDD_PIN);
	int8_t TSic_result = receiveTSicData();
	GPIO_PinOutClear(TSIC_VDD_PORT, TSIC_VDD_PIN);

	if (TSic_result == TSIC_IS_OK) {
		float temperatureCelsius = calculateCelsius(fullTSicTransmission);
		Display_ShowTemperature(temperatureCelsius);
	} else if (TSic_result == TSIC_PARITY_ERROR) {
		Display_ShowParityError();
	} else if (TSic_result == TSIC_TIMING_ERROR) {
		Display_ShowTimingError();
	}
}

Важно!

Здесь пора отметить, что рассмотренный в этой статье код — совершенно не оптимален. То есть совсем-совсем не оптимален. Ниже вы увидите, как фронты и спады сигнала детектируются с помощью while, как временные интервалы отсчитываются без использования прерываний и прочая, прочая.

Причина такого подхода — желание рассмотреть максимально простой и понятный пример, в котором не будет использоваться вообще никаких специфических для конкретного микроконтроллера функций.

Итак, функция приёма данных receiveTSicData() — это приём двух пакетов данных, вычленение из каждого из них бита чётности и проверка целостности для обоих пакетов.

int8_t receiveTSicData(void) {
	uint16_t firstTSicPacket = 0;
	uint16_t secondTSicPacket = 0;
	bool firstParityBit = 0;
	bool secondParityBit = 0;

	/* Time critical section [all interrupts disable]:
	 * Receive two data packets from TSic sensor
	 */
	INT_Disable();
	if (readTSicPacket(1) == PACKAGE_READING_OK) {
		firstTSicPacket = currentTSicPacket;
	} else {
		INT_Enable();
		return TSIC_TIMING_ERROR;
	}
	if (readTSicPacket(0) == PACKAGE_READING_OK) {
		secondTSicPacket = currentTSicPacket;
	} else {
		INT_Enable();
		return TSIC_TIMING_ERROR;
	}
	INT_Enable();

	/* Decode received packets */
	/* Get parity bit from first packet */
	firstParityBit = firstTSicPacket & 0x01;
	/* Get 3 data bits from first packet */
	firstTSicPacket = firstTSicPacket & 0x0007;
	/* Delete first parity bit */
	firstTSicPacket >>= 1;
	/* Get parity bit from second packet */
	secondParityBit = secondTSicPacket & 0x01;
	/* Delete second parity bit */
	secondTSicPacket >>= 1;

	/* Check parity errors and assemble full temperature transmission from TSic */
	if (checkParity(firstTSicPacket, firstParityBit) == PARITY_OK
			&& checkParity(secondTSicPacket, secondParityBit) == PARITY_OK) {
		fullTSicTransmission = (firstTSicPacket << 8) + secondTSicPacket;
		return TSIC_IS_OK;
	} else {
		return TSIC_PARITY_ERROR;
	}
}

Функция readTSicPacket(), возвращающая currentTSicPacket, может выглядеть следующим образом.

int8_t readTSicPacket(bool isTheFirstPacket) {
	currentTSicPacket = 0;

	/* Wait until start bit occurs, return error if it takes too long
	 */
	if (isTheFirstPacket) {
		/* If we are waiting after powering up the sensor */
		myTIMER_Start(PRESCALER_1024);
		while (TSIC_DATA_HIGH) {
			if (TIMER_COUNTER >= WAITING90MS_TICKS) {
				return NO_SIGNAL_OCCURS;
			}
		}
		myTIMER_Stop();
	} else {
		/* If we are waiting just for time between first and second packet */
		myTIMER_Start(NO_PRESCALER);
		while (TSIC_DATA_HIGH) {
			if (TIMER_COUNTER >= TSTROBE_TICKS * 4) {
				return NO_SECOND_PACKAGE;
			}
		}
		myTIMER_Stop();
	}

	/* Check if start bit has occurred:
	 *
	 * As Tstrobe = 125 us / 2 = 62.5 us,  we need to check if the signal is
	 * low for about Tstrobe time and then goes high for about Tstrobe time.
	 */
	myTIMER_Start(NO_PRESCALER);
	while (TSIC_DATA_LOW) {
		if (TIMER_COUNTER >= TSTROBE_TICKS * 1,1) {
			return START_BIT_ERROR;
		}
	}
	while (TSIC_DATA_HIGH) {
		if (TIMER_COUNTER >= TSTROBE_TICKS * 2,2) {
			return START_BIT_ERROR;
		}
	}
	if (TIMER_COUNTER <= TSTROBE_TICKS * 1,8) {
		return START_BIT_ERROR;
	}
	myTIMER_Stop();

	/*
	 * Receive 8 data bits + 1 parity bit
	 */
	for (uint8_t i = 0; i <= 8; i++) {

		/* Wait for exact Tstrobe time to check the line state */
		myTIMER_Start(NO_PRESCALER);
		while (TIMER_COUNTER < TSTROBE_TICKS) {
		}
		myTIMER_Stop();

		/* Read bit */
		currentTSicPacket <<= 1;
		if (TSIC_DATA_HIGH) {
			currentTSicPacket |= 1;
		}

		/* Wait until the end of one-bit-timeframe.
		 */
		if (TSIC_DATA_LOW) {
			myTIMER_Start(NO_PRESCALER);
			while (TSIC_DATA_LOW) {
				if (TIMER_COUNTER >= TSTROBE_TICKS * 0,6) {
					return PACKAGE_TIMING_ERROR;
				}
			}
			myTIMER_Stop();
		}
		/* Last bit (parity bit) doesn't end up with falling edge so we should
		 * wait for the next falling edge just for data bits.
		 */
		if (i != 8) {
			myTIMER_Start(NO_PRESCALER);
			while (TSIC_DATA_HIGH) {
				if (TIMER_COUNTER >= TSTROBE_TICKS * 1,1) {
					return PACKAGE_TIMING_ERROR;
				}
			}
			myTIMER_Stop();
		}
	}

	return PACKAGE_READING_OK;
}

Настройки самого микроконтроллера и таймера слишком сильно зависят от используемой платформы, чтобы приводить их в тексте статьи про датчик.

Функции проверки целостности и вычисления температуры в градусах Цельсия также не представляют собой совершенно ничего примечательного.

Функция проверки целостности пакета TSic
int8_t checkParity(uint16_t package, bool parity) {
	uint8_t parityCounter = 0;

	for (uint8_t i = 0; i <= 7; i++) {
		if (package & (1 << i)) {
			parityCounter++;
		}
	}
	if (parityCounter % 2 == parity) {
		return PARITY_OK;
	} else {
		return PARITY_ERROR;
	}
}

Функция расчета температуры в градусах Цльсия для датиков TSic 206, TSic 306 и TSic 506
float calculateCelsius(uint16_t transmissionData) {
	/* TSic20x / 30x sensors: LT = -50, HT = 150, Digital output 11 bit */
	//float celsius = ((float) transmissionData * 200 / 2047) - 50;

	/* TSic50x sensors: LT = -10, HT = 60, Digital output 11 bit */
	float celsius = ((float) transmissionData * 70 / 2047) - 10;

	return celsius;
}

Код целиком доступен по ссылке.

Ссылки




Заключение


В заключении традиционно благодарю читателя за внимание и напоминаю, что вопросы по применению продукции, о которой мы пишем на хабре, можно также задавать на email, указанный в моем профиле.
Tags:продам датчикпродам микроконтроллерIST AG
Hubs: Блог компании ЭФО corporate blog Industrial Programming Robotics development Programming microcontrollers Development for IOT
+17
7.9k 27
Comments 12