Сегодня получилось (третий день уже над этой проблемой корпел) сделать управление N термодатчиками, сидящими на шине 1-wire. Вот — архив с прошивкой.
Естественно, т.к. я очень ленив, сначала было нагуглено некоторое количество примеров для работы с 1-wire на STM32 (прежде всего, с easyelectronics.ru). После этого я целый день ковырялся в коде примеров, чтобы сделать что-то, пригодное для использования у меня. Весь вчерашний день я убил на отладку функции получения температуры, а сегодня потратил еще приличное количество времени на отладку функции опроса адресов датчиков, сидящих на шине.
Итак, вкратце, как это все работает
Стандартная схема подключения 1-wire подразумевает наличие диода Шоттки (коего у меня, естественно, не оказалось), однако, я нагуглил, что USART_TX можно сконфигурировать как выход с открытым коллектором (GPIO_Mode_AF_OD), в этом случае диод не потребуется.
Подключение 1-wire (даю ссылку на easyelectronics.ru, т.к. не хочу закидывать картинку на imageshack, а в ЖЖшке до сих пор постинг картинок не работает)
1-wire работает с использованием USART3 (можно было бы и вручную "дергать ногами", но это же неинтересно, тем паче, мне USART3 все равно не нужен будет). Работа с портом осуществляется посредством DMA. В общем, на easyelectronics на этот счет расписано подробней.
В принципе, все украденное работало прилично, кроме функции OW_Scan, которая искала устройства на шине. В алгоритм вникать мне не хотелось (в принципе, он несложный, но реализаций может быть уйма, а любой промах сразу отправит коту под хвост все старания), поэтому где-то я утащил готовый, подрихтовал его и воткнул в код прошивки.
Остальной код был взят из предыдущих опытов (поэтому управление светодиодом до сих пор работает). Я сделал небольшие изменения: чтобы не вызывать тяжелые функции в обработчиках прерываний, завел флаги. Команда пользователя просто устанавливает флаг, а в main все флаги проверяются, обрабатываются и сбрасываются.
Пока что функционал скудный: помимо "блымкания" светодиодом теперь прошивка умеет опрашивать 1-wire для поиска адресов висящих там термометров, выдавать эти адреса, а также выплевывать девятибайтовый буфер термометров (первый байт — искомая температура, второй — знак, но есть еще и вспомогательные байты, которые могут помочь измерять температуру более точно). Еще в термометрах есть два буфера для критических температур, их я пока не использую (но надо будет, наверное).
На стадии опытов оказалось, что при смене термометров "на горячую", если их больше одного, происходили всякие глюки, поэтому лучше всего "жамкать" reset при смене датчиков.
Термометров этих у меня 10 штук, для начала я решил посмотреть их коды. Распаял на макетке небольшую панельку, куда можно втыкать датчики и подпаял проводки для подключения двух термометров. Вот "Выхлоп" при работе с двумя термометрами:
Уже видно, что на полградуса показания отличаются.
Потом, попарно втыкая в панельку термометры и нажимая 'c'+'p', я получил список адресов всех датчиков:
(кстати, на сей раз глюков не было: после смены датчиков поиск работал нормально).
Первый байт адреса (или кода) датчика (0x10) — тип устройства (термометр). Далее следуют 6 байт собственно серийного номера датчика (судя по цифрам, little-endian, как и порядок бит в байтах), а завершает это — контрольная сумма.
Еще я столкнулся с такой штукой: иногда датчик писал "+85°C" (0xaa, 0x00):
Похоже, виноват плохой контакт (хотя, как ни странно, свои адреса эти штуки отдают).
Конкретно определить, какой датчик какой номер имеет, можно довольно просто: подключаем всю гроздь датчиков, определяем их адреса, а затем отключаем интересующий датчик. При опросе вместо температуры получим для него все "единицы" (понятное дело: шина-то подтянута на +3.3В):
Так как в этом буфере есть константы (байты 2 и 3 мы можем изменить, байты 4 и 5 всегда равны 0xff, в байте 7 всегда лежит 0x10), легко найти, какой датчик отключен.
Для указанной пары датчиков, пока я писал это, температуры довольно-таки прилично выровнялись:
(в байте 6 лежит остаток, полученный после вычисления температуры): 29.5°C.
Формула для вычисления точного значения температуры (в отсчетах, 1 отсчет == 0.5°C), предложенная в "даташите" термометра, мне не внушила доверия:
T = Tr - 0.25 + (B7-B6)/B7
(Tr - считанная температура, имеющая погрешность ±0.5 отсчета; B7,B6 - седьмой и шестой байты полученных данных).
Дело в том, что т.к. число B6 всегда меньше B7 (по крайней мере, сколько я раз ни запускал для разных датчиков измерения температуры, всегда было так), получается, что поправка всегда лежит в диапазоне [-0.125, 0.375]°C, но надо будет это проверить. Для более точного вычисления температур стоит, на мой взгляд, просто запустить длительный мониторинг показаний термометров при изменении их температур в широком диапазоне, медианную температуру считать истинной, получая таким образом градуировочные таблицы.
Вот пример показаний другой пары:
Воспользовавшись формулой, получаем для первого: T = 59 - 0.25 + (16-2)/16 = 59.625 отсчетов (29.81°C), а второй дает температуру на 4/16=0.25 отсчетов (0.125°C) ниже. Вообще же, флуктуации показаний этих термометров довольно-таки приличные, так что вряд ли можно сказать, что точность их превышает заявленные 0.5°C.
В принципе, нужно, наверное "причесать" функции для работы с 1-wire (чтобы не нужно было писать простыней вида OW_Send(0, (uint8_t*)"\xbe\xff\xff\xff\xff\xff\xff\xff\xff\xff", 10, buf, 9, 1), а просто OW_SendFN + OW_Read. Ну и конечно же добавить проверку CRC.
no subject
Date: 2015-01-01 11:10 am (UTC)