Goto page 1, 2 Next
Atlantis
Guest
Wed Apr 23, 2014 5:10 pm
Próbuję właśnie uruchomić BMP085 w jednym ze swoich urządzeń i powoli
zaczynam z tego powodu siwieć. ;)
Na samym początku, bez większego problemu udało mi się znaleźć taką oto
bibliotekę w Sieci:
http://www.sicklinger.com/en/component/remository/Microcontroller/ATMEL-AVR-ATMEGA-BMP085-library-in-C/?Itemid=54
Skompilowała się uruchomiła bez problemu. Wystarczyło właściwie tylko
dodać pliki nagłówkowe do istniejącego projektu. Niestety moja radość
nie trwała długo - okazało się, że wartość ciśnienia jest nieprawidłowa
- wychodzi jakieś 300 HPa...
Pierwsze o czym pomyślałem to uszkodzony czujnik. Wyjąłem więc z
szuflady Arduino i wgrałem ten kod:
https://www.sparkfun.com/tutorials/253
Wszystko ruszyło bez najmniejszego problemu, wartości były prawidłowe (a
przynajmniej prawdopodobne).
Zabrałem się więc za porównywanie kodu zawartego w obydwu bibliotekach.
Odczytywanie danych kalibracyjnych wygląda praktycznie tak samo,
podobnie jak końcowa konwersja.
Jedyny fragment, w którym mógłbym się czegoś dopatrywać to odczyt
wartości ciśnienia ze scalaka. W bibliotece pod AVR wygląda to następująco:
pressure = bmp085ReadShort(0xF6,error_code);
pressure = pressure << 8;
pressure = pressure >> (8-OSS);
Funkcja bmp085ReadShort zwraca uint16_t, a więc czytane są tylko dwa bajty.
Natomiast w kodzie na Arduino znajduje się następujący fragment:
msb = Wire.read();
lsb = Wire.read();
xlsb = Wire.read();
up = (((unsigned long) msb << 16) | ((unsigned long) lsb <<

|
(unsigned long) xlsb) >> (8-OSS);
Jak widać odczytywane są tutaj trzy jednobajtowe (char) zmienne, które
potem są konwertowane do zwracanej wartości unsigned long.
Czy moja dedukcja jest prawidłowa? A może to nie ma nic do rzeczy i
źródła problemu powinienem szukać gdzie indziej?
Pszemol
Guest
Wed Apr 23, 2014 5:44 pm
"Atlantis" <marekw1986NOSPAM@wp.pl> wrote in message
news:lj8s5v$q9a$1@portraits.wsisiz.edu.pl...
Quote:
Jedyny fragment, w którym mógłbym się czegoś dopatrywać to odczyt
wartości ciśnienia ze scalaka. W bibliotece pod AVR wygląda to
następująco:
pressure = bmp085ReadShort(0xF6,error_code);
pressure = pressure << 8;
pressure = pressure >> (8-OSS);
Funkcja bmp085ReadShort zwraca uint16_t, a więc czytane są tylko dwa
bajty.
Natomiast w kodzie na Arduino znajduje się następujący fragment:
msb = Wire.read();
lsb = Wire.read();
xlsb = Wire.read();
up = (((unsigned long) msb << 16) | ((unsigned long) lsb <<

|
(unsigned long) xlsb) >> (8-OSS);
Jak widać odczytywane są tutaj trzy jednobajtowe (char) zmienne, które
potem są konwertowane do zwracanej wartości unsigned long.
Czy moja dedukcja jest prawidłowa? A może to nie ma nic do rzeczy
i źródła problemu powinienem szukać gdzie indziej?
Co to jest za identyfikator OSS i jak jest ustawiony w obu porównywanych
kodach? Zauważ, że od wartości OSS zależy przesunięcie wyniku w prawo aż o 8
bitów! Zła wartość OSS będzie bardzo silnie wpływać na wynik.
Pszemol
Guest
Wed Apr 23, 2014 5:55 pm
"Pszemol" <Pszemol@PolBox.com> wrote in message
news:lj8u5o$e8k$1@dont-email.me...
Quote:
Co to jest za identyfikator OSS i jak jest ustawiony w obu porównywanych
kodach? Zauważ, że od wartości OSS zależy przesunięcie wyniku w prawo aż o
8 bitów! Zła wartość OSS będzie bardzo silnie wpływać na wynik.
Z datasheeta:
https://www.sparkfun.com/datasheets/Components/General/BST-BMP085-DS000-05.pdf
wynika że cyfryzacja ciśnienia może działać na dokładności 16-19 bitów.
Na stronie 18 jest przykład 16 bitowy, dwa bajty danych, sprawdź czy tak
jest ustawiony.
p.s. latasz na lotni czy szybowcach?
Atlantis
Guest
Wed Apr 23, 2014 9:51 pm
Hmm... Dziwna sprawa. Sądziłem, że winę za taki stan rzeczy ponosi błąd
w bibliotece. Jednak trafiłem na inną służącą do obsługi BMP085.
http://davidegironi.blogspot.com/2012/10/avr-atmega-bmp085-pressure-sensor.html#.U1g0nFdpNIJ
Po podmienieniu plików, dostosowaniu źródeł i wgraniu hex-a okazało się,
że efekt nie zniknął. Ciągle otrzymuję dziwną wartość ciśnienia.
Prawdopodobieństwo wystąpienia tego samego błędu w dwóch różnych
bibliotekach jest niewielkie, więc należy założyć, że błąd tkwi w innym
miejscu.
W chwili obecnej procedura wysyłania wyniku wygląda w sposób następujący:
char result[10];
int32_t pressure = bmp085_getpressure();
itoa(pressure, result, 10);
strcpy_P(pAnswer, PSTR("+PRESS: "));
strcat(pAnswer, result);
strcat_P(pAnswer, PSTR("\r\n"));
Wskaźnik do bufora pAnswer jest następnie przekazywany do funkcji
zajmującej się wysyłaniem odpowiedzi na zapytania UDP.
Próbowałem także zastosować stdio:
printf_P(pAnswer, PSTR("+PRESS: %d\r\n"), bmp085_getpressure());
Efekt był dokładnie taki sam.
Ktoś ma jakiś pomysł gdzie mogę zacząć szukać przyczyny, co jeszcze
ewentualnie mogę sprawdzić?
Grzegorz Niemirowski
Guest
Wed Apr 23, 2014 11:06 pm
Atlantis <marekw1986NOSPAM@wp.pl> napisał(a):
Quote:
Hmm... Dziwna sprawa. Sądziłem, że winę za taki stan rzeczy ponosi błąd
w bibliotece. Jednak trafiłem na inną służącą do obsługi BMP085.
http://davidegironi.blogspot.com/2012/10/avr-atmega-bmp085-pressure-sensor
.html#.U1g0nFdpNIJ
Po podmienieniu plików, dostosowaniu źródeł i wgraniu hex-a okazało się,
że efekt nie zniknął. Ciągle otrzymuję dziwną wartość ciśnienia.
Prawdopodobieństwo wystąpienia tego samego błędu w dwóch różnych
bibliotekach jest niewielkie, więc należy założyć, że błąd tkwi w innym
miejscu.
W chwili obecnej procedura wysyłania wyniku wygląda w sposób następujący:
char result[10];
int32_t pressure = bmp085_getpressure();
itoa(pressure, result, 10);
strcpy_P(pAnswer, PSTR("+PRESS: "));
strcat(pAnswer, result);
strcat_P(pAnswer, PSTR("\r\n"));
Wskaźnik do bufora pAnswer jest następnie przekazywany do funkcji
zajmującej się wysyłaniem odpowiedzi na zapytania UDP.
Próbowałem także zastosować stdio:
printf_P(pAnswer, PSTR("+PRESS: %d\r\n"), bmp085_getpressure());
Efekt był dokładnie taki sam.
Ktoś ma jakiś pomysł gdzie mogę zacząć szukać przyczyny, co jeszcze
ewentualnie mogę sprawdzić?
Zacząłbym od zignorowania bibliotek nietrzymających się dokumentacji BMP085.
A ta mówi, żeby odczytać trzy bajty: najstarszy MSB, młodszy LSB i
najmłodszy XLSB. Są to rejestry F6, F7 i F8. Te bajty są składane w inta, a
potem całość przesuwana jest w prawo o 8-oss, gdzie oss oznacza
over-sampling setting. W ten sposób otrzymujemy nieskompensowaną
temperaturę. Następnie wykonywane są obliczenia kompensacyjne.
A jaki mikrokontroler? Ma JTAG? Jak ma to użyj, bo kombinujesz strasznie
zamiast użyć debuggera. Jak nie ma JTAGa, to użyj czegoś innego, np. portu
szeregowego. Sprawdź jakie wartości masz odczytane w MSB, LSB i XLSB.
Następnie zobacz co robi z nimi kod kompensacyjny. Na oko wygląda dobrze,
ale może gdzieś jest pomieszane signed i unsigned. Prześledź działanie kodu
w trakcie działania. Wrzucając hexy i patrząc na końcowy wynik będzie Ci
bardzo trudno ustalić co się dzieje. Pomóc Ci też jest trudno, jeśli nie
podajesz odczytanych wartości MSB, LSB i XLSB. Ja niestety nie posiadam
BMP085 i nie porównam ze swoim, ale jakbyś podał wartości, to myślę, że
byłoby łatwiej. Mógłbym np. odpalić sobie biblioteki z danymi z Twojego
czujnika. Poza tym wkleiłeś bardzo krótkie fragmenty kodu, np. nie wiadomo
jak Arduino liczy kompensację. Czy też dzielenie robi przesunięciem bitowym?
A może robi normalne dzielenie? Bo to nie jest to samo: patrz przesuwanie
bitów w liczbach ujemnych. I jeszcze jedno: o ile dobrze rozumiem, to żeby
prawidłowo obliczyć ciśnienie, musisz mieć zmierzoną najpierw temperaturę.
Mierzysz ją?
--
Grzegorz Niemirowski
http://www.grzegorz.net/
OE PowerTool i Outlook Express:
http://www.grzegorz.net/oe/
Uptime: 12 days, 22 hours, 55 minutes and 19 seconds
Pszemol
Guest
Wed Apr 23, 2014 11:31 pm
"Atlantis" <marekw1986NOSPAM@wp.pl> wrote in message
news:lj9clo$e2i$1@portraits.wsisiz.edu.pl...
Quote:
Ktoś ma jakiś pomysł gdzie mogę zacząć szukać przyczyny,
co jeszcze ewentualnie mogę sprawdzić?
Wcześniej pisałeś że masz wynik około 300hPa...
Może zamiast 1000hPa czytasz coś jak 344hPa?
Jeśli tak, to stawiam hipotezę, że obcinasz górny bajt
z trzy-bajtowego wyniku...
1000hPa to 100000Pa, czyli w bajtach 0x01 0x86 0xA0.
Jeśli weźmiesz pod uwagę że Twój kod mógł skrócić
long'a do int'a i zamiast 0x186A0 dostaniesz 0x86A0
to uzyskasz wynik 34464, czyli 344,64hPa...
Poszukaj więc w swym kodzie miejsc, gdzie używasz
funkcji oczekującej argumentu typu int (2 bajty) i tam
posyłasz argument typu long (4 bajty) który zostaje przez
kompilator ucięty do oczekiwanych przez funkcję 2 bajtów.
Podejrzewałbym następujące linie Twojego kodu:
1) itoa(pressure, result, 10);
Prototyp funkcji:
char * itoa ( int value, char * str, int base );
Funkcja oczekuje int'a, posyłasz jej argument typu int32.
Bad boy! :-)
2) printf_P(pAnswer, PSTR("+PRESS: %d\r\n"), bmp085_getpressure());
Funkcja printf dekodując format %d szuka na stosie wartości
typu int, co ma dwa bajty a Ty podajesz wartość 4-bajtową.
Zamień ten format %d na %ld, czyli zapisz tą linię tak:
printf_P(pAnswer, PSTR("+PRESS: %ld\r\n"), bmp085_getpressure());
http://www.cplusplus.com/reference/cstdio/printf/
Pszemol
Guest
Wed Apr 23, 2014 11:34 pm
"Grzegorz Niemirowski" <gnthexfiles@poczta.onet.pl> wrote in message
news:lj9h2d$sl2$1@node1.news.atman.pl...
Quote:
ale jakbyś podał wartości, to myślę, że byłoby łatwiej.
Podał przecież... Cytuję:
"że wartość ciśnienia jest nieprawidłowa - wychodzi jakieś 300 HPa..."
Elektrolot
Guest
Thu Apr 24, 2014 8:32 am
W dniu 2014-04-23 19:10, Atlantis pisze:
Quote:
Próbuję właśnie uruchomić BMP085 w jednym ze swoich urządzeń i powoli
zaczynam z tego powodu siwieć.
Na tej stronie też jest przykładowy soft do obsługi BMP085:
https://www.olimex.com/Products/Modules/Sensors/MOD-BMP085/open-source-hardware
Atlantis
Guest
Thu Apr 24, 2014 2:26 pm
W dniu 2014-04-24 01:31, Pszemol pisze:
Quote:
Podejrzewałbym następujące linie Twojego kodu:
1) itoa(pressure, result, 10);
Dokładnie, ta diagnoza okazała się być poprawną. Najpierw nie
zauważyłem, że itoa() przyjmuje short inta, a potem przeoczyłem literkę
"l" w tokenie obsługującym przesyłaną wartość w sprintf_P. Zaowocowało
to takim samym błędem.
Teraz wszystko działa, otrzymuję ciśnienie o prawdopodobnej wartości.
Jeśli chodzi o temperaturę, to zastosowana biblioteka zwraca ją jako
double. Myślę, że nie będę się już bawił w jej przerabianie, zresztą
miło byłoby, gdyby wynik był zwracany w normalnych jednostkach, a nie
0,1 stopnia C.
Włączanie operacji zmiennoprzecinkowych w stdio.h raczej nie chodzi w
grę. Nie dosyć, że kod od tego tyje, to jeszcze zużywane są cykle procesora.
Dobrze pamiętam tę sztuczkę?
double temperature = bmp085_gettemperature();
int16_t intpart = (int16_t)temperature;
int16_t decpart = ((int16_t)(temperature*2)%2);
sprintf_P(pAnswer, PSTR("+TEMP: %d.%d\r\n"), intpart, decpart);
Atlantis
Guest
Thu Apr 24, 2014 3:13 pm
W dniu 2014-04-24 16:26, Atlantis pisze:
Quote:
int16_t decpart = ((int16_t)(temperature*2)%2);
Tfu! Tutaj oczywiście nie chodziło mi o liczbę miejsc po przecinku
wpisywaną w formie wartości bezwzględnej, ale jako mnożnik. Czyli 10,
100, 1000 itp.
Pszemol
Guest
Thu Apr 24, 2014 6:04 pm
"Atlantis" <marekw1986NOSPAM@wp.pl> wrote in message
news:ljb6vm$mdt$1@portraits.wsisiz.edu.pl...
Quote:
W dniu 2014-04-24 01:31, Pszemol pisze:
Podejrzewałbym następujące linie Twojego kodu:
1) itoa(pressure, result, 10);
Dokładnie, ta diagnoza okazała się być poprawną. Najpierw nie
zauważyłem, że itoa() przyjmuje short inta, a potem przeoczyłem literkę
"l" w tokenie obsługującym przesyłaną wartość w sprintf_P. Zaowocowało
to takim samym błędem.
Teraz wszystko działa, otrzymuję ciśnienie o prawdopodobnej wartości.
No to fajnie

) Cieszę się, że mi kryształowa kula wciąż działa dobrze ;-)
Quote:
Jeśli chodzi o temperaturę, to zastosowana biblioteka zwraca ją jako
double. Myślę, że nie będę się już bawił w jej przerabianie, zresztą
miło byłoby, gdyby wynik był zwracany w normalnych jednostkach, a nie
0,1 stopnia C.
Włączanie operacji zmiennoprzecinkowych w stdio.h raczej nie chodzi w
grę. Nie dosyć, że kod od tego tyje, to jeszcze zużywane są cykle
procesora.
Dobrze pamiętam tę sztuczkę?
double temperature = bmp085_gettemperature();
int16_t intpart = (int16_t)temperature;
int16_t decpart = ((int16_t)(temperature*2)%2);
sprintf_P(pAnswer, PSTR("+TEMP: %d.%d\r\n"), intpart, decpart);
Hm... Sprawdźmy na szybko... :-)
Temperatura pokojowa, załóżmy 21,563C.
Mamy więc wartość zmiennej 'temperature' w dziesiątych Celciusza: 215.63
A więc wartość intpart jest automagicznie 215, tu OK.
Wartość decpart obliczamy, w kolejności, mnożąc 215.63*2 = 431.26
Teraz rzutujemy takiego doubla do inta, mamy 431.
Reszta z dzielenia tego 431 przez 2 wyjdzie nam 1.
Czyli sprintf wyświetli 215.1 zamiast 215.63 - kiepsko.
Lepiej chyba zrobić tak:
double dblTemperature = bmp085_gettemperature();
int iTemperature = ( dblTemperature < 0 ) ? dblTemperature - 0.5 :
dblTemperature + 0.5;
sprintf(pAnswer, "+TEMP: %d.%d\r\n"), iTemperature, iTemperature%10);
Podstawmy nasz przykład z dblTemperature = 215.63.
iTemperature = (int)(216.13);
Zatem
iTemperature = 216
Dla wartości z przedziału < xx.5, np dblTemperature = 215.33.
iTemperature = (int)(215.83);
Zatem
iTemperature = 215
Dla temperatur ujemnych, np dblTemperature = -215.63.
iTemperature = (int)(-216.13);
Zatem
iTemperature = -216
Ale nie bardzo rozumiem czemu skoro już masz typ zmiennej double
w swoim kodzie, a więc musiałeś włączyć takie liczby, nie?
Czemu więc nie zrobisz po prostu tak:
double dblTemperature = bmp085_gettemperature();
sprintf_P(pAnswer, PSTR("+TEMP: %.1f\r\n"), dblTemperature/10.0);
I od razu uwaga, pewnie zauważyłeś dodałem przedrostki oznaczające
typ zmiennej... Tak się po prostu łatwiej czyta kod, zwłaszcza jak używasz
zmiennych o bardzo różnych typach które dawałyby niebezpieczne efekty
przy cichym (domyślnym) rzutowaniu przez kompilator...
Takie przedrostki to popularna konwencja zwana "notacją węgierską",
warto się jej od razu nauczyć i trzymać nawet w małych programach
a jak wejdzie Ci w nawyk to będziesz miał później jak znalazł
http://pl.wikipedia.org/wiki/Notacja_w%C4%99gierska
Sylwester Ĺazar
Guest
Thu Apr 24, 2014 7:01 pm
Ładnie chłopcy pomujecie ten produkt
No muszę przyznać, że zupełny profesjonalizm!
I są gotowe przykłady i miła obsługa...
Jednak dorzuciłbym ten klaser:
http://www.kamami.pl/index.php?ukey=product&productID=203517
To jest niezwykle ciekawa rzecz i cena niemal ta sama.
Poważnie piszę.
S.
Sylwester Ĺazar
Guest
Thu Apr 24, 2014 7:01 pm
Ładnie chłopcy pompujecie ten produkt
Muszę przyznać, że zupełny profesjonalizm!
I są gotowe przykłady i miła obsługa...
Jednak dorzuciłbym ten klaser:
http://www.kamami.pl/index.php?ukey=product&productID=203517
To jest niezwykle ciekawa rzecz i cena niemal ta sama.
Poważnie piszę.
S
Grzegorz Niemirowski
Guest
Thu Apr 24, 2014 7:10 pm
Pszemol <Pszemol@PolBox.com> napisał(a):
Quote:
Podał przecież... Cytuję:
"że wartość ciśnienia jest nieprawidłowa - wychodzi jakieś 300 HPa..."
Nie podał. Pytałem o wartości trzech bajtów odebranych po I2C, a nie końcowy
wynik obliczeń.
--
Grzegorz Niemirowski
http://www.grzegorz.net/
OE PowerTool i Outlook Express:
http://www.grzegorz.net/oe/
Uptime: 13 days, 19 hours, 23 minutes and 58 seconds
Sylwester Ĺazar
Guest
Thu Apr 24, 2014 7:14 pm
Quote:
Ładnie chłopcy pompujecie ten produkt
Muszę przyznać, że zupełny profesjonalizm!
I są gotowe przykłady i miła obsługa...
A Ty znowu zapomniałeś dziś zażyć lekarstwa i masz te swoje chore
urojenia?
Dlaczego jesteś taki szorstki?
Wolę, żebys tutaj się udzielał niż w wątku ze zwykłymi życzeniami, który
dzięki Tobie rozrósł się do ćwierć tysiąca postów (!!!).
Doceń to, jak ja doceniam Twoją pracę.
S.
Goto page 1, 2 Next