Алгоритм программы
начало
Инициализация
OK_ввод==1
да нет
Ставим
прочерки Во
всех ридах
Инициализация
И
считыван
(Temp
–H8(1и3)
да нет да
Вычислить
отрецательний
Вычис
целая значен темпер
конец
Краткое описание программы
Скомпилированная программа представляет собой файл типа сof, который прошиваем на микроконтроллер Аtmegа 8 семейства АVR.
Соединяем компоненты рабочей модели прибора, получаем сигнал с температурного датчика, считываем температуру окружающей среды .
Для общения микроконтроллера с датчиком понадобятся три функции:
функция инициализации или сброса датчика(DS18B20_init();), функция чтения одного байта из датчика(read_18b20();) и функция записи одного байта в датчик(write_18b20();). Для отсчета временных задержек используем стандартную функцию WINAVR util/delay.h, также для корректной работы датчика необходимо прописать в компиляторе реальную тактовую частоту микроконтроллера:
Программный код
// Практическое применение термодатчиков DS18B20. Простой термометр
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL // устанавливаем рабочую частоту контроллера //------------------0-----1-----2-----3-----4-----5-----6
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D,
//------------------7-----8-----9-----dp---minus-blank
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,
tempint1 = 12; // то гасим 1 разряд индикатора
if(tempint2 < 1) // если вторая цифра значения температуры меньше 1,tempint2 = 12; // то гасим 2 разряд индикатора
// выводим значения на дисплей
display1 = tempint1; display2 = tempint2;
display3 = tempint3; display4