Датчик температуры DS18B20

Датчик температуры DS18B20 работает по протоколу 1-Wire (с английского «один провод»). Протокол был разработан компанией Dallas Semiconductor (в 2001 году выкуплена Maxim Integrated Products). Как понятно из названия, для передачи данных используется один провод (не считая земли), следовательно, требуется всего одна ножка GPIO (в общем случае). Более того, на один провод (который называют шиной DQ) вы можете посадить несколько устройств, и тогда обращение к конкретному устройству можно будет произвести по определенному идентификатору. В ваших часах всего один датчик на шине, поэтому мы рассмотрим работу всего с одним устройством.

Справедливости ради стоит заметить, что реализуют работу с датчиками в данном протоколе по-разному.

В режиме ожидания (англ. idle) на шине должен быть высокий уровень, что достигается подтяжкой линии к питанию через нагрузочный резистор (англ. push-up). Величина подтягивающего резистора указывается в документации на подчиненное устройство. Давайте скачаем документацию на датчик DS18B20 и найдем необходимую нам информацию.

ds18b20 structure

Структура датчика DS18B20, изображение из документации

Кроме того, что сопротивление резистора подтяжки — 4,7 кОм, можно найти и другую важную для нас информацию, например: ножка главного устройства должна быть в режиме открытого стока. Кроме того, из описания датчика нам становится известно, что он способен работать при температурах от -55 °C до +125 °C, с погрешностью ±0.5 °C (в диапазоне от -10 °C до +85 °C). Точность измерений задается пользователем (от 9 до 12 бит). Чем больше точность — тем больше время для обработки.

Сейчас будет описано, как работает данный датчик температуры, однако критически важно, чтобы вы не просто прочитали этот текст, но и сами заглянули в документацию и отследили каждое утверждение, которое мы делаем. Не поленитесь, ведь наша с вами цель — научится пользоваться документацией, где в большинстве случаев есть всё, что нам требуется. Приготовим заголовочный файл ds18b20.h, он будет включать в себя следующие прототипы функций и перечисление:

Перечисление DS18B20_RESOLUTION_t содержит все возможные разрядности для температуры (стр. 8 Configuration register). Функция ds18b20_init( ... ) позволит нам инициализировать порт и ножку, к которой подключен датчик (см. схему). Кроме того, через эту функцию мы установим разрядность. В документации также указано, какое время занимает преобразование (для 12 бит это 750 мс — от этого числа мы и будем отталкиваться для корректировки задержки). Заметим сразу, мы не будем реализовывать «универсальный драйвер», т. к. это займет больше времени, а смысл останется тот же. Полученный код вы с легкостью сможете портировать на другой МК, поменяв пару строк.

Для работы модуля нам потеряются некоторые функции, такие как запись бита или его чтения. Создадим их прототипы внутри файла исходного кода (они не должны быть доступны извне модуля), пояснения будут позже.

Линия данных DQ подключена к ножке 1 порта A. Его необходимо настроить как открытый сток.

Вторая функция, ds18b20_set_resolution( ... ), позволит нам менять разрядность в любом участке кода. Внимательно изучив документацию мы получим следующее:

  1. отправляем команду пропуска ожидания адреса (устройство на шине одно);
  2. отправляем команду, что хотим записывать в регистры;
  3. отправляем название регистров;
  4. устанавливаем разрешение;
  5. пересчитываем время конвертации.

Она вызывает ряд функций, разобраться в нужности которых (а также в том, как их писать) нам еще предстоит ниже. Но перед этим обратим внимание на строчку:

Так как мы можем задавать разную разрядность преобразования, нам нужно контролировать время задержки между началом преобразования и началом чтения данных из памяти датчика. Реализуем функцию получения делителя задержки.

Теперь приступим к описанию работы самого протокола. Обмен всегда ведется по инициативе главного устройства (в нашем случае МК) и начинается с импульса сброса (англ. reset). Главное устройство подтягивает линию к логическому нулю на время не менее 480 мкс, а затем переключается в режим входа. При переключении линия через резистор подтяжки кратковременно подтягивается к высокому уровню, и подчиненное устройство, выждав 15-60 мкс, отправляет импульс приветствия (англ. presence), подтягивая линию к низкому уровню на длительность от 60 до 240 мкс.

ds18b20 init

Импульс приветствия, изображение из документации

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

Обмен данными по шине происходит последовательно, начиная с младшего бита. Передача/прием одного бита выполняется за определенное время, которое называется временным слотом (англ. time-slot). Сам временной слот находится в интервале от 60 до 120 мкс, а между ними обязательно должен быть предусмотрен разделяющий интервал не менее 1 мкс. Всего их может быть 4 вида: прием логической «1»; прием логического «0»; отправка логической «1»; отправка логического «0».

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

ds18b20 read write

Временые слоты записи и чтения, изображение из документации

Чтобы передать «0», главное устройство должно установить на шине низкий уровень в течение всего временного слота. Для передачи «1» главное устройство устанавливает низкий уровень на шине на период от 1 до 15 мкс, а затем отпускает её (что ведет к установлению высокого уровня) и держит паузу до конца временного слота.

DS18B20 — подчиненное устройство, а значит, он может передавать данные только тогда, когда ему это позволят (соответствующей командой) и сформируют для него временной слот. Главное устройство может получить данные от подчиненного про прошествии 15 мкс после начала слота. Главное устройство просаживает линию к низкому уровню на 1 мкс и отпускает её. Если подчиненное устройство хочет передать «0», то оно оставляет линию в низком уровне, если хочет передать «1» — то держит 1 до конца слота.

Таким образом мы можем записать все необходимые задержки (с небольшим запасом):

Мы рассмотрели, что необходимо сделать в общем случае. Теперь нам предстоит получить от датчика значение температуры. Последовательность будет следующая:

Команды представлены ниже:

Самая важная функция — ds18b20_get_temperature() — вернет нам целочисленное значение температуры (домноженное на 10 — это нужно для простой обработки данных).

Для записи разрядности последовательность примерно такая же (см. функцию ds18b20_set_resolution( ... )):

Функции записи:

Функции чтения:

Таким образом мы написали драйвер для работы с датчиком температуры DS18B20. Всё, что остается сделать — просто вызвать пару функций:

Пока мы не умеем выводить данные на дисплей, поэтому проверьте получившийся результат через режим отладки, прочитав значение переменной.

Код урока можно найти на github: CMSIS.


Назад | Оглавление | Дальше