temp ujemne w DS 1820 / DS 18B20
-
elektronWielki
- Użytkownik
- Posty: 247
- Rejestracja: 30 maja 2006, 12:45
- Lokalizacja: kontownia
temp ujemne w DS 1820 / DS 18B20
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?
pierwszy pomiar jest z reguly poprawny ale kolejne to jakies bzdury.
mial ktos podobny problem?
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
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
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.
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
piotruś
https://elportal.pl/dom
piotruś, przy wklejaniu kawałka kodu programu uzywaj tagów np.
bedzie bardziej czytelne
Kod: Zaznacz cały
Kod: Zaznacz cały
void DS18xxTempObl(u08 TOi)
{
static s16 temperature;
static s16 temp;
...
}
-
elektronWielki
- Użytkownik
- Posty: 247
- Rejestracja: 30 maja 2006, 12:45
- Lokalizacja: kontownia
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.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).
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 
-
elektronWielki
- Użytkownik
- Posty: 247
- Rejestracja: 30 maja 2006, 12:45
- Lokalizacja: kontownia
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.
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.
-
elektronWielki
- Użytkownik
- Posty: 247
- Rejestracja: 30 maja 2006, 12:45
- Lokalizacja: kontownia
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.
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.