Урок 26. Подключение термодатчиков DS18B20 к Ардуино. Библиотека OneWire. Точный Ардуино термометр-регистратор.

Ардуино термометр на DS18B20

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

Предыдущий урок     Список уроков     Следующий урок

DS18B20 это интегральный датчик температуры с цифровым последовательным интерфейсом 1-Wire. Датчик с уникальными параметрами и функциональными возможностями. Я написал статью о нем.  Сейчас я подчеркну особенности этого устройства, благодаря которым он получил такое широкое распространение. Датчику DS18B20 свойственны:

  • Высокая точностью измерения, погрешность не превышает 0,5 °C. Датчик откалиброван при изготовлении, дополнительной калибровки не требует.
  • Разрешающая способность задается программно и достигает 0,0625 °C при максимальном разрешении 12 бит.
  • Широкий диапазон измерения температуры -55 … + 125 °C.
  • Датчик осуществляет преобразование температуры в цифровой код, т.е. дополнительного АЦП не требует.
  • Передача информации осуществляется по последовательному протоколу 1-Wire, требуется только три провода для подключения термодатчика к микроконтроллеру.
  • Поддерживает режим ”паразитного питания”, в котором датчик получает питание от линии связи. В этом режиме для подключения устройства к микроконтроллеру достаточно двух проводной линии связи.
  • На одну линию связи может быть включено несколько датчиков.

 

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

Подключение датчика DS18B20 к микроконтроллеру.

Самый распространенный вариант исполнения DS18B20 в корпусе TO-92.

DS18B20

Выводы на схемах подключения указаны для такого варианта. Существуют две стандартные схемы подключения DS18B20 к микроконтроллеру.

Схема питания с внешним источником.

Схема подключения DS18B20

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

Схема в режиме ”паразитного питания” позволяет подключить термодатчик к микроконтроллеру всего двумя проводами, что особенно важно при размещении датчика на значительном расстоянии от контроллера.

Схема подключения DS18B20

В этом режиме сигнал шины данных заряжает внутренний конденсатор датчика и за счет энергии на нем происходит питание устройства при низком уровне на шине. У режима ”паразитного питания ” много особенностей. Можно почитать по ссылке. Сейчас скажу главное, что в этом режиме не гарантируется работа датчика при температуре свыше 100 °C. Надо использовать схему с внешним питанием.

Для такого случая я использую следующую схему.

Схема подключения DS18B20

Датчик работает в режиме внешнего питания, которое запасается через диод на дополнительном конденсаторе. В моих устройствах схема работает без проблем, но я не уверен, что такой вариант поддерживает библиотека OneWire. Я использовал эту схему только на PIC контроллерах с собственной библиотекой.

 

Обмен информацией с термодатчиком по шине интерфейса 1-Wire.

Если кто-то желает узнать подробную информацию по этому вопросу я опять дам ссылку на статью о DS18B20. Сейчас я перечислю необходимые нам операции работы с устройством:

  • Инициализация – последовательность импульсов, с которых начинается любая операция на шине.
  • Запись байта – передача байта данных в устройство DS18B20.
  • Чтение байта – прием данных из устройства DS18B20.

Этих трех операций достаточно для работы с термодатчиком, все они поддерживаются библиотекой OneWire.

Библиотека Ардуино OneWire для работы с интерфейсом 1-Wire.

Загрузить последнюю версию библиотеки OneWire  можно по этой ссылке. Как установить ее можно посмотреть в уроке 9.

Нас интересуют следующие методы.

OneWire( uint8_t pin);

Конструктор, Pin – номер вывода, к которому подключен датчик.

OneWire sensDs (14);  // датчик подключен к выводу 14

uint8_t reset(void);

Инициализация операции на шине. С этой команды должна начинаться любая операция обмена данными. Возвращает:

  • 1 – если устройство подключено к шине (был ответный импульс присутствия);
  • 0 – если устройство отсутствует на шине (ответного импульса не было).

void write(uint8_t v, uint8_t power = 0);

Запись байта. Передает байт в устройство на шине.

  • v – байт;
  • power – признак выбора режима питания;
    • power=0 – питание от внешнего источника
    • power=1 – “паразитное” питание.

uint8_t read(void);

Чтение байта – принимает байт, переданный устройством. Возвращает значение принятого байта.

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

void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);

Запись блока байтов.

  • buf – указатель на массив;
  • count – число байтов;
  • power – признак выбора режима питания.

void read_bytes(uint8_t *buf, uint16_t count);

Чтение блока байтов.

  • buf – указатель на массив;
  • count – число байтов.

static uint8_t crc8(const uint8_t *addr, uint8_t len);

Функция вычисления 8ми разрядной контрольной суммы.

  • addr - указатель на массив данных;
  • len – число байтов.

Возвращает вычисленную сумму.

 

Последовательность операций работы с DS18B20.

Я приведу и объясню самую простую последовательность команд. Для измерения температуры необходимо выполнить следующую последовательность действий:

  • sensDs.reset() - Инициализация. Выполняет сброс шины, готовит ее для выполнения новой операции.
  • sensDs.write(0xCC, power) – Команда пропуск ROM. У нас только один датчик на шине. Поэтому нет необходимости в поиске устройства с нужным адресом. Мы эту операцию пропускаем.
  • sensDs.write(0x44, power) - Команда инициирует измерение температуры.
  • Пауза 1 сек. Ожидание на время, необходимое для выполнения датчиком преобразования температуры. Это время зависит от выбранной разрешающей способности датчика. Мы используем максимальное разрешение 12 бит.  Это разрешение установлено в датчике по умолчанию. Время преобразования для него – 750 мс. Если необходима другая разрешающая способность, то ее необходимо задать дополнительными командами.
  • sensDs. reset() - Инициализация. Мы собираемся выполнить новую операцию на шине 1-Wire.
  • sensDs.write(0xCC, power) – Команда пропуск ROM.
  • sensDs.write(0xBE, power) – Команда чтения памяти датчика. Команда используется для чтения всех 9ти байтов памяти DS18B20.
Байт 0 Температура мл. байт
Байт 1 Температура ст. байт
Байт 2 Th регистр порога сигнализации
Байт 3 Tl регистр порога сигнализации
Байт 4 Регистр конфигурации
Байт 5 Зарезервирован
Байт 6 Зарезервирован
Байт 7 Зарезервирован
Байт 8 Циклический код CRC
  • read_bytes(buf, 9) - Чтение 9ти байтов данных.
  • crc8(addr, 8) - Вычисление контрольного кода данных.
  • Сравнение контрольного кода с принятым.

После этой последовательности операций значение температуры содержится в первых двух байтах массива из принятых 9ти байтов.

Формат данных

Отрицательная температура записывается в дополнительном коде.

Таблица соответствия кодов температуре

Младший разряд имеет вес 0,0625 °C.

Проект Ардуино термометра с использованием датчика DS18B20.

Создадим термометр с функциями, аналогичными устройствам из урока 24 и урока 25. Использование термодатчика DS18B20 позволяет добиться:

  • высокой точности измерения  0,5 °C;
  • высокой разрешающей способности 0,0625 °C:
  • диапазон измерения составляет -55 … +125 °C.

Схема термометра с датчиком DS18B20.

Схема Ардуино термометра на DS18B20

Led индикатор подключен по привычной схеме из предыдущих уроков. Есть два варианта подключения термодатчика: с внешним питанием и ”паразитным питанием.”

На моем макете устройство выглядит так.

Макет Ардуино термометра на DS18B20

Резидентная программа Ардуино термометра.

Структура и большая часть программы из предыдущих уроков 24 и 25. Последовательность операций для DS18B20 подробно описаны выше. Поэтому я сразу приведу скетч программы.

// термометр, датчик DS18B20
#include <MsTimer2.h>
#include <Led4Digits.h>
#include <OneWire.h>

#define POWER_MODE  0 // режим питания, 0 - внешнее, 1 - паразитное

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

OneWire sensDs (14);  // датчик подключен к выводу 14

byte bufData[9];  // буфер данных
float temperature;  // измеренная температура

void setup() {
  MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
  MsTimer2::start();               // разрешаем прерывание по таймеру
  Serial.begin(9600); // инициализируем порт, скорость 9600 
}

void loop() { 

  sensDs.reset();  // сброс шины
  sensDs.write(0xCC, POWER_MODE); // пропуск ROM
  sensDs.write(0x44, POWER_MODE); // инициализация измерения
  delay(900);  // пауза 0,9 сек
  sensDs.reset();  // сброс шины
  sensDs.write(0xCC, POWER_MODE); // пропуск ROM 
  sensDs.write(0xBE, POWER_MODE); // команда чтения памяти датчика 
  sensDs.read_bytes(bufData, 9);  // чтение памяти датчика, 9 байтов

  if ( OneWire::crc8(bufData, 8) == bufData[8] ) {  // проверка CRC
    // данные правильные
    temperature=  (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.0625 + 0.03125;
 
    // вывод измеренной температуры на индикаторы
    if (temperature >= 0) {
      // температура положительная
      disp.print((int)(temperature * 10.), 4, 1);        
    }
    else {
      // температура отрицательная
      disp.print((int)(temperature * -1 * 10.), 3, 1);        
      disp.digit[3]= 0x40;  // отображается минус
    }
    disp.digit[1] |= 0x80;  // зажечь точку второго разряда                
       
    // передача температуры на компьютер
    Serial.println(temperature);   
  }
  else { 
    // ошибка CRC, отображается ----
      disp.digit[0]= 0x40;
      disp.digit[1]= 0x40;
      disp.digit[2]= 0x40;
      disp.digit[3]= 0x40;        
  }   
}

//-------------------------------------- обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора
}

Загрузить скетч можно по этой ссылке. Программа использует библиотеки OneWire, MsTimer2 и Led4Digits.

Не забудьте выбрать в программе режим питания датчика:

#define POWER_MODE  0 // режим питания, 0 - внешнее, 1 – паразитное

 

Программа верхнего уровня для Ардуино термометра-регистратора.

С этим устройством работает программа Thermometer из урока 24. В уроке можно загрузить программу, получить информацию по установке и применению программы.

Программа Ардуино термометра на DS18B20

Регистратор Ардуино термометра на DS18B20

Реализация измерения температуры параллельным процессом.

В проекте термометра управление термодатчиком DS18B20 происходит в основном цикле программы. Задержка 0,9 секунд реализована функцией delay(). Программа на это время зависает и никаких других действий производить не может. Хорошо, что нам в термометре больше ничего делать не надо. А если у нас сложная программа с множеством других задач.

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

// термометр, датчик DS18B20
#include <MsTimer2.h>
#include <Led4Digits.h>
#include <OneWire.h>

#define POWER_MODE  0 // режим питания, 0 - внешнее, 1 - паразитное
#define MEASURE_PERIOD 500  // время измерения, * 2 мс

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

OneWire sensDs (14);  // датчик подключен к выводу 14

int timeCount;     // счетчик времени измерения
boolean flagSensReady;  // признак готовности данных с датчика
byte bufData[9];  // буфер данных
float temperature;  // измеренная температура

void setup() {
  MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
  MsTimer2::start();               // разрешаем прерывание по таймеру
  Serial.begin(9600); // инициализируем порт, скорость 9600 
}

void loop() { 

  if ( flagSensReady == true ) {
    flagSensReady= false;
    // данные готовы

   if ( OneWire::crc8(bufData, 8) == bufData[8] ) {  // проверка CRC
      // данные правильные
      temperature=  (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.0625 + 0.03125;
 
      // вывод измеренной температуры на индикаторы
      if (temperature >= 0) {
        // температура положительная
        disp.print((int)(temperature * 10.), 4, 1);        
      }
      else {
        // температура отрицательная
        disp.print((int)(temperature * -1 * 10.), 3, 1);        
        disp.digit[3]= 0x40;  // отображается минус
      }
      disp.digit[1] |= 0x80;  // зажечь точку второго разряда                
       
      // передача температуры на компьютер
      Serial.println(temperature);   
    }
    else { 
      // ошибка CRC, отображается ----
        disp.digit[0]= 0x40;
        disp.digit[1]= 0x40;
        disp.digit[2]= 0x40;
        disp.digit[3]= 0x40;        
    }   
  } 
}

//-------------------------------------- обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора

  // управление датчиком DS18B20 паралллельным процессом
  timeCount++; if ( timeCount >= MEASURE_PERIOD ) { timeCount=0; flagSensReady=true; }
 
  if (timeCount == 0) sensDs.reset();  // сброс шины  
  if (timeCount == 1) sensDs.write(0xCC, POWER_MODE); // пропуск ROM
  if (timeCount == 2) sensDs.write(0x44, POWER_MODE); // инициализация измерения

  if (timeCount == 480) sensDs.reset();  // сброс шины
  if (timeCount == 481) sensDs.write(0xCC, POWER_MODE); // пропуск ROM 
  if (timeCount == 482) sensDs.write(0xBE, POWER_MODE); // команда чтения памяти датчика 
   
  if (timeCount == 483 ) bufData[0]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 484 ) bufData[1]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 485 ) bufData[2]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 486 ) bufData[3]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 487 ) bufData[4]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 488 ) bufData[5]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 489 ) bufData[6]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 490 ) bufData[7]= sensDs.read();  // чтение памяти датчика
  if (timeCount == 491 ) bufData[8]= sensDs.read();  // чтение памяти датчика    
}

После получения данных с датчика DS18B20 формируется признак о готовности данных и в основном асинхронном процессе они могут быть использованы.

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

 

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

Предыдущий урок     Список уроков     Следующий урок

48 комментариев на «Урок 26. Подключение термодатчиков DS18B20 к Ардуино. Библиотека OneWire. Точный Ардуино термометр-регистратор.»

  1. спасибо за материал, очень доходчиво. планируется ли продолжение с подключением других устройств 1-wire, например ds2450, ds2406

    • Спасибо, приятно слышать. На счет подключения других датчиков 1-wire пока не знаю. Сейчас в планах много других интересных тем, которые я еще не рассматривал.

  2. Скажите пожалуйста, что надо изменить в программе чтоб изменить на датчик ds1820? у меня температура при домашней 24,33 показывает 2,33

    • Я боюсь ошибиться, но различие этих датчиков в разрешающей способности. У DS1820 это 0,5 C.
      Попробуйте строчку
      temperature= (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.0625 + 0.03125; заменить на temperature= (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.5 + 0.25;

  3. Получилось! Спасибо!
    если я пишу так
    temperature= (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.5 + 0.5;
    то температура меньше на 1 градус от другого термометра на ds18b20.

    • Рад, что помог.
      Надо писать:
      temperature= (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.5 + 0.25; + 0.25 - это округление половины значащего разряда.

  4. Спасибо автору!
    Вместо резистора 4,7 кОм (у кого нет),
    использовал подтягивающий резистор A2 (15)
    digitalWrite(15, HIGH),
    Соединяем 14 и 15 (A0 и A1)… Работает!

  5. Спасибо за полезную статью.
    Подскажите, можно упростить код, если не нужны значения температуры после запятой? (нужны только целые значения температуры).

    • Только целое значение температуры можно вывести так. Блок
      // вывод измеренной температуры на индикаторы
      if (temperature >= 0) {
      // температура положительная
      disp.print((int)(temperature * 10.), 4, 1);
      }
      else {
      // температура отрицательная
      disp.print((int)(temperature * -1 * 10.), 3, 1);
      disp.digit[3]= 0x40; // отображается минус
      }
      disp.digit[1] |= 0x80; // зажечь точку второго разряда

      заменить на блок

      // вывод измеренной температуры на индикаторы
      if (temperature >= 0) {
      // температура положительная
      disp.print((int)(temperature + 0.5), 4, 1);
      }
      else {
      // температура отрицательная
      disp.print((int)(temperature * -1. + 0.5), 3, 1);
      disp.digit[3]= 0x40; // отображается минус
      }

      • Я может не совсем правильно выразил свой вопрос.
        Мне на дисплей не нужно выводить показания.
        Мне просто достаточно точности в один градус.
        Я хотел спросить, можно ли изменить код в Вашем последнем примере, что бы датчик передавал температуру с разрешением 0,5 градуса.
        В Вашей статье про датчик написано «Основная функция DS18B20 – преобразование температуры датчика в цифровой код. Разрешение преобразования задается 9, 10, 11 или 12 бит. Это соответствует разрешающей способность — 0,5 (1/2) °C, 0,25 (1/4) °C, 0,125 (1/8) °C и 0,0625 (1/16) °C. При включении питания, состояние регистра конфигурации устанавливается на разрешение 12 бит.»

        Хотелось бы упростить свою программу
        // два датчика DS18B20
        #include
        #include

        #define POWER_MODE 0 // режим питания, 0 — внешнее, 1 — паразитное
        #define MEASURE_PERIOD 1000 // время измерения, * 2 мс

        OneWire sensOut (4); // датчик внешний подключен к выводу 4
        OneWire sensIn (5); // датчик внутренний подключен к выводу 5
        int timeCount; // счетчик времени измерения
        boolean flagSensReady; // признак готовности данных с датчика
        byte bufDataOut[9]; // буфер данных снаружи
        byte bufDataIn[9]; // буфер данных внутри
        float temperatureOut; // измеренная температура снаружи
        float temperatureIn; // измеренная температура внутри
        void setup() {
        MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
        MsTimer2::start(); // разрешаем прерывание по таймеру
        Serial.begin(9600); // инициализируем порт, скорость 9600
        }

        void loop() {

        if ( flagSensReady == true ) {
        flagSensReady= false;
        // данные готовы

        if ( OneWire::crc8(bufDataOut, 8) == bufDataOut[8] ) { // проверка CRC
        // данные правильные
        temperatureOut
        = (float)((int)bufDataOut[0] | (((int)bufDataOut[1]) << 8)) * 0.0625 + 0.03125;

        // передача температуры на компьютер
        Serial.println(temperatureOut);
        }
        if ( OneWire::crc8(bufDataIn, 8) == bufDataIn[8] ) { // проверка CRC
        // данные правильные
        temperatureIn
        = (float)((int)bufDataIn[0] | (((int)bufDataIn[1]) <= MEASURE_PERIOD ) { timeCount=0; flagSensReady=true; }

        if (timeCount == 0) sensOut.reset(); // сброс шины
        if (timeCount == 1) sensOut.write(0xCC, POWER_MODE); // пропуск ROM
        if (timeCount == 2) sensOut.write(0x44, POWER_MODE); // инициализация измерения

        if (timeCount == 480) sensOut.reset(); // сброс шины
        if (timeCount == 481) sensOut.write(0xCC, POWER_MODE); // пропуск ROM
        if (timeCount == 482) sensOut.write(0xBE, POWER_MODE); // команда чтения памяти датчика

        if (timeCount == 483 ) bufDataOut[0]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 484 ) bufDataOut[1]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 485 ) bufDataOut[2]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 486 ) bufDataOut[3]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 487 ) bufDataOut[4]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 488 ) bufDataOut[5]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 489 ) bufDataOut[6]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 490 ) bufDataOut[7]= sensOut.read(); // чтение памяти датчика
        if (timeCount == 491 ) bufDataOut[8]= sensOut.read(); // чтение памяти датчика

        if (timeCount == 500) sensIn.reset(); // сброс шины
        if (timeCount == 501) sensIn.write(0xCC, POWER_MODE); // пропуск ROM
        if (timeCount == 502) sensIn.write(0x44, POWER_MODE); // инициализация измерения

        if (timeCount == 980) sensIn.reset(); // сброс шины
        if (timeCount == 981) sensIn.write(0xCC, POWER_MODE); // пропуск ROM
        if (timeCount == 982) sensIn.write(0xBE, POWER_MODE); // команда чтения памяти датчика

        if (timeCount == 983 ) bufDataIn[0]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 984 ) bufDataIn[1]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 985 ) bufDataIn[2]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 986 ) bufDataIn[3]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 987 ) bufDataIn[4]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 988 ) bufDataIn[5]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 989 ) bufDataIn[6]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 990 ) bufDataIn[7]= sensIn.read(); // чтение памяти датчика
        if (timeCount == 991 ) bufDataIn[8]= sensIn.read(); // чтение памяти датчика
        }

        • Для этого надо запрограммировать регистр конфигурации датчика. Я не помню, как это делается. Надо разбираться. У меня на сайте есть статья с форматами регистров. Не проще оставить все как есть. Так даже команд меньше. Что Вы сэкономите? Только время измерения.

  6. Вопрос от начинающего.
    Не компилируется строка:
    MsTimer2::set(2,timerInterrupt); // задаем период прерывания по таймеру 2 мс

    выдаётся сообщение:
    exit status 1
    ‘timerInterrupt’ was not declared in this scope

    Если её комментировать, то компилируется нормально.
    В чём может быть причина?

      • Еще раз проверил. У меня все компилируется без ошибок. Если библиотека установлена, еще раз внимательно скопируйте код с сайта.

  7. Попробовал обе версии из статьи и скачанный скетч. Не компилируется. Библиотека MsTimer2.h установлена.
    Как я понимаю, таймер нужен только для индикации.
    Индикация мне не нужна, Если я закомментирую строки с обращениями к таймеру, всё остальное должно работать (измерение и передача в комп). Если нет то вместо него можно попробовать вставить delay? Вообще нужно раз в несколько минут измерять температуру и по запросу отправлять SMS, AT-командами через модем.

  8. Скажите пожалуйста, что надо изменить в программе, если к шине подключено 2 датчика DS18B20 (как прописать адрес датчика) ?

    • Это достаточно сложная последовательность операций. Я сейчас не помню. Может проще 2 линии связи использовать.

  9. Вопрос от начинающего.
    Пробовал примеры из разных уроков, результат тот же.
    Библиотека MsTimer2 установлена.
    Не компилируется строка:
    MsTimer2::set(2,timerInterrupt);

    Arduino: 1.6.13 (Windows 8.1), Плата:»Arduino/Genuino Uno»

    G:\РђСЂРґСѓРёРЅРѕ\DS18B20_РђСЂРґСѓРёРЅРѕ\DS18B20_Ard\DS18B20_Ard.ino: In function ‘void setup()’:

    DS18B20_Ard:17: error: ‘timerInterupt’ was not declared in this scope

    exit status 1
    ‘timerInterupt’ was not declared in this scope

    Если её закомментировать, то компилируется нормально.
    Следующая за ней строка:
    MsTimer2::start();
    компилируется нормально.

    • Даже не знаю, что сказать. У меня компилируется нормально.
      Сообщение ‘timerInterupt’ was not declared in this scope означает, что переменная или функция не объявлены. Попробуйте изменить имя функции обработчика прерывания. Может при копировании что-то у Вас портится. Напишите имя функции заново.
      Не понятно, почему у Вас в сообщении timerInterupt с одной буквой r. Проверьте внимательно. В программе везде timerInterrupt.

  10. Всё получилось.
    Проект по умолчанию сохранялся в папке документы, путь к которой содержал русские буквы.
    Сохранил в корень диска С папка «12345» и компиляция прошла успешно.
    Спасибо за внимание к начинающим.

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

    • А что отображается вместо 0? Цифра 0 не отображается в любом месте? У меня все индикаторы с общим анодом. Наверное, аппаратная ошибка.

      • У меня не отображается ноль при переходе с плюсовой температуры на минусовую и обратно. Пример: +3, +2, +1, , -1, -2. Т.е. вообще не загарается индикация. А для цифр +10, +20, -10, -20 и.т. д. нули нормально загараются.

        • А еще точнее. Должно выводиться 0.2 а выводится _._, т.е. только точка? И только для индикаторов с общим анодом?

  12. Подскажите пожалуйста, при компиляции выдает ошибку на библиотеку Led4Digits:
    This report would have more information with
    «Show verbose output during compilation»
    enabled in File > Preferences.
    Arduino: 1.0.6 (Windows XP), Board: «Arduino Uno»
    In file included from Led4Digits.cpp:12:
    Led4Digits.h:40: error: a brace-enclosed initializer is not allowed here before ‘{‘ token
    Led4Digits.h:57: error: ISO C++ forbids initialization of member ‘_segCod’
    Led4Digits.h:57: error: making ‘_segCod’ static
    Led4Digits.h:57: error: invalid in-class initialization of static data member of non-integral type ‘const byte [16]’
    Led4Digits.cpp: In member function ‘void Led4Digits::tetradToSegCod(byte, byte)’:
    Led4Digits.cpp:88: error: ‘_segCod’ was not declared in this scope
    Что делать?

    • Даже не знаю. Впервые такое случилось. Попробуйте в новый пустой скетч добавьте библиотеку. Будет ошибка?

      #include
      void setup() {
      }

      void loop() {
      }

  13. Открыл новый скетч , добавил библиотеку:
    #include
    void setup(){}
    void loop(){}
    Выдал ошибку:
    This report would have more information with
    «Show verbose output during compilation»
    enabled in File > Preferences.
    Arduino: 1.0.6 (Windows XP), Board: «Arduino Uno»
    In file included from sketch_jan05a.ino:3:
    C:\Program Files\arduino-1.0.6\libraries\Led4Digits/Led4Digits.h:40: error: a brace-enclosed initializer is not allowed here before ‘{‘ token
    C:\Program Files\arduino-1.0.6\libraries\Led4Digits/Led4Digits.h:57: error: ISO C++ forbids initialization of member ‘_segCod’
    C:\Program Files\arduino-1.0.6\libraries\Led4Digits/Led4Digits.h:57: error: making ‘_segCod’ static
    C:\Program Files\arduino-1.0.6\libraries\Led4Digits/Led4Digits.h:57: error: invalid in-class initialization of static data member of non-integral type ‘const int [16]’
    Может у меня ARDUINO IDE 1.0.6 -как бы под устарела?

  14. Обновил IDE до 1.6.13, скомпилировал скетч .Теперь другая ошибка:
    Arduino: 1.6.13 (Windows XP), Плата:»Arduino/Genuino Uno»

    C:\Documents and Settings\Олег\РњРѕРё документы\Arduino\РјРѕРё sketch\led_4digits\led_4digits.ino: In function ‘void setup()’:

    led_4digits:20: error: ‘timerInterrupt’ was not declared in this scope

    exit status 1
    ‘timerInterrupt’ was not declared in this scope

    Этот отчёт будет иметь больше информации с
    включенной опцией Файл -> Настройки ->
    «Показать подробный вывод во время компиляции»

    • Такая ошибка у кого-то была. Если я правильно помню, то он разместил скетч программы в папке названной русскими символами. Проверьте, что название всех каталогов только латинскими символами.

  15. Убрал «русские» папки и все равно ошибка:

    Arduino: 1.6.13 (Windows XP), Плата:»Arduino/Genuino Uno»

    libraries\Led4Digits\Led4Digits.cpp.o (symbol from plugin): In function `Led4Digits::Led4Digits(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)’:

    (.text+0x0): multiple definition of `Led4Digits::Led4Digits(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)’

    sketch\Led4Digits.cpp.o (symbol from plugin):(.text+0x0): first defined here

    libraries\Led4Digits\Led4Digits.cpp.o (symbol from plugin): In function `Led4Digits::Led4Digits(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)’:

    (.text+0x0): multiple definition of `Led4Digits::Led4Digits(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)’

    sketch\Led4Digits.cpp.o (symbol from plugin):(.text+0x0): first defined here

    libraries\Led4Digits\Led4Digits.cpp.o (symbol from plugin): In function `Led4Digits::Led4Digits(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)’:

    (.text+0x0): multiple definition of `Led4Digits::regen()’

    sketch\Led4Digits.cpp.o (symbol from plugin):(.text+0x0): first defined here

    libraries\Led4Digits\Led4Digits.cpp.o (symbol from plugin): In function `Led4Digits::Led4Digits(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)’:

    (.text+0x0): multiple definition of `Led4Digits::tetradToSegCod(unsigned char, unsigned char)’

    sketch\Led4Digits.cpp.o (symbol from plugin):(.text+0x0): first defined here

    libraries\Led4Digits\Led4Digits.cpp.o (symbol from plugin): In function `Led4Digits::Led4Digits(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)’:

    (.text+0x0): multiple definition of `Led4Digits::print(unsigned int, unsigned char, unsigned char)’

    sketch\Led4Digits.cpp.o (symbol from plugin):(.text+0x0): first defined here

    collect2.exe: error: ld returned 1 exit status

    exit status 1
    Ошибка компиляции для платы Arduino/Genuino Uno.

    Уже мозг кипит.

    • Какая-то грубая ошибка. Попробуйте заново. Удалите библиотеку. Убедитесь, что она исчезла из списка в Arduino IDE. В папке с проектами создайте папку libraries. Скопируйте туда папку Led4Digits с файлами библиотеки. Запустите Arduino IDE, убедитесь, что библиотека появилась в списке. Затем в новый пустой файл включите библиотеку через Arduino IDE и скомпилируйте. У всех работает. Попробуйте с другой библиотекой, например, LedDigitsKeys.h

  16. Эдуард, точка и значения после запятой выводятся именно цифра ноль не выводятся, пример: .2, .4,- .5. У меня подозрение на датчик температуры, а чтоб проверить пока нет запасной. Хотя на индикации с общим катодом работало все идеально. Буду разбираться.

    • Так программа и должна работать. Там установлен признак гашения не знащащих нулей. Посмотрите в уроке 20.
      •blank – признак гашения незначащих разрядов. blank=0 означает, что число должно отображаться со всеми нулями. Число ”7” будет выглядеть “0007”. При blank, отличном от 0 незначащие нули будут гаситься.
      Можете отключить гашение
      disp.print((int)(temperature * 10.), 4, 0);

      Но, тогда температура будет отображаться в виде 00.2

  17. Эдуард, Благодарю за помощь!
    Все сделал, работает так, как я хотел. А кому интересно (для начинающих!):
    if (temperature >= 0) {
    // температура положительная
    disp.digit[3]= 0x00; // гасим знак минус
    disp.print((int)(temperature * 10.), 3, 0);
    if (temperature — 10)
    {disp.digit[2]= 0x00; // гасим ненужные
    disp.print((int)(temperature * — 1 * 10.), 2, 0); // разряды
    }
    }

    disp.digit[0] = 0x63; // отображаем знак градуса

    Здесь гасятся не нужные разряды и не будет отображаться типа 09, 08, … -03, -05. И вместо цифр после запятой будет отображаться знак градуса.

  18. В предыдущей почему- то не правильно отобразилось программа, еще раз пробую отправить
    if (temperature >= 0) {
    // температура положительная
    disp.digit[3]= 0x00;
    disp.print((int)(temperature * 10.), 3, 0);
    if (temperature — 10)
    {disp.digit[2]= 0x00;
    disp.print((int)(temperature * — 1 * 10.), 2, 0);
    }
    }
    //disp.digit[1] |= 0x80; // зажечь точку второго разряда
    disp.digit[0] = 0x63; // отображаем знак градуса

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

  20. Эдуард, по Вашему совету сделал следующее:
    1. удалил библиотеку;
    2.создал папку «libraries» в папке «may sketch», распаковал туда «Led4Digits.rar», но она нигде не появилась;
    3.удалил «libraries» из «may sketch»;
    4.добавил библиотеку «Led4Digits.h» как обычно, она появилась в основной «libraries»;
    5.открыл пустой скетч, подключил библиотеку «Led4Digits.h» , скомпилировал— о чудо , все получилось.
    6. «на радостях» компилирую полный скетч—- ошибка:
    Arduino: 1.6.13 (Windows XP), Плата:»Arduino/Genuino Uno»

    collect2.exe: error: ld returned 5 exit status

    exit status 1
    Ошибка компиляции для платы Arduino/Genuino Uno.

    Этот отчёт будет иметь больше информации с
    включенной опцией Файл -> Настройки ->
    «Показать подробный вывод во время компиляции»
    Взрыв мозга!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    • Олег, а у вас Windows XP?
      В интернете полно обсуждения этой ошибки. Наберите в поисковом запросе Яндекса: ардуино collect2.exe error ld returned 5 exit status.

  21. Да, Windows XP. «Погуглил» : предлагали поменять файл LD на на такой же, но из старой версии ( у меня осталась 1.0.6). Ничего не вышло. Снёс версию 1.6.13. У меня был архив версии 1.6.1 (в прошлом году скачал , а почему не установил — не помню).
    Установил 1.6.1 подсунул файл LD, и вуаля—все срослось .
    Эдуард спасибо что удили время.

  22. Здравствуйте, Эдуард.
    Обращаюсь к вам как с специалисту, так как в микроэлектронике соображаю снова и всего пару дней.
    Год назад я сделал температурный контроль теплиц в шестью датчиками DS18B20 и общей длиной провода в 235 метров. Плата Arduino UNO через библиотеки Даллас и 1-wire исправно выдавала температуры всех датчиков на экран компьютера.
    Ртутные градусники , установленные физически в этих же местах теплиц подтверждали реальное отсутствие погрешностей и система ни разу не дала сбой.
    К сожалению, я почти позабыл, как именно я это сделал и почему система работала целый год, пока меня не попросили наворотить её побогаче, да пожирнее…
    Добавив ещё пару таких же датчиков и метров 5 точно такого же провода (кспвг 4х0,2) система работала ещё пару дней на восьми датчиках пока я не добавил в плату двух релейный блок повесив его по доброте душевной на тот же пин питания 5в платы Arduino UNO, на котором висит вся сеть…
    Короче, плата начала видеть верхние сектора подпространства, призраков, фей и попросила звонить «03».
    Я вкратце опишу схему сети до потустороннего вмешательства:
    К каждому датчику DS18S20 во влагозащищённом корпусе на конце провода длиной около метра (на этом проводе датчик продаётся) припаяно сопротивление 4,7 К, которое находится в непосредственной близости к месту подсоединения к линии обычными колодками под отвёртку.
    Сеть собрана по схеме «Карусель».
    Длина первой линии с одним датчиком на конце до точки слияния со второй линией — 30 метров. Длина второй линии до точки слияния с первой — 85 метров. Дальше 5 метров вместе до точки слияния с третьей линией.
    На второй линии стоят два датчика. Один на конце, второй в 40 метрах от конца
    На третьей линии длиной 120м, стоят три датчика. До ближайшего 50м, до следующего 80 и конечный.
    Чтобы схема «Карусель» заработала, необходимо запитать плату не только от USB, но и от внешнего источника и ни в коем случае нельзя ставить сопротивление рядом с платой Arduino UNO.
    Ближайшее подтягивающее сопротивление 4,7К находится на расстоянии 35 метров!
    В моём случае для дополнительного питания платы используется трансформатор 5В на 100 мА.
    Сеть начинается одним проводом кспвг 4х0,2 (во всей сети из него используются только три отдельных жилы), затем разделена физически сначала на две линии (если мы «идём» от платы) с примерно одинаковым «весом» для уравновешивания.
    В моём случае это 120 метров против 115-ти.
    Линия в 120 метров не будет работать без линии в 115 метров, так как она «тащит» вольтаж, необходимый для того, чтобы параллельная «река» тока, после развилки, достигла самого дальнего датчика.
    В свою очередь, линия в 115 метров так же оснащена «корягой» в виде ближайшего к плате датчика, который подтягивает вольтаж первым в сети сопротивлением, находящимся на расстоянии 35 метров от платы.
    Расстояния до девайсов линии с «корягой» такие: (35м+45м/85м)
    У третьей, «простой» линии: (50м/80м/120м)
    Понимаю, как «страшно» всё это звучит на языке чайника Гарри, но поверьте, я вычитал как «ЭТО» сделать именно в интернете и помню, что для схемы «Бурлаки на линии» советовалось выбрать провод именно сечением 0,2 а не 0,5 мм кв.
    Я понимаю, что увеличив количество датчиков до восьми, нужно было бы перепаять сопротивления на поменьше, но я не смог найти следов Творца, научившего меня фокусам. 🙁
    Дело в том, что сейчас заказчик попросил меня не только добавить два датчика, но и переставить имена датчиков на экране компьютера и, по ходу, подсоединить три сирены, которые бы будили кочегара, где бы он не прилёг поспать.
    Но мне уже не до сирены…
    Вот этот скетч (из-за того, что он больше предыдущего) уже забирает питание с платы на питание самой платы на время обработки более сложной задачи и напряжение на концах сети еле-еле хватает:
    [quote]
    #include 
    #include 

    #define ONE_WIRE_BUS 10
    #define TEMPERATURE_PRECISION 9

    [color=#CC6600]OneWire[/color] oneWire(ONE_WIRE_BUS);

    [color=#CC6600]DallasTemperature[/color] sensors(&oneWire);
      
    [color=#CC6600]DeviceAddress[/color] Thermometer1 = {
      0x28, 0xA3, 0xF0, 0xA8, 0x04, 0x00, 0x00, 0x96 };
    [color=#CC6600]DeviceAddress[/color] Thermometer2 = {
      0x28, 0x74, 0x31, 0x55, 0x05, 0x00, 0x00, 0x7F };
    [color=#CC6600]DeviceAddress[/color] Thermometer3 = {
      0x28, 0xBE, 0xD6, 0x67, 0x05, 0x00, 0x00, 0xEB };
    [color=#CC6600]DeviceAddress[/color] Thermometer4 = {
      0x28, 0x63, 0x6C, 0x55, 0x05, 0x00, 0x00, 0xD8 };
    [color=#CC6600]DeviceAddress[/color] Thermometer5 = {
      0x28, 0x11, 0x8A, 0x54, 0x05, 0x00, 0x00, 0xE7 };
    [color=#CC6600]DeviceAddress[/color] Thermometer6 = {
      0x28, 0xE2, 0x58, 0x54, 0x05, 0x00, 0x00, 0x11 };
    [color=#CC6600]DeviceAddress[/color] Thermometer7 = {
      0x28, 0xEF, 0x1A, 0x55, 0x05, 0x00, 0x00, 0xBE };
    [color=#CC6600]DeviceAddress[/color] Thermometer8 = {
      0x28, 0x44, 0xFF, 0x5A, 0x05, 0x00, 0x00, 0x88 };

    [color=#CC6600]void[/color] [color=#CC6600][b]setup[/b][/color]()
    {
      sensors.[color=#CC6600]begin[/color]();
      
      sensors.[color=#CC6600]setResolution[/color](Thermometer1, 10);
      sensors.[color=#CC6600]setResolution[/color](Thermometer2, 10);
      sensors.[color=#CC6600]setResolution[/color](Thermometer3, 10);
      sensors.[color=#CC6600]setResolution[/color](Thermometer4, 10);
      sensors.[color=#CC6600]setResolution[/color](Thermometer5, 10);
      sensors.[color=#CC6600]setResolution[/color](Thermometer6, 10);
      sensors.[color=#CC6600]setResolution[/color](Thermometer7, 10);
      sensors.[color=#CC6600]setResolution[/color](Thermometer8, 10);
      
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]begin[/color](9600);
    }
     
    [color=#CC6600]void[/color] printTemperature([color=#CC6600]DeviceAddress[/color] deviceAddress) {
      [color=#CC6600]float[/color] tempC = sensors.[color=#CC6600]getTempC[/color](deviceAddress);
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]println[/color](tempC);
    }
    [color=#CC6600]void[/color] [color=#CC6600][b]loop[/b][/color]() {
     
      sensors.[color=#CC6600]requestTemperatures[/color]();
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Sens1 «[/color]);
      printTemperature(Thermometer1); 
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Sens2 «[/color]);
      printTemperature(Thermometer2);    
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Sens3 «[/color]);
      printTemperature(Thermometer3); 
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Sens4 «[/color]);
      printTemperature(Thermometer4);   
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Sens5 «[/color]);
      printTemperature(Thermometer5);
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Sens6 «[/color]);
      printTemperature(Thermometer6);  
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Big «[/color]);
      printTemperature(Thermometer7);
      [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]print[/color]([color=#006699]»Small «[/color]);
      printTemperature(Thermometer8);
    }
     

    [/quote]
    После замены погибшей платы и записи нового скетча систему приходится запускать в следующем порядке:
    1. Подключаем плату в USB порт компьютера.
    2. Запускаем программу Arduino 1.0.6 \\плата тут же начинает опрос датчиков, но ей не хватает силёнок.
    3. Включаем внешнее питание на плату. \\спустя несколько секунд монитор порта начинает выдавать цифры.
    А мне нужно дописать ещё и скетч на релюшки и подключить их…
    Не могли бы Вы подсказать:
    -Как вычислить сопротивление, которое нужно перепаять на каждом датчике, чтобы питание до датчиков доходило легче?
    До вмешательства был не важен порядок включения, контроль температуры вёлся платой постоянно от включенного в сеть транса, а USB разъём, готовый к включению в комп, валялся на столе.

    • Станислав, здравствуйте!
      Может Вы откроете тему на форуме сайта и скопируете туда ваш вопрос. Там есть раздел форума датчики температуры.
      Во первых проще будет обсуждать.
      Во вторых кто-нибудь поделится своим опытом.
      Если по каким-либо причинам Вы не желаете общаться на форуме, то сообщите мне. Я напишу ответ на сайте.

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

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