Сегодня, ценой одного 500-рублевого датчика, я добавил в свой ircontroller поддержку термодатчиков TSic по ZacWire.
Протокол ZacWire довольно хитрый. Чтобы упростить работу с ним, я использовал таймер 2 в режиме ШИМ-захвата. Код спер
отсюда, почти не изменяя.
Сразу столкнулся с проблемой питания: я пытался запитать датчик, подавая к нему на "+" напряжение 5В, поджимая "-" к земле портом в режиме "плавающий выход". Но не тут-то было! Амплитуда выходных сигналов получилась низкой. Поэтому пришлось сажать "-" датчика на общий, а "+" поджимать к +3.3В в пушпульном режиме (думаю, нужно будет просто воткнуть мосфет и по-человечески запитывать датчик пятью вольтами: судя по мануалу, при U=5В его точность наиболее приличная).
Да, насчет предыдущего абзаца: на самом деле первым, с чем я столкнулся, был "косяк" в документации: выводы в ней были нарисованы наоборот. Поэтому я поменял "+" и "-", что привело к благоухающей смерти одного датчика. В другом мануале выходы были нарисованы наоборот, так все заработало.
Но даже при напряжении питания 3.3В датчики поразили меня своей стабильностью, воспроизводимостью и калибровкой: у всех оставшихся трех датчиков плавает только младший разряд, а т.к. температура высчитывается по формуле T=((val/2047)*70-10)°C, то получается, что дискрет датчиков составляет 0.034°C! Производителем заявлена точность в 0.1°C, но, похоже, имелась в виду точность по всему диапазону измеряемых температур (от -10°C до +60°C), т.к. один и тот же датчик стабильно держал свои показания на протяжении десятка минут!
Калибровка датчиков тоже поразила меня: поочередно меняя датчики (после смены я выжидал пару минут, чтобы датчик остыл до окружающей температуры: сразу после подключения показания были ~30°C - корпус миниатюрный и в руках быстро нагревается) и проверяя их показания, я заметил отличия лишь в младшем разряде (которому все равно доверять нельзя)!
Вот пример выхлопа. Датчик 1:
0x00 0x31
0x01 0x4b
0x02 0x4b
0x03 0x4b
0x04 0x4b
0x05 0x4b
0x06 0x4b
0x07 0x18
0x08 0x18
0x09 0x24
0x0a 0x31
0x0b 0x18
0x0c 0x18
0x0d 0x18
0x0e 0x4b
0x0f 0x4b
0x10 0x18
0x11 0x4b
0x12 0x4b
ZakWire: 0x03e3
Датчик 2:
0x00 0x31
0x01 0x4a
0x02 0x4a
0x03 0x4a
0x04 0x4a
0x05 0x4a
0x06 0x4a
0x07 0x18
0x08 0x18
0x09 0x24
0x0a 0x31
0x0b 0x18
0x0c 0x18
0x0d 0x18
0x0e 0x4a
0x0f 0x4a
0x10 0x4a
0x11 0x18
0x12 0x4a
ZakWire: 0x03e2
Датчик 3:
0x00 0x31
0x01 0x4a
0x02 0x4a
0x03 0x4a
0x04 0x4a
0x05 0x4a
0x06 0x4a
0x07 0x18
0x08 0x18
0x09 0x24
0x0a 0x31
0x0b 0x18
0x0c 0x18
0x0d 0x18
0x0e 0x4a
0x0f 0x4a
0x10 0x4a
0x11 0x18
0x12 0x18
ZakWire: 0x03e3
Показания "0x3e3" соответствуют ровно 24°C.
В вывод я добавил отладочные сообщения: номер считанного бита (первый столбец) и значение скважности импульса в процентах (второй столбец), т.к. поначалу у меня возникла путаница с протоколом.
По поводу протокола. В "расслабленном" состоянии на шине данных удерживается логическая единица. Порция данных выдается не сразу после включения питания, а с паузой 65..85мс. Вначале выдается строб со скважностью 50% - чтобы принимающая сторона настроилась на период передатчика (около 125мкс). Далее идут 8 бит данных, завершаемые битом четности. Потом - пауза длиной в 1 бит, а после нее - второй байт данных. Затем идет небольшая пауза и повторяется выдача. Из-за этого (ну, а также для того, чтобы датчики не разогревались) и приходится подавать питание только на момент проведения измерений.
Первый байт данных несет 5 нулей и 3 старших бита значения температуры. Второй байт - младшие 8 бит. Сразу возникла проблема с началом отсчета: я поставил прерывание на задний фронт бита (т.е. на перепад с 0 до 1), поэтому таймер пытался сделать захват ШИМ сразу после подачи питания, что приводило к ошибке. В функцию обработчика прерывания было добавлено вычисление скважности и анализ ее значения: вызов команды добавления бита к считанному числу выполнялся лишь если скважность считанного импульса не была равна нулю.
Скважность у меня тоже считается не так, как обычно: т.к. бит начинается с нулевого импульса, длительность которого и считает первый канал таймера, я по сути измеряю значение (1-скважность).
После определения скважности вызывается функция добавления бита, которая "на всякий пожарный" проверяет значение скважности: оно не должно сильно отличаться от 50% для стробового бита и от 25% или 75% для битов данных. Если получается большое отличие, измерения прерываются и выдается сигнал ошибки.
Биты четности я пропускаю. Первый - просто так, неохота мне было проверять. А второй пришлось: дело в том, что после передачи последнего бита в шине так и остается единица, т.е. прерывания для измерения скважности не будет → значение этого бита останется неизвестным.
Для того, чтобы иметь возможность проверки: а есть ли в цепи датчик и исправен ли он, я оставил в сворованном коде "предохранительный" третий канал таймера. Суть такова: третий канал считает до 50мс, и если захвата по первому не происходит (а первый и второй каналы синхронизированы: первый считает длительность 0, второй - длительность импульса, выдавая прерывание по окончании счета), то происходит прерывание, где инкрементируется счетчик ошибок. Если счетчик достигает значения 10, он обнуляется, а пользователю выдается сообщение ошибки. Таким образом, если отключить термодатчик, через полсекунды пользователю вывалится сообщение об его отсутствии.
Надо будет подключить все три датчика через коммутатор и погонять их при разных температурах. Если они так и будут сохранять точность показаний в диапазоне (-10..+25)°C, то их и можно будет использовать для контроля температуры зеркала БТА: мало того, что с ними легко работать, так еще и стоят они недорого (точные терморезисторы стоят тысячу-две рублей) + не нужно лепить к ним точный АЦП.
Кстати, теперь у меня на очереди научиться работать с АЦП. Но для этого сначала надо сделать переходничок TSSOP→DIP (я что-то проглючил и забыл заказать сразу, вчера-то заказал
на ибее 20 штучек, но вряд ли они придут до нового года. Придется таки одну штучку самостоятельно сделать.