temp ujemne w DS 1820 / DS 18B20

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
elektronWielki
Użytkownik
Posty: 247
Rejestracja: 30 maja 2006, 12:45
Lokalizacja: kontownia

temp ujemne w DS 1820 / DS 18B20

Post autor: elektronWielki » 17 sie 2006, 20:08

dlaczego termometr DS 1820 i DS 18B20 w temperaturze ponizej zera podaja nieprawidlowe wyniki?

pierwszy pomiar jest z reguly poprawny ale kolejne to jakies bzdury.

mial ktos podobny problem?

Awatar użytkownika
radzio
Użytkownik
Posty: 573
Rejestracja: 07 gru 2004, 23:06
Lokalizacja: Sosnowiec
Kontakt:

Post autor: radzio » 17 sie 2006, 20:20

A czy procerudki konwersji odczytanych danych na postać czytleną dla człowieka są dostosowane do odczytu liczb ujemnych? Sporo przykładowych kodów obsługuje tylko temperatury dodatnie.

piotruś
-
Posty: 22
Rejestracja: 05 gru 2005, 23:44
Lokalizacja: Białystok
Kontakt:

Post autor: piotruś » 17 sie 2006, 20:25

Funkcja obliczająca temperaturę z DS18xx

void DS18xxTempObl(u08 TOi)
{
static s16 temperature;
static s16 temp;
temp=0;
temp=(u16)(DS18ScrBuf[1]<<8);
temp+=DS18ScrBuf[0];
//temp=DS18ScrBuf[0];
//temp|=(DS18ScrBuf[1]<<8); // złóż w 16-bitową ze znakiem
if (EEReadByte(TOi*0x20+1)==DS1820FamilyCode)
{
temp>>=1; // teraz usuń bit 0,5oC - tylko całkowite stopnie
temperature=(10*(temp*DS18ScrBuf[7]+(DS18ScrBuf[7]-DS18ScrBuf[6])-DS18ScrBuf[7]/4));
temperature /= DS18ScrBuf[7];
}
if (EEReadByte(TOi*0x20+1)==DS18B20FamilyCode)
{
temperature=(10*temp/16);
}
REJ_BUF[TOi*8+tempH]=(temperature>>8);
REJ_BUF[TOi*8+tempL]=(u08)temperature;
}

i wyświetlająca ja na LCD

void DS18xxword2dec(u16 val, char *s)
// zamienia zmienną val(0..65536) z formatu binarnego na ciąg znaków ASCII ( 5 znaków )
// czas trwania ok. 1512cm (136us)
{
//s[0]='0'+(val/10000); // to nie będzie wykorzystywane
// s[0] przeznaczony jest na znak -/spacja(+)
s[1]='0'+((val-((val/10000)*10000))/1000); // tysiące ( setki oC )
if (s[1]=='0') s[1]=' '; // likwiduj niepotrzebne zera
s[2]='0'+((val-((val/1000)*1000))/100); // setki ( dziesiątki oC )
if (s[1]=='0'&&s[2]=='0') s[2]=' '; // jeżeli dziesiątki równe 0 i jednocześnie setki
// =0, to zlikwiduj to zero
s[3]='0'+((val-((val/100)*100))/10); // dziesiątki ( jedności oC )
//s[4]='0'+((val-((val/100)*10))%10); // gdy ta instrukcja, to czas trwania 1941cm
//s[4] przeznaczony jest na przecinek
s[4]=',';
s[5]='0'+(val%10); // jedności ( dziesiąte części oC )
s[6]=0;
}

//-------------------------------------------------------------------------------------------
void DS18xxTempDisplay(char x, char y, u08 TDi)
// funkcja wyświetla temperaturę odczytana z i-tego termometru
// format wyświetlanej temperatury jest taki
// znak/setki/dziesiątki/jedności/przecinek/dziesiąte części/ np. 123,5 lub -12,6
{
static s16 temp;
static char s[6];
//temp=TempOblDS1820();
//temp=DS18B20TempObl();
temp=(u16)(REJ_BUF[TDi*8+tempH]<<8);
temp+=REJ_BUF[TDi*8+tempL];
if (temp&0x8000) // jeżeli temperatura ujemna
{
temp=((~temp)+1); // zamień liczbę z kodu U2 na zwykły
DS18xxword2dec(temp,s);
s[0]='-'; // znak minus
LCDWriteTextXY(x,y,s);
}
else
{
DS18xxword2dec(temp,s);
s[0]=' '; // zlikwiduj znak minus
LCDWriteTextXY(x,y,s);
}
LCDWriteTextXYP(x+6,y,PSTR("oC")); // narazie małe o jako znaczek stopni
}
całość skompilowana za pomoca WinAVR

elektronWielki
Użytkownik
Posty: 247
Rejestracja: 30 maja 2006, 12:45
Lokalizacja: kontownia

Post autor: elektronWielki » 18 sie 2006, 8:07

piotruś pisze: void DS18xxTempObl(u08 TOi)
{
static s16 temperature;
static s16 temp;
temp=0;
temp=(u16)(DS18ScrBuf[1]<<8);
temp+=DS18ScrBuf[0];
//temp=DS18ScrBuf[0];
//temp|=(DS18ScrBuf[1]<<8); // złóż w 16-bitową ze znakiem
if (EEReadByte(TOi*0x20+1)==DS1820FamilyCode)
{
temp>>=1; // teraz usuń bit 0,5oC - tylko całkowite stopnie
temperature=(10*(temp*DS18ScrBuf[7]+(DS18ScrBuf[7]-DS18ScrBuf[6])-DS18ScrBuf[7]/4));
temperature /= DS18ScrBuf[7];
}
if (EEReadByte(TOi*0x20+1)==DS18B20FamilyCode)
{
temperature=(10*temp/16);
}
REJ_BUF[TOi*8+tempH]=(temperature>>8);
REJ_BUF[TOi*8+tempL]=(u08)temperature;
}

mozesz podac komentarze? zastanawia mnie co robi funkcja EEReadByte()

[ Dodano: 2006-08-19, 10:55 ]
ktoś miał podobne problemy podczas budowy termometru na tym czujniku? Nie chodzi mi o to że mam problem z konwersją dwóch bajtów na temperature ale z tym, że czujnik podaje bzdury przy temperaturze ujemnej, czasami poda prawdziwą ale większośc odczytów to bzdury jakieś.
Dotyczy to czujników DS1820 jak i DS18B20.

Dodam, że czujnik umieszczam w wodzie zamykam w zamrażalniku i wyjmuje jako bryłkę lodu z wystającym kabelkiem.

Nie sprawdzam sumy kontrolnej scratchpada.

piotruś
-
Posty: 22
Rejestracja: 05 gru 2005, 23:44
Lokalizacja: Białystok
Kontakt:

Post autor: piotruś » 19 sie 2006, 18:10

Kod który podałem pochodzi z 8-kanałowego rejestratora temperatury z termometrami rodziny DS18xx. Na początku trzeba zarejestrować każdy z czujników i jego parametry sa wpisywane do pamięci EEPROM mikrokontrolera, m.in. podawany jest typ czyjnika. Funkcja EEReadByte() odczytuje jaki jest typ czujnika w danym kanale pomiarowym i w zależości od tego wybiera sposób obliczania temperatury. Dla DS18B20 jest duzo mniej obliczeń. Polecam lekturę noty katalogowej AVR318 dostepnej na stronie ATMEL'a. Jak znajdę chwilke czasu, to opiszę swoje "przygody" z termometrami Dallas'a(Maxima).

piotruś

https://elportal.pl/dom

Wojtek
Moderator
Posty: 2606
Rejestracja: 04 sie 2002, 19:00
Lokalizacja: --
Kontakt:

Post autor: Wojtek » 19 sie 2006, 18:38

piotruś, przy wklejaniu kawałka kodu programu uzywaj tagów np.

Kod: Zaznacz cały

void DS18xxTempObl(u08 TOi) 
{ 
  static s16 temperature; 
  static s16 temp; 
  ...
}
bedzie bardziej czytelne

elektronWielki
Użytkownik
Posty: 247
Rejestracja: 30 maja 2006, 12:45
Lokalizacja: kontownia

Post autor: elektronWielki » 19 sie 2006, 19:12

piotruś pisze:Kod który podałem pochodzi z 8-kanałowego rejestratora temperatury z termometrami rodziny DS18xx. Na początku trzeba zarejestrować każdy z czujników i jego parametry sa wpisywane do pamięci EEPROM mikrokontrolera, m.in. podawany jest typ czyjnika. Funkcja EEReadByte() odczytuje jaki jest typ czujnika w danym kanale pomiarowym i w zależości od tego wybiera sposób obliczania temperatury. Dla DS18B20 jest duzo mniej obliczeń. Polecam lekturę noty katalogowej AVR318 dostepnej na stronie ATMEL'a. Jak znajdę chwilke czasu, to opiszę swoje "przygody" z termometrami Dallas'a(Maxima).
Nie w tym problem. Z rozróżnieniem typu czujnika oraz wszystkimi innymi przeszkodami już sobie poradziłem. Pytam teraz czy przy ujemnych temperaturach isnieje duże ryzyko błędnego pomiaru i czy konieczne jest sprawdzanie sumy kontrolnej bajtów ze scratchpada. Termometr wariuje przy temperaturach ujemnych, przy dodatnich daje poprawne wyniki.

Daymian
-
Posty: 82
Rejestracja: 25 lip 2006, 21:23
Lokalizacja: Bochnia
Kontakt:

Post autor: Daymian » 19 sie 2006, 19:43

Czujniki te przy temperaturach dodatnich podają prawidłowe wyniki ponieważ jeden z bitów odpwiedzialnych za znak liczby nie wpływa na wynik. Jeśli temperatura spadnie poniżej zera to znak sie zmienia czyli bit ten zmienia swój stan na przeciwny...i tu pojawia sie problem bo przy odczyie danych z czujnika trzeba opóścić ten bit i wykorzystać go jako "-". Liczba złożona z pozostałych bajtów odpowiada prawidłowej temperaturze...ten bajt to...poszukaj w Data Sheets tych czujników :grin:

elektronWielki
Użytkownik
Posty: 247
Rejestracja: 30 maja 2006, 12:45
Lokalizacja: kontownia

Post autor: elektronWielki » 19 sie 2006, 20:20

Daymian
Dzięki za pomoc ale widze, ze sam niedokladnie przeczytales datasheet.
Temperatura zapisana jest na dwóch bajtach w kodzie U2. W zależności od modelu (1820 lub 18B20) znak stanowi kilka bitów w rejestrze MSB, oznaczonych przez "S" w datasheet.

Przy odczycie danych wystarczy, ze złoży sie te 2 bajty w 16-bitową zmienną signed int i dalej juz pozostaje arytmetyka.
Co do odczytu wartości bezwzględnej zakodowanej w kodzie U2 to sprawa nie wygląda tak prosto. Dla wartości dodatnich wiadomo nic nie trzeba zmieniac, ale dla wartości ujemnej wszystkie bity trzeba zanegowac a następnie dodac 1 do rejestru. I otrzymujesz wartosc bezwzgledna.

Daymian
-
Posty: 82
Rejestracja: 25 lip 2006, 21:23
Lokalizacja: Bochnia
Kontakt:

Post autor: Daymian » 19 sie 2006, 20:36

Kurde, rzeczywiście, coś dziś niemrawy jestem :oops:
Ja używałem gotowych kawałków programu z EdW więc nie miałem problemu...a Wy to w czym konkretnie macie problem? W artmetyce czy...napiszcie bo nie jarze dziś za bardzo :oops: :mrgreen:

elektronWielki
Użytkownik
Posty: 247
Rejestracja: 30 maja 2006, 12:45
Lokalizacja: kontownia

Post autor: elektronWielki » 19 sie 2006, 21:02

Ja to mam problem tak, ze nikt nie chce czytac moich postów.

piotruś
-
Posty: 22
Rejestracja: 05 gru 2005, 23:44
Lokalizacja: Białystok
Kontakt:

Post autor: piotruś » 20 sie 2006, 15:14

Poszukałem w swoich notatkach i okazało się, że miałem sporo problemów z układami DS1820 kiedy trzeba było mierzyć temperatury bliskie 0oC ( konkretnie z zakresu -0,2oC do +0,2oC). Okazało sie, że jest to związane z zawartościa rejestrów Count_per_c i count_remain oraz sposobem obliczania temperatury przez moje procedury. W zasadzie problem został rozwiązany, poprzez przerobienie procedury obliczajacej temperaturę, ale dla pewności zrezygnowałem z układów DS1820 na rzecz DS18B20. Z tym modelem nie miałem problemów. Taki termometr pracował przez całą ostatnią zimę na zewnątrz i wskazania były poprawne. Ponizej zamieszczam komentarz do oprogramowania które umieściłem wcześniej.
Dla DS18B20
// obliczenia odbywać się będą na podstawie formuły (DS18B20-pomiar z rozdz.12bitów !!!)
// temperatura=(10*temp_read(16bitów))/16
// liczba 16-bitowa odczytana z DS18B20 musi być pomnożona przez 0,0625 ponieważ jest to
// najmniejszy "krok" temperatury - mnożone jest przez 0,625 ponieważ wynik jest w
// dzięsiątych częściach oC ( jak przy DS1820 )
// ostatecznie odczyt z DS jest mnożony przez 10 i dzielony przez 16 (*0,0625)
// wynik będzie liczbą 16-bitową ze znakiem (U2) w następującym formacie
// bit.15 ustawiony(1) mówi, że temperatura jest ujemna
// wynik 289=28,9oC

Dla DS1820
// obliczenia odbywać się będą na podstawie formuły
// temperatura={10*(temp_read*count_per_C+(count_per_C-count_rem)-Count_Per_C*0,25)}/count_per_C
// wynik będzie liczbą 16-bitową ze znakiem (U2) w następującym formacie
// bit.15 ustawiony(1) mówi, że temperatura jest ujemna
// wynik 289=28,9oC

Wybrałem taki sposób obliczeń, żeby nie używać zmiennych zmiennoprzecinkowych.

ODPOWIEDZ