Na ostatnim spotkaniu przed przerwą świąteczną rozwinęliśmy projekt rozpoczęty na poprzednich zajęciach tj. wyświetlanie cyfr przy pomocy wyświetlacza siedmiosegmentowego oraz rejestru przesuwnego. Główną korzyścią tej metody jest użycie jedynie trzech pinów cyfrowych Arduino. Okazuje się, że dołączenie drugiego wyświetlacza siedmiosegmentowego wymaga podłączenia drugiego rejestru przesuwnego, ale liczba pinów cyfrowych pozostaje taka sama !
Logika stosowania wielu rejestrów przesuwnych może być porównana do tworzenia jednego rejestru, który przedłużamy kolejnymi chipami 74HC595.
Podłączenie drugiego układu scalonego 74HC595 ogranicza się do podłączenia pinów RCLK oraz SRCLK do tych samych pinów arduino co odpowiadające RCLK oraz SRCLK piny pierwszego rejestru. Będzie to oznaczało, że nowy chip będzie on otrzymywał te same sygnały sterujące co pierwszy. Różnicą jest podłączenie pinu SER. Zamiast bezpośrednio do Arduino, podłączamy ten pin do wyjścia 9 naszego pierwszego rejestru przesuwnego. Dzięki temu całość będzie funkcjonowała jak jeden, przedłużony rejestr przesuwny.
Nasuwa się pytanie: jak zmodyfikować ostatnio napisany przez nas program tak, by poprawnie działał?
Odpowiedź jest prosta. Przygotowaliśmy się na to już na poprzednim spotkaniu i wystarczy wprowadzić nową wartość dla zmiennej ileScalakow (widocznej od razu w pierwszej linijce kodu), tak by równała się liczbie zastosowanych rejestrów, czyli 2:
Cały kod pozwalający sprawdzić działanie wyświetlaczy
#define ileScalakow 2 #define ilePinow ileScalakow * 8 int SER=8; int RCLK=9; int SRCLK=10; int rejestr[ilePinow]; void setup(){ pinMode(SER, OUTPUT); pinMode(RCLK, OUTPUT); pinMode(SRCLK, OUTPUT); czyscRejestr(); zapiszRejestr(); } void czyscRejestr(){ for(int i=0; i<ilePinow; i++) rejestr[i]=LOW; } void zapiszRejestr(){ digitalWrite(RCLK, LOW); for(int i=ilePinow-1; i>=0; i--){ digitalWrite(SRCLK, LOW); digitalWrite(SER, rejestr[i]); digitalWrite(SRCLK, HIGH); } digitalWrite(RCLK, HIGH); } void ustawPin(int ktory, int wartosc){ rejestr[ktory]=wartosc; } void loop(){ int i; for(i=0;i<ilePinow;i++) ustawPin(i, LOW); zapiszRejestr(); delay(500); for(i=0;i<ilePinow;i++){ ustawPin(i, HIGH); zapiszRejestr(); delay(500); } }
Po tej prostej zmianie kod działa poprawnie. Jest to przykład jak odpowiednie wprowadzanie zmiennych pozwala na skalowalność i rozwijanie kreowanych programów.
Sterowanie serwomechanizmami
Serwomechanizm, lub potocznie serwo, to nic innego jak silniczek prądu stałego sterowany PWM (modulator szerokości impulsu) z podłączonym odpowiednim układem zębatek. To niewielkie i niedrogie urządzenie pozwala wygenerować niespodziewanie dużą siłę i moment obrotowy, szczególnie zważywszy na jego rozmiary i nieduży pobór mocy (przy mini serwach np. używanych przez nas SG92r produkcji TowerPro rzędu kilku watów).
Przed rozpoczęciem jakichkolwiek doświadczeń z serwami warto pamiętać właśnie o poborze mocy. Rekomendowane jest zasilanie ich z zewnętrznego źródła mocy np. baterii lub zasilacza prądu stałego. Przyczyną jest niebezpieczeństwo, jakie niesie za sobą skok natężenia prądu podczas ruchu serw – podłączenie kilku na raz do Arduino może niechybnie doprowadzić do spalenia sterownika.
Tworzenie programu sterującego serwami
Arduino posiada dedykowaną bibliotekę do sterowania serwami, co niezwykle ułatwia sterowanie i zarządzanie.
#include <Servo.h>
Nasz program pozwala na wpisywanie wartości do monitora szeregowego i dyktowanie ich serwomechanizmom.
Servo serwomechanizm; int pozycja = 90; void setup() { serwomechanizm.attach(9); Serial.begin(9600); }
„Servo” jest formą deklaracji, że dany obiekt o nazwie „Serwmechanizm” ma być traktowany przez interpreter kodu jako serwomechanizm. Deklarujemy je w tej samej konwencji, co np. zmienne typu integer. Traktowanie go jak serwomechanizm oznacza, że możemy przypisać mu jakiś pin oraz pozycję (będą to odpowiednie zmienne w obiekcie Servo).
W naszym kodzie w etapie setup() przypisaliśmy pozycję wyjściową 90 stopni (2. linijka), pin 9 (7. linijka) oraz uruchomiliśmy monitor szeregowy dla częstotliwości 9600 baud. Następnie w loop() przy pomocy metody „parseInt” każemy „nasłuchiwać” wartości, które zostaną przypisane zmiennej „pozycja”.
void loop() { if (Serial.available() > 0) { pozycja = Serial.parseInt(); } if (pozycja > 0 && pozycja < 180) { serwomechanizm.write(pozycja); } else { pozycja = pozycja%160+10; serwomechanizm.write(pozycja); } }
Tym sposobem możemy sterować serwomechanizmem z klawiatury przypisując mu kąt od 0 do 180 stopni. Warto jednak pamiętać, by unikać skrajnych pozycji takich jak 0 i 180 stopni, gdyż w niektórych przypadkach może to doprowadzić do uszkodzenia serwomechanizmu.
Adnotacja: W bloku „else” umieściłem zabezpieczenie, które nie pozwoli również na przypisanie wartości większych niż 180. Była to nadprogramowa metoda, która pozwala ograniczyć przypisywane na serwo wartości tak, by zamykały się pomiędzy bezpiecznymi kątami 10 – 170 stopni. Sposoby zabezpieczania zależą od nas, jednak nie warto ich zaniedbywać. Szkoda naszego sprzętu i nerwów!
Pomiar prądu płynącego przez serwo.
Na bardziej ciekawych czekała również możliwość pomiaru prądu płynącego przez serwo. Warto pamiętać, że pomiar natężenia prądu należy przeprowadzać szeregowo względem badanego układu. Oznacza to, że multimetr w trybie pomiaru prądu musi być „po drodze” prądu między źródłem zasilania, a serwem. Dlatego zrobiliśmy to w następujący sposób:
Źródło napięcia (bez obaw, 5V i prąd zdecydowanie poniżej 1 A można swobodnie „izolować” suchymi dłońmi) dołączyliśmy do czerwonej sondy multimetru, a czarną do wejścia 5V serwa – jest to właśnie połączenie szeregowe.
Przy okazji mogliśmy zbadać wartość prądu pobieraną przez pracujące serwo. Wartości te na ogół wynosiły kilkadziesiąt mA, ale czasami (w skarajnym położeniu a także podczas zmiany położenia) wynosiły 100-200 mA. Oznacza to, że podłączenie kilku serw do Arduino jako źródła napięcia (a nie tylko do zadawania sygnału) skończyłoby się spaleniem płytki. Dlatego budując bardziej złożone układy z pewnością użyjemy zewnętrznych źródeł napięcia.
Do zobaczenia na kolejnym spotkaniu!
Maciej (c)