Kurs podstawowy
Pierwszy projekt - migająca dioda

Zdobyliśmy wystarczającą wiedzę aby stworzyć nasz pierwszy projekt obejmujący warstwę sprzętową i oprogramowanie. W tym artykule wykorzystamy wszystkie omówione wcześniej zagadnienia. Nasza aplikacja nie będzie już bezczynnym układem, lecz nabierze konkretnej funkcjonalności.

 

 

Jak mawiał klasyk "Nadejszła wiekopomna chwila".  Rozpoczynamy projektowanie układów w oparciu o mikrokontrolery i programowanie ich w języku C. Korzystać będziemy ze środowiska Atmel STudio 7.0. Naszym pierwszym projektem będzie mrugająca dioda LED. Jest to takie "Witaj świecie" dla mikrokontrolerów. No ale od czegoś trzeba zacząć.

 

Krok pierwszy.

Każdy nowy projekt zaczynamy od określenia celu. W naszym przypadku będzie to układ zapalający i gaszący diodę LED w równych odcinkach czasu. Układ ma być zbudowany w oparciu o mikrokontroler ATmega32. Będziemy wykorzystywali tylko część cyfrową mikrokontrolera. Skorzystamy z wcześniej zbudowanego układu, do którego podłączymy diodę LED.  Mikrokontroler taktowany będzie zegarem o częstotliwości 16 MHz. Dioda będzie podłączona bezpośrednio do pinu PA0 przez rezystor ograniczający. Nie będziemy wykorzystywali przycisku reset.

 

Krok drugi.

Wykonamy schemat naszego układu i dobierzemy niezbędne elementy.

 

Rys. 1. Schemat wstępny układu z mrugającą diodą.

 

Rysunek 1 przedstawia wstępny schemat migającej diody sterowanej przez mikrokontroler ATmega32. Pozostało nam jeszcze dobranie rezystora ograniczającego prąd o odpowiedniej wartości, która zależeć będzie od parametrów diody LED. Ja użyję diody LED czerwonej CQXP04 produkcji CEMI. (polski producent mikroelektroniki). Napięcie przewodzenia diody to 2 V, prąd przewodzenia 20 mA. Zakładamy, że napięcie na pinie PA0 w stanie wysokim wynosi Vcc. Wartość rezystora dobieramy korzystając ze wzoru:

 

\frac{Vcc - U_{_{F}}}{I_{F}} = \frac{5-2}{0.02} = 150\Omega

 

Nanosimy wszystkie informacje na schemat, aby otrzymać jego ostateczną wersję.

 

Rys. 2. Schemat układu.

 

Korzystając ze schematu przygotowujemy wykaz potrzebnych elementów.

U1: ATmega32-16PU - 1szt.

Y1: Kwarc 16 MHz - 1szt.

C1, C2: Kondensator ceramiczny 22 pF - 2 szt.

C3, C4, C5: Kondensator ceramiczny 100 nF - 3 szt.

LED1: Dioda CQXP04 - 1 szt.

R1: Rezystor 150R 1 szt.

R2: Rezystor 10k 1 szt.

 

Krok trzeci

Gdy mamy już zebrane wszystkie potrzebne elementy możemy zmontować układ na płytce prototypowej.

 

Rys. 3. Układ zmontowany na płytce prototypowej.

 

Krok czwarty.

Dobieramy ustawienia fusebitów zgodnie ze schematem oraz specyfikacją projektu. Sposób doboru i ustawienia fusebitów opisany jest w artykule Fusebity, czyli konfiguracja mikrokontrolera. Dla tego układu Fuse High Byte = 0xC9, a Fuse Low Byte = 0x7F.

 

Krok piąty.

Uruchamiamy środowisko programistyczne Atmel STudio 7.0 i tworzymy nowy projekt.

 

Rys. 4. Atmel Studio 7.0 - uruchomienie kreatora nowego projektu.

Wybieramy język C/C++, zaznaczamy GCC C Executable Project, wpisujemy nazwę projektu, możemy podać własną lokalizację, zaznaczamy opcję aby program utworzył katalog projektu i zatwierdzamy wszystko klikając w przycisk OK.

 

Rys. 5. Wybór ustawień kreatora nowego projektu.

 

Po chwili wyświetli się okienko, w którym wybieramy mikrokontroler, dla którego będziemy pisali program. Ja wybrałem ATmega32, gdyż taki mam zamontowany na płytce prototypowej i klikamy przycisk OK. Kreator tworzy nowy projekt i zapisuje nowe pliki na dysku we wskazanej lokalizacji. Gdy kreator zakończy działanie otworzy się okno programu Atmel Studio 7.0 na karcie main.c, na której będziemy pisać program dla mikrokontrolera.

 

Rys. 6. Okno programu

 

Możemy rozpocząć pisanie kodu dla mikrokontrolera.

 

/*
 * Blinking LED.c
 *
 * Created: 09.10.2017 15:49:38
 * Author : Orici
 */ 

/* Dołaczenie biblioteki z definicjami rejestrów i bitów I/O */
#include < avr/io.h >

/* Podanie częstotliwości taktowania mikrokontrolera. Niezbędne dla biblioteki delay.h */
#define F_CPU 16000000UL

/* Dołączenie biblioteki delay.h z funkcjami opóźnień */
#include < util/delay.h >

/* Definicja stałej dla portu do którego podłączono diodę */
#define LED (1 << PA0)


int main(void)
{
   /* Ustawienie wszystkich pinów jako wyjścia */
   DDRA = 0xFF;
   DDRB = 0xFF;
   DDRC = 0xFF;
   DDRD = 0xFF;
   
    while (1) 
    {
		/* Zmiana stanu na pinie PA0 na przeciwny */
		PORTA ^= LED;
		
		/* Oczekiwanie 500 ms */
		_delay_ms(500);
    }
}

 

#include < avr/io.h > - biblioteka dołączona automatycznie przez Atmel Studio. Znajdują się w niej definicje portów, rejestrów i pinów wejścia wyjścia. Ta biblioteka musi być dołączana zawsze.

#define F_CPU 16000000UL - definicja stałej F_CPU niezbędnej dla biblioteki delay.h. W definicji stałej F_CPU podajemy częstotliwość taktowania mikrokontrolera wyrażoną w Hertzach.

#include < util/delay > - dołączenie biblioteki delay.h, w której znajdują się funkcje realizujące opóźnienia.

#define LED (1 << PA0) - definicja stałej wskazującej na pin PA0. W funkcji głównej wystarczy posługiwać się wyrażeniem LED aby móc manipulować pinem PA0.

int main(void) {...} - funkcja główna programu, w której umieszcza się definicje oraz deklaracje funkcji i zmiennych, a także instrukcje inicjalizujące, konfigurujące. W funkcji głównej znajduje się również pętla główna programu.

DDRA = 0xFF; DDRB = 0xFF; DDRC = 0xFF; DDRD = 0xFF; - zapisanie wartości 1 do wszystkich bitów każdego rejestru kierunkowego mikrokontrolera. W ten sposób zrealizowałem ustawienie wszystkich pinów jako wyjścia. Uniknąłem tym samym niepodłączonych pinów wejściowych w stanie wysokiej impedancji.

while(1) {...} - pętla główna programu. Pętla nieskończona, w której znajdują się instrukcje wykonywane przez mikrokontroler zgodnie z cyklami zegarowymi.

PORTA ^= LED - instrukcja która zmienia stan pinu PA0 na przeciwny. W tej jednej linii zawarty jest cały program mikrokontrolera. Tę samą instrukcję można by rozpisać na kilka linii oddzielnie ustawiając naprzemiennie stan wysoki oraz stan niski na pinie.

_delay_ms(500) - zatrzymanie wykonywania pętli programu na czas 500 ms. Stan na pinie utrzymywany jest przez 500 ms.

 

Na listingu widoczne są także komentarze. Zalecam je stosować. W komentarzach umieszczajcie wskazówki dla siebie i innych. Dzięki nim nawet po długim czasie będziecie w stanie bardzo szybko zlokalizować błędy, nanieść usprawnienia, przenieść program na inny mikrokontroler. Przy dużych programach można się na prawdę pogubić.

 

Krok szósty

Podłączamy programator do układu, podłączamy zasilanie i programujemy fusebity następnie kompilujemy program i ładujemy go mikrokontrolera.

Wgrywanie programu za pomocą programatora wspieranego przez Atmel Studio 7.0.

Zaczynamy od wyboru programatora klikając w przycisk No Tool na belce przycisków.

 

Rys. 7. Wybór programatora w Atmel Studio 7.0 - krok 1.

 

Rys. 8. Wybór programatora w Atmel Studio 7.0 - krok 2.

 

Ja wybrałem programator AVRISP MKII klikając w jego nazwę na liście rozwijanej. Przechodzimy z powrotem na kartę main.c. Programator został wybrany i możemy w razie konieczności dokonywać zmian w programie. Aby załadować program do mikrokontrolera wystarczy kliknąć przycisk Start Without Debugging lub wcisnąć kombinację klawiszy Ctrl+Alt+F5.

 

Rys. 9. Uruchomienie Toolchaina i załadowanie programu do mikrokontrolera.

 

Gdy Atmel Studio zakończy kompilację programu i załaduje go mikrokontrolera w oknie wyjściowym zobaczymy raport. Jeżeli wszystko przebiegło pomyślnie i w raporcie nie będzie żadnych informacji o błędach oznacza to, że nasz program był napisany prawidłowo.

 

Rys. 10. Widok okna wyjściowego Atmel Studio po prawidłowo wykonanej kompilacji i załadowaniu programu do mikrokontrolera.

 

To wszystko. Mikrokontroler rozpocznie wykonywanie programu. Dioda podłączona do portu PA0 zacznie migać.

 

Wgrywanie programu za pomocą USBasp z poziomu Atmel Studio 7.0.

Tutaj sytuacja wygląda troszkę inaczej, gdyż używając programatora wspieranego przez Atmel Studio 7.0 nie jest generowany plik *.hex. Aby znalazł się on w katalogu Debug należy najpierw kliknąć w przycisk Start Debugging lub wcisnąć klawisz F5, a następnie przycisk pod którym znajduje się nasz USBasp. Sposób integracji programatora USBasp z Atmel Studio 7.0 znajdziesz w artykule Integracja Atmek Studio 7.0 z programatorem USBasp.

 

Rys. 11. Kompilacja i wgrywanie programu do mikrokontrolera za pomocą programatora USBasp.

 

Rozpoczęcie kompilacji zakończy się podobnym wynikiem jak na rys. 10. Kliknięcie na przycisk programatora USBasp załaduje program do mikrokontrolera, który rozpocznie działać zapalając i gasząc diodę podłączoną do pinu PA0.

Układ działa prawidłowo, co widać na załączonym krótkim filmie.

 

 

Programowanie mikrokontrolerów nie jest wcale trudnym zajęciem. Wystarczy wiedzieć co mikrokontroler ma robić i napisać program krok po kroku zapisując kolejne instrukcje.

Na koniec poddamy nasz układ prostym badaniom. Na ekranie oscyloskopu obejrzymy przebieg napięcia na pinie PA0 do którego podłączona jest dioda LED1.

 

Rys. 12. Przebieg oraz pomiary napięcia na pinie PA0 z podłaczoną diodą LED1.

 

Dioda zapalana jest na 500 ms, a następnie gaszona na 500 ms. Cykl ten jest powtarzany. Na ekranie oscyloskopu widać ładny przebieg prostokątny. Wykorzystałem funkcje oscyloskopu do wykonania kilku pomiarów sygnału. Szerokość impulsu wynosi 500 ms, czyli tyle ile założyliśmy. Częstotliwość sygnału wynosi 1 Hz, a okres przebiegu 1 s. Wynika z tego, że nasz program działa bardzo dobrze, a funkcja _delay_ms precyzyjnie odmierza czas. Chcę jednak zwrócić uwagę na poziom napięcia sygnału. Napięcie na obciążonym diodą LED1 pinie PA0 wynosi 4,56 V. Sprawdźmy, jak będzie wyglądało to napięcie na pinie nieobciążonym.

 

Rys. 12. Przebieg oraz pomiary napięcia na pinie PA0 bez podłączonej diody LED1.

 

Widać wyraźnie, że napięcie w stanie wysokim wzrosło do 5,08 V. Można przyjąć, że jest to napięcie Vcc. Spadek napięcia na obciążonym pinie wynosi zatem 0,52 V. Prąd płynący przez diodę w stanie wysokim wynosi 20 mA. Potwierdza się zatem charakterystyka prądowo-napięciowa pinu przedstawiona w dokumentacji. Temat dokładnie został omówiony w artykule Wejścia i wyjścia binarne. Nasuwa się wniosek, że przy większych prądach płynących przez pin wyjściowy mikrokontrolera warto stosować układy buforujące, aby zapobiec poziomom logicznym w paśmie zabronionym. Na to trzeba się wyczulić, a uniknie się przykrych niespodzianek.

 

Ten prosty i banalny z pozoru projekt przybliżył wiele aspektów, które należy brać pod uwagę przy tworzeniu indywidualnych konstrukcji. Nauczyliśmy się ustawiać poziomy logiczne na pinie. Na bazie tego projektu można zrealizować wiele bardziej atrakcyjnych wizualnie efektów świetlnych, czy też zbudować prosty generator przebiegu prostokątnego. Co prawda mikrokontroler ten jest zbyt potężny do takich zadań, ale w celach edukacyjnych spisuje się wyśmienicie. Bez żadnego problemu można taki program przygotować na mniejsze i tańsze mikrokontrolery.

Autor: Orici
Wyświetleń: 701|Komentarzy: 0|Ocena: 0|Głosów: 0