Изучаем DS1820/DS18B20. Делаем простой термометр

Рейтинг:  5 / 5

Звезда активнаЗвезда активнаЗвезда активнаЗвезда активнаЗвезда активна
 

В этой статье займемся изучением практического применения цифровых датчиков температуры DS18B20. Сделаем простой термометр на семисегментных индикаторах, который будет показывать положительную и отрицательную температуру с разрешением 0,1 градус Цельсия. Для этой цели используем микроконтроллер Atmega8, который работает от внутреннего генератора частотой 8 МГц, семисегментный индикатор с общим анодом(четырехразрядный) и датчик температуры DS18B20. Схема устройства показана на рисунке 1. Шину данных датчика подключаем к порту PC0, а также подключаем к плюсу питания через резистор R1 номиналом 4,7 кОм, поскольку выходной транзистор датчика имеет открытый сток. При питании датчика от шины данных(паразитное питание) вывод 3 датчика остается свободным.

Как уже известно последовательность действий при работе с одним датчиком будет такая:

1) послать сигнал обнуления линии (480...960 мкc);
2) принять импульс присутствия или заполнить время паузой (60...240 мкc);
3) послать команду пропуска идентификации 0xCC;
4) послать команду начала преобразования 0x44;
5) пауза не менее 500 мкc для завершения процесса преобразования;
6) обнулить линию;
7) послать команду пропуска идентификации 0xCC;
8) послать команду считывания блокнота 0xBE;
9) принять 9 байт;
10) выделить и проанализировать бит десятых долей градуса с установленной точностью, в нашем примере это 0,0625;
11) проанализировать бит знака;
12) если знак отрицательный, то перевести значение температуры в дополнительный код;
13) делаем преобразование целой и дробной части значения температуры и выводим на дисплей.

Подключение термодатчиков DS1820, DS18B20 к микроконтроллерам AVR (часть 2). Делаем простой термометр

Рисунок 1.

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

Для общения микроконтроллера с датчиком понадобятся три функции: функция инициализации или сброса датчика(DS18B20_init();), функция чтения одного байта из датчика(read_18b20();) и функция записи одного байта в датчик(write_18b20();). Для отсчета временных задержек используем стандартную функцию WINAVR util/delay.h, также для корректной работы датчика необходимо прописать в компиляторе реальную тактовую частоту микроконтроллера:

#define F_CPU 8000000UL

или же установить ее в настройках проекта.

Полный текст программы смотрите ниже:

/*** Практическое применение термодатчиков DS18B20. Простой термометр ***/
#define F_CPU 8000000UL // устанавливаем рабочую частоту контроллера
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

//------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9----dp---minus-blank                      
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x80, 0x40, 0x00};
volatile unsigned char segcounter = 0;
volatile int display1 = 0, display2 = 0, display3 = 0, display4 = 0;
/*** Прерывание по переполнению T2, динамическая индикация ***/
ISR (TIMER2_OVF_vect)
{	
PORTD = 0xFF;
PORTB = (1 << segcounter);
	
switch (segcounter)
{	
case 0:
PORTD = ~(SEGMENTE[display1]);
break;
case 1:
PORTD = ~(SEGMENTE[display2]);
break;	
case 2:
PORTD = ~((SEGMENTE[display3])|0x80); // добавляем точку 
break;		
case 3:
PORTD = ~(SEGMENTE[display4]);
break;		
}
if ((segcounter++) > 2) segcounter = 0;	
}
unsigned char Temp_H = 0,Temp_L = 0,OK_Flag = 0,temp_flag;
/*** Инициализация DS18B20 ***/
unsigned char DS18B20_init(void)
{
PORTC &= ~(1 << PC0); // устанавливаем низкий уровень
DDRC |= (1 << PC0);
_delay_us(490);
DDRC &= ~(1 << PC0);
_delay_us(68);
OK_Flag = (PINC & (1 << PC0)); // ловим импульс присутствия датчика
// если OK_Flag = 0 датчик подключен, OK_Flag = 1 датчик не подключен
_delay_us(422);
return OK_Flag;
}
/*** Функция чтения байта из DS18B20 ***/
unsigned char read_18b20(void)
{
unsigned char i;   
unsigned char dat = 0;
for(i = 0;i < 8;i++) 
{		
DDRC |= (1 << PC0);
_delay_us(2);        
DDRC &= ~(1 << PC0);
_delay_us(4);        
dat = dat >> 1;	    
if(PINC & (1 << PC0))
{			
dat |= 0x80; 
}
_delay_us(62);
}	
return dat;
}
/*** функция записи байта в DS18B20 ***/
void write_18b20(unsigned char dat)
{
unsigned char i;	
for(i = 0;i < 8;i++)
{
DDRC |= (1 << PC0);
_delay_us(2);      		
if(dat & 0x01)
{
DDRC &= ~(1 << PC0);	
}
else
{
DDRC |= (1 << PC0);
}
dat = dat >> 1; 
_delay_us(62); 
DDRC &= ~(1 << PC0);
_delay_us(2); 
}	
}
/*** Главная функция ***/
int main(void)            
{
DDRD = 0xFF;
DDRB |= (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3);
PORTD = 0x00;
PORTB = 0x00;
TIMSK |= (1 << TOIE2); // разрешение прерывания по таймеру2
TCCR2 |= (1 << CS21);  // предделитель на 8 
    
_delay_ms(50);
	
unsigned int tempint = 0,tempint1,tempint2,tempint3; // переменные для целого значения температуры
unsigned int temppoint = 0,temppoint1; // переменные для дробного значения температуры
sei(); //глобально разрешаем прерывания
	
while(1)
{				    	
if(OK_Flag == 1) // если датчик не ответил
{
// ставим прочерки во всех разрядах
display1 = 11; display2 = 11;
display3 = 11; display4 = 11;
}
DS18B20_init();        // инициализация DS18B20
write_18b20(0xCC);     // проверка кода датчика
write_18b20(0x44);     // запуск температурного преобразования
_delay_ms(1000);
DS18B20_init();        // инициализация DS18B20
write_18b20(0xCC);     // проверка кода датчика
write_18b20(0xBE);     // считываем содержимое ОЗУ
Temp_L = read_18b20(); // читаем первые 2 байта блокнота
Temp_H = read_18b20(); 
temp_flag = 1;         // флаг знака температуры равен 1(плюс)
if(Temp_H &(1 << 3))   // проверяем бит знака температуры на равенство единице 
{			
signed int tmp;
temp_flag = 0;      // флаг знака равен 0(минус)
tmp = (Temp_H << 8) | Temp_L;
tmp = -tmp;
Temp_L = tmp;
Temp_H = tmp >> 8; 
}		
tempint = ((Temp_H << 4) & 0x70)|(Temp_L >> 4); // вычисляем целое значение температуры
tempint1 = tempint % 1000 / 100;  
tempint2 = tempint % 100 / 10;  
tempint3 = tempint % 10;        
temppoint = Temp_L & 0x0F; // вычисляем дробное значение температуры
temppoint = temppoint * 625;       // точность температуры 
temppoint1 = temppoint / 1000;        
		
if(temp_flag == 0) // если флаг знака температуры равен 0, в первом разряде ставим минус
tempint1 = 11;
if(tempint1 < 1) // если первая цифра значения температуры меньше 1, то гасим 1 разряд индикатора
tempint1 = 12;
if(tempint1 == 12 && tempint2 < 1) // если первая цифра погашена и вторая цифра значения температуры меньше 1, то гасим 2 разряд индикатора
tempint2 = 12;
if(tempint2 < 1 && temp_flag == 0) // если вторая цифра значения температуры меньше 1 и знак равен "минус", то гасим 2 разряд индикатора
tempint2 = 12;
// выводим значения на дисплей
display1 = tempint1;
display2 = tempint2; 
display3 = tempint3;
display4 = temppoint1;
}
}


Архив для статьи "Изучаем термодатчики DS1820/DS18B20"
Описание: Проект AVRStudio и Proteus
Размер файла: 53.04 KB Количество загрузок: 5 654 Скачать

Метки: DS18B20

Печать E-mail

Комментарии  

0 #121 Михаил_001 22.08.2018 20:30
И все-таки как вы решили, проблему что на датчике -0.2 показывает -0.1, в протеусе?
Сообщить модератору

Авторизация