Tajemnice wejść analogowych Arduino Leonardo i Yun

W Arduino Leonardo i Arduino Yun zastosowano inny kontroler niż w tradycyjnych płytkach. Jest nim ATmega32u4. Ma on kilka zalet w porównaniu z poprzednikami – sprzętowe USB, więcej wyjść PWM i więcej wejść analogowych.

Wejścia analogowe oprócz tradycyjnych cech opisanych w poprzednim wpisie mają też nowe możliwości.

long readADC(byte ref, byte input)
{
  ADMUX = (input & 31) | ((ref & 3) << 6);
  bitWrite(ADCSRB, 5, ((input & 32) >> 6));
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  long result = ADCL;
  result |= ADCH<<8;
  
  return result;
}

void setup() 
{
  while (!Serial);
  Serial.begin(9600);
}

void loop() 
{
  Serial.println(readADC(3, 39));
  delay(1000);
}

Użyta w programie funkcja readADC pozwala je odkryć.

word value = readADC(ref, input);

  • value – wartość odczytana z wejścia analogowego (0 – 1023)
  • ref – numer źródła napięcia referencyjnego
  • input – numer wejścia analogowego.

Argument “ref” może przyjąć następujące wartości:

  • 0 – napięcie referencyjne to napięcie zasilania
  • 1 – napięcie referencyjne pochodzi z pinu AREF
  • 3 – napięcie referencyjne pochodzi z dokładnego źródła 2,56 V

Jeśli czytałeś poprzedni wpis to zadanie i możliwości napięcia referencyjnego są ci znane.

Dużo ciekawiej jest z drugim argumentem “input”. Zacznę od standardowych możliwości.

Wprowadzając tam jedną z tych wartości odczytujesz standardowe wejścia analogowe:

  • 0    A5
  • 1    A4
  • 4    A3
  • 5    A2
  • 6    A1
  • 7    A0
  • 32    D4/A6
  • 33    D12/A7
  • 34    D6/A8
  • 35    D8/A9
  • 36    D9/A10
  • 37    D10/A11

Do tej pory nuuuda. Wszystko prawie jak bibliotekach Arduino, tylko bardziej zagmatwane ;-). Jednak mamy do dyspozycji więcej liczb w tym argumencie, które kryją dodatkowe możliwości.

Następna grupa to:

  • 30    1.1 V
  • 31    0 V
  • 39    Temperatura

Wartość 30 argumentu podaje na wejście przetwornika dokładne napięcie 1,1 V. Pozwala to skalibrować wynik podawany przez wejście i napięcie odniesienia. Tak jak w poprzednim wpisie.

Wartość 31 podaje na wejście analogowe 0 V. To taka wartość testowa, czy przetwornik zwróci wynik 0.

Wartośc 39 odczytuje temperaturę panującą w środku kontrolera. Pomiar nie jest zbyt precyzyjny. Ma dokładność +/-10 stopni Celsjusza. Służy głównie do tego by kalibrować wewnętrzne elementy wrażliwe na temperaturę (jak generator RC). Trudno nim zmierzyć temperaturę w pokoju, bo przecież kontroler też się nagrzewa podczas pracy.

Kolejne wartości dotyczą wejść symetrycznych.

Standardowo wejścia analogowe Arduino mierzą napięcie między pinami GND i wybranym wejściem analogowym.

W wejściach symetrycznych dostajesz do dyspozycji 2 wejścia analogowe. Jedno z biegunem dodatnim “+”, a drugie z biegunem ujemnym “-”. Napięcie jest mierzone między tymi biegunami.

Wejścia symetryczne ułatwiają wiele obwodów w których nie chcesz do pomiarów używać GND. Jak np. w pomiarze prądu za pomocą rezystora o małej wartości, albo przy czujnikach wagi w układzie mostka.

Wartości wejść symetrycznych to:

  • 16    +A5    -A4
  • 20    +A3    -A4
  • 21    +A2    -A4
  • 22    +A1    -A4
  • 23    +A0    -A4

Czyli biegun dodatni takiego wejścia jest w wybranym pinie A0, A1, A2, A3, A5, a biegun ujemny jest w pinie A4.

Wejścia symetryczne mają jeszcze jedną opcję. Pozwalają przepuścić wejście przez wzmacniacz i wzmocnić sygnał od 10 do 200 razy.

Kombinacja wejść symetrycznych i siła wzmocnienia przypisana jest do następujących wartości:

  • 9    +A4    -A5    x10
  • 11    +A4    -A5    x200
  • 38    +A4    -A5    x40
  • 40    +A3    -A5    x10
  • 41    +A2    -A5    x10
  • 42    +A1    -A5    x10
  • 43    +A0    -A5    x10
  • 44    +A3    -A4    x10
  • 45    +A2    -A4    x10
  • 46    +A1    -A4    x10
  • 47    +A0    -A4    x10
  • 48    +A3    -A5    x40
  • 49    +A2    -A4    x40
  • 50    +A1    -A5    x40
  • 51    +A0    -A5    x40
  • 52    +A3    -A4    x40
  • 53    +A2    -A4    x40
  • 54    +A1    -A4    x40
  • 55    +A0    -A4    x40
  • 56    +A3    -A5    x200
  • 57    +A2    -A5    x200
  • 58    +A1    -A5    x200
  • 59    +A0    -A5    x200
  • 60    +A3    -A4    x200
  • 61    +A2    -A4    x200
  • 62    +A1    -A4    x200
  • 63    +A0    -A4    x200

Wzmocnienie 200 razy przy napięciu odniesienia 2,56 V pozwoli zmierzyć napięcia nawet do 12,5 mikrowolta.

sprae

Dokładniejsze wejścia analogowe w Arduino Yun i Leonardo

Każde Arduino ma wejścia analogowe w sekcji ANALOG IN (od A0 do A5). Pozwalają one dokładnie mierzyć napięcie.
Arduino Yun i Leonardo mają więcej wejść analogowych. Są one ukryte w pinach sekcji DIGITAL.

  • Pin cyfrowy 4 to wejście analogowe A6
  • Pin cyfrowy 6 to wejście analogowe A8
  • Pin cyfrowy 8 to wejście analogowe A9
  • Pin cyfrowy 9 to wejście analogowe A10
  • Pin cyfrowy 10 to wejście analogowe A11
  • Pin cyfrowy 12 to wejście analogowe A7

Napięcie na wejściach analogowych mierzysz za pomocą funkcji “analogRead”

word value = analogRead(numer_wejścia);

Gdzie:

  • value – zmienna przechowująca wynik pomiaru od 0 do 1023. Gdzie 0 to 0 V, a 1023 to domyślnie 5 V.
  • numer_wejścia – numer wejścia analogowego zależnie od pinu w Yun to wartości do 0 dla pinu A0 do 11 dla pinu A11.

Dokładność pomiaru wejść analogowych zależy od napięcia odniesienia.

Napięcie odniesienia to wzorcowe napięcie, przy którym przetwornik wejścia analogowego wskazuje wartość maksymalną (1023).

Napięcie odniesienia ustawiasz za pomocą funkcji “analogReference”.

analogReference(reference);

reference – rodzaj napięcia odniesienia.
Rodzaj wybieramy za pomocą stałych, gdzie:

  • DEFAULT – napięciem odniesienia jest napięcie zasilania około 5 V
  • INTERNAL – napięciem odniesienia jest dokładne napięcie 2,56 V
  • EXTERNAL – napięciem odniesienia jest napięcie podłączone do pinu AREF

W zależności od tego jaki zakres wyjść ma czujnik podłączony do wejścia analogowego, wartość napięcia odniesienia powinna być większa lub równa z jego zakresem.

Najbardziej dokładny jest rodzaj INTERNAL, ale nadaje się od tylko do urządzeń z wyjściem od 0 do 2,5 V (np pojedyncze ogniwa baterii).

Najmniej dokładny jest rodzaj DEFAULT, bo napięcie zasilania nie ma idealnie 5 V. Zmienia się pod wpływem różnych warunków np. obciążenia, albo zakłóceń.

Można poprawić dokładność pomiaru z referencją DEFAULT. W tym celu przerobiłem mały programik, który zwróci dokładne napięcie odniesienia.

long readVcc()
{
  ADMUX = _BV(REFS0) | _BV(MUX1) | _BV(MUX2) | _BV(MUX3) | _BV(MUX4);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  long result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}

void setup() 
{
  while (!Serial);
  Serial.begin(9600);
}

void loop() 
{
  Serial.println(readVcc());
  delay(1000);
}

Funkcja “readVcc” zwraca dokładną wartość napięcia zasilania w mili voltach. Właśnie dla takiego napięcia przetwornik będzie zwracał wartość 1023.

Ciekawe, że Arduino Yun zwróciło mi wartość zasilania 4200 mV.

sprae

Licznik na przerwaniach

Wczoraj zamieściłem wpis “Najszybszy projekt na świecie”, w którym opisałem jak zbudować licznik do orbitreka. Michał poprosił w komentarzach, bym w celach edukacyjnych pokazał jak napisać taki licznik na przerwaniach.

Przerwanie – sygnał z urządzenia peryferyjnego, który powoduje zatrzymanie programu głównego i uruchomienie funkcji obsługującej przerwanie.

W Arduino wejścia przerwań są w pinach cyfrowych 2 i 3. W UNO przerwanie 0 jest w pinie 2, a przerwanie 1 w pinie 3. W Leonardo jest odwrotnie :-.

Do obsługi przerwań służy funkcja “attachInterrupt”

attachInterrupt(int, func, mode);

  • int – numer przerwania 0 lub 1 w zależności od pinu
  • func – nazwa fukcji obsługującej przerwanie
  • mode – ustala kiedy przerwanie ma być wywołane:
    LOW – kiedy na pinie jest stan niski;
    CHANGE – kiedy zmienia się stan;
    RISING – kiedy zmienia się stan z LOW na HIGH;
    FALLING – kiedy zmienia się stan z HIGH na LOW.

Program licznika z użyciem przerwania będzie wyglądał tak:

word steps;

void setup()
{
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, onStep, FALLING);
}

void loop()
{
}

void onStep()
{
  static unsigned long lastTime;
  unsigned long timeNow = millis();
  if (timeNow - lastTime < 50)
    return;
    
  steps++;
  Serial.println(steps);
  lastTime = timeNow;
}

Ustawiłem przerwanie nr 0 (pin 2 w UNO). Ma ono wywoływać funkcję “onStep”. Wywołanie nastąpi gdy stan na pinie zmieni się z HIGH na LOW.

Funkcja “onStep” zaczyna się od fragmentu eliminującego drgania styków.
Gdy włącznik (u nas kontaktron) zwiera styki, to przez ułamek sekundy one drgają. Te drgania mogą spowodować, że wywoła się kilka przerwań i funkcja zaliczy kilka kroków.
Dlatego początek sprawia, że pierwsze przerwanie będzie zaliczone, a każde kolejne przez 50 ms zostanie zignorowane jako drgania styków i nie zaliczy kroku.

Liczba kroków przechowywana jest jak poprzednio w zmiennej globalnej “steps”.

W funkcji “loop” możesz napisać dowolny fragment programu. Gdy pojawi się impuls na pinie 2, program w “loop” zostanie przerwany i wykonana zostanie funkcja “onStep”. Po jej zakończeniu program w “loop” zacznie pracę tam gdzie skończył.

Fragment eliminujący drgania styków działa tak:

Zmienna typu static przechowuje wartość nawet po wyjściu z funkcji. Na początku ma wartość 0. Po ponownym uruchomieniu funkcji będzie miała wartość taką, jaka była w niej ostatnio zapisana.
W tej zmiennej (“lastTime”) zapisany jest czas ostatniego wywołania przerwania.

W zmiennej “timeNow” zapisany jest aktualny czas,

Po odjęciu timeNow od lastTime uzyskujemy czas jaki upłynął w milisekundach od ostatniego przerwania.
Jeśli jest on mniejszy niż 50 ms, to wychodzimy z funkcji (return).

Jeśli czas jest większy niż 50 ms, zaliczany jest krok, wysyłany do Monitora portu szeregowego i zapisywany jest nowy czas ostatniego przerwania w zmiennej “lastTime”.

sprae

Najszybszy projekt na świecie

Mimo lata to był nieprzyjemny dzień. Było zimno i padało. To nie jest idealna pogoda na bieganie. A ja uwielbiam biegać. W tym miesiącu zrobiłem tak pewnie już ponad 200 km.

Trzeba się czymś zająć. Obok był orbitrek, dzięki któremu utrzymuje formę zimą. Niestety ma zepsuty licznik. Nie wiem czemu, ale lubię doglądać swoich osiągnięć. Szybkość i dystans mnie motywują.

Do czasu na bieganie pozostało 15 minut, a ja postanowiłem, że odbuduje licznik przy pomocy Arduino.

W tego typu maszynach przebyty dystans oblicza się za pomocą liczby obrotów korby pedałów. Czujnikiem jest kontaktron. To taki włącznik, który przewodzi prąd, gdy zbliży się do niego magnes. Na kole jest magnes, a gdzieś do ramy obok przytwierdzony jest kontaktron.

Jeden impuls kontaktronu to jeden obrót pedałami orbitreka, czyli 2 kroki.

Czujnik podłączyłem do Arduino między cyfrowy pin 2 i GND.
Takie wejście ustawiasz w programie jako:

pinMode(2, INPUT_PULLUP);

Wtedy gdy czujnik nie przewodzi prądu, na wejściu jest poziom HIGH. Gdy magnes zbliży się do czujnika, na wejściu pojawi się poziom LOW.
Poziom wejścia czujnika badasz za pomocą:

byte level = digitalRead(2);

W zmiennej “level” będzie pojawiała się wartość LOW albo HIGH.

Podczas spacerów z GPS ustaliłem, że przejście 10 m zabiera mi około 12 do 14 kroków. Przebiegnięcie 100 m to jakieś 66 kroków, ale tego wyniku nie jestem pewny, bo pomiar robiłem tylko raz.

Dla jednego kroku chodu, wychodzi około:

10 m / 13 kroków = 76 cm/krok

Ponieważ jeden impuls to 2 kroki – wychodzi 1,52 metra/impuls

Biegania nie jestem pewny, ale wyszło 3,03 metra na impuls.

Skoro mam już dane, przyszedł czas na napisanie programu.

word steps;
byte state;

void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(13, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(2) == LOW && state == HIGH)
  {
    digitalWrite(13, HIGH);
    steps++;
    state = LOW;
    onStep();
  }
  
  else if (digitalRead(2) == HIGH)
  {
    digitalWrite(13, LOW);
    state = HIGH;
  }
}

void onStep()
{
  Serial.print(F("Steps: "));
  Serial.print(steps * 2);
  Serial.print(F(" "));
  Serial.print(F("Distance: "));
  float distance = 3.03 * steps;
  Serial.print(distance/1000.0, 3);
  Serial.println(F(" km "));
}

Funkcja “loop” uruchamiana jest kilkaset tysięcy razy na sekundę. Gdy warunek “if” wykryje impuls, może go odczytać przy każdym uruchomieniu “loop” jako kolejny krok i za jednym obrotem zaliczy nam 1000 kroków. Dlatego po wykryciu kroku trzeba zapamiętać, że już jest zaliczony i poczekać na zmianę poziomu czujnika na HIGH. Tym zajmuje się zmienna “state”.

Zmienna “steps” zlicza obroty korby czyli podwójne kroki.

Ponieważ miałem tylko 15 minut program wyświetla dane jedynie w Monitorze portu szeregowego. Pokazuje liczbę kroków i przebytą odległość. Sam możesz go rozwinąć bardziej o obsługę wyświetlacza LCD, Bluetooth i telefonu/tabletu, albo ładniejszy interfejs użytkownika na ekranie laptopa. Nad tym ostatnim od jakiegoś czasu pracuję. Szczegóły wkrótce.

sprae

Samo balansujący pojazd na Arduino

Samo-balansujący pojazd to takie urządzenie – na jednym, albo dwóch kołach, które samo utrzymuje równowagę. Kierujący przechylając się na pojeździe przesuwa punkt równowagi tak, że urządzenie, by się nie przewrócić musi jechać w kierunku przechylenia. W ten sposób powstały proste pojazdy wyręczające nas w chodzeniu.

Lauszus z bloga TKJ Electronics postanowił zrobić taki pojazd. Wykorzystał do tego 2 silniki elektryczne z przekładnią, sterowniki MOSFET, Arduino Pro Mini oraz czujnik położenia (żyroskop + akcelerometr).


Zdjęcie pochodzi z bloga TKJ Elekctronics

Zasada działania jest prosta. Czujniki położenia obliczają kąt pod jakim przechylone jest jest urządzenie. Arduino stara się ustawić taką moc silników by ten kąt się nie zwiększał i urządzenie się nie przewracało.

Algorytmy wykorzystywane do takiego działania to:

  • Filtr Kalmana – odfiltrowuje szumy z czujników położenia starając się wyłuskać z nich prawdziwy stabilny kąt przechyłu. Bez względu na wibracje spowodowane nierównościami na drodze.
  • Regulator PID – to dynamiczny algorytm dobierający moc silników do przechylenia ciała, tak by była odpowiednia przy jeździe na równej drodze, jak i pod górkę.

Matematyczne podstawy regulatora PID zostały opisane na naszym blogu Starter-Kit.

Do strojenia algorytmów Lauszus podłączył do Arduino moduł Bluetooth. Dzięki niemu pojazd komunikuje się z telefonem na Androidzie, gdzie odpowiednia aplikacja wyświetla jego parametry.

Tak urządzenie prezentuje się podczas jazdy:

sprae

Detektor rodziców na Raspberry PI

Czasem rodzice, albo wredne rodzeństwo mogą wkurzać. Szczególnie gdy grzebią w twoich prywatnych rzeczach bez pytania. Gdy nie ma cię w domu.
Twórcy Raspberry PI znaleźli na to sposób. Można stworzyć takie urządzenie, które nagrywa twój pokój, gdy ktoś do niego wejdzie.

Elementy potrzebne do jego budowy to:

Raspberry PI,

image

moduł kamery RPI

image

oraz czujnik ruchu PIR.

image

Do napisania programu trzeba ogarniać język Python i moduł picamera.

Czujnik ruchu to taki włącznik, który się rozłącza gdy wykryje przed sobą coś ciepłego np. człowieka. Można podłączyć czujnik do wejścia GPIO w malinie i sprawić by program coś robił gdy kogoś wykryje. W tym przypadku nagrywa obraz z kamery do pliku.
Można rozszerzyć program by wysyłał zdjęcie “gościa” na email, albo powiadamiał o wizycie przez telefon.

Mam jeszcze pomysł na ciekawszy projekt. Wykrywacz rodziców zbliżających się do pokoju ;-).

sprae

Wózek golfowy odpalany odciskiem palca

To co można zrobić z ATtiny to nie śniło się nawet fizjologom.
Użytkownik Ramicaza zbudował sobie na ATtiny85 i analizatorze odcisków palca ze Sparkfun – osobisty włącznik wózka golfowego.

Czujnik odcisku palca to Fingerprint Scanner – 5V TTL (GT-511C1). Ma bardzo proste podłączenie. Wymaga tylko zasilania 5V, GND oraz szeregowych sygnałów Serial – RX i TX.

Cały kod urządzenia dostępny jest w serwisie Github. Kod jest napisany na platformę Arduino i zadziała z każdą płytką Arduino oraz Teensy.

sprae

Tym czasem w dziale rozwoju Nettigo

Sebastian zbudował smartwatch wg projektu z bloga hardcopyworld.com.

Zegarek pokazuje godzinę i łączy się za pomocą bluetooth z Androidem. Dzięki aplikacji RetroWatch pokazuje wybrane informacje z telefonu.

Zegarek składa się z:

  • Małego wyświetlacza OLED sterowanego przez i2c/TWI
  • Arduino pro mini 3.3 V
  • Modułu Bluetooth HC05
  • Akumulatorka, ładowarki USB oraz przycisku.

Projekt jest dość prosty i świetnie nadaje się do rozbudowy o kolejne ciekawe elementy.
Myśleliśmy nad tym, by zastąpić moduł BT, akcelerometrem i zrobić licznik kroków dla biegaczy. Możliwości jest tyle, że tylko wyobraźnia stanowi granicę.

Części do zegarka możesz kupić w Nettigo.

sprae

Numery linii w Arduino IDE

Arduino IDE to fajny prosty edytor do pisania programów dla Arduino. Brak nadmiaru opcji sprawia, że nikt się w nim nie pogubi. Pewnie dlatego Arduino odniosło taki sukces.
W końcu Minecraft też nie jest zaawansowanym edytorem 3D, a miliony ludzi wyżywa się w nim kreatywnie tworząc prawdziwe cuda. 

Wychodzi na to, że kreatywność bierze się z prostoty i spartańskich warunków, a zaawansowane narzędzia są najwyżej po to, by dodać temu co tworzysz jakości.

Przypomniał mi się wywiad z Linusem Torvaldsem – twórcą Linuksa. Mówił, że gdy był mały, u niego w domu się nie przelewało i był zmuszony kupować tanie toporne komputery, na które nie było zbyt wielu programów. Musiał je sobie sam pisać. Twierdzi, że gdyby kupował inne to pewnie by grał.

Przepraszam za ten przydługi wstęp.

Niedawno grzebiąc w ustawieniach Arduino IDE 1.5.7 natrafiłem na ciekawą opcje dodającą numery linii z lewej strony edytora.

Opcję znajdziesz w oknie, które wywołuje się za pomocą menu:

Plik -> Preferencje

image

Po jej uaktywnieniu edytor będzie wyglądał tak:

image

Numery linii ułatwiają nawigację po programie. Gdy kompilator napotka błąd w kodzie to wypisuje numery linii w której on wystąpił.

sprae

Numitron – lampowy zegarek na rękę

Jeśli jesteś geekiem albo lubujesz się w modzie steampunk ten projekt jest dla ciebie.


Zdjęcie pochodzi ze strony projektu Numitron

Jest to zegarek na rękę z lampami Nixie. Lampy te to przodkowie późniejszych wyświetlaczy 7-segmentowych na bazie diod świecących. Dziś używa się ich w projektach w których chce się osiągnąć nawiązanie do starego stylu. W Polsce były często stosowane w dużych kalkulatorach Unitra z lat ‘70 i świeciły na zielono.

Numitron ze względu na mały rozmiar, wyświetla na raz tylko 2 cyfry. Pełna godzina wyświetlana jest po kolei – godzina, mrugnięcie, minuty, mrugnięcie, sekundy – po naciśnięciu przycisku na obudowie.

Projekt oparty jest na kontrolerze ATMega328p, który możesz znaleźć w Arduino UNO. Zegarek ma wbudowany Bootloader Arduino i można go przeprogramować za pomocą adaptera USB-Serial i Arduino IDE.

Zasilanie zrealizowane jest za pomocą małego akumulatorka Li-Po pochodzącego z mikro modeli helikopterów.

Film autora projektu przedstawiający budowę zegarka – po niemiecku.

Na stronie projektu Numitron jest więcej filmów przedstawiających prototypowanie zegarka, działanie wyświetlaczy i to jak je połączyć z kontrolerem.

sprae