Подписаться на получение новых статей на почту:

ds18b20 and 1-wire на AVR. Подключение. Программа на Си. Шаг №6

Обновлено 9.04.15. Здравствуйте дорогие друзья. В предыдущей статье мы с Вами рассмотрели подключение и алгоритм работы с семи сегментным индикатором. В этом посте я расскажу о цифровых датчиках температуры ds18b20.  Рассмотрим подключение, напишем программу на Си используя техническую документацию. Познакомимся с интерфейсом 1-Wire.  Выведем температуру на индикатор.

Итак из технического описания DS18B20 – это цифровой термометр ,датчик температуры, разрешающая способность измерения температуры, которого, может быть установлена от 9 до 12 бит. Диапазон измерений от –55°C до +125°C . Датчик фирмы DALLAS Semiconductor, работает как один так и вгруппе с другими НА ОДНОЙ ЛИНИИ через интерфейс 1-Wire. Что и является изюминкой данного «девайса».
Что ж разберем далее что из себя представляет данный интерфейс.
1-Wire — двунаправленная шина связи для устройств с низкоскоростной передачей данных (обычно 15,4 Кбит/с, максимум 125 Кбит/с в режиме overdrive), в которой данные передаются по цепи питания (то есть всего используются два провода — один для заземления, а второй для питания и данных; в некоторых случаях используют и отдельный провод питания) — разработана корпорацией Dallas Semiconductor и является её зарегистрированной торговой маркой. Соответственно, топология такой сети — общая шина. Сеть устройств 1-Wire со связанным основным устройством названа «MicroLan», это также торговая марка Dallas Semiconductor.
На рисунке ниже приведена схема подключения датчика с внешним питанием.

Cхема подключения ds18b20

При подключении главное не перепутать полюс питания, т.к. погреется и выйдет из строя – горький опыт!!! Что ж давайте разберем даташит.
Давайте попробуем разобраться в алгоритме. Я буду писать как можно проще, самые основные функции. Для анализа я брал библиотеку аппноута 318 (протокол 1-Wire для семейства датчиков ds) а также библиотеки слегка измененные.
Первое что нам надо знать, это как работать с данным интерфейсом. Так вот основные операции, это импульс сброса, запись бита и чтение. В даташите приведены тайм слоты для всех этих операций. Итак начнем писать. Для оживления датчика необходимо подать импульс сброса, а микроконтроллер должен получить сигнал присутствия. На диаграмме ниже приведены временные задержки для инициализации.
Диаграмма инициализации ds18b20
Микроконтроллер на 480 мкс «проваливает»  шину в ноль, а затем «отпускает» ее. Если к шине подключен термометр , то он  обнаруживает положительный перепад и после паузы в 15-60 мкс уже датчик отвечает микроконтроллеру импульсом присутствия — «проваливает» шину в ноль на время от 60 до 240 мкс.

1. Функция инициализации на СИ.

init_devise ()                                   //функция инициализации датчика
{
        cli ();                                                    //Запретим общие прерывания
        DDRC |= _BV (PC2);                           //1 — выход
        PORTC &= ~_BV (PC2);                      //0
        _delay_us (480);                                //задержка 480 мкс
        //«отпускает»
        DDRC &= ~_BV (PC2);                                    //0 — вход
        PORTC &= ~_BV (PC2);                      //0
        _delay_us (70);           //задержка 70 мкс ,берем чуть больше после перепада
        if (!(PINC2 & 0×04))   //Если 0 в регистре, то получен сигнал присутствия 
             Display (111);      /*Вывожу на индикатор единицы, если сигнал присутствует*/
       else
             Display (000); // иначе на индикатор выводится нули
       _delay_us (410); //остальная задержка для окончания импульса присутствия
       sei ();                                       // разрешаем прерывания
}
Датчики откликнулись и готовы к приему команд. Т.к. у нас несколько датчиков на линии, то нам необходимо послать команду SEARCH ROM [F0h] — (ПОИСК ROM) –  эта  команда идентификация кодов ROM всех подчиненных устройств на шине. Эту процедуру необходимо выполнить столько раз, сколько датчиков, чтобы идентифицировать все из подчиненных устройств. Если есть только одно подчиненное устройство на шине.
Напишем функцию по отправке команд. Временные задержки расписаны на временной диаграмме, на рисунке ниже.

Временные диаграммы ds18b20  Обмен данными по  шине происходит последовательно, младшим битом вперед. Передача или прием одного бита данных выполняются в течении фиксированного промежутка времени, так называемого тайм слота (time slot). Различают тайм слоты записи и тайм слоты чтения. Длительность всех тайм слотов должна быть > 60 мкс, а пауза между тайм слотами  > 1 мкс.

Для передачи нуля микроконтроллер «проваливает» 1-Wire шину на время от 60 до 120 мкс. Затем «отпускает» ее и перед записью следующего бита выдерживает паузу >1  мкс!!!

Для передачи единицы микроконтроллер «проваливает» 1-Wire шину на время от 1 до 15 мкс,  «отпускает» ее и выдерживает паузу. Пауза должна быть такой, чтобы длительность тайм слота была > 60+1 мкс!!!

2. Функция передачи комманды.

send_command (unsigned char command)
{
            unsigned char i;
            for (i=0; i < 8; i++)
            {
                        if (command & 0×01)         // если позиция бита 1, то передаем 1
                        {
                                   cli ();                            //Запретим общие прерывания
                                   DDRC |= _BV (PC2);   //1 — выход
                                   PORTC &= ~_BV (PC2);    //0
                                   _delay_us (15);           //задержка 15 мкс
                                   //«отпускает»
                                   DDRC &= ~_BV (PC2);            //0 — вход
                                   PORTC &= ~_BV (PC2); //0
                                    _delay_us (45);           //задержка 46 мкс ,берем чуть больше
                                   sei ();                            // разрешаем прерывания
                        }
                        else                                         //передаем 0
                        {
                                   cli ();                            //Запретим общие прерывания
                                   DDRC |= _BV (PC2);   //1 — выход
                                   PORTC &= ~_BV (PC2);          //0
                                   _delay_us (120);         //задержка 120 мкс
                                   //«отпускает»
                                   DDRC &= ~_BV (PC2);            //0 — вход
                                   PORTC &= ~_BV (PC2);          //0
                                   _delay_us (1); //задержка перед записью следующего бита
                                   sei ();                            // разрешаем прерывания
                        }
                        command >>= 1; //сдвигаем для обработки следующего бита
            }
}

Команду отправили. Все устройства на линии, начинают генерировать свои уникальные 64-битные коды, одновременно, причем посылают каждый бит дважды, первый фактический, втрой инверсный, т.е. микроконтроллер считывает состояние одного бита в течение двух Времен (тактов). Общий сигнал на линии формируется по законам умножения логического «И». Далее нам необходимо прочитать эти биты.

DS18B20 является подчиненным устройством и может передавать данные, только когда микроконтроллер формирует на шине тайм слоты чтения. Для формирования тайм слота чтения микроконтроллер «проваливает» шину на время от 1 до 15 мкс, а затем «отпускает» ее, передавая  управление состоянием шины датчику. Если термометр передает ноль, он удерживает шину в «проваленном» состоянии (в состоянии логического нуля) до конца тайм слота. Если он передает 1, он оставляет шину в «подтянутом» состоянии. Микроконтроллер может считывать данные датчика DS18B20 через 15 мкс после начала тайм слота чтения.
3. Напишем функцию чтения битов.
unsigned char  read_data (void)
{
            unsigned char bit;
            cli ();                                                    //Запретим общие прерывания
            DDRC |= _BV (PC2);                           //1 — выход
            PORTC &= ~_BV (PC2);                      //0
            _delay_us (15);                                  //задержка 15 мкс
            //«отпускает», управление передается датчику
            DDRC &= ~_BV (PC2);                        //0 — вход
            PORTC &= ~_BV (PC2);                      //0
            bit1 = (PINC & 0×04);
            _delay_us (45);              //задержка 1 мкс ,перед записью следующего бита
            sei ();                                                   // разрешаем прерывания
            return bit;
}

Написали, теперь давайте разберемся в алгоритме распознавания устройств. Техническая документация говорит следующее: если все устройства содержат в этой позиции двоичного разряда:
• «0», чтение будет «01»;
• «1», результат будет «10»;
Если устройства содержат в этой позиции двоичного разряда и «1» и «0», чтение приведет «00» битов, указывая на конфликт. Главное устройство в следующем (третьем такте) слоте Времени формирует разрядное значение 1 или 0, чтобы отобрать устройства, которые останутся в процессе выбора. Все устройства у которых бит не соответствует биту сформированному главным устройством перейдут в состояние ожидания и будут находиться в нем пока они не получат импульс Сброса. После первой стадия выбора, будут следовать 63 читающих/выбора цикла, пока, наконец, главное устройство не определит Код ROM одного подчиненного устройства и обратиться к нему. Каждая стадия выбора состоит из двух слотов Времени считывания и один слот Времени записи. Полный процесс изучения и одновременная адресация — приблизительно три раза длина команды ROM Соответствия, но это позволяет выбрать из всех связанных устройств последовательно все коды ROM.

4. Что ж давайте напишем функцию, соответствующую этому алгоритму. Функция поиска датчиков.

if (n == 0)     //переменная, для одного входа в цикл поиска всех датчиков
{
       unsigned char p = 1;         // переменная для цикла считыввания кода
       unsigned char bit = 0×01;         // начальная позиция бита
       unsigned char New_conflict = 0; //переменная для нвой позиции бита
       unsigned char last_conflict = 0; //переменная для старой позиции бита           
       for (i = 0; i < 2; i++)                //обнулим массив
       {
            for (j = 0; j < 8; j++)              //8-м байт
            {
                        data[i][j] = 0×00;
            }
       }
       j = 0;                   //обнуляем
       i = 0;                   //обнуляем
       unsigned char bit1, bit2;  //для сравнения битов двух тайм слотов        
       do
       {
            New_conflict = 0;
            n++;
            init_devise ();                            // импульс сброса
            send_command (0xf0);             // команда поиска
// сигнал сброса и команда поиска необходимо подавать для каждого датчика
            while (p <= 64)                      // пока не будут прочитаны все 64 бита
            {
                        bit1 = read_data ();               //первый тайм-слот
                        bit2 = read_data ();               //второй тайм-слот
                        if (bit1 && bit2)     /*сравниваем полученные биты , если обе единицы*/
                        Display (000);              // датчиков нет на линии
                        else if ((bit1) && (!bit2)) 
                        data[i][j] |= bit;           //записываем бит
                        else if ((!bit1) && (bit2))       
                        data[i][j] &= ~bit;                                                        
                        else if ((!bit1) && (!bit2))                  //Конфликт оба 0
                        {
/*сдесь будем сравнивать позиции битов,  в номерах которых произошли конфликты  в переменной N_conflict*/                                             
                                  if (p == last_conflict) /*если текущая позиция бита в котром произошел конфликт ==  позиции в предыдущем исчеслении (скорей всего 0-ая позиция), то запишем в адресс 1*/
                                          data[i][j] |= bit;
                                  else if (p > last_conflict) /* если номер позиции больше, номера предыдущего опроса, то запишем 0 и номер позиции конфликта обновим*/
                                 {
                                         data[i][j] &= ~bit;
                                         New_conflict = p;      
                                  }
/*если вдруг текущий номер позиции меньше, номера позиции предыдущего исчесления(Если вдруг текущий бит, при конфликте, при очередном исчеслении не дошел еще до номера конфликта предыдущего исчесления,  содержит 0 , то это будет считаться новым конфликтом)*/
                                   else if (!(data[i][j] & bit))
                                               New_conflict = p;
                        }
                                              
/* Далее запишем соответствующий бит, который при следующем исчеслении включит соответствующие устройства*/
                        if (data[i][j] & bit)
                        {
                                    cli ();                              //Запретим общие прерывания
                                   DDRC |= _BV (PC2);   //1 — выход
                                   PORTC &= ~_BV (PC2);          //0
                                   _delay_us (15);                       //задержка 15 мкс
                                   DDRC &= ~_BV (PC2);                        //0 — вход
                                   PORTC &= ~_BV (PC2);                      //0
                                   _delay_us (45);                                                                                                                          sei ();                           // разрешаем прерывания
                        }
                        else                             //передаем 0
                        {
                                   cli ();                                        //Запретим общие прерывания
                                   DDRC |= _BV (PC2);               //1 — выход
                                   PORTC &= ~_BV (PC2);                      //0
                                   _delay_us (120);                     //задержка 120 мкс
                                   DDRC &= ~_BV (PC2);                        //0 — вход
                                   PORTC &= ~_BV (PC2);//0
                                   _delay_us (1);//задержка 1 мкс ,перед записью ,бита
                                   sei ();    // разрешаем прерывания
                          }          
                          p++;                //увеличиваем на 1           
                          bit <<= 1;        //сдвигаем влево
                          if (!bit)          //сдвиг проходит все 8 бит и значение равно 0
                          {
                                 data[i][j++];
                                 bit = 0×01;
                           }          
                   }                      //выходит из цикла после обработки 64-х битов
                   last_conflict = New_conflict;
                   p = 1;
                   if (last_conflict != 0)
                   data[i++][j];
                   j = 0;
                   bit = 0×01;
            } while (last_conflict != 0);  /* пока номер бита конфликта не равен 0, если равен то все датчики найдены*/
            Display (n);                 // выводим количество найденых датчиков
            _delay_ms (1000);
}

Для подлинности целостности информации необходимо проверить переданный код. Для этих целей применяется CRC  это ( cyclic redundancy check) контроль при помощи циклического избыточного кода. Основная идея алгоритма CRC состоит в представлении сообщения в виде огромного двоичного числа, делении его на другое фиксированное двоичное число и использовании остатка от этого деления в качестве контрольной суммы. Получив сообщение, приёмник должен выполнить аналогичное действие и сравнить полученный результат с принятой контрольной суммой. Сообщение считается достоверным, если выполняется это равенство. В CRC алгоритме используется полиномиальная арифметика по модулю 2. Это означает, что действия, выполняемые во время вычисления CRC, являются арифметическими операциями без учёта переноса. То есть сложение и вычитание выполняются побитово без учёта переноса, благодаря чему эти две операции дают эквивалентный результат. Ниже представлена схема формирования контрольной суммы CRC-8. Порождающий многочлен g (x) = x8+x5+x4+1.

Проверка информации CRC 

Устройство управления шиной может повторно вычислить циклический контроль избыточности и сравнить его со значениями циклического контроля избыточности от DS18B20, используя полиномиальный генератор, который показывается в иллюстрации выше. Эта схема состоит из сдвигового регистра и логического элемента XOR, биты сдвигового регистра инициализированы как 0. Старт с наименьшего значащего бита кода ROM или наименьшего значащего бита байта 0 в ОЗУ, один бит одновременно должен быть сдвинут в сдвиговом регистре. После смещения в 56-ом бите от ROM или наиболее значительного бита байта 7 от ОЗУ, полиномиальный генератор будет содержать перерасчетный циклический контроль избыточности. Затем, 8-битовый код ROM или сверхоперативный циклический контроль избыточности от датчика должен быть сдвинут в схеме. Если перерасчетный циклический контроль избыточности был правилен, сдвиговый регистр будет содержать все нули.

5. Функция проверки кода CRC.

i = 0;                //обнулим, начнем проверрку с 0-х индексов
j = 0;
while (i != 2)    /*обрабатываем количество устройствначинаем с последнего устройства*/
{         
      crc8 = 0;          
      for (j = 0; j < 7; j++)
      {          
            unsigned char bit_crc; //локальная переменная
            data_crc = data[i][j];
            for (u = 0 ; u < 8; u++)
            {
                        bit_crc = ((crc8 ^ data_crc) & 0×01);
                        if (bit_crc == 0)
                                   crc8 >>= 1;
                        else
                        {
                                   crc8 ^= 0×18;   //  11000 , по модулю т.е. там где0 и 1 будут 1
                                   crc8 >>= 1;      //сдвгаем влево
                                   crc8 |= 0×80;  //+ 1000 0000
                        }
                        data_crc >>=1;
            }
}
if (crc8 == data[i][j]) // если последний байт четности равныто хорошо
{
            i++;
            Display (i); //выводит количество
            _delay_ms (1000);
            j = 0;
}
else
            Display (000); //На индикатор выведутся нули, если ошибки
}

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

Регистры памяти ds18b20

                                                   TEMPERATURE REGISTER FORMAT
Регистр температуры ds18b20Здесь нам важно знать что при положительном результате S = 0, отрицательный S = 1. При 12-битном преобразовании все биты содержат значения, при 11 –битном  0-й неопределен, при 10 – битном 0-й и 1-й, при 9 – битном 0, 1 и 2 биты неопределенны. Это нам поможет при написании кода.

6. Основной цикл выполнения программы.
while (1)
{                     
      for (i = 0; i< 2; i++)     //начинаем с первого датчика
      {
            init_devise ();  //импульс сброса и присутствие
            send_command (0×55); /*MATCH ROM [55h] Соответствие ROM [55h] Команда соответствия ROM, сопровождаемая последовательностью кода ROM на 64 бита позволяет устройству управления шиной обращаться к определенному подчиненному устройству на шине. Только подчиненное устройство, которое точно соответствует 64 битам последовательности кода ROM, ответит на функциональную команду, выпущенную главным устройством. Все другие подчиненные устройства на шине будет ждать импульса сброса.*/
 
// после передадим код устройства к которому обращаемся        
              for (j = 0; j < 8 ; j++)
             {
                        unsigned char data_byte; // переменная для передачи кода
                        data_byte = data[i][j];
                        send_command (data_byte); //передаем побайтово код устройства
              }          
              send_command (0×44); /*Конвертировать температуру [44h]  - эта команда начинает единственное температурное преобразование. После окончания преобразования данные сохраняются в 2-байтовом температурном регистре в оперативной памяти, а DS18B20 возвращается в неактивное состояние с низким энергопотреблением  Если DS18B20 питается от внешнего источника питания, главное устройство может считывать состояние шины после команды Конвертирования температуры [44h]. Если на шине логический «Ноль» — это значит, что DS18B20 выполняет температурное преобразование. Если на шине логическая «Единица» – это значит, что преобразование окончено и можно, считывать данные. */
               while (!read_data ());  /* выполняется цикл до тех пор пока на линии не установится 1*/
                init_devise ();             //импульс сброса и присутствие
                send_command (0×55);         //комманда соответствия
                for (j = 0; j < 8 ; j++)  /*передаем адресс устройствак которому будем обращаться*/
                {
                      unsigned char data_byte; // переменная для передачи кода
                      data_byte = data[i][j];
                      send_command (data_byte); //передаем побайтово код устройства
                 }
                 send_command (0xbe);        /*Чтение памяти [BEh] — эта команда позволяет Устройству управления читать содержание ПАМЯТИ. Передача данных начинается с наименьшего значащего бита байта 0 и продолжается до 9-ого байта (байт 8 — циклический контроль избыточности). Устройство управления может выполнить сброс, чтобы закончить чтение в любое время, если необходимо только часть данных.*/
                 for (j = 0; j < 2; j++)      //считываем первые два байта температуры
                {          
                     unsigned char i;    //локальная переменная для внутреннего цикла
                     unsigned char data_temp = 0×00;
                     for (i = 0; i < 8; i++)
                     {          
                           data_temp >>= 1;
                           if (read_data ())          //если 1, то устанавливаем  старший бит 1
                               data_temp |= 0×80;
                      }
                     temperature[j] = data_temp;
         }
         init_devise (); //сброс для прекращения передачи данных   
// проверим знак , по старшему биту, старшего регистра
         if ((temperature[1]&128) == 0)
          ; // то плюс , зажигаем красный диод
        else
        {          
               temp = ((unsigned int) temperature[1]<<8) | temperature[0]; /* приравниваем двухбайтное число*/
/* В DS18B20 для представления отрицательной температуры используется дополнительный код. Особенность этого кода заключается в том, что он позволяет осуществлять операции вычитания через сложение. Чтобы получить дополнительный код числа, нужно выполнить над числом поразрядную инверсию (~) и прибавить к результату единицу. */
                temp = ~temp + 1;    //инвертируем
                temperature[0] = temp;
                temperature[1] = temp>>8; 
                ;  //то минус , зажигаем зеленый диод
       }          
       temp_int = ((temperature[1]&7)<<4)|(temperature[0]>>4); /*выводим  целое знач. температуры*/
//выделяем с помощью битовой маски дробную часть
       temp_float = (temperature[0]&15);
    //преобразуем в целое число
 /* Для перевода дробной части температуры в градусы, нужно умножить ее значение на 0,0625.*/
       temp_float *= 0.0625; //делим на 16 или умножаем на 0.0625 
       Display (temp_int + temp_float );//Выводим результат на индикатор
       _delay_ms (2000);     
       temp_int = 0;
       temp_float = 0;
       }              
    }            // закрывающая скобка бесконечного цикла
}      // закрывающая скобка основной программы

Термометр ds18b20 и семисегментный индикаторЭтот код я связал с кодом с предыдущего поста, подключение семисегментного индикатора. На рисунке слева виден результат работы в железе на AVR. В последующих записях мы научились программу разбивать на библиотеки с возможностью настройки кода под свой «камень» и порты, там же исходники. Так что  пробуем пишем, меняем, эксперементируем, оставляем комментарии.  Здесь исходник выше приведенного кода и результатат в железе:

temperatura ( Скачали: 1725 чел. ) 

В следующей статье рассмотрим небольшой помощник для работы с микроконтроллерами — Atmega fusebit doctor. Который выручит в случаях, когда происходит неправильная конфигурация, либо другие непредвиденные ситуации и кажется что микроконтроллер «умер». Меня он выручил не раз.  На этом все. До скорой встречи.

Литература:

1. DS18B20 Programmable Resolution 1-Wire Digital Thermometer .DS18B20 русское описание работы с датчиком температуры. (2009).

Просмотрено 35160 раз.

Я на Google+

ds18b20 and 1-wire на AVR. Подключение. Программа на Си. Шаг №6: 56 комментариев

  1. Здравствуйте! К сожалению, прикрепленный файл пуст. Не получается посмотреть полный код программы

    • Здравсвуйте! Спасибо Вам за сигнал, что файл пуст, вообще непонятная ошибка, перезаписал путь в плагине и вроде как пошло... ну да ладно. Качайте на здоровье

      • Спасибо огромное за оперативность! И за проект. Всё толково и доступно изложено.

  2. Здравствуйте!

    Извиняюсь за дурацкий вопрос, я новичёк в программировании.

    Подскажите пожалуйста, в массиве data[i][j]; i- это количество подключаемых датчиков?

    • Здравствуйте. Вопрос вполне нормальный. i- это количество подключаемых датчиков.

  3. Спасибо!

    И ещё один вопрос. Чтобы функция поиска искала четыре датчика

    будет достаточно до функции задать массив:

    unsigned char data [4] [8];

    а в функции поиска изменить for (i = 0; i < 2; i++) , на for (i = 0; i < 4; i++)?

    Или есть нюансы?

    Проверяю в железе с двумя датчиками всё работает хорошо, а когда подключаю третий bit 1 и bit 2 = 1 т.е. как будто датчики не подключены, не понимаю, может временные слоты нужно корректировать?

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

  4. Доброго времени суток!Не подскажете как можно убрать десятые и добавить буквуС,или знак градус.

    • Здравствуйте в программе есть строка

      temp_int = ((temperature[1]&7)< <4)|(temperature[0]>>4); //выводим целое знач. температуры

      дальше следует строка вещественног числа ее мы закоиентируем, ну и передаем только целое значение

      Display (temp_int);

      далее изеняем функцию передачи на дисплей

      void Display (int Number)

      {

      short unsigned int Num1, Num2, Num3;

      Num1=Num2=0;

      while (Number >= 10)

      {

      Number -= 10;

      Num1++;

      }

      Num2 = Number;

      Elem1 = Slot[Num1];

      Elem2 = Slot[Num2];

      }

      и прерывание

      ISR (TIMER0_OVF_vect)

      {

      PORTB &= 0x3e; //Очистка PB7, PB6, PB0

      for (j = 0; j< =30; j++){} // Задержка для выключения транзистора

      (k == 3) ? k = 0 : k++;

      switch (k)

      {

      case 0:

      PORTB |= (1 < < PINB7); // отвечает за вывод знака градусы

      PORTD = 195; //активируем ножку, отвечающую за элемент a,f,e,d, на индикаторе, который покажет минус

      break;

      case 1: PORTB |= (1 < < PINB6); // Десятки

      PORTD = Elem2;

      break;

      case 2: PORTB |= (1 < < PINB0); // Сотни

      PORTD = Elem1;

      }

      }

      Код проверил — работает. Выводит бездесятыхи знак.

  5. Здравствуйте, пожалуйста подскажите как подключить более 2х датчиков? Спасибо.

    • Здравствуйте. Код я давно разбил на библиотеки. Так что переходите нв статью №21. В конце статьи исходник целого проекта. Там библиотеки для датчика температуры. Открывайте заголовочный файл ds18b20.h. В нем строка #define kol_vo 2. Вот тут и пробуйте менять цифру количества датчиков. Пробуйте должно работать, если что пишите, подкорректирую.

  6. Здравствуйте, взял код из статьи 21, всё равно если более 2х датчиков, то виснет. Пожалуйста подскажите как подключить больше.

    • Здравствуйте. Завтра постараюсь добраться до устройство, подключу третий датчик. По идее должно все работать. Короче проверю в железе и отпишу Вам.

    • Быстренько накидал три датчика в протеусе — работает. Конечно протеус не показатель, но все же. Ладно завтра попробую в железе.

  7. Здравствуйте. Спасибо, буду у себя искать в чем проблема, может в том что мой проект в CodeVision. Соберу в AvrStudio. Меня интересует только поиск датчиков, все остальные функции у меня есть. Хочу перенести проект на STM32 (компилятор IAR 6.30). В CovdeVisionAVR есть функция w1_search из за неё я не могу перенести проект (выдрать w1_search из CodeVision не получается, я даже EXEшник внутри перекопал). Все другие библиотеки что нашел в инете рассчитаны на работу с одним датчиком.

  8. Спасибо автору за большую проделанную работу!

    Но я желаю начать освоение DS18B20 с работы с одним Датчиком.

    Прошу упростить код для случая когда всего один Датчик на линии.

    • В статье №21 можно скачать архив с исходниками. Там код разнесен по хидерам. Там же можно настроить ножку контроллера и количество датчиков на линии.

  9. Разрешите добавить уточнения.

    1. Используемый микроконтроллер ATmega16.

    2. Программа-среда WinAVR.

    3. Индикатор с общим катодом.

    4. Используемые пины микроконтроллера:

    — PD0 (линия 1-Wire);

    — PC0 ... PC7 (сегменты Индикатора);

    — PD1, PD4, PD5 (сигналы на базы транзисторных ключей для подключения катодов на общий провод);

    — PB0 (красный светодиод);

    — PB1 (зелёный светодиод).

    5. Код предельно уменьшить (отказ от поиска Датчика и от использования кода CRC).

    6. Желательно ввести функцию ввода значений Верхней температуры и Нижней температуры в регистры TH и TL (кнопками через пины PD2, PD3, PB2).

    7. Желательно вывести сигнал для включения/выключения нагревательного котла (пин PB3) (сигнал для управления транзисторным ключом включающим реле с контактами).

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

    • Здравствуйте я думаю Вы уже сами разобрались. Вывод по середине данные.через 4,7 кОм подсоединяется к +.

  11. На плюс подсоединял датчик микросхема не видит, если на минус то видит. Если я вам пришлю свою программу можете посмотреть что не так?

  12. проверил, мне кажется у меня сам датчик неисправен. Программа у вас правильная я думаю. Как вы думаете они часто отказывают?

    На моей плате еще установлена DS1302, которая как часы работает у вас нет примеров для нее?

    • Здравствуйте. Бывает такое что они изначально не работают, зависит от партиии. Программой не я один пользовался поэтому рабочая. C DS1302 не работал, но я думаю программ в нете куча, перепешите по себя.

  13. но я посмотрел она похожа на 1307, на которую у вас есть программа. Попробую.

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

      • Бывает иногда, но чаще просто где то отошел контакт.

  14. нашел ошибку в программе и часы пошли. Хотел вас спросить, многие и вы том числе пишите про Proteus, что это за программа, можно ли ее скачать бесплатно где-нибудь?

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

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

    • Да Григорий, конечно можете разместить основной код,только в статье приближеной темы №30 или 32. Каждый труд достоин внимания.

      • ок. Попробую в ближайшее время.

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

      • Вот смотрите, в инициализации у вас написано (!(PINC & 0×04)) — так в тексте который я скачал по вашей ссылке, хотя на сайте выложено PINC2. Как же все таки правильно? Пробовал запускал только инициализацию работает корректно только если PINC2 и тоже самое касается функции чтения там нужно писать PINC или PINC2?

      • Здравствуйте Григорий. В общем в 21 — й статье скачайте архив там код для датчика разделен. 1-й исходник, 2 — хидер — внем настрлоите под себя, ножка контроллера, кл- во датчиков.

    • Кажется я понял в чем ошибка, у меня резистор стоит больше на 12 кОм, может в этом ошибка. Датчику не хватает сил чтобы просаживать этот уровень. МОжет в этом дело?

      • Может конечно и в этом быть.

  17. Здравствуйте, у меня какая то ерунда с задержками, то есть я пишу 485 мкс, а он реально после компиляции в 3 раза меньше дает, поэтому он и не работал, пробую экспериментирую где ошибка не пойму. Вы в AVR Studio пишите или нет? delay.h тоже вроде правильно включаю.

  18. Программу сделал, заработала, но опять же к задержкам шел методом тыка. Пришел к следующему выводу чтобы более менее соответствовало программе при компиляции выставляю частоту 11.98 МГц, после компиляции пошагово прогоняю программу смотрю что с задержками (процессор при этом пишет что работает на 4 МГц, как его поменять не знаю), а саму Атмегу 8 выставляю на 8 МГц фьюз-битами, тогда работает, микросекунды соответствуют тому что написано в программе. А миллисекунды нет, чтобы они соответствовали надо ставить 16 МГц. Программу упростил до предела, так как датчик у меня один. Исходя из вышеизложенного у меня к вам несколько вопросов, какие вы используете данные при компиляции, то есть в окошке выбора микросхемы и частоты генератора вы какую частоту пишете? Можно ли в Винавре поменять частоту процессора? Я конечно еще совсем дилетант, но сам я не нашел как это сделать. Фьюз-битами вы насколько выставляете атмегу?

    • Здравствуйте Григорий. Пишу в WinAVR.Прошиваю через avrstudio. Он же использует библиотеки WinAVR. Я писал код под 1 МГц. delay стандартная библиотека по временым задержкам. Меняете частоту в железе, указываете в Makefile, ищете может еще где прописывается переопределение связаное чс частотой. Фьюзы не скажу. Нет под рукой железа. Ну в общем как то так.

  19. Сделал программу где есть часы и датчик температуры. Но датчик неточно показывает завышает где то на 2 градуса пол. Темп. Отрицательные после минус 10 некорр. Показывает. Вы уверены в правильности преобр. При выводе отриц. Темп.?

      • Здравствуйте, можете объяснить по фьюз битам, как их правильно выставлять. Если я купил кварц на 8 МГц, в фьюз — калькуляторе мне что выбирать? Внешний резонатор или внешняя RC — цепочка. Понимаю что пишу не в тему, но просто я думаю вам было бы хорошо написать статью про фьюз-биты.

  20. Здравствуйте, мне кажется у вас ошибка в коде чтения бита.

    У вас написано:

    unsigned char read_data (void)

    {

    unsigned char bit;

    cli (); //Запретим общие прерывания

    DDRC |= _BV (PC2); //1 — выход

    PORTC &= ~_BV (PC2); //0

    _delay_us (15); //задержка 15 мкс

    //«отпускает», управление передается датчику

    DDRC &= ~_BV (PC2); //0 — вход

    PORTC &= ~_BV (PC2); //0

    bit1 = (PINC & 0×04);

    _delay_us (45); //задержка 1 мкс ,перед записью следующего бита

    sei (); // разрешаем прерывания

    return bit;

    }

    должно быть:

    unsigned char read_data (void)

    {

    unsigned char bit;

    cli (); //Запретим общие прерывания

    DDRC |= _BV (PC2); //1 — выход

    PORTC &= ~_BV (PC2); //0

    //«отпускает», управление передается датчику

    DDRC &= ~_BV (PC2); //0 — вход

    PORTC &= ~_BV (PC2); //0

    _delay_us (15); //задержка 15 мкс

    bit1 = (PINC & 0×04);

    _delay_us (45); //задержка 1 мкс ,перед записью следующего бита

    sei (); // разрешаем прерывания

    return bit;

    }

    необходима задержка 15 мкс перед чтением данных с датчика

  21. Насчет AVRStudio могу сказать так я и не разобрался как сделать, чтобы он точно выставлял длительности импульсов, переписал код в CODEVision там он работает, выглядит так:

    unsigned char read_data (void)//

    {

    unsigned char s;//

    #asm («cli»); //

    PORTC.2=0;;//0

    DDRC.2=1;

    DDRC.2=0;/

    delay_us (15);//

    s = PINC.2;

    delay_us (45);

    #asm («sei»);//

    return s; //

    }

  22. Еще хочу сказать, что датчик выдает показания некорректно, команды инициализации, опроса, чтения и т.д. разогревают его на 3-4 градуса, то есть корректные показания можно получить в первые 5-10 минут его работы. Чтобы более менее точно он работал просто из его показаний вычитаю цифру 4. Может у кого была такая проблема и он знает как ее решить?

    • Здравствуйте Григорий. Что б не было саморозогрева рекомендуют использовать не чаще двух измерений в минуту

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

Ваш e-mail не будет опубликован.

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Subscribe without commenting