Продолжаем осваивать периферию, на очереди измерение температуры. Рассмотрим вариант измерения, при помощи датчика температуры DS18b20.
Характеристики датчика: диапазон измерения от -55 до +125°С. Точность измерения ±0,5°С гарантируется в диапазоне от -10 до +85°С. Возможность измерения с разрешением 9, 10, 11 и 12 бит, т.е. с шагом 0,5; 0,25; 0,125; 0,0625°С. Для обмена информацией с AVR микроконтроллером используется 1-Wire протокол. Каждый датчик имеет свой уникальный адрес, поэтому имеется возможность посадить на шину сразу несколько датчиков.
Для сборки схемы понадобится жк дисплей, датчик и резистор на 4,7кОм. Теперь перейдем непосредственно к прошивке.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <mega8.h> #include <delay.h> // 1 Wire Bus functions #asm .equ __w1_port=0x18 ;PORTB .equ __w1_bit=2 #endasm #include <1wire.h> #include <ds18b20.h> // Alphanumeric LCD Module functions #asm .equ __lcd_port=0x12 ;PORTD #endasm #include <lcd.h> #include <stdio.h> char lcd_buf[17]; void main(void) { float temper; lcd_init(16); w1_init(); ds18b20_init(0,-20,50,DS18B20_12BIT_RES); while(1) { temper=ds18b20_temperature(0); sprintf(lcd_buf,"t=%.1f\xdfC",temper); lcd_clear(); lcd_puts(lcd_buf); delay_ms(1500); }; } |
Теперь обо всем по порядку:
1 2 3 4 | #asm .equ __w1_port=0x18 ;PORTB .equ __w1_bit=2 #endasm |
Данный код означает, что датчик подключен к порту В, PB2 ножке
1 2 | #include <1wire.h> #include <ds18b20.h> |
Используется протокол 1wire, тип датчика ds18b20
1 2 3 | float temper; w1_init(); ds18b20_init(0,-20,50,DS18B20_12BIT_RES); |
Переменная temper (с плавающей точкой) используется для хранения температуры,
w1_init(); — ищем датчик,
ds18b20_init(0,-20,50,DS18B20_12BIT_RES); — настройка датчика: 0-номер датчика, -20 -нижний предел измерения, 50 — верхний предел измерения,
DS18B20_12BIT_RES используется 12 битный режим(с шагом 0,0625°С). В принципе настройку можно не производить, по умолчанию выставлен 12 битный режим. Показано лишь для того, чтобы вы могли самостоятельно изменить режим измерения, если это понадобится.
1 2 3 4 5 6 | temper=ds18b20_temperature(0); sprintf(lcd_buf,"t=%.1f\xdfC",temper); lcd_clear(); lcd_puts(lcd_buf); delay_ms(1500); |
temper=ds18b20_temperature(0); — читаем значение температуры с датчика
sprintf(lcd_buf,»t=%.1f\xdfC»,temper); преобразовываем к понятному для lcd виду %.1f — вывод числа с плавающей точкой 1 знак после запятой, не забываем в свойствах проекта указать (s)printf features float.
\xdf — вывод на экран значка градуса.
В результате должно получиться нечто похожее
Отрицательной температуры поблизости не было :D, поэтому попробовал остудить бутылочкой соуса из холодильника, результат что то не сильно впечатлил.
Зато от нагрева рукой, температура довольно быстро повысилась.
Проект доступен тут
Проект для DS18s20
Проект для двух датчиков
Проект для DS18b20 на семисегментниках
Проект Алексея(Alyes)для Atmega16 и шести сегментов + бонус видео устройства
Подскажите пожалуйста как программно проверить наличие/отсутствие датчика DS18b20. Есть устройство которое отвечает за вкл\откл нагрузки , необходимо осуществить проверку датчика, и, в случае если он отсутствует вывести соответствующее сообщение. Заранее благодарен .
Артур, будет ли обновление статьи в AVR Studio 6. К code vision возвращаться больше нет желания 😐 . Или лучше задать тему на форуме?
Спасибо!
у протеуса в папке примеров есть исходник для avr studio, будет возможность добавлю в статью
А как найти соответствие того,что возвращается в переменную temper и температурой в градусах цельсий? Например как написать условия, что ,допустим, у меня при -12 градусов включается порт b3(типа термореле)?
if(temper < -12){}
Никак не могу понять уже вторую неделю… Как мне на семисегментнике сделать чтобы поочередно показывали два детчика. У вас прошивка есть только под LCD.
в конце статьи есть примеры и для семисегментников и для нескольких датчиков
как преобразовать чтоб temper через spi перекинуть другому mega8?
spi передает тип char, самое простое — преобразовываете свое число через sprintf в массив символов и отравляете посимвольно. на принимающей стороне собираете.
а к порту С как? на b просто spi находится немного некорректно получается
А вот в примере где два датчика. unsigned char ds18b20_rom_codes [2][9]; Что означают индексы в квадратных скобках?
показывает значение -9999. В чем может быть проблема?
Чудес не бывает, если прошивка в протеусе работает, значит проблема в физ подключениях. Еще вариант, если у вас мк с заводскими фьюзами на 1мгц, а проект под 8мгц. Тогда работать не будет. Меняйте фьюзы при прошивке и все будет ок.
Добрый день!
Подскажите пожалуйста в чем причина, при подключении датчика по вашей схеме температура отображается а при подключении по схеме с паразитный питанием температура показывается 127,9 градусов?
Да и при не имении резистора в 4,7к Ом использовал с номиналом 4,5кОм будет ли это сказываться на работу?
Резистор роли не сыграет. По поводу паразитного питания ничего не могу сказать, не пробовал.
на какой частоте должен работать мк? от внеш кварца или от внутр рц? частота?
8мгц, без разницы от чего тактировать
.equ __w1_port=0x18 ;PORTB
Скажите, как получилось число 0х18?
Допустим для Atmega8 открываем даташит находим таблицу Register summary, 0x18 это адрес портаВ
Спасибо за пояснение. У меня проблема. Сделал термостат на основе вашего урока, на семисегментном индикаторе но переодически загораеться число 83 вместо норм температуры.
С чем это может быть связано?
Динамическая индикация по прерыванию от ТС0, опрос кнопок в прерывании по ТС1, чтение температуры с датчика и деление для вывода на два разряда выделил в функцию и вызиваю в основном цикле. Спасибо.
попробуйте убрать прерывание от кнопок и посмотреть останется ли проблема
Убрал опрос вместе с прерыванием- ничего не изменилось(
Попробуйте в протеусе погонять, будет ли такой же эффект. Я бы вначале убрал все прерывания, все что может мешать считываться температуре.
Вообщем скину исходник посмотрите пожалуйста. P.S В протеусе все так же.#include
#include
#include
#include
static flash unsigned char display[]= // масив для индикатора
{
(~0b11000000), // 0
(~0b11111001), // 1
(~0b10100100), // 2
(~0b10110000), // 3
(~0b10011001), // 4
(~0b10010010), // 5
(~0b10000010), // 6
(~0b11111000), // 7
(~0b10000000), // 8
(~0b10010000) // 9
};
int temper,temper_down,temper_up,temp[2],temp_down[2],temp_up[2];
char i=0,rezhim=0;
bit butt1,butt2,butt3; // биты для кнопок
//////////////////ФУНКЦИЯ ДЕЛЕНИЯ ТЕМПЕРАТУРЫ////////////
void del_temp()
{
temper=ds18b20_temperature(0);
temp[0]= temper/10; // реальная температура
temp[1]= temper%10;
temp_down[0]= temper_down/10; // нижний порог
temp_down[1]= temper_down%10;
temp_up[0]= temper_up/10; // верхний порог
temp_up[1]= temper_up%10;
delay_ms(1500);
}
////////////// ОПРОС КНОПОК ///////////////
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
TCNT1H=0x00;
TCNT1L=0x00;
if(PINB.4==0&&butt1==0)
{
rezhim++;
butt1=1;
if(rezhim>=3) rezhim=0;
}
if(PINB.4==1) butt1=0;
if(rezhim==0) PORTC.3=1; // РЕАЛЬНАЯ ТЕМПЕРАТУРА //
else PORTC.3=0;
if(rezhim==1) // НИЖНИЙ ПОРОГ //
{
PORTC.2=1;
if(PINB.2==0&&butt2==0)
{
temper_down++;
butt2=1;
}
if(PINB.2==1) butt2=0;
if(PINB.3==0&&butt3==0)
{
temper_down—;
butt3=1;
}
if(PINB.3==1) butt3=0;
}
else PORTC.2=0;
if(rezhim==2) // ВЕРХНИЙ ПОРОГ //
{
PORTC.4=1;
if(PINB.2==0&&butt2==0)
{
temper_up++;
butt2=1;
}
if(PINB.2==1) butt2=0;
if(PINB.3==0&&butt3==0)
{
temper_up—;
butt3=1;
}
if(PINB.3==1) butt3=0;
}
else PORTC.4=0;
}
/////////ДИНАМИЧЕСКАЯ ИНДИКАЦИЯ////////////
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTC &= ~(1<=2) i=0;
if(rezhim==0)
{
PORTD=display[temp[i]];
PORTC|=(1<<i);
}
if(rezhim==1)
{
PORTD=display[temp_down[i]];
PORTC|=(1<<i);
}
if(rezhim==2)
{
PORTD=display[temp_up[i]];
PORTC|=(1<<i);
}
}
void main(void)
{
PORTB=0x1C;
DDRB=0x00;
PORTC=0x00;
DDRC=0x1F;
PORTD=0x00;
DDRD=0x7F;
TCCR1A=0x00;
TCCR1B=0x05;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x4E;
OCR1BH=0x00;
OCR1BL=0x00;
// TC0
TCCR0=0x03;
TCNT0=0x00;
TIMSK=0x11;
w1_init();
#asm("sei")
while (1)
{
del_temp(); // вызов функции деления
if(temper=temper_up) PORTC.5=0;
};
}
Попробуйте поменять точность на 9 бит.
Не помогло, только опрос датчика быстрее стал…
пришлите проект со схемой в протеусе sttn@mail.ru
Скажите, как добиться вывода с датчика ds18s20 дробной части? на данный момент выводится только целая часть, после запятой стоит ноль(((
Serafim, в настройках проекта float включить
включил. добился вывода значения с точностью до 0,5. а вот как сделать чтобы точность вывода была 0,1? сейчас сделано вот так:
float temp;
temp=ds1820_temperature_10(0);
sprintf(lcd_buffer,»temp=%.1f\xdfC»,temp/10);
но если в протеусе ставлю шаг датчика 0,1 — значение округляется до 0,5. у вас же на фотках видно, что шаг 0,1.
спасибо!
Инициализацию измените на:
ds18b20_init(0,-20,50,DS18B20_12BIT_RES);
Добрый день!
пробую запустить на atmega168.
но инициализация датчика не проходит, в чем может быть проблема?
проект создал по подобию как в примере, заменив МК на mega168.h
проверьте фьюзы, частоту, подключение
пока пробую в протеусе. не получается никак(( меняю на atmega8 в прошивке и в симуляторе — все работает.
у atmega168 есть еще предделитель основной частоты, он настроен?
Здравствуйте, уважаемый автор. Подскажите пожалуйста, никак не могу понять для чего в программе мы используем массив char lcd_buf[17]; почему именно из 17 символов он состоит? Не понятны для меня так же следующие строки
lcd_clear();
lcd_puts(lcd_buf);
delay_ms(1500);
зачем мы выводим значения массива на дисплей? lcd_puts(lcd_buf);
В CAVR нет понятия строковых переменных, любая строка это массив символов. Экран 8х2 символов, можете сделать массив из 16 символов, это не принципиально.
lcd_clear — очистка экрана
lcd_puts(lcd_buf) — вывод значения температуры на дисплей
delay — задержка
Если вам не нужно выводить значение температуры, можете не выводить массив.
действительно, дело было в частоте))
огромное спасибо!
Добрый день! Хочу заставить микроконтроллер одновременно измерять и температуру через DS18B20 и напряжение через ADC, но твориться какая-то ерунда: при подключении ножки AVCC к +5В вместо температуры отображается -9999, если же из прошивки исключить ADC — все нормально…? И при измерении напряжения на батарейке на дисплее напряжение все время скачет, что это может быть? Заранее спасибо!
Сложно сказать не видя исходник