Krótkie wprowadzenie
Dawno mnie nie było, ale poważnym tematem się zająłem ;) i dlatego tyle to trwało.Jak widać na blogu od jakiegoś czasu zajmuję się monitorowaniem warunków (temperatura, wilgotność) w mieszkaniu i na zewnątrz.
Jestem w posiadaniu stacji pogodowej (mniej więcej takiej http://www.biowin.pl/bioterm/elektroniczne-stacje-pogody/bezprzewodowy-barom--term--higrom-wew--zew-/bezprzew-stacja-pog-barometr-pogod-zeg-kal-rcc) z bezprzewodową sondą temperatury i wilgotności i postanowiłem nauczyć się odczytywać jej wskazania i przesyłać je do komputera.
Zapytanie do producenta
Pierwsze co postanowiłem zrobić to zapytać producenta o ten protokół. Początek był obiecujący. Miły pan wprawdzie nie wiedział nic więcej ponad to, że sonda nadaje na częstotliwości 433 MHz, ale obiecał się dowiedzieć. Skończyło się jednak na "Tak, pytałem u źródła, niestety, nie da się tak zrobić, aby czujka sczytywała do innego urządzenia niż nasza stacja bazowa."Oczywiście nie uwierzyłem :)
Pytanie na majsterkowo.pl
Postanowiłem poszukać pomocy gdzie indziej, a mianowicie na portalu http://majsterkowo.pl.Zadałem pytanie w wątku http://majsterkowo.pl/forum/arduino-i-bezprzewodowy-czujnik-temperatury-i-wilgotnosci-t816.html licząc na jakąś pomoc. Jednak znowu chciano mnie zniechęcić bo odpowiedź jaką dostałem brzmiała "W opisie jest napisane z jaką stacją to współpracuje. Do pracy z Arduino tego raczej nie zmusisz, producent na pewno zadbał o odpowiednie kodowanie sygnału."Oczywiście nie uwierzyłem :)
Kupno odbiornika RF 433
W międzyczasie zakupiłem odbiornik i nadajnik RF 433 MHz.Analiza sygnału
Kupno analizatora
Buszując gdzieś po sieci natrafiłem na pojęcie "analizatora stanów logicznych". Pomyślałem, że właśnie tego potrzebuję. W sieci znalazłem przebogatą ofertę tego typu urządzeń od takich za wiele tysięcy złotych (np http://www.conrad.pl/websale7/?Ctx={ver%2f7%2fver}{st%2f3ec%2fst}{cmd%2f0%2fcmd}{m%2fwebsale%2fm}{s%2fconrad%2fs}{l%2f01-aa%2fl}{p1%2fd2f6e56f669660582c6750d86eaf57b8%2fp1}{md5%2f5ffac58ff15c6a24fcf953c797b8c9b3%2fmd5}&act=product&prod_index=123271&cat_index=SHOP_AREA_17630_1114018&otp1=tablink2) do bardzo prostych podłączanych bezpośrednio do portu LPT (drukarkowego) w komputerze.Ostatecznie zdecydowałem się na urządzenie o takie:
Ma 8 kanałów, częstotliwość do 24 MHz i ... kosztuje tylko 57 PLN :)
Odczyt sygnałów
Aby odczytać nadawane przez sondę sygnały postanowiłem podłączyć analizator bezpośrednio do nadajnika RF wewnątrz sondy. Po otwarciu sondy wnętrze przedstawia się następującoNastępnie rozpocząłem pomiar. Ustawiłem częstotliwość próbkowania na 1 MHz, wyłaczyłęm wszystkie czujniki poza pierwszym. Włączyłem dla niego opcję "Require rising edge transition" i nacisnąłem "Start".
Po jakimś czasie (sonda nadaje co ok 50-56 sekund - więcej o tym później) na ekranie ujrzałem taki obrazek:
Widać na nim, że odczytane zostały dane, że nadawanie trwało trochę ponad 0,8s.
Po powiększeniu początku danych zobaczyłem:
Widać, że sonda nadaje krótki "piki" (stan wysoki), a pomiędzy nimi przerwy.
Stan wysoki zawsze trwa ok 560μs, a przerwy pomiędzy nimi 8640, 3800 i 1900μs. Przerwa 8640 μs występuje na samym początku transmisji, na samym końcu oraz tylko kilka razy w środku. Przerwy 3800 i 1900 o wiele częściej i są pomieszane. Wydaje się, że 8640 to jakiś sygnał synchronizująco-rozdzielający, a te dwie pozostałe przerwy oznaczają bit 0 i 1.
Czas to sprawdzić.
Analiza w arkuszu kalkulacyjnym
Analizę danych postanowiłem przeprowadzić w LibreOffice Calc - to taka darmowy odpowiednik Excela.Po wybraniu opcji "Options/Export Data" (Ctrl+E) pojawia się okienko
Po wybraniu opcji jak na obrazku na dysku mamy plik z następującymi danymi (początkowy fragment):
Time[s], czujnikW pierwszej kolumnie jest czas mierzony w sekundach, w drugiej kolumnie jest wartość sygnału jaka się pojawiła na wejściu w tym czasie.
13.539262, 0
23.539262, 1
23.53983, 0
23.548476, 1
23.549044, 0
23.552861, 1
23.553429, 0
23.555343, 1
23.555911, 0
23.557816, 1
23.558384, 0
23.562232, 1
...
Zaimportowałem zatem te dane do arkusza i dodałem dwie kolejne kolumny: czas i stan.
W kolumnie czas wpisałem wszędzie formułę (dla komórki C3) =1000*(A4-A3). Dzięki temu otrzymałem czas w milisekundach trwania danego stanu.
Widać ponownie, że stan wysoki zawsze trwa ok 560μs, a stan niski 8640, 3800 i 1900μs. W czwartej kolumnie wpisuję regułę, które dla przerwy równej 3800μs wylicza, że to 1, a dla 1900μs wylicza, że to 0. Dla 8640μs wypisuje wartość "dystans". Oto przykładowe dane:
Time[s] | SCIO | czas | analiza |
0 | 0 | ||
11,35824 | 1 | 0,56 | |
11,3588 | 0 | 8,64 | dystans |
11,36744 | 1 | 0,56 | |
11,368 | 0 | 3,8 | 1 |
11,3718 | 1 | 0,56 | |
11,37236 | 0 | 1,88 | 0 |
11,37424 | 1 | 0,56 | |
11,3748 | 0 | 1,92 | 0 |
11,37672 | 1 | 0,56 | |
11,37728 | 0 | 3,84 | 1 |
Taka analiza pozwoliła mi zauważyć, że podczas pojedynczej transmisji 6 razy przesyłanych jest 37 bitów. Za każdym razem takich samych.Serie 37 bitów rozdzielane są "dystansami".
Ok, spróbujmy zatem przeanalizować te bity. Najpierw wykorzystując autofiltr przeniosłem do drugiego arkusz taką paczkę 37 bitów do pierwszej kolumny. W kolejnych kolumnach zapisałem następujące formuły. Kolumny te miały następujące znaczenie.
Kol. | formuła | znaczenie |
B | =1-A2 | odwrotny bit (nie wiem czy długa przerwa to bit czy krótka) |
C | =A2+2*(A3+2*(A4+2*(A5+2*(A6+2*(A7+2*(A8+2*A9)))))) | wartość bajtu zaczynającego się od tego bitu przy założeniu, że: długa przerwa to 1, a krótka to 0, najpierw jest najmłodszy bit a potem coraz starsze. |
D | =B2+2*(B3+2*(B4+2*(B5+2*(B6+2*(B7+2*(B8+2*B9)))))) | wartość bajtu zaczynającego się od tego bitu przy założeniu, że: długa przerwa to 0, a krótka to 1, najpierw jest najmłodszy bit a potem coraz starsze. |
E | =A9+2*(A8+2*(A7+2*(A6+2*(A5+2*(A4+2*(A3+2*A2)))))) | wartość bajtu zaczynającego się od tego bitu przy założeniu, że: długa przerwa to 1, a krótka to 0, najpierw jest najstarszy bit a potem coraz młodsze. |
F | =B9+2*(B8+2*(B7+2*(B6+2*(B5+2*(B4+2*(B3+2*B2)))))) | wartość bajtu zaczynającego się od tego bitu przy założeniu, że: długa przerwa to 0, a krótka to 1, najpierw jest najstarszy bit a potem coraz młodsze. |
Dla następujących danych:
- kanału nr 3
- temperatury 24,1 stopnia celsjusza
- wilgotności 43%
A | B | C | D | E | F |
1 | 0 | 137 | 118 | 145 | 110 |
0 | 1 | 68 | 187 | 34 | 221 |
0 | 1 | 162 | 93 | 69 | 186 |
1 | 0 | 209 | 46 | 139 | 116 |
0 | 1 | 104 | 151 | 22 | 233 |
0 | 1 | 52 | 203 | 44 | 211 |
0 | 1 | 26 | 229 | 88 | 167 |
1 | 0 | 141 | 114 | 177 | 78 |
0 | 1 | 70 | 185 | 98 | 157 |
1 | 0 | 35 | 220 | 196 | 59 |
1 | 0 | 17 | 238 | 136 | 119 |
0 | 1 | 8 | 247 | 16 | 239 |
0 | 1 | 4 | 251 | 32 | 223 |
0 | 1 | 130 | 125 | 65 | 190 |
1 | 0 | 193 | 62 | 131 | 124 |
0 | 1 | 224 | 31 | 7 | 248 |
0 | 1 | 240 | 15 | 15 | 240 |
0 | 1 | 120 | 135 | 30 | 225 |
0 | 1 | 60 | 195 | 60 | 195 |
0 | 1 | 30 | 225 | 120 | 135 |
1 | 0 | 143 | 112 | 241 | 14 |
1 | 0 | 71 | 184 | 226 | 29 |
1 | 0 | 35 | 220 | 196 | 59 |
1 | 0 | 145 | 110 | 137 | 118 |
0 | 1 | 72 | 183 | 18 | 237 |
0 | 1 | 164 | 91 | 37 | 218 |
0 | 1 | 82 | 173 | 74 | 181 |
1 | 0 | 169 | 86 | 149 | 106 |
0 | 1 | 212 | 43 | 43 | 212 |
0 | 1 | 106 | 149 | 86 | 169 |
1 | 0 | ||||
0 | 1 | ||||
1 | 0 | ||||
0 | 1 | ||||
1 | 0 | ||||
1 | 0 | ||||
0 | 1 |
Na żółto zaznaczyłem te bajty gdzie widać pewne interesujące dane. w ostatniej żółtej komórce widać wilgotność, a w przedostatniej temperaturę pomnożoną przez 10. Pierwsze dwie zaznaczyłem na żółto bo to po prostu wcześniejsze dwa bajty. Że to ta kolumna to utwierdziłem się po kilku kolejnych pomiarach dla różnych wartości temperatury i wilgotności.
Powstają oczywiście pytania:
- czy na wilgotność potrzeba aż 8 bitów? skoro jej wartości są od 0-99 to wystarczy 7.
- na ilu bitach i w jaki sposób kodowana jest temperatura, ten jeden bajt wystarczy na temperatury od 0.0 do 25.5 stopni Celsjusza, a ma wystarczyć na jakieś -50.0 do 70.0 czyli 1200 wartości więc co najmniej 11 (w praktycznie 12) bitów
Po kolejnych pomiarach i próbach, których nie będę tu szczegółowo opisywał (było ich ok 10) wynik jest następujący:
licznik | bity | wartości | komentarz |
1 | 1 | 9 | jakieś 4 bity |
2 | 0 | ||
3 | 0 | ||
4 | 1 | ||
5 | 1 | 219 | losowe id |
6 | 1 | ||
7 | 0 | ||
8 | 1 | ||
9 | 1 | ||
10 | 0 | ||
11 | 1 | ||
12 | 1 | ||
13 | 0 | 0 | jakieś 2 bity |
14 | 0 | ||
15 | 0 | 1 | kanał (od 0) |
16 | 1 | ||
17 | 0 | 332 | temperatura |
18 | 0 | ||
19 | 0 | ||
20 | 1 | ||
21 | 0 | ||
22 | 1 | ||
23 | 0 | ||
24 | 0 | ||
25 | 1 | ||
26 | 1 | ||
27 | 0 | ||
28 | 0 | ||
29 | 0 | 25 | wilgotność |
30 | 0 | ||
31 | 0 | ||
32 | 1 | ||
33 | 1 | ||
34 | 0 | ||
35 | 0 | ||
36 | 1 | ||
37 | 0 | 0 | jakiś bit |
Czyli mamy po kolei:
- jakieś 4 bity - te bity ani razu nie zmieniły swojej wartości
- losowe id - wg dokumentacji po każdej zmianie baterii konieczne jest ponowne synchronizacja stacji bazowej z sondą ponieważ sonda zaczyna wysyłać nowe, losowe id - to prawdopodobnie te bity
- jakieś 2 bity - nigdy się nie zmieniły
- kanał (od 0) - w sondzie można wybrać kanał, jego wartość wysyłana jest właśnie na tych dwóch bitach
- temperatura - zakładam, że wysyłana jest na tych 12 bitach jako liczba całkowita będąca wartością temperatury pomnożoną przez 10. Podejrzewam, że najstarszy bit to bit znaku, ale nie robiłem jeszcze testów dla temperatur ujemnych
- wilgotność - jest przechowywana jako liczba całkowita na tych bitach. Możliwe, że nie na 8 od 29 bitu, a tylko na 7 od 30 bitu, a bit 29 jest do czegoś innego.
- jakiś bit - jego wartość nigdy się nie zmieniła.
Wysłanie samemu danych do odbiornika
Jako pierwszy test czy dobrze rozpracowałem format było zmontowanie układu do nadawania i próba nadania temperatury i wilgotności do stacji bazowej czyli udawanie sondy.W tym celu zmontowałem następujący układ:
todo: wstawić schemat układu z atmega, nadajnikiem i wyświetlaczem lcd.
Napisałem następujący programik:
#include <LiquidCrystal.h> #define RF_DATA_PIN 9 #define LED_PIN 10 #define UP_TIME 560 #define SEPARATOR_TIME 8640 #define ZERO_TIME 1900 #define ONE_TIME 3800 LiquidCrystal lcd(2, 3, 4, 5, 6, 7); int BITS [37] = { 1,0,0,1,0,0,0,1, 0,1,1,0,0,0,1,0, 0,0,0,0,1,1,1,1, 0,0,0,1,0,0,1,0, 1,0,1,1,0 }; void setup () { pinMode(RF_DATA_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT); lcd.begin(16, 2); } // nadaje wysoki poziom przez określony czas void writeOne() { digitalWrite(RF_DATA_PIN, HIGH); delayMicroseconds(UP_TIME); digitalWrite(RF_DATA_PIN, LOW); } // nadaje wysoki poziom, a potem czeka określony czas // z niskim poziomem void writeOneTick(unsigned int microsTime) { writeOne(); delayMicroseconds(microsTime); } void writeAllData () { // sonda tego nie nadaje, // ale to dla odbiornika żeby zdążył się wygrzać for (int i = 0; i < 30; i++) writeOneTick(UP_TIME); writeOneTick(SEPARATOR_TIME); // 6 razy nadajemy for (int i = 0; i < 6; i++) { // paczkę 37 bitów for (int j = 0; j < 37; j++) { if (BITS [j]) writeOneTick(ONE_TIME); else writeOneTick(ZERO_TIME); } writeOneTick(SEPARATOR_TIME); } writeOne(); } // za każdym razem nadaję inną wilgotność // ta zmienna przechowuje jej wartość int humidity = 50; void loop () { // zapalam diodę aby widzieć kiedy trwa nadawanie digitalWrite(LED_PIN, HIGH); // na wyświetlaczu LCD wypisuję // wartość wilgotności lcd.setCursor(0, 1); lcd.print(humidity); lcd.print(" "); // ustawienie bitów w tablicy aby // aby wilgotność była wysłana int h = humidity; for (int i = 0; i < 8; i++) { BITS [35 - i] = h % 2; h = h / 2; } // wysłanie danych writeAllData(); // zwiększenie wilgotności humidity = humidity == 99 ? 0 : humidity + 1; // zgaszenie diody digitalWrite(LED_PIN, LOW); // odczekanie odpowiedniego czasu do następnej // transmisji // kanał 1 - 50 s w sumie // kanał 2 - 53 s w sumie // kanał 3 - 56 s w sumie delay(55300); }
Po uruchomieniu całości efekt jest następujący:
todo: wstawić filmik z pokazującą się temperaturą i wilgotnością
Jedyny problem jaki miałem to odstępy pomiędzy nadawaniem wartości. Okazało się, że odstęp jest różny na różnych kanałach i tak:
- na kanale 1 wynosi on 50s
- na kanale 2 wynosi on 53s
- na kanale 3 wynosi on 56s
Odczyt danych
Odczyt danych okazał się najtrudniejszą częścią, a to za sprawą dużej ilości błędów.Po pierwsze kiedy sonda nie nadaje to odbiornik i tak wychwytuje "coś" z powietrza i ciągle na jego wyjściu stan się zmienia. Kiedy sonda zaczyna nadawać to odbiornik chwilę potrzebuje żeby się "dostroić" do mocy sygnału i pierwsze bity są uszkodzone często.
Poza tym wychodzi, że czułość odbiornika jest niewielka i już przy odległości rzędu metra liczba niedokładnych odczytów mocno rośnie.
Pierwsze podejście
W tej chwili program do odczytu wygląda następująco:Wymaga on jeszcze paru poprawek więc nie będę się o nim rozpisywał, kiedy go poprawię to w kolejnym wpisie więcej napiszę.// ustawienie tej definicji powoduje, że program // wypisuje na rs232 różne informacje diagnostyczne #define DEBUG9 // ustawienie tej definicji powoduje, że program // po dokonaniu pomiaru ustawia na chwilę stan wysoki // na jednym z wyjść, podłączony tam analizator // stanów logicznych zaczyna wtedy pomiar // ponieważ posiada on bufor na jakiś czas przed // rozpoczęciem pomiwaru więc można przeanalizować // co pojawiło się na wyjściu z odbiornika RDF #define DEBUG_SALAE1 // wyjśącie odbiornika RDF #define RF_DATA_PIN 11 // wyjście z diodą świecącą #define LED_PIN 13 // czasy stanu wyokiego i przerw #define UP_TIME 560 #define SEPARATOR_TIME 8640 #define ZERO_TIME 1900 #define ONE_TIME 3800 // makra sprawdzające czy czas mieści się w buforze #define CHK_T(CT,T) ((CT >= (T - 250)) && (CT <= (T + 250))) #define CHK_T2(CT,T) ((CT >= (T - 800)) && (CT <= (T + 800))) // liczba bitów jednej wiadomości i liczba // paczek, które są nadawane #define NUM_OF_BITS 37 #define NUM_OF_SERIES 6 // specjalna wartość oznaczająca, że odczyt był błędny #define BAD_VALUE 0b1000000000000000 // bufor na bity int8_t bits [NUM_OF_BITS]; // za każdym z 6 pomiarów na określonej pozycji mogę zmierzyć // 0 lub 1 (na skutek błędów transmisji) // jeżeli zmierzę 1 to zwiększam tę wartość, // a jeśli 0 to zmniejszam int8_t bit_adds [NUM_OF_BITS]; // za każdym poprawnym pomiarem zwiększam tę wartość o 1 uint8_t bit_measures [NUM_OF_BITS]; // licznik pomiarów całej paczki uint8_t measure_number; uint32_t last_report_time = 0; uint32_t last_pulse_time; #ifdef DEBUG9 uint16_t arr_bit_times [NUM_OF_SERIES][NUM_OF_BITS][3]; #define PRE_DEBUG_BUF_SIZE 10 uint16_t arr_pre_buf_times [PRE_DEBUG_BUF_SIZE][3]; int pre_buf_counter; #endif #ifdef DEBUG_SALAE1 #define DEBUG_SALAE1_PIN 6 #endif uint32_t getvalue(int bitStart, int bitNum) { uint32_t ret = 0; for (int i = 0; i < bitNum; i++) { if (bits [bitStart + i] > 1) return BAD_VALUE; ret *= 2; ret += bits [bitStart + i]; } return ret; } void setup() { Serial.begin(115200); pinMode(RF_DATA_PIN, INPUT); pinMode(LED_PIN, OUTPUT); #ifdef DEBUG_SALAE1 pinMode(DEBUG_SALAE1_PIN, OUTPUT); #endif } void loop() { // czyszczę wszystkie zmienne na początku for (int i = 0; i < NUM_OF_BITS; i++) { bit_adds [i] = 0; bit_measures [i] = 0; #ifdef DEBUG9 for (int j = 0; j < NUM_OF_SERIES; j++) { arr_bit_times [j][i][0] = 0; arr_bit_times [j][i][1] = 0; arr_bit_times [j][i][2] = 0; } #endif } measure_number = 0; #ifdef DEBUG9 for (int i = 0; i < PRE_DEBUG_BUF_SIZE; i++) { arr_pre_buf_times [i][0] = 0; arr_pre_buf_times [i][1] = 0; arr_pre_buf_times [i][2] = 0; } pre_buf_counter = 0; #endif uint32_t highTime, time, lowTime; // czekam na prawidłowy pierwszy pulse high last_pulse_time = micros(); while (true) { highTime = pulseIn(RF_DATA_PIN, HIGH); time = micros(); lowTime = time - last_pulse_time - highTime; last_pulse_time = time; #ifdef DEBUG9 arr_pre_buf_times [pre_buf_counter][0] = lowTime; arr_pre_buf_times [pre_buf_counter][1] = highTime; arr_pre_buf_times [pre_buf_counter][2] = millis(); pre_buf_counter = (pre_buf_counter + 1) % PRE_DEBUG_BUF_SIZE; #endif if (CHK_T (highTime, UP_TIME) && CHK_T2 (lowTime, SEPARATOR_TIME)) { break; } } int bit_number = 0; // wykonuję sześć pomiarów while (measure_number < NUM_OF_SERIES) { // odczytuję pulse highTime = pulseIn(RF_DATA_PIN, HIGH); // ignoruję takie krótkie pulsy tak jakby ich nie było if (highTime < 300) { continue; } time = micros(); // zbyt długie traktuję jako krótki który się zlał z normalnym if (highTime > 750) { highTime = UP_TIME; } lowTime = time - last_pulse_time - highTime; last_pulse_time = time; #ifdef DEBUG9 if (bit_number < NUM_OF_BITS) { arr_bit_times [measure_number][bit_number][0] = lowTime; arr_bit_times [measure_number][bit_number][1] = highTime; arr_bit_times [measure_number][bit_number][2] = millis(); } #endif // sprawdzam czy pulse ma dobry czas if (!CHK_T (highTime, UP_TIME)) { // i jeśli nie to koniec //Serial.println("1"); break; } // sprawdzam czy to znacznik końca serii if (CHK_T2 (lowTime, SEPARATOR_TIME)) { // sprawdzam czy została odpowiednia liczba bitów odczytana if (bit_number <= NUM_OF_BITS) { measure_number++; bit_number = 0; } else { // została odczytana zła liczba bitów Serial.print("2 - "); Serial.println(bit_number); break; } } // sprawdzam czy kolejny bit został odczytany else if (CHK_T2 (lowTime, ZERO_TIME)) { if (bit_number >= NUM_OF_BITS) { break; } bit_adds [bit_number]--; bit_measures [bit_number]++; bit_number++; } else if (CHK_T2 (lowTime, ONE_TIME)) { if (bit_number >= NUM_OF_BITS) { break; } bit_adds [bit_number]++; bit_measures [bit_number]++; bit_number++; } else { // to nieprawidłowy bit break; } } // jeżeli choć jeden pomiar się udał wypisuję raport if (measure_number > 0) { for (int i = 0; i < NUM_OF_BITS; i++) { if (bit_adds[i] > (bit_measures[i] / 2)) { bits[i] = 1; } else if (bit_adds[i] < (-bit_measures[i] / 2)) { bits[i] = 0; } else { bits[i] = 2; } } uint32_t nChannel = getvalue (14, 2); uint32_t nTemp = getvalue (16, 12); uint32_t nHumidity = getvalue (28, 8); #ifdef DEBUG_SALAE1 if (nChannel == 1) { digitalWrite(DEBUG_SALAE1_PIN, HIGH); delay(10); digitalWrite(DEBUG_SALAE1_PIN, LOW); } #endif Serial.print("channel: "); if (nChannel != BAD_VALUE) Serial.print(nChannel + 1); else Serial.print("???"); Serial.print (", temperature: "); if (nTemp != BAD_VALUE) Serial.print(nTemp / 10.0); else Serial.print("???"); Serial.print (" *C, humidity: "); if (nHumidity != BAD_VALUE) Serial.print(nHumidity); else Serial.print("???"); Serial.print(" %, Num of measures: "); Serial.println(measure_number); //wypisuję liczbę pomiarów dla bitów Serial.print("lb: "); for (int i = 0; i < NUM_OF_BITS; i++) { Serial.print(" "); Serial.print(bit_measures[i]); Serial.print(","); } Serial.println(); Serial.print("sb: "); for (int i = 0; i < NUM_OF_BITS; i++) { if (bit_adds[i] >= 0) { Serial.print(" "); } Serial.print(bit_adds[i]); Serial.print(","); } Serial.println(); Serial.print("b: "); for (int i = 0; i < NUM_OF_BITS; i++) { Serial.print(" "); if (bits[i] > 1) Serial.print("?"); else Serial.print(bits[i]); Serial.print(","); } Serial.println(); #ifdef DEBUG9 for (int i = 0; i < PRE_DEBUG_BUF_SIZE; i++) { Serial.print("pre "); Serial.print(i); Serial.print("-"); Serial.print(pre_buf_counter); Serial.print(": "); Serial.print("("); Serial.print(arr_pre_buf_times [pre_buf_counter][2]); Serial.print(", "); Serial.print(arr_pre_buf_times [pre_buf_counter][0]); Serial.print(", "); Serial.print(arr_pre_buf_times [pre_buf_counter][1]); Serial.print("), "); Serial.println(); pre_buf_counter = (pre_buf_counter + 1) % PRE_DEBUG_BUF_SIZE; } #endif #ifdef DEBUG9 for (int i = 0; i < NUM_OF_BITS; i++) { Serial.print("bit "); Serial.print(i); Serial.print(": "); for (int j = 0; j < NUM_OF_SERIES; j++) { Serial.print("("); Serial.print(arr_bit_times [j][i][2]); Serial.print(", "); Serial.print(arr_bit_times [j][i][0]); Serial.print(", "); Serial.print(arr_bit_times [j][i][1]); Serial.print("), "); } Serial.println(); } #endif Serial.println("---------------------------------"); } }
Problemy z zasięgiem
Jak już pisałem kiedy żaden nadajnik nie nadaje odbiornik "łapał coś" i stan na wyjściu co chwila się zmieniał. Założyłem jednak, że kiedy nadajnik zacznie nadawać to odbiornik zacznie reagować prawidłowo.Pierwsza wersja programu została napisana tak, że program czeka na stan wysoki o odpowiedniej długości, a następnie odczytuje dane spodziewając się prawidłowych czasów zarówno stanów wysokich jak i niskich. Po pierwszym błędzie program przerywał odczyt i próbował zanalizować odczytane dane, a mianowicie jeżeli udało się odczytać choć dwie serie danych to następowało porównywanie odczytanych serii.
Pierwsze próby robiłem nadając mój testowy sygnał z nadajnika, który zakupiłem razem z odbiornikiem. Sygnał nadawany był z niewielkiej odległości. Zauważyłem, że dane nie odczytują się do końca poprawnie. Często zamiast sześciu serii danych odczytywane było pięć serii.
Przyczyną okazało się to, że kiedy nadajnik zaczynał nadawać to odbiornik tak jakby potrzebował chwili aby się do niego dostroić.
Dużo gorzej było kiedy próbowałem odczytać sygnał z oryginalnej sondy, tu już przy jednometrowej odległości zaczynały się spore problemy. Często nie udawało się odczytać w ogóle danych lub najwyżej jedną, dwie serie.
Przyczyną jak się okazało było pojawianie się na wyjściu stanów wysokich mimo tego, że sonda nadawała stan niski.
Próbowałem poprawić czułość sondy przylutowując antenkę w postaci kawałka druta długości około 15 cm, ale niewiele to pomogło. Wywiązała się nawet dyskusja na forum majsterkowo.pl. Jak tylko znajdę moment to popracuję nad tą antenką.
Kolejnym sposobem było ignorowanie krótkich stanów wysokich, to poprawiło nieco jakość odbioru.
Oto przykład wadliwie odczytanych danych:
To co zamierzam zrobić to:
- jeszcze bardziej uniewrażliwić oprogramowanie na sporadyczne błędy
- nie przerywać pomiaru po pierwszym poważnym błędzie tylko czekać na kolejną serię danych
- być może pewną inteligencję wprowadzić
Co dalej
W tej chwili muszę zrobić dwie rzeczy:- poprawić kod aby nie przerywał odczytu po pierwszym błędzie tylko czekał na kolejną porcję danych, po tej zmianie projekt będzie gotowy do opublikowania
- poprawić czułość odbiornika, być może konieczny będzie zakup kolejnego
SZACUN
OdpowiedzUsuńPodłączyłem odbiornik RX 433mhz z tym czujnikiem ze stacji meteo.
Działało to jak kierunkowskaz (działa nie działa).
Grzebałem w kodzie do bólu raz działało wszystko na 100%
Raz tak jak chciało. zainwestowałem w trochę droższy odbiornik i nic.
No to jazda nasłuch na 432,000-435,000 nadajnik siedzi w 433,850 a w okolicy cisza totalna.
No to wio zamiast Serial print to na lcd i to samo. no to przez BT z tym samym skutkiem.
Pomiary napięcia na usb nic filtry do zasilania nic petle i inne dziwne poradniki.
Zrezygnowany osobne czujniki zamówiłem.
PC stan uśpienia i 100% sukces zasilane przez baterie to samo.
BANAN na twarzy i ide zajarać :)
Ten komentarz został usunięty przez autora.
OdpowiedzUsuńA jakie stacje pogodowe polecacie do użytku domowego? Zależy mi na tym, aby była to stacja dobrej jakości, ponieważ wolę zainwestować raz, a porządnie. Myślę, że strona https://www.oleole.pl/stacje-pogody,_biowin.bhtml jak i opinie na niej zawarte bardzo mi pomogą.
OdpowiedzUsuńZobaczyłem ten artykuł i naprawdę podziwiam i gratuluję projektu. Złamanie zamkniętego kodowania to jest naprawdę trudna sprawa. Dobra robota :)
OdpowiedzUsuń