Programowanie równoległe Attiny85 lub dynia z wielokolorowymi oczami: 7 kroków
Programowanie równoległe Attiny85 lub dynia z wielokolorowymi oczami: 7 kroków
Anonim

By jumbleviewJumbleview.infoObserwuj Więcej autora:

Krzyk
Krzyk
Krzyk
Krzyk
Wymiana baterii NiCd na zewnętrzne źródło zasilania
Wymiana baterii NiCd na zewnętrzne źródło zasilania
Wymiana baterii NiCd na zewnętrzne źródło zasilania
Wymiana baterii NiCd na zewnętrzne źródło zasilania
Uchwyt aparatu cyfrowego
Uchwyt aparatu cyfrowego
Uchwyt aparatu cyfrowego
Uchwyt aparatu cyfrowego

O: Pracuję jako inżynier oprogramowania w jednej z firm Bay Area (Kalifornia). Kiedy mam czas, lubię programować mikrokontrolery, budować zabawki mechaniczne i robić projekty majsterkowania. Więcej o jumbleview »

Ten projekt pokazuje, jak sterować dwoma 10-milimetrowymi, trójkolorowymi diodami LED z anodą (wielokolorowe oczy Pumpkin Halloween Glitter) za pomocą układu Attiny85. Celem projektu jest zapoznanie czytelnika ze sztuką programowania współbieżnego oraz z wykorzystaniem biblioteki protowątków Adama Dunkelsa. Ten projekt zakłada, że czytelnik zna się na 8-bitowych kontrolerach AVR, potrafi napisać program w języku C i ma pewne doświadczenie ze studiem Atmel.

Kod projektu opublikowany na GitHub:

Kieszonkowe dzieci

Przed programowaniem trzeba jeszcze zbudować układ. Oto komponenty:

  • Kontroler Attiny85 (dowolny dostawca elektroniki).
  • Dwie trzy kolorowe diody LED 10mm ze wspólną anodą. Diody LED Adafruit
  • Rezystory 100 Ohm, 120 Ohm, 150 Ohm 0,125 lub 0,250 Wt (dowolny dostawca elektroniki).
  • Sześciopinowe złącze dla interfejsu AVR ISP. Może być wykonany z tego nagłówka Adafruit
  • Jakaś tablica do chleba lub drukowana tablica szablonów. Użyłem tego
  • Interfejs AVR ISP MKII i Atmel Studio 6.1 (późniejsza wersja również powinna działać).

Krok 1: Obwód

Obwód
Obwód

Konstrukcja wykorzystuje pięć pinów chipowych:

  • Dwa piny używane do sterowania anodami: każda anoda LED dołączona do dedykowanego pinu.
  • Trzy piny podłączone (poprzez rezystory) do katod diod LED (katoda tego samego koloru każdej diody podłączona do tego samego pinu)

Ktoś mógłby zapytać: dlaczego nie wykorzystać wszystkich sześciu pinów wejścia/wyjścia układu, aby anody LED były podłączone bezpośrednio do +5 V, a każda katoda będzie miała swój dedykowany pin? To sprawi, że programowanie będzie proste. Niestety jest problem: pin PB5 (RESET) jest słabym pinem, który może dostarczyć tylko ~2 mA prądu, podczas gdy trzeba mieć ~20 mA.

Oczywiście można zbudować wzmacniacz tranzystorowy dla tego słabego pinu, ale ja sam w miarę możliwości wolę rozwiązywać problem za pomocą kodu.

Krok 2: Diagram czasowy

Schemat czasowy
Schemat czasowy

Diagram czasowy pomaga nam zrozumieć, czego potrzebujemy do programowania.

Dwa górne rzędy na schemacie pokazują zmianę napięcia na anodach LED. Napięcie na pinach podłączonych do anod LED oscyluje z częstotliwością ~250 Hz. Ta oscylacja napięcia dla lewej diody LED jest przeciwieństwem oscylacji prawej diody LED. Gdy napięcie na anodzie jest wysokie, odpowiednia dioda LED może być jasna. Gdy jest niski, odpowiednia dioda LED jest ciemna. Oznacza to, że każda dioda LED może świecić przez 2 milisekundy i ciemnieć przez kolejne 2 milisekundy. Ponieważ oko ludzkie ma pewną bezwładność, mruganie o częstotliwości 250 Hz nie jest zauważalne dla obserwatora. Trzy dolne rzędy na schemacie pokazują zmianę napięcia na pinach podłączonych do katod diod LED. Spójrzmy na pierwszą kolumnę diagramu. Pokazuje przypadek, gdy lewa dioda jest w kolorze czerwonym, a prawa w kolorze zielonym. Tutaj CZERWONA katoda pozostaje na niskim poziomie, podczas gdy lewa anoda jest na wysokim poziomie, ZIELONA katoda pozostaje na niskim poziomie, a prawa anoda jest na wysokim poziomie, a NIEBIESKA katoda cały czas pozostaje na niskim poziomie. Inne kolumny na diagramie pokazują kombinacje napięcia katodowego i anodowego dla różnych kolorów.

Jak widać istnieje współzależność od stanu pinów. Bez pewnych ram nie byłoby to łatwe do rozwiązania. I tu przydaje się biblioteka protothread.

Krok 3: Programowanie. Makra i definicje

Programowanie. Makra i definicje
Programowanie. Makra i definicje

Przykład w krokach programowania przedstawia nieco uproszczoną wersję. Program jest skrócony, a niektóre definicje symboliczne zastąpione wyraźnymi stałymi.

Zacznijmy od początku. Program zawiera pliki pochodzące z Atmel Studio oraz nagłówek biblioteki protothread. Dalej są dwa makra do manipulowania poziomami pinów i kilka definicji, które nadają logiczne nazwy sygnałom pinów. Jak dotąd nic specjalnego.

Krok 4: Programowanie. Główna pętla

Programowanie. Główna pętla
Programowanie. Główna pętla

Następnie spójrzmy na koniec, aby zobaczyć, co zawiera główna procedura.

Funkcja main po wykonaniu jakiejś inicjalizacji pozostaje w nieskończonej pętli. W tej pętli wykonuje kolejne kroki:

  • Wywołuje procedurę protothread dla lewej diody LED. Zmienia napięcie niektórych pinów.
  • Zrób dwie milisekundy opóźnienia. Nie ma zmiany napięcia pinów.
  • Wywołuje protothread dla prawej diody LED. Zmienia pewne napięcie pinów.
  • Zrób 2 opóźnienie MS. Nie ma zmiany napięcia pinów.

Krok 5: Programowanie. Funkcje pomocnicze

Programowanie. Funkcje pomocnicze
Programowanie. Funkcje pomocnicze

Zanim zaczniemy omawiać protowątki, musimy przyjrzeć się kilku funkcjom pomocniczym. Najpierw są funkcje do ustawienia konkretnego koloru. Są proste. Takich funkcji jest tyle, jak liczba obsługiwanych kolorów (siedem) oraz jeszcze jedna funkcja ustawienia ściemniania LED (NoColor).

I jest jeszcze jedna funkcja, która zostanie bezpośrednio wywołana przez procedurę protothread. Jego nazwa to DoAndCountdown().

Technicznie rzecz biorąc, korzystanie z takiej funkcji nie jest obowiązkowe, ale uznałem to za wygodne. Ma trzy argumenty:

  • Wskaźnik do ustawienia funkcji koloru LED (np. RedColor lub GreenColor itp.)
  • Wartość początkowa licznika odwrotnego: ile razy funkcja ta musi być wywołana na danym etapie protowątku.
  • Wskaźnik do odwrócenia licznika. Zakłada się, że w przypadku zmiany koloru licznik odwrotny wynosi 0, więc w pierwszej iteracji kod przypisze do tego licznika wartość początkową. Po każdej iteracji licznik jest zmniejszany.

Funkcja DoAndCountdown() zwraca wartość licznika wstecznego.

Krok 6: Programowanie. Protowątki

Programowanie. Protowątki
Programowanie. Protowątki

A oto rdzeń frameworka: procedura protothread. Dla uproszczenia przykład ograniczony tylko do trzech kroków: zmiana koloru na CZERWONY, ZIELONY i NIEBIESKI.

Funkcja jest wywoływana z dwoma argumentami:

  • Wskaźnik do struktury protothread. Ta struktura została zainicjowana przez main przed rozpoczęciem głównej pętli.
  • Wskaźnik do odwrócenia licznika. Został ustawiony na 0 przez main przed rozpoczęciem głównej pętli.

Funkcja ustawia napięcia, aby aktywować lewą diodę LED, a następnie uruchamia segment protothread. Ten segment znajduje się między makrami PT_BEGIN i PT_END. Wewnątrz znajduje się kod, który w naszym przypadku powtarza tylko makra PT_WAIT_UNTIL. To makra wykonuje dalej:

  • Wywołanie funkcji DoAndCountdown. To ustawia napięcie na katodach LED, aby emitować określony kolor.
  • Zwracany wynik w porównaniu z 0. Jeśli warunek jest 'false', funkcja protothread natychmiast zwraca i przekazuje kontrolę do pętli głównej.
  • Gdy protothread jest wywoływany następnym razem, ponownie wykonuje kod przed PT_BEGIN, a następnie przeskakuje bezpośrednio do makr PT_WAIT_UNTIL, z których wrócił ostatnio.
  • Takie akcje są powtarzane aż wynik DoAndCountdown wyniesie 0. W takim przypadku nie ma powrotu, program pozostaje w protowątku i wykonuje kolejną linię kodu. W naszym przypadku jest to kolejny PT_WAIT_UNTIL, ale ogólnie mówiąc może to być prawie każdy kod w C.
  • Przy początkowym wykonaniu drugiego licznika odwrotnego PT_WAIT_UNTIL wynosi 0, więc procedura DoAndCountdown() ustawia go na wartość początkową. Drugie makra ponownie zostaną wykonane 250 razy, aż licznik odwróceń osiągnie 0.
  • Stan struct pt jest resetowany, gdy tylko kontrola osiągnie makra PT_END. Gdy funkcja protothread zostanie wywołana następnym razem, segment protothread rozpocznie wykonywanie wiersza kodu zaraz po PT_BEGIN.

Dla prawej diody LED istnieje podobna procedura protothread. W naszym przykładzie po prostu wymusza inną kolejność kolorów, ale jeśli możemy to zrobić zupełnie inaczej: nie ma ścisłego sprzężenia między lewą i prawą procedurą LED.

Krok 7: Wewnętrzne

Wewnętrzne
Wewnętrzne

Cały program zajmuje mniej niż 200 linii kodu (z komentarzami i pustymi liniami) i zajmuje mniej niż 20% pamięci kodu Attiny85. W razie potrzeby można tu wykorzystać kilka dodatkowych podprogramów protowątkowych i przypisać im znacznie bardziej skomplikowaną logikę.

Biblioteka Protothreads to najprostsza forma komputerowego programowania współbieżnego. Programowanie współbieżne to podejście pozwalające podzielić program na logiczne części: czasem nazywane są współprogramami, czasem wątkiem, czasem zadaniami. Zasada jest taka, że każde takie zadanie może dzielić tę samą moc procesora, zachowując jednocześnie mniej lub bardziej liniowy kod i niezależny od innych części. Zadania z logicznego punktu widzenia mogą być wykonywane jednocześnie.

W przypadku zaawansowanych systemów kontrola takich zadań wykonywana jest albo przez jądro systemu operacyjnego, albo przez środowisko uruchomieniowe języka osadzone w pliku wykonywalnym przez kompilator. Natomiast w przypadku protowątków programista steruje nimi ręcznie, używając biblioteki makr protothreads w procedurach zadaniowych i wywołując takie procedury (zwykle poza pętlą główną).

Prawdopodobnie chcesz wiedzieć, jak faktycznie działa protothread? Gdzie ukryta jest magia? Protowątki opierają się na specjalnej funkcji języka C: fakcie, że instrukcja C switch case może być osadzona w if lub innym bloku (np. while lub for). Szczegóły można znaleźć na stronie Adama Dunkelsa

Elektronika wewnętrzna tego projektu jest bardzo prosta. Zdjęcie powyżej daje pewną wskazówkę. Jestem pewien, że możesz zrobić lepiej.