AVR Урок 20. Подключаем датчик температуры DS18B20. Часть 2



 

Урок 20

Часть 2

 

Подключаем датчик температуры DS18B20

 

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

Продолжим работать с ней далее.

Добавим ещё одну переменную в теле данной функции для возврата результата функции

 

cli(); //запрещаем прерывание

char dt;

 

Теперь для удобства работы с ножками порта давайте напишем некоторые дефайновые замены в заголовочном файле DS18B20.h

 

#include «main.h»

#define PORTTEMP PORTD

#define DDRTEMP DDRD

#define PINTEMP PIND

#define BITTEMP 1

 

Также здесь давайте сделаем ещё некоторые макроподставновки

 

#include «main.h»

#define NOID 0xCC //Пропустить идентификацию

#define T_CONVERT 0x44 //Код измерения температуры

#define READ_DATA 0xBE //Передача байтов ведущему

 

Здесь мы присваиваем удобные имена командам датчикам.

Ну давайте их посмотрим.

Первая команда 0xCC

 

image03

 

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

Следующая команда 0x44

 

image04

 

Данная команда инициализирует начало конвертирования данных в цифровой код.

Следующая команда 0xBE

 

image05

Данная команда читает регистры датчика. Вот эти регистры

 

image06

 

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

 

 

Посмотрим теперь все тайминги инициализации датчика

 

image07

 

Здесь видно что мы здесь притягиваем шину, держим её в таком состоянии как минимум 480 микросекунд, затем отпускаем её, ждём максимум 60 мкс (мы подождём побольше — 65 мкс) ответа датчика, датчик должен нам ответить таким же притягиванием шины к земле за данное время. Если обнаружится ноль, то значит устройство на шине есть, а если шина так и останется висеть в воздухе, то данного датчика на шине нет.

Ну. и на остове вышепрочитанного продолжим нашу функцию определения наличия датчика на шине

 

char dt;

DDRTEMP |= 1<<BITTEMP; //притягиваем шину

_delay_us(485); //задержка как минимум на 480 микросекунд

DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину

_delay_us(65); //задержка как минимум на 60 микросекунд

if ((PINTEMP & (1<<BITTEMP))==0)//проверяем, ответит ли устройство

{

  dt=1;//устройство есть

}

else dt=0;//устройства нет

 

В условии у нас идёт проверка, опустилась ли шина.

Затем мы стеку вернём его первоначальное состояние

 

else dt=0;//устройства нет

SREG = stektemp;// вернем значение стека

 

Отдельной командой после этого разрешать прерывания не требуется, так как все эти команды как раз и управляют определёнными битами регистра SREG. Если прерывания были разрешены до сохранения стека, то они, ясное дело, опять разрешатся, так как все биты регистра мы возвращаем в прежнее положение.

 

 

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

 

  SREG = stektemp;// вернем значение стека

  _delay_us(420); //задержка как минимум на 480 микросекунд, но хватит и 420, тк это с учетом времени прошедших команд

  return dt; //вернем результат

}

 

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

 

//функция чтения байта с устройства

unsigned char dt_readbyte(void)

{

  char c=0;

  char i;

}

 

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

 

//функция чтения бита с устройства

char dt_readbit(void)

{

}

 

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

 

//функция чтения бита с устройства

char dt_readbit(void)

{

  char stektemp=SREG;// сохраним значение стека

  cli(); //запрещаем прерывание

  char bt; //переменная хранения бита

 

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

 

image08

 

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

 

char bt; //переменная хранения бита

DDRTEMP |= 1<<BITTEMP; //притягиваем шину

_delay_us(2); //задержка как минимум на 2 микросекунды

 

Смотрим дальше. Мы должны шину отпустить от земли, а затем задержка для считывания результата. Здесь стоит общая задержка 15 микросекунд, так как мы уже две подождали, осталось нам 13

 

_delay_us(2); //задержка как минимум на 2 микросекунды

DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину

_delay_us(13);

 

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

 

_delay_us(13);

bt = (PINTEMP & (1<<BITTEMP))>>BITTEMP; //читаем бит

 

До считывания следующего байта, судя по диаграмме мы ждём 45 микросекунд, затем возвращаем значение стека в стек и возвращаем результат функции считывания бита на шине

 

  bt = (PINTEMP & (1<<BITTEMP))>>BITTEMP; //читаем бит

  _delay_us(45);

  SREG = stektemp;// вернем значение стека

  return bt; //вернем результат

}

 

Теперь, используя данную функцию, допишем тело функции считывания с датчика целого байта, последовательно занося байты в переменную c, применяя битовый сдвиг, а затем ещё же и возвращая.

 

  char i;

  for(i=0;i<8;i++)

  c|=dt_readbit()<<i; //читаем бит

  return c;

}

 

Ну вот. Самая, можно сказать, важная функция написана.

Продолжим функцию конвертирования считанных байтов

 

  unsigned int tt=0;

  if(dt_testdevice()==1) //если устройство нашлось

  {

  }

  return tt;

}

 

В теле условия по определению присутствия датчика на шине, прежде чем что-то считать с нашего датчика, мы должны ему будем передать команды. А чтобы их передать, мы должны будем написать также функцию отправки байта в устройство. Но так как мы и так уже много чего в данной части написали, то сделаем это в следующей части урока.

 

 

Предыдущая часть Программирование МК AVR Следующая часть

 

Техническая документация на датчик DS18B20

 

Программатор, датчик температуры DS18B20 на плате и дисплей можно приобрести здесь:

Программатор (продавец надёжный) UUSBASP USBISP 2.0

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

Дисплей LCD 16×2

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR Подключаем датчик температуры DS18B20

9 комментариев на “AVR Урок 20. Подключаем датчик температуры DS18B20. Часть 2
  1. Sergiy:

    DDRTEMP |= 1<<BITTEMP; //притягиваем шину ? 

    Почему притягиваем, если в итоге на PD1 логическая единица?Объясните пожалуйста начинающему!

    • Тут не так всё. Мы не уровнями управляем. а направлением. Если мы меняем направление на 1 (на выход), то ножка притягиватеся, так как уровень устанавливается ноль. А если меняем направление на 0 (вход), ножка начинает мерить входные уровни, а следовательно, отрывается от земли. Всё гениальное просто!

      • Sergiy:

        Спасибо большое! да все так…  еще вопрос по дефайну в заголовочном файле DS18B20.h    #define PORTTEMP PORTD  зачем если нигде не используется?

  2. Иван:

    Почему здесь такая не согласованность, с начало говорится максимум 480 микросекунд, а потом в коментарии указывается минимум, хотя на рисунке написано минимум, а если минимум 480 то 420 микросекунд не может пройти, но у Вас пройдет только благодаря тому, что перед этим было 65 микросекунд и опеределенные команды займут по пару микросекунд и в сумме дадут более 480 микросекунд, но если бы не эти «НО» то от датчика Вы бы не дождались ответа и это очень запутывает.
    Дальше. судя по диаграмме, которая у нас находится выше, мы должны выдержать время максимум 480 микросекунд, но так как после последней задержки у нас уже прошло некоторое количество времени, то хватит и 420, тем более задержка эта не фиксированная, а максимальная. Ну, и добавим эту задержку в тело функции далее, и в оконцовке вернём результат функции.
    SREG = stektemp;// вернем значение стека
    _delay_us(420); //задержка как минимум на 480 микросекунд, но хватит и 420, тк это с учетом времени прошедших команд
    return dt; //вернем результат
    }

  3. qwas:

    да, как-то всё запутано

  4. Иван:

    Не понял зачем нужно отключать прерывания?

  5. Влад:

    Да, чем дальше изучаешь, тем более запутанным становится объяснение простых, по мнению автора, вещей. Это проблема всех интернет-учителей: они считают всё это понятным и простым со своей точки зрения, поэтому все «мелочи» и опускаются, и получается постоянное перескакивание с одного на другое, за объяснением следует неожиданный вывод или решение о том, что нужно ввести очередную функцию или переменную и т. д. Это похоже на то, как если бы человеку, не знакомому с сигналами светофора, сказали: «Увидишь красный сигнал светофора — стой». А на вопрос:»А почему я должен стоять?»., — ответили бы: «Просто стой, так будет надёжнее».

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

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

*