В этой статье займемся изучением практического применения цифровых датчиков температуры 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) делаем преобразование целой и дробной части значения температуры и выводим на дисплей.
Рисунок 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_MSB, Temp_LSB, 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 buffer; 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_LSB = read_18b20(); // Читаем первые 2 байта блокнота Temp_MSB = read_18b20(); temp_flag = 1; // Флаг знака температуры равен 1(плюс) // Вычисляем отрицательную температуру if(Temp_MSB &(1 << 3)) // Проверяем бит знака температуры на равенство единице { signed int temp; temp_flag = 0; // Флаг знака равен 0(минус) temp = (Temp_MSB << 8)|Temp_LSB; temp = -temp; // Переводим дополнительный код в прямой Temp_LSB = temp; Temp_MSB = temp >> 8; } // Вычисляем целое значение температуры buffer = ((Temp_MSB << 4) & 0x70)|(Temp_LSB >> 4); temp_int_1 = buffer % 1000 / 100; temp_int_2 = buffer % 100 / 10; temp_int_3 = buffer % 10; // Вычисляем дробное значение температуры if(temp_flag == 0) buffer = (Temp_LSB & 0x0F) + 1; else buffer = (Temp_LSB & 0x0F); temp_point = buffer * 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 Количество загрузок: 7 537 | Скачать |
Комментарии
только пока так
Код:
// Вычисляем дробное значение температуры
if(temp_flag == 0) buffer = (Temp_LSB & 0x0F) + 1; // Корректировка
else buffer = (Temp_LSB & 0x0F);
temp_point = buffer * 625 / 1000; // Точность темпер.преобразования(0.0625)
Этой операцией
Код:
((Temp_MSB << 4) & 0x70)
выделяем из старшего байта регистра температуры 8,9 и 10 биты, т.е. сначала сдвигаем их в левую часть и применяем маску 0x70, чтобы убрать все не нужные биты
Изучаете информацию о портах ввода/вывода данного микроконтроллер а, а за управление портами отвечают регистры такие как PORTx, DDRx