Изучаем 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) принять 12 байт(по умолчанию);
10) выделить и проанализировать бит десятых долей градуса с установленной точностью, в нашем примере это 0,0625;
11) проанализировать бит знака;
12) если знак отрицательный, то перевести значение температуры в дополнительный код;
13) делаем преобразование целой и дробной части значения температуры и выводим на дисплей.

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

Рисунок 1.

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

Для общения микроконтроллера с датчиком понадобятся три функции:

  • функция инициализации или сброса датчика DS18B20_init;
  • функция чтения одного байта из датчика read_18b20;
  • функция записи одного байта в датчик write_18b20;

Для отсчета временных задержек используем стандартную функцию AVRStudio util/delay.h, также для корректной работы датчика необходимо прописать в компиляторе реальную тактовую частоту микроконтроллера:

#define F_CPU 8000000UL

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

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

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

// Массив значениий для семисегментного индикатора
char SEGMENTE[] = 
{
0x3F, // 0 
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F, // 9
0x40, // "минус" 
0x00  // "пусто"
};
unsigned char segcounter = 0;
volatile unsigned char display_1, display_2, display_3, display_4;

// Прерывание по переполнению T2, динамическая индикация
ISR (TIMER2_OVF_vect)
{  
PORTD = 0xFF;
PORTB = (1 << segcounter);
     
switch (segcounter)
{  
case 0:
PORTD = ~(SEGMENTE[display_1]);
break;
case 1:
PORTD = ~(SEGMENTE[display_2]);
break; 
case 2:
PORTD = ~((SEGMENTE[display_3])|0x80); // добавляем точку
break;     
case 3:
PORTD = ~(SEGMENTE[display_4]);
break;     
}
if ((segcounter++) > 2) segcounter = 0; 
}

unsigned char Temp_H, Temp_L, OK_Flag, temp_flag;

// Инициализация DS18B20
unsigned char DS18B20_init(void)
{
DDRC |= (1 << PC0); // PC0 - выход
PORTC &= ~(1 << PC0); // Устанавливаем низкий уровень
_delay_us(490);
DDRC &= ~(1 << PC0); // 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, data = 0;
for(i = 0; i < 8; i++)
{      
DDRC |= (1 << PC0); // PC0 - выход
_delay_us(2);       
DDRC &= ~(1 << PC0); // PC0 - вход
_delay_us(4);       
data = data >> 1; // Следующий бит      
if(PINC & (1 << PC0)) data |= 0x80;
_delay_us(62);
}  
return data;
}

// Функция записи байта в DS18B20
void write_18b20(unsigned char data)
{
unsigned char i;   
for(i = 0; i < 8; i++)
{
DDRC |= (1 << PC0); // PC0 - выход
_delay_us(2);          
if(data & 0x01) DDRC &= ~(1 << PC0);
else DDRC |= (1 << PC0);
data = data >> 1; // Следующий бит
_delay_us(62);
DDRC &= ~(1 << PC0); // PC0 - вход 
_delay_us(2);
}  
}

// Главная функция 
int main(void)           
{
// Настройка портов ввода/вывода
DDRB |= (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3); // Разряды
PORTB = 0x00;
DDRD = 0xFF; // Сегменты
PORTD = 0x00;
// Настройка Т2
TIMSK |= (1 << TOIE2); // Разрешение прерывания по Т2
TCCR2 |= (1 << CS21);  // Предделитель на 8
     
unsigned int temp = 0;
unsigned int temp_int_1,temp_int_2,temp_int_3; // Переменные для целого значения температуры
unsigned int temp_point; // Переменная для дробного значения температуры

sei(); // Глобально разрешаем прерывания
     
while(1)
{
// Если датчик не ответил выводим "минус" во всех разрядах                      
if(OK_Flag) display_1 = display_2 = display_3 = display_4 = 10;

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))   // Проверяем бит знака температуры на равенство единице
{          
temp_flag = 0;      // Флаг знака равен 0(минус)
temp = (Temp_H << 8)|Temp_L;
temp = -temp; // Переводим дополнительный код в прямой
Temp_L = temp;
Temp_H = temp >> 8;
}      

// Вычисляем целое значение температуры
temp = ((Temp_H << 4) & 0x70)|(Temp_L >> 4);
temp_int_1 = temp % 1000 / 100; 
temp_int_2 = temp % 100 / 10; 
temp_int_3 = temp % 10;

// Вычисляем дробное значение температуры       
temp = (Temp_L & 0x0F) + 1; 
temp_point = temp * 625 / 1000; // Точность темпер.преобразования(0.0625)

// Если флаг знака температуры равен 0, в первом разряде ставим минус         
if(temp_flag == 0) temp_int_1 = 10; // "минус"
// Если первая цифра значения температуры меньше 1, то гасим 1-й разряд индикатора
if(temp_int_1 < 1) temp_int_1 = 11; // "пусто"
// Если первая цифра погашена и вторая цифра значения температуры меньше 1, то гасим 2-й разряд индикатора
if(temp_int_1 == 11 && temp_int_2 < 1) temp_int_2 = 11; // "пусто"
// Если вторая цифра значения температуры меньше 1 и знак равен "минус", то гасим 2-й разряд индикатора
if(temp_int_2 < 1 && temp_flag == 0) temp_int_2 = 11; // "пусто"

// Выводим значения на дисплей
display_1 = temp_int_1;
display_2 = temp_int_2;
display_3 = temp_int_3;
display_4 = temp_point;

}
}


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

Метки: DS18B20

Печать Электронная почта

Комментарии  

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

Авторизация