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

 

 

 

 

Урок 20

Часть 3

 

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

 

 

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

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

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

 

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

void dt_sendbyte(unsigned char bt)

{

  char i;

}

 

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

 

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

void dt_sendbit(char bt)

{

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

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

}

 

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

 

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

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

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

 

Дальше мы уже будем решать, что именно мы будем посылать. если будем посылать 0, то мы шину отпускать не будем, а, если нам нужно послать 1, то будем шину отпускать

 

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

if(bt)

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

 

Дальше мы ждём от 60 до 120 микросекунд, ну, подожём 65, как обычно. То есть если мы предаём ноль, то мы просто выжидаем с притянутой шиной данный временной интервал, а если передаём единицу, то делаем то же самое, но отпустив перед этим шину, так как сработает условие в коде. Затем мы отпускаем шину. То есть, если мы передаём единицу, то она уже у нас отпущена, если ноль, то отпускаем. ну и затем возвращаем сохраненное значение в стек

 

  if(bt)

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

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

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

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

}

 

Теперь продолжим, используя данную функцию, функцию записи (или отправки) байта в шину

 

  char i;

  for(i=0;i<8;i++)//посылаем отдельно каждый бит на устройство

  {

    if((bt & (1<<i)) == 1<<i)//посылаем 1

        dt_sendbit(1);

    else //посылаем 0

        dt_sendbit(0);

  }

}

 

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

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

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

 

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

{

  dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине

 

Затем мы уже отправляем команду на считывание температуры

 

dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине

dt_sendbyte(T_CONVERT); //измеряем температуру

 

Данная команда — это только команда, а не само считывание температуры. По данной команде датчик начнёт измерение температуры и конвертацию её в цифровой код и занесение его в регистровую пару. Данный процесс у датчика длится значительно долго, около 750 милисекунд, не микро. Данное время необходимо, чтобы датчик успел записать все 12 бит

 

image09

 

Здесь мы видим, что если нам особая точность не нужна, то мы можем считать другое количество бит, тем самым сэкономив значительное количество времени. Но мы напишем идеально 750, так как мы никуда не спешим

 

dt_sendbyte(T_CONVERT); //измеряем температуру

_delay_ms(750); //в 12битном режиме преобразования — 750 милисекунд

 

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

 

_delay_ms(750); //в 12битном режиме преобразования — 750 милисекунд

dt_testdevice(); //снова используем те же манипуляции с шиной что и при проверке ее присутствия

dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине

 

И затем мы уже даем команду датчику считывать байты с регистра. Судя по временным диаграммам, они там уже должны быть

 

dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине

dt_sendbyte(READ_DATA); //даем команду на чтение данных с устройства

 

 

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

 

    dt_sendbyte(READ_DATA); //даем команду на чтение данных с устройства    bt = dt_readbyte(); //читаем младший бит

    tt = dt_readbyte(); //читаем старший бит MS

    tt = (tt<<8)|bt;//сдвигаем старший влево, младший пишем на его место, тем самым получаем общий результат

  }

  return tt;

}

 

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

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

 

//преобразование температуры в единицы

char converttemp (unsigned int tt)

{

  char t = tt>>4;//сдвиг и отсечение части старшего байта

  return t;

}

 

Напишем на данную функцию прототип в хедер-файле

 

int dt_check(void); //функция преобразования показаний датчика в температуру

char converttemp (unsigned int tt); //преобразование температуры в единицы

 

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

 

int main(void)

{

  unsigned int tt=0; //переменная для хранения температуры

 

Напишем код для вызова функции измерения температуры в бесконечном цикле

 

sendcharlcd(sec%10+0x30);//Преобразуем число в код числа

sendcharlcd(' ');

tt = converttemp(dt_check()); //измеряем температуру

 

Отобразим показания температуры на дисплее

 

  tt = converttemp(dt_check()); //измеряем температуру

  sendcharlcd(tt/10+0x30);//Преобразуем число в код числа

  sendcharlcd(tt%10+0x30);//Преобразуем число в код числа

  sendcharlcd('*');

  sendcharlcd('C');

}

 

Прежде чем собирать код и прошивать контроллер, посмотрим подключение нашей всей схемы (нажмите на картинку для увеличения изображения)

 

image10_0500

 

Посмотрим также поближе модуль с припаянным датчиком

 

image12

 

Вот так выглядит модуль с другой стороны, желтым прямоугольником отмечен контакт данных термодатчика

 

image11

 

Соберём код и прошьём контроллер. А вот и результат

 

image13

 

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

 

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

 

Исходный код

 

 

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

 

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

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

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

Дисплей LCD 16×2

 

 

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

 

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

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

    А как быть если точность не нужна, а нужна скорость. Как снизить до 9 бит. Никак не выходит!

    • Да легко!
      Не использовать младшие 3 бита и всё и посчитать по даташиту, какая должна быть без них задержка

      В регистры биты записываются последовательно, начиная со старшего. Это принцип АЦП.

  2. Андрей:

    а для отображения отрицательных и положитьельных выше 99 градусов какие преобразования нужны?

  3. Дмитрий:

    Не интересно…Хотелось бы полнее! Долю градуса, знак, несколько устройств! Уважаемый Автор, не соизволили бы дополнить урок?

  4. Роман:

    Как подключить два датчика температуры?

    • Можно параллельно, можно каждый к своей ножке порта. По параллельному подключению нескольких датчиков есть урок 94 для STM. Пусть это другой контроллер, но принцип, думаю, поймёте. Я там рассказываю много об адресации и считывании ROM-кодов для дальнейшего обращения по ним к датчикам.

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

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

*