Приветствую Вас, Гость! Регистрация RSS

Суббота, 20.04.2024
Главная » Статьи » Cтатьи

Подключение датчика ds18b20 к микроконтроллеру ATmega8535


В комплекте с CodeVisionAVR имеется библиотека ds18b20.h ( соответственно в составе с ds18b20.lib ), которая позволяет работать с датчиком температуры ds18b20 - основная задача, заключается в предоставлении значения измеренной температуры. В этой статье поговорим о некоторых, наиболее применимых функциях библиотеки.


Небольшой обзор

DS18B20 – это цифровой термометр с программируемым разрешением, от 9 до 12–bit, которое может сохраняться в EEPROM памяти прибора. DS18B20 обменивается данными по 1-Wire шине и при этом может быть как единственным устройством на линии так и работать в группе. Все процессы на шине управляются центральным микропроцессором.
DS18B20 состоит из ПЗУ содержащее 64-битный последовательный код, который позволяет, общаться с множеством датчиков DS18B20 установленных на одной шине, контроллера MicroLAN, температурного датчика, двух регистров для хранения верхнего и нижнего порогов температуры и регистра конфигурации. Регистр конфигурации позволяет пользователю устанавливать разрешающую способность цифрового преобразователя температуры к 9, 10, 11, или 12 битам, это и влияет на время конвертирования температуры.
Термометр не содержит внутреннего источника, а использует "паразитное” питание от однопроводной шины. Однако при измерении температуры и записи данных в ЭППЗУ ток потребления микросхемы превышает 1 мА, в то время как максимальный ток, который может обеспечить ведущий шины с помощью нагрузочного резистора 1,5…5 кОм, составляет 3,3…1 мА. Применение внешнего источника питания ускоряет преобразование температуры, поскольку от ведущего шины не требуется ожидания в течение максимально возможного времени преобразования. В этом случае все приборы DS18B20, расположенные на шине, могут выполнять преобразование температуры одновременно и во время обмена данными шины MicroLAN.
После завершения преобразования полученное значение сравнивается с величинами, хранящимися в регистрах TH и TL. Если измеренная температура выходит за установленные пределы, устанавливается сигнальный "флаг” (впрочем, его установка производится после каждого измерения). Выходные температурные данные DS18B20 калиброваны в градусах Цельсия.


Внешний вид датчика в разных, корпусных исполнениях

Расположение выводов


 

1- GND – корпус.
2- DQ – линия ввода\вывода данных.
3- Vdd – питание датчика.


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

На один датчик

 

С множеством датчиков

null

Программная часть. Подключение одного датчика

Подключим единственный датчик к микроконтроллеру atmega8535. Теперь начинаем творить программную часть. Подключаем к основному коду программы заголовочный файл ds18b20.h

#include
<ds18b20.h>


Чтобы начать работать с одним датчиком, достаточно воспользоваться двумя функциями:

Функция инициализации

ds18b20_init( адрес датчика, нижний порог Т, верхний порог Т, разрешающая способность );


функция чтения температуры

ds18b20_temperature( адрес датчика );

Структура будущей программы

...
...
void main( void )

  ...
  ...
 
  if( //инициализация ds18b20 ) //Проверяем, есть ли устройство на линии 1-wire
  {  
   
    while( 1 ){ //Цикл, в котором выполняется чтение и вывод значения температуры на LCD
   
    if( ) { } //Проверяем считанную температуру на отрицательное значение
   
    if( ) { } //Аварийное состояние считанной температуры
   
    }
  }else{ } //Ошибка - устройство не найденно 
}


Полный код программы:

//Цель: производим чтение температуры и выводим на LCD индикатор
#include <mega8535.h>
#include <delay.h>
#include <stdio.h>
#include <lcd.h>
#asm
  .equ __lcd_port=0x15; PORTC
#endasm
#include
<ds18b20.h>
#asm  
  .equ __w1_port=0x1B; PORTA
  .equ __w1_bit=0 
#endasm

int temper;                //Переменая для хранения значения температуры
unsigned char lcdBuff[16]; //Массив для хранения фоматированной строки

#pragma rl+
char *str1="найден датчик ds18b20";
char *str2="датчик ds18b20 отсутствует";
#pragma rl-

void main( void )
{
  lcd_init( 16 );
  lcd_clear( );
   
  if( ds18b20_init( 0, 30, 60, DS18B20_12BIT_RES ) ) //инициализация датчика. Анализ присутствия датчика
  {
    lcd_clear( ); lcd_puts( str1 ); delay_ms( 1000 );  
   
  while( 1 ){
   
    temper=ds18b20_temperature( 0 ); //Чтение температуры, адрес нуль
    delay_ms( 30 );
   

  //Анализ на отрицательную температуру

  if( temper>1000 ) { temper=4096-temper; temper=-temper; }
//если переменая temper больше 1000
                                                            //То вычитаем от 4096 значение
                                                            //переменой temper и далее
                                                            //присваиваем ей знак минус

   
 
if( temper>60 ) { /* какая-либо функция, например alarm ( ); */ } //Аварийное состояние считанной температуры
  sprintf( lcdBuff,"t %u\xdfC", temper ); //помещаем форматированую строку в массив
 
  //выводим на индикатор значение температуры
  lcd_clear( ); lcd_gotoxy( 0,0 ); lcd_puts( lcdBuff ); }
   
  }else{ lcd_clear( ); lcd_puts( str2 ); }  
}




Если необходимо выводить значение температуры с точностью до одной сотой, необходимо в функции
sprintf заменить тип формата %u на %.3f
( как использовать этот тип формата, будет описано ниже ) и переменную temper объявить как float.

Описание программной части


Функция инициализации датчика ds18b20:

unsigned char ds18b20_init( unsigned char *addr, signed char temp_low, signed char temp_high, unsigned char resolution );

*addr            – адрес датчика ( ROM данные ), к которому обращается микроконтроллер в случае, когда их много.
                         Если датчик один, то всегда нуль.  
temp_low      - значение нижнего порога температуры
temp_high    - значение верхнего порога температуры
resolution  – установка разрешающей способности цифрового преобразователя температуры к 9, 10, 11, или 12
                        битам. Принимает значения:  
• DS18B20_9BIT_RES
• DS18B20_10BIT_RES
• DS18B20_11BIT_RES
• DS18B20_12BIT_RES

Функция возвращает положительное значение в случае присутствия датчика на линии 1-wire.

Функция чтения температуры:

float ds18b20_temperature( unsigned char *addr );

*addr – адрес датчика, к которому обращается микроконтроллер в случае, когда их много. Если датчик один, то всегда нуль.
Функция возвращает число с плавающей точкой значения температуры ( тип float )
 

Подключение двух датчиков

При подключении более одного датчика ds18b20 на линию 1-wire, необходимо выполнять чтение ROM каждого датчика, чтоб обращаться к каждому индивидуально. Используя функцию w1_search, производим поиск устройств 1-wire, тем самым выясняем их количество на линии и производим чтение ROM данных каждого датчика:

unsigned char devices;
unsigned char rom_code[2][9];

devices=w1_search( 0xF0, rom_code ); //0xF0 можно заменить на DS18B20_SEARCH_ROM_CMD


null 

Переменная devices будет содержать целое число найденых устройств 1-wire ( датчики ds18b20 ), а массив rom_code будет содержать 8байт ( 64бита ) уникального кода датчика ds18b20. Этот код имеет следующий состав:

 

Теперь по прочитанному ROM-коду можно обращаться к соответствующим датчикам.

Полный код программы

#include <mega8535.h>
#include <delay.h>
#include <stdio.h>
#include <lcd.h>
#asm
  .equ __lcd_port=0x15; PORTC
#endasm
#include <ds18b20.h>
#asm  
  .equ __w1_port=0x1B; PORTA
  .equ __w1_bit=0 
#endasm 

#pragma rl+
char *str1="ЧТЕНИЕ ТЕМПЕРАТУРЫ";
char *str2="No SENSOR!";
#pragma rl-

unsigned char devices;
unsigned char LcdBuffDevices[20];
unsigned char RomCode[2][9];
unsigned char LcdBuff1[20];
unsigned char LcdBuff2[20];

void main( void )
{
  lcd_init( 20 );
  lcd_clear( );
   
  devices=w1_search( DS18B20_SEARCH_ROM_CMD, RomCode ); //поиск датчиков на линии 1-wire
   
  if( devices )
  {
    sprintf( LcdBuffDevices,"DS18B20 = %u", devices ); //выводим информацию о кол-ве датчиков
   
    lcd_gotoxy( 0,1 ); lcd_puts( LcdBuffDevices ); lcd_gotoxy( 0,0 ); lcd_puts( str1 );
   
    ds18b20_init( &RomCode[0][0], 30, 60, DS18B20_12BIT_RES ); //инициализация первого датчика
    ds18b20_init( &RomCode[1][0], 30, 60, DS18B20_12BIT_RES ); //инициализация второго датчика

  while( 1 )
  {
    //чтение температуры первого датчика
    sprintf( LcdBuff1,"t1 %.2f \xefC", ds18b20_temperature( &RomCode[0][0] ) );
 
    lcd_gotoxy( 0,2 ); lcd_puts( LcdBuff1 );
   
    //чтение температуры второго датчика
    sprintf( LcdBuff2,"t2 %.2f \xefC", ds18b20_temperature( &RomCode[1][0] ) );
 
    lcd_gotoxy( 0,3 ); lcd_puts( LcdBuff2 ); }
   
  }else{ lcd_gotoxy( 0,0 ); lcd_puts( str2 ); }
}

Текст и значение температур выводил на 4 строчный по 20 символов индикатор.  Проект использования двух датчиков ds18b20

Впрочем инициализацию можно не выполнять, в том случае, если от датчика не требуется чтение «аварии», тем более по умолчанию установлено 12 битное значение преобразования температуры. 

Вспомним функцию sprintf ( Функция sprintf стандартной библиотеки stdio.h ).Используем тип формата f число с плавающей точкой в записи с фиксированной десятичной точкой, т.е:

%.0f – без вывода после запятой   t 20 'C
%.1f – единицы                            t 20.6 'C
%.2f – десятки                            t 20.62 'C
%.3f – сотки                               t 20.625 'C


Чтобы данный тип формата работал в функции, необходимо в среде CodeVisionAVR зайти в Configure the project выбрать вкладку C Compiler, Code Generation выбрать из списка (s)printf Features строку float, width, precision 



Цикл программы, в котором происходит чтение температуры датчиков

while( 1 )
  {
    //чтение температуры первого датчика
    sprintf( LcdBuff1,"t1 %.2f \xefC", ds18b20_temperature( &RomCode[0][0] ) );
    lcd_gotoxy( 0,2 ); lcd_puts( LcdBuff1 );
   
    //чтение температуры второго датчика
    sprintf( LcdBuff2,"t2 %.2f \xefC", ds18b20_temperature( &RomCode[1][0] ) );
    lcd_gotoxy( 0,3 ); lcd_puts( LcdBuff2 );
  }


Можно изменить на такой, более удобный


unsigned char 
num=1;
while( 1 )
  {
    //чтение температуры датчиков (  испытание на два датчика )
    do{ sprintf( LcdBuff1,"t%u %.2f \xefC",num, ds18b20_temperature( &RomCode[j][0] ) );  
  
    lcd_gotoxy( 0,j );
    lcd_puts( lcdBuff );
   
    if(
--num<devices ){}else{ num=1; }
   
    }while( ++j<devices );
   
    if( j==devices ) { j=0; }
  }




Подключение датчиков на разные биты порта

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



Категория: Cтатьи | Добавил: Автор (19.10.2010)
Просмотров: 79502 | Комментарии: 25 | Теги: программирование ds18b20, схема подключения ds18b20, Датчик ds18b20, подключение двух датчиков ds18b20, чтение rom кода ds18b20 | Рейтинг: 4.2/5
Всего комментариев: 251 2 »
1 ai92  
0
Спасибо за статью! Всего за час, потраченный, на чтение текста и самостоятельное опробывание кодов, я научился большему чем за неделю лазания по инету в поисках ответов на бональные вопросы. А главное я наконец то начал понимать как формируются классические куски кода, которые используют все, но никто не объясняет как они работают. Я думаю, что о таких вещах так и надо писать (исли уж пишешь статью для обучения). Хотелось бы еще подбной инфы.

2 Автор  
0
Спасибо ai92 за отзыв по статье. Стараюсь и буду стараться писать статьи в таком плане smile

3 Дима  
0
Code

while( 1 )
{
//чтение температуры первого датчика
sprintf( LcdBuff1,"t1 %.2f \xefC", ds18b20_temperature( &RomCode[0][0] ) );
lcd_gotoxy( 0,2 ); lcd_puts( LcdBuff1 );

//чтение температуры второго датчика
sprintf( LcdBuff2,"t2 %.2f \xefC", ds18b20_temperature( &RomCode[1][0] ) );
lcd_gotoxy( 0,3 ); lcd_puts( LcdBuff2 );
}

Не пойму а где же проверка на отрицательное значение?


4 Автор  
0
Попробуй эту запись__
Code

float temper_one;
float temper_two;

    while( 1 )    
    {
      //чтение температуры первого датчика   
     temper_one = ds18b20_temperature( &RomCode[0][0] );
      if( temper_one > 1000 ) { temper_one = 4096-  temper_one; temper_one = -temper_one; }   
      sprintf( LcdBuff1,"t1 %.2f \xefC", temper_one  );
      lcd_gotoxy( 0,2 ); lcd_puts( LcdBuff1 );    

      //чтение температуры второго датчика
     temper_two = ds18b20_temperature( &RomCode[1][0] );
      if( temper_two > 1000 ) { temper_two = 4096-temper_two; temper_two = -temper_two; }
      sprintf( LcdBuff2,"t2 %.2f \xefC", temper_two );
      lcd_gotoxy( 0,3 ); lcd_puts( LcdBuff2 );    
    }

25 123LancerX  
0
Может глупый вопрос, я учусь. Откуда взялось 1000 для сравнения? почему нужно от 4096 отнимать значение temper?
4096 это понятно откуда. Мы выбрали в настройках датчика 12бит. а дальше? Если можно поподробней.

5 Дима  
0
Вот спасибо =)) Тут вижу =))

6 Дима  
0
Вот какой вопросик когда просто датчики опрашиваю эта программка работает но вот когда совмещаю несколько кусочков уже своих программ то после того как ставлю Configure the project выбрать вкладку C Compiler, Code Generation выбрать из списка (s)printf Features строку float, width, precision Ну как бы работу с плавающей точкой то выдает ошибку error in library: C:\cvavr\inc\math.h line:26, function doesyh`t math previous declaration. Тоесть получается что просто с датчиками работает эта плавающая точка как часы по и2с подключаю начинает ругаться что же делать? =))

7 Артем  
0
Отличная статья!!! Автору респект!
тоже за час времени разобрался с кодом.
У меня возник вопрос:
А как подключить 4 датчика и более?
У меня не получается подключить больше двух...
вот так я пишу:
Code

//чтение температуры третьего датчика
sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[0][1]) );

lcd_gotoxy( 0,3 ); lcd_puts( LcdBuff3 );
if ( ds18b20_temperature(&RomCode[0][1])<-55)
{
lcd_gotoxy( 0,3 ); lcd_puts( str3 );
}
else
{
sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[0][1]) );
lcd_gotoxy( 0,3 ); lcd_puts( LcdBuff3);
}
//-----------------------------------------------------------------------

//чтение температуры четвертого датчика
sprintf( LcdBuff4,"K %.1f \xefC", ds18b20_temperature(&RomCode[1][1]) );

lcd_gotoxy( 10,3 ); lcd_puts( LcdBuff4 );

if ( ds18b20_temperature(&RomCode[1][1])<-55)
{
lcd_gotoxy( 10,3 ); lcd_puts( str4 );
}
else
{
sprintf( LcdBuff4,"K %.1f \xefC", ds18b20_temperature(&RomCode[1][1]) );
lcd_gotoxy( 10,3 ); lcd_puts( LcdBuff4 );
}
}

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

8 Дима  
0
Ну мне кажется что по поводу 4 датчиков

Code

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[0][4]) );

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[1][4]) );

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[2][4]) );

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[3][4]) );

9 Дима  
0
А нет
Code

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[0][0]) );

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[1][0]) );

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[2][0]) );

sprintf( LcdBuff3,"U %.1f \xefC", ds18b20_temperature(&RomCode[3][0]) );

10 Николай  
0
Тоесть если я правильно понил,то 4 датчика будут одновременно работать и на табло будит выдаваться 4 измерения так,а мегу 8 возможно использовать?

12 Автор  
0
Так и есть, будут выводиться 4 температуры, но в случае с индикатором на 4-строки, если с инд. 2-строки, то нужно выводит сперва 2 значения, очищать экран и выводить следующие два. Мега 8 подойдет.

11 Николай  
0
Люди дайте пожалуста совет,правильно ли я написа в 10 ветке?

13 Алексей  
0
народ помогите при возникновении радиопомех вызваных искрением в оборудовании датчик температуры глючит , что делать?

1-10 11-17
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]