Sterowanie oświetleniem w pokoju cz.1/3

Sterowanie oświetleniem w pokoju cz.1/3

Witam

Mam na imię Krzysiek. Na Majsterkowie jestem już od jakiegoś czasu. Projekt, którym pragnę się z Wami podzielić będzie służył do sterowania oświetleniem w moim pokoju. Jakiś czas temu wykonałem już sterowanie światłem za pomocą pilota na podstawie projektu Łukasza. Do rozwiązania, które zaprezentował Łukasz dołożyłem możliwość sterowania światłem za pomocą przycisków. Rozwiązanie miało jednak małą wadę – nigdy nie miałem pod ręką pilota! Sytuacja wyglądała mniej więcej tak, że jak byłem na kanapie to pilot leżał przed kompem pilot przy kompie ja na kanapie. Zawsze kończyło się to tak, że trzeba było wstać do przełączników i włączyć/wyłączyć światło. Do już obecnie zaimplementowanych rozwiązań postanowiłem dodać możliwość włączania i wyłączania oświetlenia bezpośrednio z aplikacji okienkowej napisanej w C++. Przedstawiony kod zarówno dla mC jak i aplikacji komputera będę starał się wytłumaczyć w całości aby każdy czytelnik mógł bez problemu wykonać podobny projekt w domu rozumiejąc za co odpowiada każda linijka w kodzie. Uzbrojony w tą wiedzę będzie mógł zaadoptować projekt do swoich potrzeb.

Funkcję w aplikacji na komputer:

  1. Włączanie i wyłączanie oświetlenia w pokoju jednym kliknięciem
  2. Zapisywanie i odczytywanie kodów pilota do pliku .txt
  3. Możliwość ustawienia parametrów komunikacji (nr portu COM oraz prędkość transmisji)
  4. Możliwość ustawienia nowego kodu pilota dla każdego światła w pokoju bez konieczności ponownego programowania mC.
  5. Zapisywanie kodów pilota do pamięci EEPROM w mC aby nie trzeba było ich ustawiać na nowo po zaniku zasilania mC (aplikacja będzie wysyłać tylko polecenie a resztą zajmie się sam mC)
  6. Aplikacja ma być schowana w trayu i nie przeszkadzać kiedy jest nie potrzebna.

Funkcje mC

  1. Odbieranie kodów pilota IR i wysyłanie ich do komputera.
  2. Sterowanie czterema światłami w pokoju
  3. Po resecie/zaniku zasilania samoczynne odczytanie kodów IR zapisanych w EEPROM
  4. Możliwość tradycyjnego włączania/wyłączania światła

Artykuł zdecydowałem się podzielić na trzy części ponieważ w jednej nikt by nie był w stanie dotrzeć do końca ;-) W pierwszej części zajmiemy się złożeniem wszystkiego na płytce stykowej oraz kodem mC a w drugiej kodem dla aplikacji na komputer a w ostatniej przeniesieniem całości na wytrawioną płytkę i instalacją.

Do projektu potrzebować będziemy:

  1. Atmel ATMEGA328P-PU
  2. Na obecnym etapie płytka stykowa
  3. Programator USB-APS
  4. Przejściówkę USB-UART
  5. Trochę drobnicy elektronicznej (rezystory, kondensatory, dławik, diody)

Na początek cały kod programu dla mC:

 

Zacznijmy od poprawnego podłączenia Atmegi do zasilania. Podłączenie Atmegi zgodnie z notą katalogową daje nam gwarancje, że mC będzie pracował prawidłowo bez problemów z samoczynnym restartowaniem się lub nawet z zawieszaniem się. W internecie można znaleźć wiele poradników dotyczących prawidłowego zasilania mC i na samym Majsterkowie wiele o tym było. Ja podłączyłem swoją wg. poniższego schematu:

zasilanie

Szczególnie ważny jest rezystor podciągający pod pin reset stan wysoki (niski resetuje mC) oraz kondensatory filtrujące zasilania mC.

Skoro układ ma gadać z komputerem do pinu TX mC podłączamy pin RXD przejściówki a do pinu RX pin TXD. Musimy także podłączyć masy układów. Przejściówka której ja używam ma także możliwość zasilania układu. Ja jednak zdecydowałem się na zasilanie układu z ładowarki do telefonu więc pin VCC zostawiłem nie podłączony. Aby sprawdzić czy wszystko się udało wgrywamy do atmegi następujący kod:

Po włączeniu Serial Monitora powinniśmy zauważyć napis Hello! nadawany przez nasz mC. Jeżeli wszystko jest ok przechodzimy dalej.

Za pomocą pinów cyfrowych będziemy sterować naszym oświetleniem – stan wysoki na pinie cyfrowym będzie zapalał światło na a niski je gasił. Potrzebujemy także przycisków do ręcznego sterowania oświetleniem. Do pinów 28, 27, 26, 25 podłączamy więc microswitche. Zdefiniowanie ich jako INPUT_PULLUP ułatwiam nam sprawę. Dzięki temu przycisk wystarczy podłączyć do pinu mC a z drugiej strony do masy. Musimy jednak pamiętać, że po takiej modyfikacji kodu odczyt pinu da nam stan wysoki w momencie kiedy przycisk jest zwolniony a niski kiedy jest wciśnięty. Jako, że w miarę dokładania linijek kodów do naszego mC będzie on coraz bardziej zapracowany i na zmianę światła musielibyśmy chwile zaczekać a my chcemy mieć to zrobione natychmiast dlatego skorzystamy z przerwań. Przerwanie zmusza mC do rzucenia wszystkiego i wykonania fragmentu kodu. Atmega umożliwia podłączenia przerwania pod każdy pin mC opisany jako PCINTxx. Szybkie zerknięcie na grafikę z rozpisanymi pinami i już wiemy, że przerwania można podpiąć do 23 różnych pinów! Niestety Arduino IDE brakuje możliwości wskazania które to mają być piny. Dlatego posłużymy się biblioteką o nazwie PinChangeInt. Wystarczy teraz, że do każdej definicji pinu podłączonego do przycisku dodamy: PCintPort::attachInterrupt(nazwa_pinu, nazwa_funkcji, zmiana_statu); Przeczytać to możemy jako “Po zmianie stanu na nazwa_pinu z wysokiego na niski rzuć wszystko i odpal funkcję nazwa_funkcji”. Czy chodzi nam o zmianę stanu z wysokiego na niski czy odwrotnie, możemy doprecyzować komendą FALLING lub RISING. Funkcje odpowiadające za sterowanie ręcznie sterowanie światłem to void button_1/2/3/4() – po jednej dla każdego przycisku. No to mamy z głowy ręczną obsługę światła. Żeby nasz projekt różnił się co nieco od zwykłego włącznika światła dodajemy obsługę odbiornika podczerwieni. Jako odbiornika podczerwieni użyłem popularnej czujki IR o nazwie TSOP2236. Podłączamy ją wg poniższego obrazka:

irpin

Niestety w programie do schematów nie mogłem odszukać odpowiedniego elementu wiec użyłem jako “zamiennika” tranzystora. Pin kolektora (nr 1) to masa. Do bazy (nr 2) przez rezystor 100 ohm zasilanie. Ostatni pin podłączamy do atmegi(23). Aby filtrować zakłócenia pomiędzy zasilanie a masę podłączamy kondensator ceramiczny 4,7uF. Kolejna niezbędna biblioteka to IRremote. Tworzymy 8 nowych zmiennych cztery typu unsigned long o nazie Kod1/2/3/4 oraz boolean d1/2/3/4. W zmiennych tych będziemy przechowywać zapisane kody IR pilota odpowiadające zmianom statu światła oraz sam ich stan. Kiedy kod odczytany przez czujkę pokryje się z kodem w zmiennej Kod1/2/3/4 zmieni zawartość zmiennej d1/2/3/4 na przeciwny. W ten oto sposób jednym przyciskiem pilota będziemy gasić lub zapalać jedno światło. Zmienna Kod1/2/3/4 zaraz po zdefiniowaniu nie ma jeszcze żadnej konkretnej wartości i musimy dodać funkcję która umieści nam w naszym pojemniku pożarną wartość. Oczywiście można by założyć, że raz wybrany pilot/guzik pilota nigdy nam się nie znudzi i na sztywno zdefiniować jaki to ma być kod. Ja jednak zamierzam umieścić docelową wytrawioną płytkę w ścianie (dokładnie w puszcze) i więcej tam nie zaglądać :-). Mamy możliwość rozmowy z naszym mC przez Serial Port i właśnie z niej skorzystamy. Na sam początek trzeba się zastanowić co dokładnie kryje się pod stwierdzeniem “kod przycisku pilota”. Otóż okazuje się po prostu, że jest to liczba całkowita zapisana w systemie szesnastkowym. Liczba ta może być duża (np 1711591382) lub też stosunkowo niewielka (np 3622) – wszystko zależy od pilota. My chcemy aby nasz układ działał z każdym pilotem niezależnie czy pod kodem przycisku kryje się cyfra 4 czy 10 cyfrowa. Poniżej przykłady z moich pilotów (sprawdziłem 7 różnych):
6604CFD6 – 1711591382, 6604CFE6 – 1711591398, 6126 – 24870, E26 – 3622.
Mamy zapisane te same liczby tyle, że w różnych systemach. Po lewej stronie myśnika system szesnastkowy a po prawej dziesiętne tak jak nas nauczyli w szkole. Założenie jest następujące: kod odebrany przez Serial Port powinien być zamieniony z jednego systemu na drugi i zapisany do odpowiedniej zmiennej. Po chwili zastanowienia zdecydowałem się na przesyłanie kodów uprzednio poprzedzając je dwoma cyframi. Pierwsza z nich to 0 aby dać znać mC, że raz otrzyma informację z kodem kolejna cyfra to 1,2,3 lub 4 aby mógł wiedzieć do której zmiennej ma zapisać otrzymany kod. Reasumując cała wiadomość będzie się wyglądała tak np. tak “01E26” albo tak 036604CFF6. Dane zostały wysłane a my musimy coś z nimi zrobić. Zakładamy więc, że chcemy zaprogramować kod do sterowania światłem nr 1 więc kod czujki pilota powinien wylądować w zmiennej o nazwie Kod1. Kod który chcemy zaprogramować to szesnastkowo zapisany 6604CFF6. Jak wspominałem wcześniej nasz kod pilot jest poprzedzony znakami sterującymi znak pierwszy czyli 0 ląduje w zmiennej x. Pierwsza instrukcja warunkowa switch(x) odsyła nas do przypadku case 48. Dlaczego 48 skoro pierwszą nadesłaną cyfrą jest 0? Już wyjaśniam. Funkcja Serial.read() odczytuje znak z bufora i traktuje go dokładnie jako znak. Czyli, jeżeli odebranym znakiem będzie np ‘a’ w efekcie działania funkcji Serial.read() dostaniemy odpowiednik tej litery w tablicy ASCII czyli 65. Szybko sprawdzany, że kod cyfry 0 w tablicy ASCII to 48. Kolejnym znakiem który już czeka w buforze jest cyfra 1 (kod ASCII to 49) i pakujemy ją do zmiennej pomocniczej y która przełącza nam kolejną instrukcję warunkową switch(y). My mamy jedynkę więc zostajemy przełączeni do przypadku case 49. Zauważmy, że w przepadkach case: 49,50,51,52 użyjemy tego samego kodu do zamiany pojedynczych znaków napływających do bufora na konkretna liczbę. Aby uniknąć redundancji (powtarzania tego samego kodu) zdecydowałem się na wycięcie tego konkretnego fragmentu do podprogramu (funkcji) która zwróci nam gotowy wynik wystarczy więc napisać Kod1=jaki_kod(). mC po natrafieniu na funkcję jaki_kod() na chwilę zatrzyma główny program wykona polecenia z funkcji jaki_kod() i zwróci nam gotowy wynik. Do zamiany znaków z bufora potrzebne nam będą dodatkowe zmienne. Zaletą funkcji którą wywołujemy jest to, że zmienne te na potrzeby funkcji jaki_kod() zostaną zarezerwowane w pamięci a po wykonaniu niezbędnych obliczeń zostaną usunięte a pamięć zwolniona. Rezerwujemy za tym tablicę ośmiu elementów typu unsigned long o nazwie hexx[8], tablicę ośmiu elementów typu char o nazie kod_odb[8] oraz zmienną pomocniczą int i. Funkcja Serial.available() zwróci nam prawdę jeżeli w buforze znajdziemy jakiś znak do odbioru to doskonały warunek dla funkcji while. Jako, że nie wiemy ile znaków trafi do bufora wypadało by je policzyć do tego wykorzystamy zmienną int i. Będziemy zwiększać ją o jeden za każdym obiegiem pętli while. Zwiększanie zmiennej i o jeden wykorzystamy także to zmiany aktualnie zapisywanej szufladki w tablicy kod_odb. Przypominam, że szufladki w tablicach numerujemy od zera. Dla naszego przykładu po wykonaniu się pętli while mamy tablicę z znakami char wyglądającą tak: [6][6][0][4][C][F][F][6]. Z oczywistych względów nie jest to liczba więc obrabiamy dalej. Na kolejnym etapie musimy się zastanowić co faktycznie oznaczają te znaki zerknijmy więc do ściągawki:

0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
A 10
B 11
C 12
D 13
E 14
F 15

Do dalszych obliczeń znak char trzeba zamienić na odpowiadającą jej cyfrę piszemy więc pętlę for. Z zmiennej int i wiem, że pętla powinna zostać powtórzona 8 razy. Zapisujemy więc for (int h=0 ; h<i ; h++ ) w pętli for porównujemy znak char do znaku char i jeżeli się zgadza do tablicy hexx zapisujemy jej cyfrowy odpowiednik. Po zakończeniu pętli mamy tablicę hexx wyglądającą tak: [6][6][0][4][12][15][15][6]. Nie jest to jeszcze nasz wynik ale w komórkach tablicy mam już zmienne całkowite które możemy dodawać odejmować mnożyć itp. Aby zamienić tak przygotowaną tablicę na liczbę w formacie dziesiętnym musimy wziąć ostatnią cyfrę i pomnożyć ją przez kolejną potęgę liczby 16. Otrzymane w ten sposób liczby należy do siebie dodać. Dla naszego przykładu wygląda to tak:

Numery cyfr od końca 8 7 6 5 4 3 2 1
Cyfra z tablicy 6 6 0 4 12 15 15 6
Do której potęgi 7 6 5 4 3 2 1 0
Po podniesieniu 268435456 16777216 1048576 65536 4096 256 16 1
Po pomnożeniu 1610612736 100663296 0 262144 49152 3840 240 6
Gotowa liczba  1711591414

Do przeliczenia w ten sposób liczby w systemie szesnastkowym na liczbę dziesiętną będziemy potrzebować potęg liczby 16. Rezerwujemy sobie tablicę unsigned long potegi. Skoro mamy już gdzie przechowywać nowe dane czas naszą tablicę wypełnić. Do tego zadania zatrudnimy funkcję o nazwie poteguj(). Po wysłaniu do niej w argumencie funkcji informacji do której potęgi chcemy podnieść liczbę (wykładnik) oraz o jaką liczbę nam chodzi (podstawa) funkcja zwróci nam gotową wartość. Dla naszego przykładu (8 cyfrowa liczba hex) pierwszy obieg pętli for przekaże do funkcji potęgi wykładnik i-h-1=7 (8-0-1) oraz podstawę 16, dla drugiego obiegu 6 (8-1-1) i tak dalej. Otrzymywane liczby zapisywane są w szufladkach od zera licząc. Sama funkcja potęgi jest banalnie prosta – mnoży liczbę 16 przez siebie samą tyle razy ile zostanie o to poproszona. Zapis liczba=pds znaczy to samo co liczba=liczbapodstawa. Mamy już gotową rozpisaną liczbę w tablicy hexx[] oraz potęgi liczby 16 w tablicy potegi[] wystarczy przemnożyć odpowiadające komórki tablic potegi[] i hexx[] przez siebie oraz wszystkie wyrazy ciągu zsumować. Funkcja return suma zwróci nam gotową liczbę do miejsca gdzie wywołaliśmy funkcję jaki_kod() – czyli prosto do zmiennej Kod1. Było to troszkę pisania ale upewniliśmy się, że mC właściwie zareaguje na kod pilota składający się z dowolnej ilości znaków nie większej niż 8.  Maksymalną liczbą jaką dzięki tym funkcjom możemy uzyskać jest 4294967295 (hex FFFFFFFF). Dlaczego nie więcej? Głownie z dwóch powodów. Ponieważ nie trafił w moje łapki pilot który wysyłał by w kodzie więcej niż 8 znaków oraz maksymalna pojemność typu unsigned long to właśnie 4294967295. Na pewno wielu z was zapyta po co cały ten system szesnastkowy skoro można by przysłać gotową liczbę (dla naszego przykładu 1711591414).  Odpowiedź jest prosta. Za młodu bawiłem się programem Girder i tam kody były zapisywane właśnie jako liczby w systemie szesnastkowym oraz każdy przykład wykorzystania biblioteki IR dla aruino wysyłający kody IR do serial monitora robi to w systemie szesnastkowym poza tym liczba 1711591414 wygląda bardziej jak stan mojego debetu niż kod pilota. Przyznacie przecież, że liczba 6604CFF6 jest dużo bardziej milsza dla oka niż  jej dziesiętny odpowiednik 1711591414.

Umiemy obsługiwać już dane przychodzące do mC. Czas wysłać sygnał sterujący z komputera który będzie nam zapalał i gasił światło. Aby zbędnie nie kombinować jeżeli w buforze pojawi się cyfra 1 zmienia się status światła nr 1 jeżeli 2 status światła 2 itd.  W jaki sposób instrukcja swtich jest przełączana wyjaśniałem już przy okazji odczytywania przysyłanych kodów. Wyjątkiem jest 5, która wyłączy wszystkie światła nie zależnie ile ich było włączonych (takie natychmiastowe zaciemnienie na wypadek nalotu naszych przyjaciół za wschodniej granicy :-))

Zmienne Kod1/2/3/4 mamy już zapisane ale w przypadku braku prądu lub restartu mC cały proces trzeba będzie powtórzyć od nowa – nie, nie tak nie może być! Musimy gdzieś przechowywać zmienne najlepiej w takim miejscu gdzie ocaleją na wypadek blackoutu. Miejscem takim jest oczywiście EEPROM mC. Pakujemy więc tam liczby z zmiennych Kod1/2/3/4 i po sprawie. Niby proste ale nie do końca. Szybko okazuje się, że pojedyncza komórka pamięci EEPROM możne pomieścić maksymalnie liczbę 254. Licząc od zera to  255 możliwych cyfr no a my mamy przedział od 0 do 4294967295. No troszkę nam brakuje. Najprostszym z możliwych rozwiązań jest rozbicie liczby 4294967295 na pojedyncze cyfry. Podczas czytania o pamięci EEPROM mC Atmega dowiedziałem się, że jest to pamięć która możemy zapisywać tylko określoną liczbę razy. Wydaje mi się, że rozsądnie jest zapisywać tam dane tylko kiedy tego na pewno potrzebujemy a nie przy każdej zmianie kodu pilota. Zasada jest taka mamy 4 kody w zmiennych i już wiemy, że chcemy akurat z nich korzystać więc wciskamy przycisk i już nam nie uciekną. Wysyłając do mC cyfrę 9 nastąpi zapis wszystkich kodów pilota tylko na nasze indywidualne życzenie.  Jako, że artykuł znacznie się wydłużył niż się na początku spodziewałem ponownie posłużę się przykładem zmiennej Kod1. Ponownie wywołamy napisaną samodzielnie funkcję.

Przy wywołaniu (eprom_write(Kod1)) funkcji musimy przekazać jej w argumencie kod który chcemy zapisać. W naszym przypadku jest to zmienna Kod1. Do pojedynczej szufladki EEPROM będziemy zapisywać jedną cyfrę więc na pewno musimy wiedzieć ile cyfr ma nasza zmienna. Do tego skorzystamy z funkcji do której trzeba będzie wysłać nasz kod. Funkcja działa na zasadzie dzielenia naszej liczby przez dziesięć do momentu kiedy osiągnie ona zero.  W zmiennej int i zliczamy liczbę obiegów pętli. Gotową wartość przekazujemy do do funkcji write_eprom() i zapisujemy do zmiennej i. Jako, że podczas dalszej pracy zmienna i ostatecznie nam się zeruje a liczba cyfr przyda się jeszcze tworzymy nową zmienną int ile i tam zapisujemy wartość zmiennej i . Skoro dokładnie już wiemy ile cyfr mamy w naszej liczbie możemy napisać pętle while(eKod>0). Która do odpowiedniej komórki tablicy o wdzięcznej nazwie tablica zapisze nam resztę z dzielenia. Tak więc przykładowo kiedy zmienna eKod ma wartość 7894 wyrażenie eKod%10 da nam wartość 4 a i-1=3, podzielenie liczby przez 10 utnie nam ostatnią cyfrę (typ całkowity zmiennej nie przechowuje wartości po przecinku). Po wykonaniu tego obiegu pętli while wartość i zmniejsza się o 1. Cały obieg pętli daje nam tablicę: tablica[7][8][9][4]. Jako, że funkcja modulo 10 zwraca nam ostatnią cyfrę (skrajną prawą)  zmiennej i użyliśmy do odwrócenia kolejności zapisywania danych do tablicy. Cel osiągnięty. Zaczynając od komórki [1] pamięci eeprom zwiększając adres komórki o jeden zapisujemy każdą cyfrę na swoje miejsce. Przy odczytywaniu z pamięci eeprom przyda nam się wiedza ile dla danego kodu musimy odczytać komórek. Dlatego też zostawiliśmy sobie wolne miejsce przez kodem eeprom[0]. Instrukcja switch za pomocą zmiennej globalnej który kod przełącza nam “miesca w eeprom” do któych zapisujemy dany kod. Jako, że zmienna ktory_kod jest zmienną globalną dostępną zarówno dla funkcji loop() jak i wirte_eprom() to przed wywołaniem funkcji ustwiamy odpowiednią wartość zmiennej ktory_kod. Poniżej tabela w jaki sposób planuje zapisywać kody do eeprom:

1 2 3 4
0  ile 20  ile 40 ile 60 ile
1  x 21  x 41  x 61  x
2  x 22  x 42  x 62  x
3  x 23  x 43  x 63  x
4  x 24  x 44  x 64  x
5  x 25  x 45  x 65  x
6  x 26  x 46  x 66  x
7  x 27  x 47  x 67  x
8  x 28  x 48  x 68  x
9  x 29  x 49  x 69  x
10  x 30  x 50  x 70  x
11  x 31  x 51  x 71  x
12  x 32  x 52  x 72  x
13  x 33  x 53  x 73  x
14  x 34  x 54  x 74  x
15  x 35  x 55  x 75  x
16  x 36  x 56  x 76  x
17  x 37  x 57  x 77  x
18  x 38  x 58  x 78  x
19  x 39 x 59  x 79 x

W tabeli znakiem x zaznaczyłem miejsca gdzie zapisujemy kod w polach ile przechowujemy liczbę znaków danego kodu.

Dla zmiennej Kod1 zaczynamy więc od u=1 dla zmiennej Kod2 zaczynamy od u+20 dla zmiennej Kod3 zaczynamy od u+40 a dla zmiennej Kod4 u+60.

No to wszelkie zaniki zasilania nam nie straszne. Zmienne z kodami pilotów resetują się tylko w przypadku zaniku zasilania lub też resetu mC. Jak wykryć reset mC? Wcale nie musimy ponieważ mamy do dyspozycji blok konfiguracyjny void setup() uruchamiany jednorazowo podczas startu mC. Wspaniale!. Wywołamy w nim funkcję run_read(), która odczyta i zapisze kody z EEPROM do zmiennych Kod1/2/3/4. Jako, że musimy także zależnie od wczytywanego kodu przełączać zmienną ktory_kod z pętli void setup wywołamy sobie funkcję, która już dalej posteruje odczytem EEPROM. Do odczytu będzie nam potrzebna tablica, która na chwile przechowa nam odczytaną wartość z komórki EEPROM deklarujemy nową tablicę unsigned long tablica[10]. Przyda się też zmienna do której zapiszemy odczytaną liczbę znaków int ile. Na początek sprawdzamy ile znaków trzeba odczytać dla pierwszego kodu informację o tym zapisaliśmy do pierwszej (zerowej) komórki pamięci. Przy odczycie pamięci z EEPROM musimy pamiętać, że w niektórych przypadkach może się zdarzyć, że nic tam aktualnie nie będzie – sytuacja ma miejsce np kiedy mC włącza się pierwszy raz po pierwszy po zaprogramowaniu (programator czyści pamięć). Skorzystamy z faktu iż taka dziewicza komórka ma wartość 255. Prosty warunek if (ile!=255) sprawdzi nam czy dana komórka była już wcześniej zapisana (spodziewamy się tam wartości od 0 do 10 a już na pewno nie 255. Sprawdziliśmy więc no i nie trafiliśmy na 255 warunek z ifa spełniony program przechodzi do pętli for. Pierwszą cyfrę mamy w komórce 1 tam też zaczynamy mamy ich odczytać i razy i przy każdym obiegu pętli zwiększamy wartość o jeden. Dla kodu 1711591414 mamy więc zapisaną tablicę o nazwie tablica[1][7][1][1][5][9][1][4][1][4] (przy wymyślaniu nazw zmiennych kreatywność mnie opuszcza tak samo jak przy wymyślaniu haseł). Trzeba to jeszcze poskładać do kupy. Zauważmy iż wystarczy ostatnią komórę tablicy pomnożyć przez jedności przed ostatnia przez dziesiątki następną przez setki i tak dalej aż do miliardów a na koniec zsumować. Zauważymy, że mnożymy przez potęgi liczby 10 no no jedności to 10^0 dziesiątki do 10^1 setki do 10^2 i tak dalej. Mamy gotową funkcję do potęgowania liczb (dlatego właśnie chciałem aby była uniwersalna) skorzystajmy więc z niej. Ponownie tabelka z przykładem:

Numer cyfry od końca 10 9 8 7 6 5 4 3 2 1
Cyfra z tablicy 1 7 1 1 5 9 1 4 1 4
Do któej potęgi 9 8 7 6 5 4 3 2 1 0
Po podniesieniu 1000000000 100000000 10000000 1000000 100000 10000 1000 100 10 1
Po pomnożeniu 1000000000 700000000 10000000 1000000 500000 90000 1000 400 10 4
Gotowa liczba 1711591414

Prawda, że proste? Funkcja eprom_read() zwraca nam gotową wartość do miejsca gdzie została wywołana czyli do zmiennej Kod1.

Aby przetestować działanie układu do pinów 11,12,13,14 przez rezystor 330 ohm podłączamy cztery diody. Na chwile obecną będziemy musieli wysyłać i odbierać kody ręcznie (za pomocą Serial Monitora) wbudowanego w Arduino IDE.

Poniżej schemat całego układu:

schemat

Jeżeli pomysł się spodoba kolejną część artykułu (program dla PC) przewiduje do końca przyszłego tygodnia. Kolejna część

Ocena: 4.18/5 (głosów: 89)

Podobne posty

10 komentarzy do “Sterowanie oświetleniem w pokoju cz.1/3

  • Qrka wodna, tyle się rozpisałeś. Przyznam szczerze, jeszcze nie programuję mC, dlatego sobie tylko przejrzałem na chybił trafił i przewinąłem na koniec.
    Mikro kontroler zamierzasz podłączać kablami do wszystkich lamp, czy wmontujesz w każdej osobny chip? Dlaczego byłoby to lepsze, niż zwykły “klaskacz”?

    Tak bardzo lubisz swoją kanapę, że światła nie możesz zapalić ręcznie? A jak będzie trzeba iść po browara, albo padnie laptop, to co? :)

    Odpowiedz
    • Sama płytka będzie zamocowana w puszcze gdzie znajdował się stary włącznik. Modułem wykonawczym będzie duet zaproponowany przez Łukasza optotriak MOC3021 oraz triak BT138. Druga lampka znajduje się w rogu pokoju to jakieś 2 metry od włącznika wiec w bezprzewodowość nie ma co się bawić. Tam będzie druga para. Czyli dwa na suficie i dwa w wolno stojącej lampce. Klaskacz może faktycznie był by lepszy dla jednej lamy. Ja tych punktów mam 4 i każdy praktycznie innej mocy. Poza tym z budowy klaskacza nie miał bym tyle frajdy co z tego.
      Wpis zajął trochę miejsca bo starałem się rozpisać i omówić ważne funkcję. Myślę, że komuś mogą się przydać czy to do obsługi EEPROM albo konwersji systemów liczbowych. Przeczytałem ostatnio bardzo dużo artykułów nie tylko na Majsterkowie w stylu “tu macie kod a tutaj schemat” powinno działać. Tylko, że później w komentarzach pojawia się masa pytań jak coś zmodyfikować do własnych potrzeb :-). A kanapę mam do wymiany strasznie nie wygodna ;]

      Odpowiedz
  • Słaby ten spam. “Znaleziono 0 ofert spełniających podane kryteria.” plus Notice: unserialize(): Error at offset 64179 of 65535 bytes in /home/energiadirect/public_html/web/application/controller/Porownanie.class.php on line 41

    Odpowiedz

Odpowiedz

anuluj

Masz uwagi?