Powrót

Kurs Arduino – Arduino Pro Mini Strong

–W poprzednim odcinku (UR014) wstępnie  zapoznaliśmy się z płytką Arduino Pro Mini. Teraz chcemy na jej podstawie zbudować taki rejestrator, jak w poprzednich ćwiczeniach.

W czasie normalnej pracy rejestrator nie będzie dołączony do komputera PC. Ale płytkę Arduino trzeba zaprogramować. Dlatego najpierw za pomocą konwertera USB/TTL połączymy komputer z Arduino i zaprogramujemy procesor. W tym czasie procesor, a nawet cały system będą zasilane z komputera za pośrednictwem konwertera USB. Potem odłączymy konwerter USB/TTL od komputera i do końcówek złącza programującego płytki Arduino dołączymy moduł OpenLog. Wtedy płytkę trzeba będzie zasilić z jakiegoś oddzielnego źródła, np. z zasilacza 5V.

W takim rozwiązaniu podczas pracy systemu (podczas rejestracji) nie ma komunikacji z komputerem, więc teraz już można i wręcz trzeba wykorzystać sprzętowe złącze szeregowe i dedykowane piny Arduino RXI,  TXO. Schemat układu pokazany jest na rysunku 1.

Rysunek 1

Jest to ten sam układ, co na rysunku 4 w odcinku 13, tylko wykorzystujemy sprzętowe łącze szeregowe. Zwróć uwagę, że piny RXI, TXO wyprowadzone są na „złącze programujące”, a Twórca OpenLog zadbał, żeby dołączenie rejestratora do Arduino Pro Mini było bajecznie proste.

Z wcześniejszego programu A1303.ino usunąłem fragmenty dotyczące programowego łącza szeregowego (SoftwareSerial). Powstał program A1501.ino (kluczowe fragmenty pokazuje szkic 1).

Szkic 1:

// NIE wykorzystujemy programowego łącza szeregowego!

#include <Wire.h> // biblioteka I2C
#include <RtcDS3231.h> // RTC – DS3231
#include <OneWire.h>
#include <DallasTemperature.h>
RtcDS3231<TwoWire> zegar(Wire); //obiekt zegar RTC
OneWire obiektOneWire(A0); //wykorzystujemy pin A0
DallasTemperature czujniki(&obiektOneWire);
int liczbaCzujnikow; DeviceAddress tmpAdresyCzujnikow;
 
void setup(void)   { zegar.Begin(); //inicjalizacja
 Serial.begin(9600);  czujniki.begin();
 liczbaCzujnikow = czujniki.getDeviceCount();
 /* tu pozostaje ustawianie czasu RTC */  }
 
void loop(void)  { if (digitalRead(A2) == LOW)
 {  delay(100);   }   else   {
 RtcDateTime czasAktualny = zegar.GetDateTime();
 czujniki.requestTemperatures();
 String mojRekord = „”; //obiekt typu String
 mojRekord += String(czasAktualny.Year());
 mojRekord += ’-’;
 mojRekord += String(czasAktualny.Month());
 mojRekord += ’-’;
 mojRekord += String(czasAktualny.Day());
 mojRekord += 'T’; // wstawiamy literkę T
 mojRekord += String(czasAktualny.Hour());
 mojRekord += ’:’;
 mojRekord += String(czasAktualny.Minute());
 mojRekord += ’:’;
 mojRekord += String(czasAktualny.Second());
 mojRekord += ’,’;
 for(int i=0;i<liczbaCzujnikow; i++)   {
  czujniki.getAddress(tmpAdresyCzujnikow, i);
  float tempC = czujniki.getTempC(tmpAdresyCzujnikow);
  mojRekord += String(tempC);
  mojRekord += „,”; } //koniec odpytywania czujników
 Serial.println(mojRekord); delay(1000);  } }

Także i tu wykorzystujemy obiekt (złożoną zmienną) typu String o nazwie mojRekord i najpierw gromadzimy w niej dane z jednego pomiaru trzech czujników, a potem całość przesyłamy łączem szeregowym do OpenLog. Jak pokazuje rysunek 2, program po kompilacji zajmie 37% pamięci programu i 23% pamięci RAM.

Rysunek 2

Ponieważ moduł OpenLog zbiera odebrane dane w buforze o pojemności 512 bajtów i dopiero wtedy zapisuje taką porcję na karcie, zamiast wykorzystywać pamięciożerny obiekt typu String, możemy obejść się bez niego i kolejne dane bezpośrednio wysyłać do modułu OpenLog, nie gromadząc ich w zmiennej mojRekord ani w żadnej innej.

Taka wersja programu zawarta jest w szkicu A1502.ino, a zmieniona pętla loop() pokazana jest w szkicu 2:

void loop(void)  { if (digitalRead(A2) == LOW)
 {  delay(100);   }   else   {
  RtcDateTime czasAktualny = zegar.GetDateTime();
  czujniki.requestTemperatures();
  Serial.print(czasAktualny.Year());
  Serial.print(’-’);
  Serial.print(czasAktualny.Month());
  Serial.print(’-’);
  Serial.print(czasAktualny.Day());
  Serial.print(’T’); // wstawiamy literkę T
  Serial.print(czasAktualny.Hour());
  Serial.print(’:’);
  Serial.print(czasAktualny.Minute());
  Serial.print(’:’);
  Serial.print(czasAktualny.Second());
  Serial.print(’,’);
  for(int i=0;i<liczbaCzujnikow; i++)   {
    czujniki.getAddress(tmpAdresyCzujnikow, i);
    float tempC = czujniki.getTempC(tmpAdresyCzujnikow);
    Serial.print(tempC);
    Serial.print(„,”); } //koniec odpytywania czujników
  Serial.println(); delay(1000);  } }

Rysunek 3

Jak widać na rysunku 3, usunięcie  zmiennej typu String znacząco odchudziło program, który zajmuje tylko 29% pamięci programu i nadal 23% pamięci RAM. Zmienne typu String są bardzo wygodne w użyciu, ale niestety okupione jest to poważnym zwiększeniem objętości programu, ponieważ nie są to „proste zmienne”, tylko obiekty o skomplikowanej obsłudze (ale przyjazne dla użytkownika). Przypomnijmy dla porównania, że nasz pierwszy program rejestratora bez OpenLog, tylko z modułem czytnika kart SD, zajmował 66% pamięci programu i 64% pamięci RAM (odcinek 13, rysunek 1).

Pierwszą wersję rejestratora do tego ćwiczenia zrealizowałem na płytce Arduino Pro Mini, będącej tanim chińskim klonem o „kanonicznych” rozmiarach, która jest mniejsza od zastosowanego modułu RTC z DS3231, co jest pokazane na fotografii 4.

Fotografia 4

Na tej fotografii widać też  opisane w poprzednim odcinku połączenie płytki Arduino (w którą wlutowana jest listwa kątowych goldpinów) z modułem OpenLog (gdzie wlutowana jest listwa z nasadką z otworami).

Na fotografii 4 widać też moduł miernika z podwójnym czterocyfrowym wyświetlaczem, który został włączony w obwód zasilania i pokazuje aktualne napięcie zasilania i pobór prądu. Ten moduł ma po cztery cyfry, więc rozdzielczość pomiaru prądu to 1mA, a napięcia 10mV.

W tej wersji zarówno programowanie, jak i rejestracja z wykorzystaniem obu omówionych szkiców nie sprawiła żadnych problemów: przebiegły jak po maśle.

Postanowiłem też wykorzystać inną wersję, chiński klon Arduino Pro Mini w postaci kwadratowej płytki. Tego rodzaju odmiany oznaczane są strong (fotografia 5), a w opisach handlowych zwykle pojawia się liczba 14.

Fotografia 5

Warto wiedzieć, że dostępne są tego rodzaju „kwadratowe” wersje Arduino Nano, Arduino Pro Micro (fotografia 6), a także innych odmian, w tym z ESP8266 z interfejsem Wi-Fi.

Fotografia 6

Dla wielu osób cenną zaletą takich wersji jest duża liczba otworów/pinów masy i zasilania VCC, bowiem przy wykorzystaniu „kanonicznych” płytek Mini/Micro, zawsze problemem jest właśnie zbyt mała liczba końcówek VCC i GND.

Niestety, przy próbie wykorzystania kwadratowej płytki w wersji „strong” z modułem OpenLog pojawiła się przedziwna zagadka. Procesor na tej płytce został prawidłowo zaprogramowany szkicem A1501.ino, ale po odłączeniu programatora, dołączeniu OpenLog i uruchomieniu rejestracji na karcie nic nie zostało zapisane. Rozwiązanie tego i kilku innych problemów zajęło mi wiele czasu. Ponieważ są to typowe problemy, związane z wykorzystaniem tak bardzo popularnych w naszym kraju tanich chińskich modułów związanych z otwartym i „bezpłatnym” systemem Arduino, koniecznie trzeba je opisać szerzej. Będzie to ostrzeżeniem, przygotowaniem, z czym trzeba się liczyć oraz zachętą i wskazówką, jak sobie z tym radzić.

Zanim omówimy problemy z układem z fotografii 7, najpierw o innych przykrych niespodziankach, na jakie natrafiłem.

Fotografia 7

Otóż do tej pory zasilaliśmy płytkę Arduino i dołączone moduły z gniazda USB komputera. Płytka cały czas była dołączona do komputera. Do wstępnych testów jest to bardzo wygodne, ale w praktycznych układach trzeba zapewnić zasilanie zewnętrzne. Zasadniczo wystarczy jakikolwiek zasilacz, nawet niestabilizowany, bo płytki Arduino mają wbudowane stabilizatory.

Ja, chcąc mieć na bieżąco kontrolę nad sytuacją, do starego transformatorowego (nie impulsowego, celowo!) zasilacza stabilizowanego 5V 500mA dołączyłem moduł monitora napięcia i prądu w wersji z 4-cyfrowym wyświetlaczem, co na jednym zakresie pozwala sprawdzać napięcie z rozdzielczością 10mV i prąd z rozdzielczością 1mA. Podłączenie jest proste. Niestety ujawnił się problem przy najmniejszych prądach: w zakresie prądów do kilku miliamperów wskazanie mojego egzemplarza jest równe zeru. Pokazany na wyświetlaczu wynik pomiaru rzędu kilku czy kilkunastu miliamperów jest więc poważnie zafałszowany. Z uwagi na inne pilne zajęcia pozostawiłem ten problem do rozwiązania w przyszłości.

Inna przykra niespodzianka dotyczyła małej liczby pinów GND i VCC „kanonicznej” wersji. Do realizacji układu testowego z małymi płytkami Arduino (fotografia 4) wykonałem więc „rozgałęziacze” (fotografia 8).

Fotografia 8

Fotografia 9

Niestety, nie było to łatwe! Okazało się, że moje tanie przewody z nasadkami (tzw. Dupont), pokazane na fotografii 9, nie są wykonane z miedzi (tylko prawdopodobnie ze stopu aluminium i magnezu). Można je zaciskać, ale za żadne skarby nie można było ich pobielić i przylutować. Straciłem niemało czasu, wypróbowując wszystkie posiadane topniki, także te agresywne. Poddałem się dopiero po wykonaniu telefonu do przyjaciela, który zajmuje się importem elektroniki z Chin i zetknął się już z tym problemem.

Trzeba było wymienić przewody. Wymagało to wyjęcia styków z plastikowych nasadek, odcięcia oryginalnych nielutowalnych przewodów i przylutowania do styków nowych przewodów miedzianych. Operacje te trzeba  przeprowadzać ostrożnie i delikatnie, żeby nie uszkodzić, nie pogiąć delikatnych blaszek.

Fotografia 10

Inną przykrą niespodzianką było to, że jeden z dwóch posiadanych modułów  OpenLog (fotografia 10) nie chciał pracować, przez co też straciłem sporo czasu. Przypuszczam, że może jest to tylko wina oprogramowania, ale nie drążyłem sprawy i znalezienie odpowiedzi też pozostawiłem na później. Wymieniłem moduł na drugi, sprawny. Podobny problem może dotyczyć wszelkich innych modułów. Dlatego bardzo dobrze jest posiadać co najmniej dwa jednakowe moduły, najlepiej pochodzące od różnych sprzedawców. W razie problemów pozwoli to zaoszczędzić mnóstwo czasu, bo prawdopodobieństwo, że oba będą uszkodzone, jest bardzo małe.

A teraz największy, symptomatyczny problem, wynikający ze specyfiki Arduino. Wersja rejestratora z kwadratowym modułem Arduino Pro Mini Strong przedstawiona na fotografii 7 stworzyła zagadkę, której zbadanie i rozwiązanie pochłonęło mnóstwo czasu.

Taki układ nie działał. Tu muszę dodać, że wcześniej, po pierwszym  podłączeniu zasilania, w tym kwadratowym module Arduino migała dioda LED dołączona do pinu 13 (SCK). Był to dowód, że producent wpisał do procesora prościutki program, co jest powszechną godną pochwały praktyką, bo od razu pokazuje użytkownikowi, że moduł jest sprawny.

Aby przekonać się, że wszystko działa, dołączyłem konwerter USB/TTL do „złącza programującego”, które ma oznaczenia identyczne jak „kanoniczna”  płytka Arduino Pro Mini, co widać na fotografii 11.

Fotografia 11

Zmodyfikowałem przykładowy szkic Blink.ino, zmieniając rytm pulsowania diod i zaprogramowałem płytkę. Ten prosty eksperyment udowodnił, że programowanie za pomocą konwertera USB/TTL działa prawidłowo, identycznie jak w „kanonicznej” płytce Arduino Pro Mini z fotografii 4.

Jednak po zaprogramowaniu szkicem A1501.ino i po zestawieniu rejestratora  według schematu z rysunku 12 i fotografii 7, gdzie do złącza programującego został podłączony OpenLog, system nie działał, a konkretnie po próbie rejestracji karta pozostawała całkiem pusta. Okazało się, że OpenLog nie zapisywał na niej nawet pliku config.txt.

Rysunek 12

Okolicznością, która mnie zmyliła było to, że jedna z dwóch diod OpenLog migała, ale w innym rytmie niż normalnie podczas rejestracji.

Jeśli dioda LED świeci, a rejestrator OpenLog nie pracuje, to narzuca się dość oczywisty wniosek, że zasilanie jest w porządku. Podejrzenie pada na linie cyfrowe złącza programującego. A jak widać na fotografii 7, OpenLog z przylutowaną nasadką, wpięty na kołki „złącza programującego”, miał podłączone nie tylko masę GND, zasilanie VCC (+5V) i linię RXI, ale też linie DTR i TXO. Podejrzenie padło na te właśnie linie złącza programującego.

Aby odciąć się od złącza programującego, najpierw dołączyłem moduł OpenLog w wersji minimalistycznej, a więc tylko trzema przewodami, jak to robiliśmy przy pierwszych eksperymentach OpenLog z płytką Arduino Uno. W przypadku Arduino Uno oraz „kanonicznej” płytki Arduino Pro Mini (rysunek 13) rejestrator działał prawidłowo.

Rysunek 13

Jednak w układzie z fotografii 7 po takim samym dołączeniu przewodami do złącza programującego „stronga”, według rysunku 14, OpenLog nie pracował.

Rysunek 14

Wiadomo, że w Arduino cyfrowy pin 0 (D0) to wejście RXI, a pin 1 (D1) to TXO.  Jednak po przepięciu linii danych według rysunku 15 rejestrator nadal nie działał!

Rysunek 15

O zgrozo, rejestrator nie działał też po przepięciu obu linii zasilania według rysunku 16 i fotografii 17!  A przecież sprawdzałem, że ten moduł OpenLog jest sprawny! Wszystko wskazywało, że problem jest gdzieś na kwadratowej płytce „strong”.

Rysunek 16

Fotografia 17

Tylko gdzie?

O ile dobrze pamiętam ze swojej wczesnej młodości, Mark Twain w książce Przygody Tomka Sawyera napisał o detektywie, który przybył do miasta, by schwytać Indianina Joego. Otóż ten detektyw wpadł na trop, ale tropu nie powiesisz zamiast mordercy, więc detektyw po tym zdumiewającym rezultacie odjechał

Po opisanych właśnie testach poczułem się dokładnie jak ten detektyw z St. Louis: też wpadłem na trop. Ale zachowanie systemu było absolutnie nieoczekiwane! I niemal niewytłumaczalne!

W trakcie dalszego badania sprawy zaczęła się ujawniać zaskakująca historia detektywistyczna. Problem okazał się obszerny, wielowątkowy, a niektóre elementy układanki wywoływały uśmiech. Szczegóły i rozwiązanie omawiamy w następnym odcinku (UR016).

Piotr Górecki