[140] Arduino i mierniki panelowe cz. 2
![[140] Arduino i mierniki panelowe cz. 2](/_next/image?url=https%3A%2F%2Farduino.pl%2Fimgproxy%2FwSQyLKYGk6B_sOWnDklYJMzcCtsM39Uyl1q2MdA5Ct0%2Ff%3Awebp%2Fw%3A1200%2FbG9jYWw6Ly8vaW1hZ2VzLzItNjk0L2JmZTM3LzkyZTk4LzItNjk0YmZlMzc5MmU5ODQyNjA2MDg1OC5wbmc%3D.webp&w=3840&q=75)
W poprzednim artykule poznaliśmy budowę mierników magnetoelektrycznych i postanowiliśmy zbudować dwie zabawki edukacyjne. Najpierw zajmijmy się egzystencjometrem, czyli zegarem-gadżetem, z którego można zrobić na przykład ciekawy prezent. Bierzmy się więc do roboty.
Arduino jak wiemy, dysponuje wyjściami PWM, czyli szybkozmiennym przebiegiem o stałej częstotliwości i zmieniającym się stosunku napięcia do jego braku. Pełny brak mamy przy zerze, przy 255 zerowych wartości w ogóle nie ma i na wyjście PWM wystawia się prąd stały o napięciu zasilającym układ. Gdy teraz podłączymy miernik do takiego wyjścia i masę, wskazówka wychyli się proporcjonalnie do wartości wstawianej w rejestr portu, a więc wypełnienia wyjścia.
Mała dygresja: miliamper to nic dla Arduino i możemy nasz miernik podłączyć bezpośrednio. Ale stanowi on jednak obciążenie indukcyjne, a to generuje wysokie napięcia podczas przełączania. Te nie zaszkodzą nijak układowi, który zaopatrzono w zabezpieczenia radzące sobie z tak małymi prądami, ale dla samej zasady wstawiłem kondensator całkujący przepięcia, niemający jednocześnie wpływu na zmianę wartości wskazywanych. Ważne, by pojemność tę umieścić na zaciskach za rezystorem pełniącym funkcję posobnika, a nie na wyjściu Arduino.

Skoro już wszystko wiemy, podłączmy sobie ustrój do Arduino: biegun ujemny do masy, a dodatni do pinu 11, który może pełnić funkcję PWM. Jak zwykle użyję tu płytki edukacyjnej TME, ponieważ mam tam jeszcze kilka drobnych elementów, które będą mi potrzebne. Ale zanim oprogramujemy tę tarczę, napiszmy program pomocniczy, służący zarówno sprawdzeniu czy skala ma sens jak i kalibracji nowych skal. Program będzie malutki.
const byte potencjometr = A1; // Adres portu, do którego podłączony jest potencjometr.
const byte miernik = 11; // Adres portu, do którego podłączony jest miernik.
void setup() {
pinMode(miernik, OUTPUT); // Deklaruj port miernika jako wyjście.
Serial.begin(115200); // Inicjuj monitor.
}
void loop() {
byte wartosc = analogRead(potencjometr) >> 2; // Zapamiętaj pozycję potencjometru.
analogWrite(miernik, wartosc); // Załaduj ją do portu PWM mierniku.
Serial.println(wartosc); // Wyślij ją na monitor.
delay(100); // Opóźnienie stabilizujące pracę.
}Deklarujemy port potencjometru – u mnie jego ślizgacz łączy się z pinem A1, a skrajne wyprowadzenia do masy i zasilania. Deklarujemy też port miernika, wykorzystujący wspomniany pin jedenasty. W części wstępnej należy zadeklarować ten port jako wyjście i zainicjować port monitora. W głównej pętli będziemy odczytywać port potencjometru i ładować tę wartość do zmiennej powoływanej lokalnie, przy czym przesuniemy wartość o dwa bity w prawo. A to dlatego, że wartości analogowe są mierzone z rozdzielczością dziesięciobitową, natomiast wartości PWM muszą zmieścić się w ośmiu bitach. Przesunięcie o dwa bity ograniczy nam zakres. Równie dobrze można tę wartość podzielić przez cztery, ale tak jest szybciej i oszczędniej.
Zmierzoną wartość ładujemy w port PWM, czyli wysyłamy ją na miernik i jednocześnie wysyłamy także na monitor, dzięki czemu będziemy mogli odczytać ją dokładnie. Czas sprawdzić dokładność skali.

Przy skręceniu potencjometru maksymalnie w lewo powinniśmy uzyskać wartości zerowe, a wskazówka winna wskazywać takież pole na skali. Korektę możemy wykonać śrubą na panelu.

Odkręcamy teraz potencjometr do końca. Widzimy wartość 255, a wskazówka powinna wychylić się na ostatnią pozycję. Jeśli w nią nie trafi, za pomocą śrubokręta regulujemy potencjometr nastawniczy, aż pole zostanie wskazane dokładnie.
Ponieważ mamy tu 31 pozycji, każda następna winna wskazywać kolejną wielokrotność ośmiu i pół, czyli 255 dzielone przez 30. Jeśli sobie kilka tych wartości policzymy i porównamy teorię z praktyką, w przypadku sprawnego urządzenia i starannego narysowania nowej skali winniśmy widzieć dość dokładne wskazywanie pozycji.
Podsumujmy: między skrajnymi wartościami możemy ustawić dowolną, oczywiście sensowną liczbę wartości pośrednich, a wartości ładowane do rejestru PWM muszą wynosić n razy 255 dzielone przez ilość pozycji skali minus jeden. Oczywiście wszelkie ułamki należy zaokrąglić – pracujemy wszak na liczbach naturalnych. Wróćmy do naszego egzystencjometru.
Założenia mamy następujące: ten dziwny zegar będzie pracował tylko między godziną siódmą, a dwudziestą pierwszą. W pozostałym czasie będzie nieczynny, czyli wskazówka opadnie na pozycję neutralną, a ustrój nie będzie zasilany. Brak zasilania to zero w rejestrze PWM. Jakie są pozostałe wartości? Oczywiście dla godziny 21 mamy 255, natomiast dla siódmej… policzmy: na skali jest 31 pozycji, 255 dzielone przez 30 da nam 8 i pół – to jest przyrost na działkę. Siódemka jest tak naprawdę pozycją drugą (jeśli liczyć od zera), bo między nią, a początkiem skali nie narysowałem kreski. Więc tutaj wskazówka zatrzyma się, jeśli w rejestr wstawię 2*8,5 czyli 17. I rzeczywiście, tak właśnie jest, co możemy sprawdzić, uruchamiając szkic do testowania mierników.
Możemy sobie sprawdzić dowolną z pozycji narysowanej na skali, ale jak mówiłem, skorzystałem z oryginalnej skali miernika, zakładając że jest wystarczająco dokładna. W związku z tym ideą zegara nie będzie zatrzymywanie się w konkretnych miejscach wyznaczonych skalą, a praca liniowa, przy wartościach PWM od 17 do 255. W związku z tym trzeba będzie w jakiś sposób przeprowadzić transformację czasu między siódmą, a dwudziestą pierwszą na wartość od 17 do 255. Można to zrobić na wiele sposobów, proponuję najprostszy: będziemy bazować wyłącznie na sekundach.
Doba ma 86400 sekund. Do siódmej rano mija ich 25200, do 21 – 75600. Stąd już prosty rachunek: wystarczy mapować ten zakres na przedział 17-255, a gdy wartości pochodzą spoza niego, wysyłać zero. Czas więc zrealizować ideę konkretnie.
#include <TimerOne.h> // Biblioteka obsługi przerwań.
const byte miernik = 11; // Adres portu, do którego podłączony jest miernik.
volatile long sekundy = 25200; // Licznik sekund.
void setup() {
pinMode(miernik, OUTPUT); // Deklaruj port miernika jako wyjście.
Timer1.initialize(1000); // Ustaw przerwania na jedną milisekundę.
Timer1.attachInterrupt(przerwanie); // Włącz przerwania z określeniem miejsca lądowania.
}
void loop() {
if (sekundy >= 25200 && sekundy <= 75600) { // Jeśli jest co najmniej 7, ale nie później niż 21...
analogWrite(miernik, map(sekundy, 25200, 75600, 17, 255)); // Przekształć czas na wypełnienie.
} else { // W przeciwnym razie...
analogWrite(miernik, 0); // Zeruj PWM
}
delay(100); // Opóźnienie stabilizujące.
}
void przerwanie() { // Obsługa przerwania.
sekundy++; // Zwiększ licznik sekund.
if (sekundy >= 86400) { // Jeśli osiągnął maksimum...
sekundy = 0; // Zeruj go.
}
}Użyjemy wielokrotnie już omawianej biblioteki TimerOne, która nie robi nic szczególnego, tylko przelicza parametry przerwań na bardziej ludzkie wartości. Docelowo przerwania ustalimy na jedną sekundę – bardzo długi interwał jak na przerwania właśnie, lecz nam tu tyle wystarczy. Ale to potem, na razie przyspieszymy zegar tysiąckrotnie po to, by móc widzieć upływ czasu na skali miernika.
Zadeklarujemy sobie zmienną sekundy, która będzie typem long, ponieważ może sięgać wartości 86400, uciekającej typowi int, nawet bez znaku. We wstępnej części deklarujemy parametry przerwania: interwał w mikrosekundach i etykietę, pod którą program ma wpadać w owych interwałach. Skoro o przerwaniach mowa, przenieśmy się tam właśnie. Nic tu szczególnego dziać się nie będzie: sekundy będą się zwiększać i jeśli wartość przekroczy owe 86400, ma się wyzerować. Co oznaczać będzie minięcie doby.
I tyle, reszta siedzi w głównej pętli. Jeśli wartość sekund należy do przedziału między siódmą, a dwudziestą pierwszą, dokonamy przemapowania owego zakresu na zakres użyteczny dla PWM, z zastrzeżeniem, że startujemy od wartości równej 17, a nie od zera. Natomiast jeśli znajdziemy się poza wspomnianym przedziałem, czyli generalnie będzie noc, na PWM wyślemy zero i wskazówka opadnie. Czas na kompilację i możemy przypatrzeć się pełzającej wskazówce. Żeby nie czekać w nieskończoność, ustawiłem punkt startu na siódmą rano, by od razu po resecie widzieć efekt.
Jak widać, przeliczanie odbywa się dziesięć razy na sekundę. Docelowo wystarczy nawet raz na minutę. Alternatywnie można ten fragment wrzucić w ogóle w blok przerwania. Nie jest to zwykle zalecane – z definicji w przerwaniach należy robić tylko minimum tego, co ma być robione cyklicznie. Jednak w naszym przypadku nic nie stracilibyśmy ze względu na bardzo długie czasy przerwań, a w świecie komputerów sekunda to taki właśnie bardzo długi czas.
Zostawmy na razie konwersję w miejscu, w którym jest i poczyńmy pewne usprawnienia „pro”, że się tak wyrażę – ale to już w kolejnym artykule.













































