Микроконтроллер AVR и датчик DS18B20


Программирование работы микроконтроллера AVR с датчиком DS18B20

Сегодня, в заключительной статье о датчиках температуры DS18B20, мы полностью рассмотрим и проанализируем работу программы общения DS18B20 с микроконтроллерами AVR (или наоборот). И хотя программа будет в Algorithm Builder (графический ассемблер), главное понять алгоритм общения датчика DS18B20 с микроконтроллером, а перевести ее потом в "классический ассемблер" большого труда не составит.

Программа общения DS18B20 с микроконтроллером


Последовательность операций для работы с датчиком DS18B20

При работе с датчиком DS18B20 очень важно выполнять последовательность выполнения операций:
1. Инициализация
2. Команда ROM
3. Функциональная команда
Если не следовать этой последовательности (что-то пропустить, или поменять местами), то датчик DS18B20 откажется общаться с микроконтроллером


Инициализация датчика DS18B20

В прошлой статье мы рассматривали этот вопрос (инициализация датчика DS18B20), но повторимся, что бы не прыгать по страницам сайта.

Процесс инициализации DS18B20 состоит из трех пунктов:
Исходное состояние - на выводе порта, к которому подключен вывод DQ датчика (шина DQ) - логическая 1 (за счет подтягивающего резистора)

1. Микроконтроллер передает в линию импульс сброса (длительность 480 микросекунд):
- переводит шину DQ в состояние логического нуля (вывод микроконтроллера переводится на вывод информации и в него записывается логический ноль) на время не менее 480 микросекунд (я обычно округляю длительность импульса до 500 микросекунд)
- через 480 микросекунд (или 500) микроконтроллер переводит шину DQ на ввод информации, в результате чего за счет подтягивающего резистора на шине восстанавливается логическая единица
- микроконтроллер ждет импульс присутствия от датчика DS18B20

2. Датчик DS18B20 передает в линию импульс присутствия (общая длительность 480 микросекунд):
- при переводе микроконтроллером шины в логический ноль на время не менее 480 микросекунд, датчик понимает, что к нему обращаются
- через 15-60 микросекунд, после того как МК перевел шину в состояние логической единицы, датчик передает импульс присутствия - переводит шину DQ в состояние логического нуля на время 60-240 микросекунд

3. Прием импульса присутствия:
- через 15-60 микросекунд, после того как микроконтроллер перевел шину в состояние логической единицы, проверяется наличие логического нуля на шине DQ (брать лучше по максимуму - 60 микросекунд)
- если на линии - логический ноль - значит датчик присутствует на шине и можно продолжать дальнейшую работу
- так-как общая длительность импульса присутствия должна быть не менее 480 микросекунд, микроконтроллер формирует дополнительную паузу длительностью 420 микросекунд

Временной график инициализации DS18B20

В ходе процесса инициализации могут возникнуть три ошибки, которые мы разберем непосредственно в программе:

Процесс инициализации датчика DS18B20 оформляется в виде подпрограммы, в данном случае имя подпрограммы "DS_Reset_Pulse"
В этой подпрограмме:
- Term_Error1 - переменная, в которой будет хранится код ошибки
- DQ_Pin, DQ_Port, DQ_DDR - присвоенные мной имена выводу порта к которому подключен датчик. Делается это не только для наглядности (можно конечно и ничего не присваивать) но в больше степени для быстрой смены вывода порта в программе, если мы вдруг захотим подключить датчик к другому выводу (не надо будет по всей программе искать где этот РВ6, чтобы заменить его, к примеру, на РС5 - проще один раз поменять в таблице)

Состояние разряда шины DQ DS18B20

Ну а теперь рассмотрим подробно саму подпрограмму "Инициализация датчика DS18B20" :

Инициализация датчика DS18B20

1. Обнуляем переменную в которую будет записан код ошибки ("Term_Error1")
2. Проверяем, есть ли на шине DQ логическая единица:
- если на шине присутствует высокий уровень (логическая единица), то переходим к формированию импульса сброса
- если на шине нет высокого уровня, то записываем в переменную "код ошибки" - 1 (код ошибки отсутствия высокого уровня на шине DQ) и выходим из подпрограммы. Затем, при выводе данных на индикатор, высвечиваем, к примеру, - "Er1". Отсутствие высокого уровня в 99 случаях означает, что не подключен подтягивающий резистор формирующий высокий уровень на шине.
3. При высоком уровне на шине микроконтроллер формирует импульс сброса продолжительностью не мене 480 мкс, путем перевода вывода порта в режим "выхода" и записи в него логического нуля.
4. Микроконтроллер отпускает шину путем перевода вывода порта в режим "входа"
5. Через 60 мкс МК поверяет наличие импульса присутствия от датчика (на шине должен присутствовать низкий уровень (логический ноль)
6. Проверяем, есть ли на шине DQ логический ноль:
- при низком уровне на шине, означающем что датчик выдал импульс присутствия, МК формирует паузу в 420 мкс
- высокий уровень на шине означает, что датчик не выдал импульс присутствия. В этом случаем записываем в переменную "код ошибки" - 2 (код ошибки отсутствия импульса присутствия от датчика), а при выводе данных на индикатор - выводим "Er2"
7. После паузы в 420 мкс проверяем наличие высокого уровня на шине после окончания импульса присутствия:
- если на шине логическая единица, значит датчик отработал и выходим из подпрограммы инициализации датчика
- если на шине логический ноль, значит датчик не вернул шину в высокий уровень. Записываем в переменную "код ошибки" - 3 (код ошибки "не восстановлен высокий уровень после импульса присутствия")
На этом инициализация датчика заканчивается.
Если ошибок нет, то МК переходит к выполнению следующих шагов - посылает на датчик команду ROM, а затем функциональную команду.
Если ошибка присутствует, то микроконтроллер дальше не идет, а постоянно выполняет подпрограмму инициализации до устранения ошибки.


Команда ROM DS18B20

Мы рассмотрим работу микроконтроллера с одним датчиком температуры, это несколько проще в том смысле, что статья получится короче, ну а разобраться как работать с двумя и более датчиками будет, я думаю, не очень сложно.
Итак, мы выполнили первый шаг - инициализация датчика DS18B20, убедились что с датчиком все в порядке, ну а датчик приготовился к приему очередных команд и выдачи нужных нам результатов.
Приступаем ко второму шагу - подаем нужную нам команду ROM.
Так как датчик у нас один, нам потребуется для работы одна команда ROM из пяти - SKIP ROM - пропуск ROM, так как мы не определяли 64-разрядный код датчика (для одного датчика этого делать не надо), соответственно отпадают и другие команды. Практически, при одном датчике на шине, используется только одна команда ROM - SKIP ROM, и очень редко - ALARM SEARCH - Поиск Тревоги.
Перед тем как передать команду ROM на датчик, давайте разберемся как вообще передавать какие-либо данные по шине 1-Wire. Сразу скажу, самое главное в этом деле строго соблюдать временные интервалы.

Давайте посмотрим на временной график записи данных в датчик и на его основе составим подпрограмму записи данных в DS18B20:

График записи в DS18B20
Расшифровываем график:
1. Слот времени передачи одного бита должен иметь продолжительность не менее 60 мкс и не более 120 мкс
2. Датчик DS18B20 гарантированно определяет логический уровень на шине через 30 мкс (минимум - 15 мкс, максимум - 60 мкс)
3. Так как датчику необходимо максимум 60 мкс для приема и записи бита информации, то делать продолжительность слота времени более 60 мкс смысла нет
3. После окончания слота времени для передачи логического нуля необходимо не менее 1 мкс для перевода шины в высокое состояние (я беру 5 мкс)
4. При передаче логической единицы в начале слота времени передачи МК должен перевести шину в низкое состояние на время от 1 до 15 мкс (я беру 5 мкс)
Я в программе общения МК с датчиком процессы записи в датчик логических уровней оформил в виде 2-х подпрограмм:
- запись логического нуля
- запись логической единицы
Теперь посмотрите на мои подпрограммы и, исходя из выше сказанного, я думаю алгоритм передачи одного бита информации датчику будет понятен:

Передача нуля и единицы в DS18B20Теперь давайте посмотрим как передать байт информации датчику (все команды для датчика однобайтовые).
Запись байта информации в датчик также оформлена в виде подпрограммы:

Передача байта информации в DS18B20Temp - рабочий регистр, в который предварительно записываем код передаваемой команды
>Temp>> - операция логического сдвига вправо с переносом рабочего регистра Temp
Передача байта информации от МК датчику производится побитно, начиная с младшего, т.е. сначала нулевой бит, затем первый и т.д.
Такую операцию очень удобно проводить с помощью команды "Логический сдвиг вправо с переносом", команда работает с регистрами общего назначения.
При логическом сдвиге вправо с переносом, младший байт заносится в бит "С" регистра SREG, а содержимое РОН сдвигается вправо на 1 бит.
Алгоритм работы подпрограммы:
1. Задаем цикл, в ходе выполнения которого над регистром Temp будет восемь раз произведена операция логического сдвига вправо с переносом.
В ходе выполнения цикла каждый бит регистра Temp, начиная с младшего "пройдет" через бит С регистра SREG
2. После каждого логического сдвига с переносом проверяем что записалось в бит С регистра SREG:
- если записан логический ноль - переходим к подпрограмме передачи нуля
- если записана логическая единица - переходим к подпрограмме передачи единицы.


Функциональные команды DS18B20

Как и команды ROM, функциональные команды однобайтовые и процесс их передачи датчику аналогичен процессу передачи команды ROM.
В основном используются две функциональные команды:
- "Конвертировать температуру", по этой команде датчик "измеряет температуру"
- "Чтение памяти", по этой команде датчик передает МК результаты конвертирования температуры

Конвертировать температуру (измерить температуру) DS18B20

Эта команда имеет одну особенность, которая заключается в том, что датчику надо время на выполнение этой команды и МК не должен мешать датчику в этот промежуток времени. Датчик в процессе конвертирования температуры удерживает шину DQ в низком состоянии, а по окончании конвертации переводит шину в высокое состояние. МК должен отслеживать этот процесс - на шине логический ноль - значит идет конвертация, на шине логическая единица - значит датчик закончил конвертацию, и можно переходить к считыванию результатов измерения.

Посмотрим на примере алгоритм подачи команды на конвертирование температуры:

Конвертирование температуры DS18B20
Как видно из приведенной программы, для измерения температуры датчиком, МК должен выполнить следующий алгоритм:
1. Инициализация датчика. Если возникла ошибка - выход из подпрограммы
2. Подать команду "Пропуск ROM", где:
- DS_SKIPROM - константа, в которой записан код команды $CC - для наглядности
- DS_Command - переменная, в которую записываются команды от МК
- DS_Send_Command - подпрограмма, в ходе выполнения которой код команды сначала записывается в рабочий регистр Temp, а затем происходит переход к подпрограмме передачи байта датчику. Можно, конечно, присвоить имя DS_Command не переменной, а сразу рабочему регистру, или записывать код команды в рабочий регистр Temp, чтобы не делать лишних движений (это называется оптимизация кода).
3. Подать команду "Конвертировать температуру"
4. Перевести шину DQ на вход и постоянно проверять ее состояние - как только на шине будет логическая единица - выходим из подпрограммы.

Чтение памяти DS18B20

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

Для чтения результатов конвертирования температуры необходимо предварительно назначить две переменные, к примеру:
- DS_Temp_Lo - для первого байта
- DS_Temp_Hi - для второго байта
Посмотрим на подпрограмму чтения результатов конвертирования температуры датчиком (подпрограмма называется Read_Temp_1):

Подпрограмма чтения данных из DS18B20
Алгоритм:
1. Инициализация датчика
2. Команда ROM - "Пропуск ROM"
3. Функциональная команда - "Чтение памяти"
4. Переход к подпрограмме чтения байтов МК (DS_Read_Byte)
5. Запись результатов в переменные

Рассмотрим как происходит чтение информации от датчика.
Временной график слотов времени передачи битов данных от датчика:

График чтения данных от DS18B20
Расшифруем график:
1. Слоты времени считывания как логического 0, так и логической 1 должны быть продолжительностью не менее 60 мкс, и разделяться между собой промежутками не менее 1 мкс
2. Для считывания бита информации МК переводит шину в низкое состояние на время не менее 1 мкс (у меня - 3 мкс), а затем возвращает шину в высокое состояние (Эта процедура является командой для датчика на передачу одного бита информации)
3. Через 15 мкс датчик передает или логическую единицу, или логический ноль:
- если логический 0 - датчик переводит шину в низкое состояние на время 45 мкс
- если логическая 1 - датчик ничего ни делает, шина остается в состоянии логической единицы
4. Через 15 мкс, после того, как МК перевел шину в низкое состояние, а затем вернул в высокое, в течение 45 мкс МК может считать данные с шины (у меня - через 23 мкс)
Давайте посмотрим подпрограмму чтения байта:

Чтение байта от DS18B20
Подпрограмма чтения байта от датчика очень похожа на подпрограммы передачи данных от МК.
Также используется цикл и команда логического сдвига вправо с переносом регистра Temp, датчик данные передает начиная с нулевого бита.
Давайте посмотрим 1 цикл выполнения подпрограммы:
1. МК переводит шину МК в низкое состояние на 3 мкс, а затем обратно в высокое
2. Через 20 мкс МК анализирует логический уровень на шине:
- если на шине низкий уровень - в бит С регистра SREG записывается 0
- если на шине выокий уровень - в бит С регистра SREG записывается 1
3. Производится логический сдвиг вправо с переносом регистра Temp, при этом содержимое бита С регистра SREG записывается в старший бит Temp.
В последующем, все данные в регистре Temp будут поочередно перемещаться в сторону младшего бита.

Считанные байты мы записываем в назначенные переменные.
Хочу обратить ваше внимание на то, что в первом байте результатов конвертирования температуры, в первых четырех битах записаны "Десятые градуса" в виде какого-то числа. К примеру, при 12-битной разрешающей способности датчика, это число может быть от 0 до 14, поэтому десятые градуса рассчитываются самостоятельно. Старшие 4 бита 1-го байта и младшие четыре байта 2 байта содержат информацию о целых градусах именно в градусах.
Это не очень удобно для работы, и поэтому сначала надо выделить "десятые" в отдельный байт путем записи первых 4-х битов 1-го байта в отдельную переменную. Старшие 4 бита 1-го байта записываем в младшие 4 бита другой переменной, и в эту же переменную, в старшие 4 бита, записываем младшие 4 бита 2-го байта. К примеру так (заодно и определяем знак температуры):

Разделение целых и десятых градуса DS18B20

И последнее, если температура отрицательная, то данные в датчике хранятся в виде дополнительного кода. Чтобы привести их в "нормальное состояние", необходимо, после того как выделим "десятые" и "целые" градуса в разные байты, проинвертировать их содержимое - 0 поменять на 1, а 1 - на 0, а затем, к полученному результату прибавить единицу. Для этого удобно применить двойной регистр (X, Y или Z).


Предыдущие статьи:

1. Устройство цифрового термометра DS18B20
2. Система команд датчика DS18B20
3. Подключение DS18B20 к микроконтроллеру


(18 голосов, оценка: 4,83 из 5)

Загрузка...


Программирование работы микроконтроллеров AVR с датчиками DS18B20
Published by: Мир микроконтроллеров
Date Published: 01/14/2016



Комментарии

Микроконтроллер AVR и датчик DS18B20 — 8 комментариев

  1. Помоему там лишняя команда 0 -> PortX.x , несколько раз встречается. Достаточно одного раза при инициализации.

    • Здравствуйте Иван!
      Исходника как такового нет, Вы можете посмотреть его в других статьях.
      Но только если Вы программируете в Algorithm Builder/
      С уважением, Admin.

      • Если честно, то я не нашел той статьи где можно было бы посмотреть пример.. Дайте пожалуйста ссылку...

        • Здравствуйте Иван!
          Исходные программы (в Algorithm Builder)
          Можно посмотреть в статьях:
          - одноканальный термометр
          - двухканальный термометр
          - термостаты
          Если АВ не устраивает, то придется подождать.
          На днях будет продолжен цикл статей по программированию (Си и Ассемблер) и там все будет пошагово рассказано.
          С уважением, Admin.

  2. Не правильно описан алгоритм чтения бита информации от датчика.
    "Замер уровня мастером должно быть произведен до истечения 15 микросекунд после установки низкого уровня, но при этом спустя достаточное время после освобождения шины, чтобы подтягивающий резистор гарантировано смог вернуть высокий уровень сигнала."
    В приведенном выше алгоритме (DS_Read_Byte) вместо 20-ти мкс (Wait_mks(20)) нужно задать не более 5-10 мкс

    • Здравствуйте Владимир!
      Спасибо за комментарий!
      Я с Вами не согласен:
      - выходные данные от датчика достоверны только через 15 мкс после того, как МК (Мастер) отпустит шину
      С уважением, Admin.

  3. Спасибо за хорошую статью, А не могли бы Вы также подробно описать как работать с датчиком давления BMP085 или BMP185
    в Algorithm Builder а то сколько не искал так ничего путного не нашел то на Си то на Бейсике, еще раз спасибо
    Mixail

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *