Датчик температуры DS18B20
- Войдите на сайт для отправки комментариев
Вс, 27/12/2015 - 16:40
Пподскажите пожалуйста. Используется код для вывода температуры на дисплей. Фишка в том, что на дисплее температура постоянно показывается со значениями, например 5.000 градусов, а бывает 5.00 и всё такое. Т.е. разное кол-во нулей. Как сделать наиболее точный вывод температуры, с возможными половинами крадуса ?
Вот код:
#include <LiquidCrystal.h>
#include <OneWire.h>
OneWire ds(13); // Подключаем датчик к 8 цифровому пину
LiquidCrystal lcd(32, 30, 28, 26, 24, 22); //Подключаем LCD
void setup(void)
{
pinMode(9, OUTPUT);
analogWrite(9, 0);
lcd.begin(16, 2); //16 знаков, 2 строки
lcd.print("Temp:"); //Печатаем верхнюю строку LCD
}
void loop(void)
{
byte i;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
// Ищем алрес датчика
if ( !ds.search(addr))
{
Serial.println();
ds.reset_search();
delay(250);
return;
}
// Проверяем не было ли помех при передаче
if (OneWire::crc8(addr, 7) != addr[7])
{
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// Определяем серию датчика
switch (addr[0])
{
case 0x10:
type_s = 1;
break;
case 0x28:
type_s = 0;
break;
case 0x22:
type_s = 0;
break;
default:
return;
}
ds.reset();
ds.select(addr); // Выбираем адрес
ds.write(0x44, 1); // Производим замер, в режиме паразитного питания
delay(10000);
ds.reset();
ds.select(addr);
ds.write(0xBE); // Считываем оперативную память датчика
for ( i = 0; i < 9; i++)
{
data[i] = ds.read(); // Заполняем массив считанными данными
} // Данные о температуре содержатся в первых двух байтах, переведем их в одно значение и преобразуем в шестнадцатиразрядное число
int16_t raw = (data[1] << 8) | data[0]; // Переводим температуру в шкалы по Цельсию и Фаренгейту
if (type_s)
{
raw = raw << 3;
}
if (data[7] == 0x10)
{
raw = (raw & 0xFFF0) + 12 - data[6];
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00)
raw = raw << 3;
else if (cfg == 0x20)
raw = raw << 2;
else if (cfg == 0x40) \
raw = raw << 1;
}
celsius = (float)raw / 16.0;
lcd.setCursor(8, 0); //Пишем в LCD на 2 строке
lcd.print(celsius); //Цельсии
}
lcd.print(celsius , 1)
Вроде так
Ну и это округлит до целых ? Может ли датчик выводить точне значения ? 1.5C; 1,2C и всё остальное ?
Округлит до 1 знака после запятой. Вы бы хоть попробовали сперва.
Разрядность самого датчика при 12бит - 0,00625гр.цельсия
Ну теперь постоянно показывает чисто.ноль. (-4.0 ; 3.0). А хочу, чтоб более точное значение было, с десятым/сотыми. Подскажите пожалуйста.
Х-ня у вас какая то, попробуйте отсюда код, четвертый пост, для одного датчика. В третьей строке впишите адрес своего датчика. Если будет также гнать только целыми, раскомментируйте блок с 12 по 17 строки. Отпишитесь, что получилось.
Вот состряпал такой франкенштейн-код. И на экране просто написанно " -1 ".
#include <OneWire.h> #include <LiquidCrystal.h> OneWire ds(12); LiquidCrystal lcd(32, 30, 28, 26, 24, 22); //Подключаем LCD byte addr[8]={0x28,0x04,0x13,0x80,0x06,0x00,0x00,0xF8}; volatile int celsius; void setup(void) { pinMode(9, OUTPUT); analogWrite(9, 0); lcd.begin(16, 2); //16 знаков, 2 строки lcd.print("Temp:"); //Печатаем верхнюю строку LCD pinMode (13,OUTPUT); WDTCSR=(1<<WDCE)|(1<<WDE); WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); ds.reset(); // сброс шины ds.select(addr); //выставить адрес ds.write(0x4E); // разрешение записать конфиг ds.write(0x7F); // Th контроль температуры макс 128грд ds.write(0xFF); //Tl контроль температуры мин -128грд ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение } void loop(void) { } ISR (WDT_vect){ //вектор прерывания WD static boolean n=0; // флаг работы: запрос температуры или её чтение n=!n; if (n) {ds.reset(); // сброс шины ds.select(addr); // выбор адреса ds.write(0x44); // начать преобразование (без паразитного питания) } else {ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad (чтение регистров) celsius = ds.read() | (ds.read()<<8); //прочитаны 2 байта } lcd.setCursor(8, 0); lcd.print(celsius); }f0rZzZ, вы что, через строчку читаете то, что вам пишут? Перечитайте ещё раз второе предложение из #5
Простите, немного туговат ) Подскажите, как узнать адресс своего датчика ?
Нужно умножить показания на 0,0625. Пример #A8 168*0,0625= 10,5
f0rZzZ, запускаете примеры из OneWire для DS18, какой то из них показывает адреса. Зачем вы создаете себе проблемы, экран на компьютере не работает? Добейтесь сперва нормального считывания, а потом работоспособный код прикручивайте к LCD.
terminal, а откуда вы такое узнали?
Так, ну в терминал выдаёт теперь температуру как и хотелось бы: -5.56
Пподскажите пожалуйста. Используется код для вывода температуры на дисплей. Фишка в том, что на дисплее температура постоянно показывается со значениями, например 5.000 градусов, а бывает 5.00 и всё такое. Т.е. разное кол-во нулей. Как сделать наиболее точный вывод температуры, с возможными половинами крадуса ?
Вот код:
#include <LiquidCrystal.h> #include <OneWire.h> OneWire ds(13); // Подключаем датчик к 8 цифровому пину LiquidCrystal lcd(32, 30, 28, 26, 24, 22); //Подключаем LCD void setup(void) { pinMode(9, OUTPUT); analogWrite(9, 0); lcd.begin(16, 2); //16 знаков, 2 строки lcd.print("Temp:"); //Печатаем верхнюю строку LCD } void loop(void) { byte i; byte type_s; byte data[12]; byte addr[8]; float celsius, fahrenheit; // Ищем алрес датчика if ( !ds.search(addr)) { Serial.println(); ds.reset_search(); delay(250); return; } // Проверяем не было ли помех при передаче if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // Определяем серию датчика switch (addr[0]) { case 0x10: type_s = 1; break; case 0x28: type_s = 0; break; case 0x22: type_s = 0; break; default: return; } ds.reset(); ds.select(addr); // Выбираем адрес ds.write(0x44, 1); // Производим замер, в режиме паразитного питания delay(10000); ds.reset(); ds.select(addr); ds.write(0xBE); // Считываем оперативную память датчика for ( i = 0; i < 9; i++) { data[i] = ds.read(); // Заполняем массив считанными данными } // Данные о температуре содержатся в первых двух байтах, переведем их в одно значение и преобразуем в шестнадцатиразрядное число int16_t raw = (data[1] << 8) | data[0]; // Переводим температуру в шкалы по Цельсию и Фаренгейту if (type_s) { raw = raw << 3; } if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; } else { byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw << 3; else if (cfg == 0x20) raw = raw << 2; else if (cfg == 0x40) \ raw = raw << 1; } celsius = (float)raw / 16.0; lcd.setCursor(8, 0); //Пишем в LCD на 2 строке lcd.print(celsius); //Цельсии }Тут ошибка
data имеет тип byte при сдвиге обнулится, потому делать нужно так
Далее, для получения результата с точностью после запятой делаем следующее
uint16_t cels = raw >> 4; uint16_t mcels = ((raw & 0xF)*625)/100; lcd.print(cels); lcd.print(','); if (mcels < 10) { //добавляем ноль перед дробной частью lcd.print(0); } lcd.print(mcels);Так, ну в терминал выдаёт теперь температуру как и хотелось бы: -5.56
Я вам для чего ссылку дал, чтобы посмотрели, как у Dimax сделаны ваши раскоряченные сдвиги и преобразования. Не нужна "собака", уберите ее и останется два фрагмента - на преобразование и на считывание. Между ними задержка 750мС при 12бит. И крутите эти фрагменты, как вам нравится.
Простите, но так и не разобрался, что подправить для большей выдержки (
#include <OneWire.h> OneWire ds(2); byte addr[8]={0x28,0x04,0x13,0x80,0x06,0x00,0x00,0xF8}; volatile int celsius; void setup(void) { Serial.begin(9600); pinMode (13,OUTPUT); //WDTCSR=(1<<WDCE)|(1<<WDE); //установить биты WDCE WDE (что б разрешить запись в другие биты //WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда // (55 страница <a href="<a href="http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf" rel="nofollow">http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf</a>" rel="nofollow">даташита</a>) // снять все ремарки если нужно поменять разрешение // ds.reset(); // сброс шины // ds.select(addr); //выставить адрес // ds.write(0x4E); // разрешение записать конфиг // ds.write(0x7F); // Th контроль температуры макс 128грд // ds.write(0xFF); //Tl контроль температуры мин -128грд // ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение } void loop(void) { Serial.print(" Temperature = "); Serial.println(celsius/16.0); //ISR (WDT_vect){ //вектор прерывания WD //static boolean n=0; // флаг работы: запрос температуры или её чтение //n=!n; //if (n) ds.reset(); // сброс шины ds.select(addr); // выбор адреса ds.write(0x44); // начать преобразование (без паразитного питания) delay(750); //else ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad (чтение регистров) celsius = ds.read() | (ds.read()<<8); //прочитаны 2 байта }Добавьте инициализацию LCD. После сериалпринтов, напишите аналогично команды для своего LCD. До делая команды на преобразование, после на считывание. В первый проход покажет чушь, все последующие правда.
Что нужно сделать, чтобы сразу показало правду?
Благодарю всех. Сделал, всё шикарно.
Ну, если нет желания поразбираться, ваше право.
Дак я понял в чём суть, подправил что надо и добился желаемого результата.
Так delay(750), это фи. 3/4 секунды программа висит. Если только выводить температуру, без разницы. Начнете приделывать кнопки и прочие фишки, начнет раздражать или непонятно работать. Собака у Dimax не просто так прикручена была.
Ну пока просто температуру и вывожу. А потом хочу попробовать проект Arduino Mega Server
Собака у Dimax не просто так прикручена была.
Alexino, конечно проще, какай разговор! А ещё проще взять даллосовскую библу, и не забивать голову лишними командами. А ещё проще вообще ничего не делать, а лежать на диване и пить пиво. Зачем извращаться и что-то самому колхозить, когда всё можно купить готовое? :)
Ну... скатились до "купить" :) Причём тут это ? Просто для чего использовать какие то нестандартные решения, если для этого есть стандартные ? Нужен периодичный опрос - юзаем системный таймер - это вполне обоснованное и адекватное решение.
Собака... Вообще, на сколько мне известно, собака ресетит чип. В таком случае, использовать её для периодичных интервалов - не совсем айс.
Далласовская библиотека. Тут она тоже немного не в тему. Она не реализует никаких периодичных опросов. Так что, не известно, проще ли её взять.
Ничего не делать. Хм... заманчиво, но не по-нашему :)
Нужен периодичный опрос - юзаем системный таймер - это вполне обоснованное и адекватное решение.
Собака... Вообще, на сколько мне известно, собака ресетит чип. В таком случае, использовать её для периодичных интервалов - не совсем айс.
Что значит не айс? Вотчдог это такой же таймер. Даже в чём-то более удобный, т.к. может работать когда МК спит.
А он не ресетит микроконтроллер ?
Alexino, по желанию. У него три варианта по истечению счёта: только прерывание, только ресет, прерывание и за ним ресет.
Всё ясно. Ну тогда да, как вариант....
Но всё равно, через millis более стандартно ))))))