Stacja meteo, czyli czyszczenie szuflad (2)

Stacja meteo, czyli czyszczenie szuflad (2)

Jednym z etapów pracy nad projektem jest wybór i testowanie elementów składowych tak, aby spełniały założenia konstrukcyjne. Raz użyte moduły najczęściej lądują w szufladach czy regałach i po pewnym czasie może się uzbierać spora ilość dobrego sprzętu, z którym najczęściej nie wiadomo co zrobić. Kontynuujemy opis stacji meteo skonstruowanej zgodnie z założeniem, że użyte zostaną tylko części z zasobów nagromadzonych w szufladach.

Czujnik wilgotności KAmodHTS221

Moduł KAmodHTS221 ma wymiary 14×15×3 mm i podobnie, jak w przypadku KAmodLPS331, na dłuższej krawędzi umieszczono punkty lutownicze z wyprowadzeniami w rastrze 2,54 mm (rysunek 13).

Rysunek 13. Moduł czujnika wilgotności KAmod HTS221

Podobnie, jak moduł barometru, moduł czujnika wilgotności ma możliwość zasilania napięciem z zakresu 2,5…5,5 V. Dwukierunkowe linie danych i zegara wyposażono w układ konwersji poziomów napięć.

Umieszczony na płytce modułu czujnik HTS221 mierzy wilgotność w zakresie od 20% do 80% RH z dokładnością ±4,5%. Pomiar może być wykonywany z częstotliwością od 1 pomiaru na sekundę do 25 pomiarów na 2 sekundy. Oprócz pomiaru wilgotności czujnik mierzy temperaturę od –40°C do +120°C z dokładnością ±0,5°C w zakresie od +15°C do +40°C, oraz ±1°C w zakresie 0°C do +60°C.

Schemat blokowy układu został pokazany na rysunku 14.

Rysunek 14. Schemat blokowy czujnika HTS221

Podstawowym elementem toru pomiaru wilgotności jest sensor pojemnościowy. Jego pojemność zmienia się w zależności od wilgotności otoczenia. Konwersja zmiany pojemności na sygnał napięciowy jest wykonywana we wzmacniaczu Charge OpAmp. Sygnały napięciowe z tego wzmacniacza lub z czujnika napięciowego są konwertowane na postać cyfrową przez 16-bitowy przetwornik analogowo cyfrowy. Do komunikacji z mikrokontrolerem hostem może być zastosowany interfejs I²C lub SPI. My będziemy używać interfejsu I²C. Układ nie ma wyprowadzeń adresowych i 8-bitowy adres slave ma jedną wartość równą 0xBE dla zapisu danych i 0xBF dla odczytu danych.

Podobnie jak w przypadku czujnika ciśnienia konfiguracja parametrów pracy i odczytywanie mierzonych wartości odbywa się przez zapisywanie i odczytywanie wewnętrznych rejestrów. Standardowo będziemy potrzebować dwu funkcji: odczytania zawartości rejestru o podanym adresie i zapisania rejestru o podanym adresie. Zapisanie rejestru rozpoczyna się od wysłania przez mikrokontroler sekwencji START, a po niej adresu Slave 0xBE. Potwierdzenia adresu przez HTS221 pozwala na wysłanie przez mikrokontroler adresu rejestru, a po nim zapisywanej danej (rysunek 15).

Rysunek 15. Sekwencja zapisania rejestru HTS221
Listing 11. Zapisanie rejestru HTS221

#define HTS_ADD 0x5f
//zapisanie rejestru HTS221
void HTS221WriteReg(uint8_t addr, uint8_t data){
I²C1_Write1ByteRegister(HTS_ADD, addr, data);
}

Na listingu 11 została pokazana procedura zapisywania rejestru z dwoma argumentami: addr – adres rejestru i data – dane do zapisania. HTS_ADD to adres slave HTS221. Pamiętamy, że procedury obsługi magistrali I²C wygenerowane przez MCC wymagają podawania adresu 7-bitowego i HTS_ADD ma wartość 0x5F. Odczytanie zawartości rejestru rozpoczyna się od wysłania sekwencji START i adresu Slave z bitem R/W=0 (zapis) i bajt adresu rejestru. Potem jest wysyłana powtórna sekwencja START, adres Slave z bitem R/W=1, a po nim odczytywany jest jeden bajt zawartości zaadresowanego rejestru (listing 12, rysunek 16).

Listing 12. Odczytanie rejestru HTS221

uint8_t HTS221ReadReg(uint8_t addr){
uint8_t data;
data = I²C1_Read1ByteRegister(HTS_ADD, addr);
return(data);
}
Rysunek 16. Sekwencja odczytania rejestru HTS221

Zestawienie rejestrów sterujących i rejestrów wyników pomiarów zostało pokazane w tabeli 4.

Pomiary wilgotności i temperatury mogą być wykonywane na żądanie, po wysłaniu polecenia (one shot), lub w sposób ciągły z określoną częstotliwością. Do programowania częstotliwości pomiarów jest przeznaczony rejestr CTRL_REG1 o adresie 0x20 opisany dokładnie w tabeli 5. Bit PD tego rejestru jest przeznaczony do wprowadzania układu w stan obniżonego poboru mocy, a bit BDU określa czy rejestr z danymi wyjściowymi wilgotności i temperatury ma być odświeżany automatycznie po wykonaniu pomiarów, czy tez po odczytaniu przez mikrokontroler 8 starszych bitów wyniku poprzedniego pomiaru. Po włączeniu zasilania bit PD jest wyzerowany i żeby można było wykonywać pomiary należy do PD wpisać jedynkę.

Wyzerowanie bitów ODR1 i ODR2 wprowadza układ w tryb pomiaru na żądanie. Żeby wyzwolić taki pomiar trzeba ustawić bit ONE_SHOT w rejestrze CTRL_REG2 (tabela 6).

Po wyzwoleniu pomiaru, ale też w trybie pomiaru ciągłego trzeba testować, czy wynik pomiaru został zapisany do rejestrów wyjściowych. Żeby to zrobić należy odczytać zawartość rejestru statusowego STATUS_REG. Ustawienie bitu H_DA (bit b1 STATUS_REG) oznacza, że wynik pomiaru wilgotności został zapisany do rejestrów wyjściowych HUMIDITY_OUT_L i HUMIDITY_OUT_H, a ustawienie bitu T_DA ( bit b0 STATUS_REG) oznacza, że wynik pomiaru temperatury został wpisany do rejestrów pomiaru temperatury. W czasie testów czujnika skonfigurowałem układ do pracy z wyzwalaniem na żądanie i z ustawionym bitem BDU. Procedura inicjalizacyjna została pokazana na listingu 13.

Listing 13. Inicjalizacja czujnika higrometru

void HTS221Init(void){
HTS221WriteReg(0x20,0 );//CTRL_REG1 Power Down
HTS221Cal();//odczytanie współczynników kalibracji
HTS221WriteReg(0x10, 0x1b);//dokładność pomiarów
//CTRL_REG1 Power On, One Shot, Update after read
HTS221WriteReg(0x20, 0x84);
}

W nieulotnej pamięci układu HTS221 umieszczono rejestry z zapisanymi w trakcie fabrycznej kalibracji wartościami kalibracji. W czasie sekwencji włączania zasilania układu dane kalibracyjne są przepisywane z pamięci Flash do rejestrów kalibracyjnych pokazanych w tabeli 7.

W trakcie inicjalizacji układu mikrokontroler musi odczytać dane kalibracyjne po to, aby je potem zastosować przy każdorazowym odczycie wilgotności i temperatury. Procedura odczytu rejestrów kalibracyjnych została pokazana na listingu 14.

Listing 14. Odczytanie rejestrów kalibracyjnych

void HTS221Cal(void){
int16_t T0,T1;
struct {
uint8_t H0_rH_x2;//addr 0x30
uint8_t H1_rH_x2;//addr 0x31
uint8_t T0_degC_x8;//addr 0x32
uint8_t T1_degC_x8;//addr 0x33
uint8_t T1_T0_msb;//addr 0x35
int16_t H0_T0_OUT;//addr 36, 37
int16_t H1_T0_OUT;//addr 3a, 3b
int16_t T0_OUT;//addr 3c, 3d
int16_t T1_OUT;//addr 3e, 3f
}cal;

//współczynniki kalibracji dla wilgotności
cal.H0_rH_x2 = HTS221ReadReg(0x30);
cal.H1_rH_x2 = HTS221ReadReg(0x31);
H0_rh = (float)cal.H0_rH_x2/2;
H1_rh = (float)cal.H1_rH_x2/2;

cal.H1_T0_OUT = HTS221ReadReg(0x3b);
cal.H1_T0_OUT <<= 8;
cal.H1_T0_OUT |= HTS221ReadReg(0x3a);

cal.H0_T0_OUT = HTS221ReadReg(0x37);
cal.H0_T0_OUT <<= 8;
cal.H0_T0_OUT |= HTS221ReadReg(0x36);

H0_ca l= cal.H0_T0_OUT;
H1_cal = cal.H1_T0_OUT;


//współczynniki kalibracji dla temperatury
cal.T0_degC_x8 = HTS221ReadReg(0x32);
cal.T1_T0_msb = HTS221ReadReg(0x35);
T0 = cal.T1_T0_msb&3;
T0 <<= 8;
T0 = T0|cal.T0_degC_x8;
T0_degC = (float)T0/8;

cal.T1_degC_x8 = HTS221ReadReg(0x33);
cal.T1_T0_msb = HTS221ReadReg(0x35);
T1 = (cal.T1_T0_msb & 0x0c);
T1>>= 2;
T1 <<= 8;
T1 = T1 | cal.T1_degC_x8;
T1_degC = (float)T1/8;

cal.T0_OUT = HTS221ReadReg(0x3d);
cal.T0_OUT <<= 8;
cal.T0_OUT |= HTS221ReadReg(0x3c);

cal.T1_OUT = HTS221ReadReg(0x3f);
cal.T1_OUT <<= 8;
cal.T1_OUT |= HTS221ReadReg(0x3e);

T0_cal = cal.T0_OUT;
T1_cal = cal.T1_OUT;
}

W wyniku działania tej funkcji zapisywane są zmienne globalne pokazane na listingu 15.

Listing 15. Zmienne kalibracji

// Temperaturea w stopniach C dla kalibracji
float T0_degC, T1_degC;
// Wyjsciowa wartosc temperatury dla kalibracji
int16_t T0_cal, T1_cal;
// Wilgotnosc dla kalibracji
float H0_rh, H1_rh;
// Wyjsciowa wartosc wilgotnosci dla kalibracji
int16_t H0_cal, H1_cal;

Te zmienne w połączeniu z 16-bitowymi danymi wyjściowymi będą służyły do wyliczenia mierzonej wartości. W przypadku temperatury wartości T0_cal, T1_cal, T0_degC i T1degC są współrzędnymi wyznaczającymi prostą kalibracji – zostało to pokazane na rysunku 17.

Rysunek 17. Wykres prostej kalibracji i wyliczanie temperatury w stopniach Celsjusza

Do zmiennej Treg jest wpisana 16 bitowa wartość odczytana z rejestrów TEMP_OUT_L i TEMP_OUT_H. Mając wartości odczytane z rejestrów kalibracji i wartość Treg wyliczamy wartość temperatury w Staroniach Celsjusza według zależności:

T_C = (Treg – T0_cal))/(T1_cal – T0_cal) * (T1_degC – T0_degC) + T0_degC

Na listingu 16 jest pokazana kompletna procedura wyzwolenia pojedynczego pomiaru, wyliczenia i wyświetlenia zmierzonej temperatury. Wartości kalibracyjne zostały jednokrotnie pobrane z rejestrów i wpisane do zmiennych w momencie inicjalizacji układu i nie ma potrzeby ich pobierać przy każdym pomiarze.

Listing 16. Odczytanie, obliczenie i wyświetlenie temperatury

//odczytanie i wyświetlenie temperatury
void HTS221ReadTemp(char *str){
int16_t Treg, tempt;
float T_C,Temperature;

//start pomiaru
HTS221WriteReg (0x21, 1);//start One shot
//czekaj na dane pomiaru
while((HTS221ReadReg(0x27) & 1) == 0);

Treg = HTS221TempRead();//odczytaj rejestr temperatury
//wylicz temperaturę na podstawie danych kalibracji
T_C = ((float)(Treg – T0_cal))/(T1_cal – T0_cal)
* (T1_degC – T0_degC) + T0_degC;
tempt = (int16_t)(T_C *100);
Temperature = ((float)tempt)/100;
//wyswietl temperature
sprintf(str,”% 4.1f C”,Temperature);
}

Podobnie wygląda sposób postępowania w przypadku odczytywania, przeliczania i wyświetlania wilgotności.

Rysunek 18. Wykres prostej kalibracji i wyliczanie wilgotności w %

Wilgotność jest wyliczana z zależności, której elementy obrazuje rysunek 18:

H_rh = (((H_T – H0_cal))/(H1_cal – H0_cal) * (H1_rh – H0_rh) + H0_rh

Procedura odczytywania przeliczania i wyświetlania wilgotności została pokazana na listingu 17. Jak widać do obliczania wyników niezbędne są wyliczenia z wykorzystaniem biblioteki operacji zmiennoprzecinkowej. Jeżeli dodamy do tego konwersję liczb zmiennoprzecinkowych na łańcuch ascii za pomocą funkcji sprintf i brak optymalizacji w bezpłatnej wersji kompilatora MPLAB XC8 to wiadomo, dlaczego kod wynikowy zajął ponad 50% całej pamięci flash o rozmiarze 16 k słów.

Listing 17. Odczytanie, obliczenie i wyświetlenie wilgotności

//odczytanie rejestrow i wyliczenie kompemsacji
void HTS221ReadHum(char *str){
int16_t H_T, humt;
float H_rh, Hum;

//start pomiaru
HTS221WriteReg(0x21,1);//start One shot
while((HTS221ReadReg(0x27)&2)==0);

H_T = HTS221HumRead();//odczytaj rejestr wilgotnosci
H_rh = ((float)(H_T – H0_cal))/(H1_cal – H0_cal)
* (H1_rh – H0_rh) + H0_rh;
humt = (int16_t)(H_rh * 100);
Hum= ((float)humt)/100;

sprintf(str + 8,”% 2.1f”,Hum);
*(str+13) = ‘%’;
}

Czujnik temperatury DS18B20

Jak wspomniałem na wstępie, do pomiaru temperatury zastosowałem czujnik temperatury DS18B20 z magistralą 1-Wire. Jak wiemy sensory ciśnienia i wilgotności mają swoje własne sensory temperatury mierzące je z wystarczającą dokładnością. Jednak, żeby pomiar nie był zafałszowany czujnik temperatury musi być oddalony od wszelkich lokalnych źródeł ciepła. W praktyce sprowadza się to do wystawienia go do pomiaru na zewnątrz w pewnej odległości od obudowy urządzenia. Umieszczenie czujnika w obudowie urządzenia z pracującymi układami elektronicznymi zawyża pomiar przynajmniej o kilka stopni. Zależy to od wydajności źródeł ciepła w układzie na przykład zasilacza, czy pracującego mikrokontrolera, ale też od rodzaju obudowy. DS18B20 nadaje się idealnie do takiego zastosowania. Magistrala 1-Wire pracuje bez problemu z przewodami o długości 1…2 m, a sam czujnik jest hermetyczny i odporny na warunki atmosferyczne. Używane przeze mnie DS18B20 pracują bezawaryjnie wiele lat w normalnym środowisku wystawione na zewnątrz. Czujnik jest umieszczony w obudowie TO-92 został pokazany na rysunku 19.

Rysunek 19. Obudowa czujnika DS18B20

Do komunikacji z mikrokontrolerem DS18B20 ma wbudowaną 1-przewodową magistralę 1-Wire składającą się z jednej dwukierunkowej linii DQ. Dodatkową zaletą 1-Wire jest programowy mechanizm identyfikacji układu dołączonego do magistrali na podstawie unikalnego kodu zapisanego w pamięci ROM. Ten mechanizm pozwala na dołączenie wielu układów do jednej magistrali. Z założenia wykorzystujemy jeden DS18B20 i oprogramowanie nie obsługuje odczytywania kodów identyfikacyjnych i identyfikacji na magistrali więcej niż jednego czujnika. Każde z urządzeń połączonych magistralą musi mieć wyjście typu otwarty dren, a sama linia sygnałowa DQ jest połączona z plusem zasilania przez rezystor 2...5 kΩ. Dwukierunkowa linia danych DQ może tez spełniać role linii zasilającej układ. Wtedy wyprowadzenia GND i Vdd są zwarte i połączone z masą sterownika, a układ jest zasilany przez rezystor.

Magistrala 1-Wire jest zorganizowana według zasady master-slave. Układem master jest mikrokontroler, a układami slave dołączane do niego czujniki – w tym przypadku termometr DS18B20. Wymiana informacji poprzez magistralę 1-Wire składa się z czterech podstawowych sekwencji:

  • sekwencji inicjalizacji (reset and presence pulses),
  • zapisu zera,
  • zapisu jedynki,
  • odczytu bitu.

W czasie, kiedy nie jest wykonywana żadna z sekwencji linia DQ musi przejść w stan wysoki (stan idle state). Każda wymiana informacji z termometrem (zapisywanie i odczytywanie) DS18B20 zaczyna się sekwencją inicjalizacji wymuszeniem przez mikrokontroler na linii DQ stanu niskiego (impulsu zerowania). Czas trwania tego impulsu to minimum 480 μs (rysunek 20).

Rysunek 20. Sekwencja inicjowania magistrali 1-Wire

W naszym układzie linia DQ jest podłączona do linii portu RC4. Czujnik jest zasilany napięciem +3,3 V

Na listingu 18 pokazano sekwencję presence. Procedura zwraca stan wysoki jeżeli czujnik został wykryty. Mikrokontroler wymusza stan niski na magistrali kiedy linia RC4 jest skonfigurowana jako wyjście (do rejestru portu PORTC4 jest programowo wpisane zero).

Listing 18. Sekwencja inicjowania magistrali 1-wire

//linia DQ port RC4
#define DQ_IO PORTCbits.RC4
#define DQ_TRIS TRISCbits.TRISC4
uint8_t DS_Reset (void){
uint8_t result;

// ustaw na DQ stan niski
//(stan linii 0 i linia wyjściowa)
DQ_TRIS = 0;
DQ_IO = 0;
//odczekaj 480usek
__delay_us(480);
//linia DQ wejściowa
//(stan wysoki ustala rezystor)
DQ_TRIS = 1;
__delay_us(70);

if (DQ_IO)
//stan niski na DQ – błąd
result = 0;
else
//stan wysoki wykryto Presence pulse
result = 1;
//dokończenie sekwencji
__delay_us(480);

return(result);
}

Ustawienie RC4 jako wejście powoduje, że rezystor podłączony pomiędzy RC4 i plus zasilania wymusza na DQ stan wysoki.

Sekwencja zapisywania zera logicznego przez mikrokontroler do termometru została pokazana na rysunku 21.

Rysunek 21. Zapisywanie zera logicznego

Mikrokontroler wymusza stan niski na magistrali przez co najmniej 60 μs. Jednak stan niski nie może trwać dłużej niż 120 μs, bo układ może to zinterpretować jako sekwencję zerowania.

Sekwencja zapisywania jedynki logicznej rozpoczyna się od wymuszenia stanu niskiego na magistrali. Stan ten nie może trwać dłużej niż 15 μs. Po tym czasie na magistrali musi się pojawić stan wysoki przez czas co najmniej 45 μs (rysunek 22).

Rysunek 22. Zapisywanie jedynki logicznej

Uniwersalna Procedura DS_WriteBit zapisuje zero logiczne lub jedynkę zależnie od wartości argumentu val (listing 19).

Listing 19. Zapis bitu na magistrali 1-wire

void DS_WriteBit(uint8_t val){
// na magistrali zero logiczne
//DQ linia wyjściowa
DQ_TRIS = 0;
DQ_IO = 0;

//val = 1 zapisujemy jedynkę
if (val){
// czekaj kilka us
asm (“nop”);
asm (“nop”);
asm (“nop”);
asm (“nop”);
//linia wejściowa
//na magistrali jedynka logiczna
DQ_TRIS = 1;
//zakończ slot czasowy
__delay_us(60);
}else{
//przez 60us zero logiczna
__delay_us(60);
// Ustaw jedynkę logiczną
DQ_TRIS = 1;
//zakończ slot czasowy
__delay_us(10);
}
}

Zapisanie dowolnej danej 8-bitowej jest już proste (listing 20).

Listing 20. Wysłanie danej 8-bitowej przez 1-wire

void DS_WriteByte(uint8_t val){
uint8_t i ;
// pętla przesłania 8 bitów LS-bit first
for (i = 0; i < 8; i ++){
//wyślij bit na magistralę
DS_WriteBit(val & 0x01);
//przesuń o jedną pozycję
//dla następnego notu
val >>= 1;
}
}
Listing 21. Odczytanie bitu za magistrali 1-wire

// odczytanie jednego bitu
uint8_t DS_ReadBit(void){
uint8_t result;
// na magistrali stan logiczny 0
DQ_TRIS = 0;
DQ_IO = 0;
//czekaj kilka us
asm (“nop”);
asm (“nop”);
asm (“nop”);
asm (“nop”);
// na magistrali stan logiczny 1
DQ_TRIS = 1;
asm (“nop”);
asm (“nop”);
asm (“nop”);
asm (“nop”);
asm (“nop”);
asm (“nop”);
//odczytaj stan linii DQ
if (DQ_IO)
result = 1;
else
result = 0;
//zakończ szczelinę czasową
__delay_us(60);
return (result);
}

Odczytywanie danych rozpoczyna się od wymuszenia przez master na magistrali stanu niskiego przez minimum 1 μs. Dane wystawiane przez DS18B20 są prawidłowe przez maksymalnie 15 μs i przed upływem tego czasu mikrokontroler musi je przeczytać. Jeżeli na magistrali jest stan niski, to odczytane zostaje zero logiczne (rysunek 23), a jeżeli stan wysoki, to odczytana zostanie jedynka logiczna (rysunek 24).

Rysunek 23. Odczytanie zera logicznego
Rysunek 24. Odczytanie jedynki logicznej

Procedury komunikacji z termometrem używają programowych opóźnień wykorzystujących wykonywanie pustego rozkazu NOP rdzenia mikrokontrolera PIC16F. Ilość tych rozkazów może być inna dla mikrokontrolera taktowanego inną częstotliwością niż przyjęta w projekcie (16 MHz). Wyposażeni w procedury zapisania i odczytania bitu przez magistralę 1-Wire możemy zapisywać i odczytywać bajty (listing 22 i listing 23).

Listing 22. Zapisanie bajtu

//zapisanie bajtu z argumentu data
void DS_WriteByte(uint8_t data){
uint8_t i;
//pętla zapisania 8 bitów
//pierwszy LSB (najmłodszy)
for (i = 0; i < 8; i++){
DS_WriteBit(data & 0x01);
//przesunięcie danej
//dla następnego bitu
data >>= 1;
}
}
Listing 23. Odczytanie bajtu

//odczytanie bajtu z czujnika przez magistrale 1- wire
uint8_t DS_ReadByte ( void ){
uint8_t i, data;
data = 0;
//pętla odczytania 8 bitów
for (i = 0; i < 8; i++){
data >>= 1;
// jeżeli odczytana jedynka
if (DS_ReadBit() == 1)
data |= 0x80;
}
return data;
}

Komunikacja z termometrem będzie polega na wysyłaniu poleceń (komend) do układu i zapisywaniu lub odczytywaniu z układu zawartości rejestrów temperatury. Zastosujemy tu uproszczone sterowanie odczytywaniem temperatury. Jest to możliwe, bo do magistrali z założenia jest dołączony jeden czujnik i nie trzeba wykonywać sekwencji identyfikacji. Pełny opis komend i sposobu sterowania czujnikiem jest opisany w dokumentacji. My tutaj wykorzystamy tylko trzy komendy: SKIP ROM DS, READ RAM i ConvertT.

Procedura inicjowania pomiaru i odczytania wyniku została pokazana na listingu 24.

Listing 24. Odczytanie rejestrów temperatury

uint8_t DS_GetTemperature(void){
// zablokowanie wszystkich przerwań
GIE = 0;

if (DS_Reset() == 0){
GIE = 1; // odblokowanie przerwań
return 0; // nie wykryto sensora
}

//komenda SKIP ROM
DS_WriteByte(DS_SKIP_ROM);
// Start konwersji temperatury
DS_WriteByte(DS_CONVERT_T);

//Czekaj na zakończenie konwersji
while (DS_ReadBit() == 0);
//__delay_ms(1000);
// czas konwersji jest zależny
// od ustawionej rozdzielczości pomiar
if (DS_Reset() == 0){
GIE = 1; // odblokowanie przerwań
// nie wykryto sensora
//po wykonaniu konwersji
return 0;
}

//komenda SKIP ROM
DS_WriteByte(DS_SKIP_ROM);
// komenda zapisania wewnętrznych rejestrów wyniku
DS_WriteByte(DS_READ_RAM);
// odczytaj rejestry wyniku pomiaru
TemperatureLow = DS_ReadByte();
TemperatureHigh = DS_ReadByte();
//koniec odczytywania rejestrów wyniku
DS_Reset();
// odblokuj przerwania
GIE = 1;
// dane odczytano poprawnie
return 1;
}

Rozpoczynamy od wykonania sekwencji resetu DS_Reset(). Jeżeli procedura zwróci wartość zerową, to oznacza, że do magistrali nie jest podłączony sprawny czujnik (lub w ogóle go nie ma). Blokowane są wszystkie przerwania, żeby nie przeszkadzały w programowym odliczaniu dość krótkich opóźnień rzędu pojedynczych mikrosekund.

Pomiar temperatury jest wyzwalany komendą DS_CONVERT_T poprzedzona komendą SKIP_ROM. Czas trwania konwersji jest zależny od rozdzielczości pomiaru: dla 9-bitowej to ok 94 ms, a dla 12-bitowej ok 750 ms. Domyślnie jest ustawiona konwersja 12-bitowa. W czasie pomiaru na linii DQ DS18B20 jest wymuszany stan niski. Testowanie linii DQ przez program pozwala na wykrycie zakończenia pomiaru – wtedy linia DQ przechodzi w stan wysoki. Wysłanie sekwencji komend DS_SKIP_ROM i DS_READ_RAM pozwala na odczytanie 2 bajtów wyniku i zapisanie ich do globalnych zmiennych TemperatureLow i TemperatureHigh.

Kolejna procedura wykonuje konwersję odczytanych i zapisanych w kodzie U2 zawartości rejestrów temperatury na wartość dziesiętną ze znakiem (tabela 8).

Dla rozdzielczości 12-bitowej, żeby wyliczyć wartość zmierzonej temperatury, trzeba zawartość rejestru podzielić przez 16. Tak uzyskaną wartość w formacie zmiennoprzecinkowym poddajemy konwersji na łańcuch znaków ascii przez funkcję sprintf (listing 25).

Listing 25. Konwersja zawartości rejestrów temperatury na wartość dziesiętną ze znakiem

uint8_t ConvTemperature(char *buffer){
uint8_t status, tenths, i;
uint16_t temperature = 0;
double temp;
uint16_t tmp = 0;

// status = 1 – wykryty sensor dane
//w rejestrze temperatury są ważne

// status = 0 - sensor nie został wykryty,
//dane w rejestrze temperatury nie są ważne

status = DS_GetTemperature();
if (status == 0)
return status;

temperature = TemperatureHigh;
temperature = (temperature << 8) | TemperatureLow;
temp = (double)temperature /16.0;
sprintf (buffer+14, “%2.1f*C”,temp);

return(status);
}

Ostatnim elementem naszej stacji meteo jest kanał transmisji radiowej pozwalający na przesyłanie danych pomiarowych. Jego konstrukcja i działanie zostaną opisane w ostatniej części artykułu, który ukaże się w kolejnym wydaniu EP.

Tomasz Jabłoński, EP

Artykuł ukazał się w
Elektronika Praktyczna
styczeń 2023

Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik kwiecień 2024

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio marzec - kwiecień 2024

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka, Podzespoły, Aplikacje kwiecień 2024

Automatyka, Podzespoły, Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna kwiecień 2024

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich kwiecień 2024

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów