подсобите пожалуйста с Dallas-ом DS18B20
- Войдите на сайт для отправки комментариев
Втр, 05/04/2016 - 21:55
Господа ардуинщики, ай нид хэлп.
Реализую для души симпатичный проект часы+температура: ОLED дисплейчик, RTC и Dallas DS18B20. Задумал плату под это дело, нарисовал уже. Корпус будет тоже хендмейд. Сделаю, если кого заинтересует, выложу результат. Сам проект с гиктаймса, наверняка многим известный:https://geektimes.ru/post/255556/.
Казалось бы, что может быть проще. Аффтар оставил архив с софтом, вся мат часть закуплена на ебэе. Повозился с удовольствием, всё работает. НО.
Dallas DS18B20 отказывался показывать температуру.На экране последовательно в случайном порядке появлялись цифры 1,3, 4. И всё. Сразу скажу, что с датчиком всё ОК - скетчи-примеры из библиотек на UNO (сам
проект на NANO) он прекрасно отрабатывал. Кусок скетча в части Dallas-а:
void temp() {
for(int x = 0; x < 10; x++){
byte data[2];
ds.reset();
ds.write(0xCC);
ds.write(0x44);
delay(350);
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
data[0] = ds.read();
data[1] = ds.read();
int Temp = (data[1] << 8) + data[0];
Temp = Temp >> 4;
Я, не понимая смысла, но чувствуя подвох, изменил скетч так:
Temp = Temp >> 1; то есть вместо 4 поставил единицу.
После чего температура стала отображаться ПРЕКРАСНО, в единицах градусов (без долей) , но, ссабакка, только от 0 и выше. Минусовую не показывает. Читал даташит, пробовал самостоятельно разобраться с регистрами,вычислениями разницы после пересечения нуля, - не получается.Лазил вокруг самой темы по инету, - тоже не нашёл ответа. Дебил, наверное.
Может кто видел или сам подскажет кусок кода, что добавить , чтобы даллас показывал и минус и температуру в ед. градусов при её отрицат.значениях ?
как раз и отвечает за обрезание долей градуса.
так что с долями градуса нужен:
У вас чего датчик в морозилке показывает? Видима какую то жуткую жару или мороз. ))
Мой вариант на скорую руку:
#include <OneWire.h> OneWire ds(4); void setup() { // put your setup code here, to run once: Serial.begin(9600); } void loop() { Serial.print("T="); Serial.println(temp()); delay(1000); } float temp() { byte data[2]; ds.reset(); ds.write(0xCC); ds.write(0x44); delay(150); ds.reset(); ds.write(0xCC); ds.write(0xBE); data[0] = ds.read(); data[1] = ds.read(); int Temp = (data[1] << 8) + data[0]; float x=Temp/16.0; return x; }Спасибо. Не работает.
SeaWanderer, Интересно, сколько вам нужно ещё сделать экспериментов, что бы заметить что у вас датчик DS18S20, а примеры вы неизмено пробуете от DS18B20 ? :)
Точно, идрит-пергидрит. А я смотрю в примерах вообще пишут DS18х20, ну и думаю, что разница непринципиальна. А сейчас увидел, что hex таблицы у них разные..
Так, прикольненько. Из-за внимательного dimax в скетче Vad33 теперь если поделить флоат на 2, а не на 16, получим вполне себе температуру вместо абракадабры:
T=28.00
T=28.00
T=27.50
Воистину одна голова -хорошо, а полторы- лучше :). Головам спасибо. Теперь всё-таки хочется по минусу понять, как сделать.
Воистину одна голова -хорошо, а полторы- лучше :). Головам спасибо. Теперь всё-таки хочется по минусу понять, как сделать.
Дык, в морозилку то пробовали или нет? Усе должно работать. ))
У меня сейчас нет ни датчика ни морозилки, но в теории все работает.
В примере подменяю реальные данные, данными как должно быть из таблицы:
#include <OneWire.h> OneWire ds(4); void setup() { // put your setup code here, to run once: Serial.begin(9600); } void loop() { Serial.print("T= "); Serial.println(temp()); delay(1000); } float temp() { byte data[2]; ds.reset(); ds.write(0xCC); ds.write(0x44); delay(150); ds.reset(); ds.write(0xCC); ds.write(0xBE); // data[0] = ds.read(); // data[1] = ds.read(); data[0] = 0xff; // Подменяем data[1] = 0xff; // то что нужно int Temp = (data[1] << 8) + data[0]; float x=Temp/2.0; return x; }В скетче нужна отдельная формула пересчёта данных из байта температуы при обнаружении бита минуса. Где-то видел в инете, но вот по-моему, не для DS18S20.
Утку уже съели, кролик осталссо...
if (Temp>4040) { Temp=Temp-4095; //здесь выводим знак минус };ну и далее выводим Temp как обычно
примерно так.
Вообще по мануалу нужно читать 9 байт и их анализировать. мы читаем только 2.
Чтобы избавится от долей нужно при выводе перевести данные в целое, функцией int( <число> ),
как вариант.
Такое впечатление, что после -8 градусов датчик отрубается и начинает выдавать FF FF
Может он на морозе тупить начинает и нужно задержку для расчета увеличивать раза в 3-5 ?! ))
Вот еще есть похожий скрипт:
#include <OneWire.h> // получаем температуру от DS18S20 OneWire ds(4); // линия 1-Wire будет на pin 4 void setup(void) { Serial. begin(9600); } void loop(void) { byte i; byte present = 0; byte data[12]; byte addr[8]; if ( !ds.search(addr)) { //Serial. print("No more addresses.\n"); ds.reset_search(); return; } /*Serial.print("R="); for( i = 0; i < 8; i++) { Serial.print(addr[i], HEX); Serial.print(" "); }*/ if ( OneWire::crc8( addr, 7) != addr[7]) { Serial.print("CRC is not valid!\n"); return; } if ( addr[0] != 0x10) { Serial.print("Device is not a DS18S20 family device.\n"); return; } ds.reset(); ds.select(addr); ds.write(0x44,1); // запускаем конвертацию delay(1000); // скорее всего достаточно 750ms present = ds.reset(); ds.select(addr); ds.write(0xBE); // считываем ОЗУ датчика /*Serial.print("P="); Serial.print(present,HEX); Serial.print(" ");*/ for ( i = 0; i < 9; i++) { // обрабатываем 9 байт data[i] = ds.read(); Serial.print(data[i], HEX); Serial.print(" "); } /*Serial.print(" CRC="); Serial.print( OneWire::crc8( data, 8), HEX); Serial.println();*/ // высчитываем температуру :) int HighByte, LowByte, TReading, Tc_100; LowByte = data[0]; Serial.print("LB= ");Serial.print(LowByte,HEX); HighByte = data[1]; Serial.print(" HB= ");Serial.print(HighByte,HEX); TReading = (HighByte << 8) + LowByte; Tc_100 = TReading/2; Serial.print(" T = ");Serial.print(Tc_100); Serial.println(); }Задержка впринципе нужна при паразитном питании, при обчном питании датчик будет отдавать показания предидущего преобразования, до тех пор пока не перепишет в регистр показания нового преобразования. При этом есди датчик сконфигурировать на точность 9 бит то для преобразования надо менее 100 мс.
В данном проекте один значительный недостаток - использование RTC DS1307 - эти часы отличаются большой неточностью хода. Если заменить эти часики на DS3231 - которые за год уходят не более чем на 2 минуты - то будет очень хорошо. Даже есть совместимость на уровне регистров отображающих время и дату.
Но главный плюс - в них есть 2 независимых будильника и встроенный датчик температуры с точностью до 0.25 градуса. Только из модуля с DS3231 необходимо выпаять диод, который рассчитан на подпитку аккумулятора, а мы обычно используем батарейку CR2032 (которой хватит больше чем на год) подпитка тольго угробит эту батарейку.
День добрый.
Возможно поможет, сам недавно озадачивался температурой:
if ((data[1]&128) == 0){ //проверяем старший разряд //положительная температура }else{ //отрицательная температура uint8_t tmp; // «склеиваем» нулевой и первый байты ОЗУ датчика tmp = ((uint16_t)data[1]<<8)|data[0]; //выполняем операцию логического отрицания tmp = ~tmp + 1; //помещаем результат в соответствующие переменные data[0] = tmp; data[1] = tmp>>8; } //выделяем целую часть temp_1 = ((data[1]&7)<<4)|(data[0]>>4); //выделяем с помощью битовой маски дробную часть temp_2 = (data[0]&15); //преобразуем в целое число temp_2 = (temp_2<<1) + (temp_2<<3);// Умножаем на 10 temp_2 = (temp_2>>4);//делим на 16 или умножаем на 0.0625Смущает
if((data[1]&128) == 0){//проверяем старший разряд128 - 10000000b
флаг S по даташиту устанавливается маской 11111xxxb в MSByte
IMHO правльнее будет
причем отрицательная температура в двичной системе инвертированна
+25.0625°C- 0000 0001 1001 0001
+10.125°C 0000 0000 1010 0010
+0.5°C 0000 0000 0000 1000
0°C 0000 0000 0000 0000
-0.5°C 1111 1111 1111 1000
-10.125°C 1111 1111 0101 1110
-25.0625°C 1111 1110 0110 1111
и разве tmp должна быть int8_t а не int16_t
Это преобразование для DS18B20.
Флаг S с 11 по 15 биты. Недостаточно проверить только старший разряд разве?
S – знак температуры (0 – положительная температура, 1 – отрицательная) BIT15-BIT11, BIT10–BIT4 - целая часть значения температуры, BIT3-BIT0 – дробная часть
В DS18B20 для представления отрицательной температуры используется дополнительный код. Чтобы получить дополнительный код числа, нужно выполнить над числом поразрядную инверсию (~) и прибавить к результату единицу.
tmp = ~tmp + 1;
И да, конечно uint16_t. Опечаточка, спасибо.
Флаг S с 11 по 15 биты. Недостаточно проверить только старший разряд разве?
ssergo,
скетч anatoliyrnd допилить до ума у меня не вышло, несмотря на кажущуюся простоту предложения. Буду допиливать скетч Vad33 из записи№12, благо там похоже просто слэшами удастся закрыть ненужное оставив нужное. Спасибо всем ещё раз.
скетч anatoliyrnd допилить до ума у меня не вышло, несмотря на кажущуюся простоту предложения. Буду допиливать скетч Vad33 из записи№12, благо там похоже просто слэшами удастся закрыть ненужное оставив нужное. Спасибо всем ещё раз.
Вот для DS18b20 полностю рабочая функция с округлением до целых градусов .
float dsconvertdata( byte *znak) { byte celsius; int16_t raw = (data[1] << 8) | data[0]; if ((data[1] & 128) == 0) { *znak = 0; //температура положительлная } else { *znak = 1; //температура отрицательная raw = ~raw + 1; } raw = raw & ~7; // 9 bit resolution //raw = raw & ~3; 10 bit res celsius = byte(raw/16); return celsius; }Только из модуля с DS3231 необходимо выпаять диод, который рассчитан на подпитку аккумулятора,
У меня нет S но насколько я помню 0,1 байты у обоих датчиков это температура, а 8 байт это CRS , вот назначение других байтов разное. Но в нашем случае поидеи должно работать.
Только еденственное не float dsconvertdata а byte dsconvertdata , т.к. функция будет возвращать целое число температуры.
Только из модуля с DS3231 необходимо выпаять диод, который рассчитан на подпитку аккумулятора,
Он у них один. Если на 3231 сделано как на 1307, то еще и резистор из нижнего плеча от батареи.