Zakres laboratorium:
- Program testowy
- Wykorzystanie przerwań wewnętrznych – praca z dokumentacją mikrokontrolera – dokumentacja
- Przerwania zewnętrzne – obsługa przycisków
- Konfiguracja układu licznikowego do pracy z zadanymi parametrami
- Obsługa wyświetlacza 7-segmentowego na przerwaniach
- Obsługa enkodera mechanicznego – impulsator
1. Program testowy
- podłączyć diodę do pinu PD0
- napisać program, który będzie migał diodą z częstotliwością 1Hz
- program w pętli while powinien zajmować tylko dwie linijki -> dwie komendy
2. Przerwania wewnętrzne, konfiguracja
- podłączyć diodę do pinu PD1
- wgrać do środowiska programistycznego poniższy kod programu
- uzupełnić fragmenty aby uruchomić przerwanie na liczniku Timer1 działające z częstotliwością 2Hz
- uzupełnić przerwanie o komendę migania diodą na porcie PD1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#include <avr/io.h> #include <stdlib.h> #include <string.h> #include <util/delay.h> #ifndef _BV #define _BV(bit) (1<<(bit)) #endif #ifndef sbi #define sbi(reg,bit) reg |= (_BV(bit)) #endif #ifndef cbi #define cbi(reg,bit) reg &= ~(_BV(bit)) #endif #ifndef tbi #define tbi(reg,bit) reg ^= (_BV(bit)) #endif void timerInit() { //Wybranie trybu pracy CTC z TOP OCR1A //Wybranie dzielnika czestotliwosci - częstotliwość Atmega328: 16 MHz //Zapisanie do OCR1A wartosci odpowiadajacej 0,5s //Uruchomienie przerwania OCIE1A } //volatile -informacja dla kompilatora aby nie optymalizował zmiennej, //zmienna bezpieczna do wykorzystania w przerwaniach volatile int zmienna=0; int main() { timerInit(); sei(); //Uruchamia przerwania globalne sbi(DDRD,PD0); sbi(DDRD,PD1); while (1) { //kod programu przełączajacy diodę LED _delay_ms(500); } } ISR(TIMER1_COMPA_vect) { } |
Pytania – zrobić notatkę:
- jak działa ten program?
- czy w pętli głównej programu możemy napisać kod blokujący (taki, który blokuje program na dłuższy czas), a dioda i tak będzie migać z dobrą częstotliwością?
- co się stanie jak w zablokujemy przerwanie, np. dodamy “_delay_ms(5000)” ? Jak będą działać diody?
3. Przerwania zewnętrzne – dioda LED
- na bazie programu z zadania 2, wykonać kolejne zadanie
- dioda podłączona do PD0 ma ciągle migać w pętli głównej programu. Dioda z pinu PD1 – działa w przerwaniu od Timer1
- podłączyć kolejną diodę do pinu PD5
- podłączyć przycisk do pinu gdzie jest możliwość obsługi przerwania zewnętrznego (INT0)
- skonfigurować pin do obsługi przycisków (PULL-UP)
- skonfigurować przerwanie zewnętrzne dla wybranego pinu z reakcją na zbocze opadające (należy ustawić dwa bity zgodnie z dokumentacją)
- funkcja przerwania INT0-> ISR(INT0_vect)
- każde przyciśnięcie przycisku generuje przerwanie, w przerwaniu powinna być przełączania dioda podłączona do pinu PD5
Pytania – zrobić notatkę:
- co to jest zbocze opadające, zbocze narastające?
- czy program przełączy stan diody natychmiast, czy będzie opóźnienie z innego przerwania lub pętli głównej? Jak zadziała jeśli w pętli głównej będzie dłuższe zadanie?
- co się stanie jak w przerwaniu od przycisku dodamy opóźnienie 5000ms? (przerwanie należy ciągle wywoływać, naciskać przycisk)
- co się stanie jak w przerwaniu od licznika dodamy opóźnienie 5000ms?
- dlaczego dwa powyższe zadania działają inaczej, jaka jest różnica i dlaczego?
4. Wyświetlacz 7-segmentowy na przerwaniach
- przerobić program z poprzedniego laboratorium tak aby wyświetlacz 7-segmetnowy obsługiwał liczby w zakresie 0-9999,
- powinna być zmienna globalna “liczba”, której wartość jest wyświetlana na wyświetlaczu
- odświeżanie wyświetlacza (multipleksowanie) należy przenieś do przerwania wewnętrznego, należy odpowiednio skonfigurować czasy przerwania
- w wywołaniu przerwania nie wolno używać funkcji opóźniających, kod programu powinien być jak najszybszy
- w pętli głównej zrobić licznik liczący od 0 do 250 co jedną sekundę, wartość wyświetlić na wyświetlaczu
5. Enkoder mechaniczny – impulsator
- na bazie zadania 4 przygotować program, który zmienia wartość zmiennej “wartosc” za pomocą enkodera i prezentuje ją na wyświetlaczu 7-segmentowym. Skasować licznik z pętli głównej programu.
- działanie enkodera zostało zaprezentowane na rysunku poniżej
- podłączyć enkoder, piny “Enc_A” i “Enc_B” do pinów mikrokontrolera, pin “Enc_com” do GND
- skonfigurować piny jak do obsługi przycisków (PULL-UP)
- napisać program, który odczyta kierunek obrotu enkodera i będzie zwiększał, zmniejszał zmienną “wartosc”
- zmienna “wartosc” ma być wyświetlana na wyświetlaczu 7-segmentowym
- zakres liczb jakie może przyjmować zmienna “wartość” to -100 do 100. Napisać odpowiednie zabezpieczenia i wyświetlanie liczby ujemnej
Zakres laboratorium 2017-2021 (nie aktualne)
Zakres laboratorium:
- Wykorzystanie przerwań wewnętrznych – praca z dokumentacją mikrokontrolera
- Obsługa wyświetlacza 7 segmentowego – 1 segment
- Obsługa wyświetlacza 7 segmentowego – 4 segmenty
- Zegarek na wyświetlaczu 7 segmentowym
- Zadanie domowe
Zadania do wykonania:
- Zadanie 1.1
- Zadanie 1.2
- Zadanie 2.1
- Zadanie 3.1
- Zadanie 4.1
- Zadanie domowe
1. Wykorzystanie przerwań wewnętrznych – praca z dokumentacją mikrokontrolera
Zadanie 1.1
Skopiować do pliku “main.cpp” poniższy kod programu (plik “GLOBAL.h“), zapoznać się z zmiennymi i funkcjami jakie występują.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include "GLOBAL.h" volatile uint8_t minuty, sekundy; volatile uint16_t liczba7Seg; volatile char znaki[4]; char cyfra[10] = { 0b1111111, 0b1111111, 0b1111111, 0b1111111, 0b1111111, 0b1111111, 0b1111111, 0b1111111, 0b1111111, 0b1111111}; //Inicjalizacja Timer1 do wywolywania przerwania co 1s void TimerInit() { //Wybranie trybu pracy CTC z TOP OCR1A //Wybranie dzielnika czestotliwosci //Zapisanie do OCR1A wartosci odpowiadajacej 0,5s //Uruchomienie przerwania OCIE1A } //Inicjalizacja portow do obsługi wyswietlacza 7 segmentowego void seg7Init() { //Inicjalizacja kolumn //Inicjalizacja segmentu } //Wyswietla na wyswietlaczu 7 segmentowym cyfre z argumentu void seg7ShowCyfra(uint8_t cyfraDoWyswietlenia) { //PORTC = cyfra[cyfraDoWyswietlenia] //co to robi - wytlumaczyc prowadzacemu } //Wyswietla na wyswietlaczu 7 segmentowym wartosc ze zmiennej liczba7Seg void seg7Show4Cyfry() { } //Funkcja wyswietla na wyswietlaczu litery, cyfry z tablicy znaki /* zadanie na ocenę 5.5 */ void seg7Show4Litery() { } int main() { minuty = 0; sekundy = 0; liczba7Seg = 0; TimerInit(); seg7Init(); sei(); //funkcja uruchamia globalne przerwania while (1) { seg7ShowCyfra(5); _delay_ms(100); } return 0; } //Funkcja uruchamiana z przerwaniem po przepelnieniu licznika w timer1 ISR(TIMER1_COMPA_vect) { } |
Przerwania – jest to mechanizm, który pozwala mikrokontrolerowi na przerwanie bieżąco wykonywanych zadań na skutek otrzymania jakiegoś zdarzenia, które wymaga pilnej obsługi. Źródłem przerwań mogą być:
- wewnętrzne układy
- liczniki – przepełnienie licznika, odliczenie ustalonej ilości impulsów
- moduł komunikacji – zdarzenie informujące o zakończeniu transmisji
- przetworniki – zdarzenie informujące o zakończeniu przetwarzania
- itd.
- zewnętrzne (sygnały podawany na wyprowadzenia mikrokontrolera)
- wciśnięcie przycisku
- enkodery – liczenie impulsów
- układy zewnętrzne generujące przerwania (czujnik pomiaru temperatury – skończył pomiar i generuje przerwanie w celu poinformowania mikrokontrolera, że może już pobrać wynik pomiaru)
- itd.
Przerwanie wewnętrzne
Należy wykorzystać przerwanie wewnętrzne pochodzące od Timer1 w celu wygenerowania sygnału prostokątnego na wyprowadzeniu mikrokontrolera PD6 o częstotliwości 1s (0,5sekundy stan niski, 0,5 sekundy stan wysoki).
Pierwsze kroki:
- podłączyć diodę z linijki diodowej do wyprowadzenia PD6, skonfigurować wyprowadzenie do pracy jako wyjście, ustawić stan w jakim dioda jest wyłączona (funkcja “main”)
Zadanie 1.2
- skonfigurować TIMER1 w funkcji “TimerInit()” tak aby wywoływał przerwanie dokładnie, co 0,5 sekundy (konfiguracja rejestrów mikrokontrolera – dokumentacja)
- uzupełnić kod przerwania “ISR(TIMER1_COMPA_vect)”, którego działanie będzie polegać na mruganiu diodą LED podłączoną do portu PD6 (makro “tbi”)
- jak działa program, co się dzieje w pętli głównej programu
2. Obsługa wyświetlacza 7 segmentowego – 1 segment
Budowa pojedynczego segmentu:
Powyżej został przestawiony schemat wewnętrzny jednego segmentu wyświetlacza ze wspólną anodą. Nazwa wyświetlacza bierze się od 7 diod LED (A,B,C,D,E,F,G) dodatkowo wyświetlacz posiada 8 diodę, która odpowiada za znak kropki (DP). Diody są ustawione w segment przedstawiony na rysunku:
Takie ułożenie pozwala na wyświetlenie wszystkich liter i całego alfabetu za pomocą odpowiedniego wysterowania 7 diodami LED. Np. wyświetlenie cyfry “0” to włączenie diod LED oznaczonych A,B,C,D,E,F. Literę “A” można uzyskać przez włączenie A,B,C,E,F,G.
Schemat wyświetlacza i jego podłączenia na płytce edu został przedstawiony na rysunku poniżej. W górnej części schematu znajduje się tranzystory typu PNP, które pozwalają na wysterowanie/
uruchomienie odpowiedniej kolumny wyświetlacza – tak aby każdy z 4 segmentów mógł wyświetlić inną wartość.
Pierwsze kroki:
- podłączyć wyświetlacz zgodnie z schematem:
Zadanie 2.1
- skonfigurować wykorzystane porty mikrokontrolera jako wyjścia -zrobić to w funkcji “seg7Init()”
- na wyprowadzenia W1,W2,W3,W4 podać stan niski – przed pętlą “while(1)” w funkcji “main” (jest to rozwiązanie chwilowe – pozwoli na testowanie jednego segmentu)
- uzupełnić kod funkcji “seg7ShowCyfra()” tak aby wyświetlała liczby z zakresu 0-9 z wykorzystaniem tablicy “cyfra” (seg7ShowCyfra(0) – ma wyświetlić 0, seg7ShowCyfra(5) ma wyświetlić 5). Należy uzupełnić tablicę cyfra aby wartości odpowiadały za wyświetlanie prawidłowych cyfr.
3. Obsługa wyświetlacza 7 segmentowego – 4 segmenty
W celu obsługi wyświetlacza składającego się z 4 kolumn 7 segmentowych można wykorzystać multipleksowanie. Metoda ta pozwala ograniczyć ilość potrzebnych portów mikrokontrolera, ponieważ na każdy kolejny segment wystarczy 1 wyprowadzenie, czyli do obsługi naszego wyświetlacza mającego 4 kolumny z 7 segmentami wykorzystamy 11 wyprowadzeń (7+4). Sterują bez
multipleksowania potrzebowalibyśmy na każdy segment 7 wyprowadzeń, czyli musielibyśmy wykorzystać 28 wyprowadzeń (7*4). Można prosto ograniczyć ilość potrzebnych połączeń jednak kosztem trudniejszego sterowania. Multipleksowanie polega na szybkim przełączaniu kolejnych segmentów i wyświetlaniu odpowiedniej wartości. Robiąc to odpowiednio szybko ludzkie oko będzie oszukiwane i człowiek zobaczy na wyświetlaczu stałą wartość. Do zrozumienia jak taki efekt uzyskać na płytce EDU należy wrócić do rysunku “Schemat podłączenia wyświetlacza na płytce EDU”, gdzie w górnej części są tranzystory PNP, które pozwalają włączyć/wyłączyć każdą kolumnę niezależnie.
Algorytm multipleksowania:
- włączyć kolumnę Wx
- wyświetlić cyfrę dla kolumny Wx
- wyłączyć kolumnę Wx
- operacje powtórzyć dla wszystkich 4 kolumn
Robiąc to odpowiednio szybko otrzymamy stałą wartość składającą się z 4 znaków (4 kolumny)
Zadanie 3.1
- usunąć kod realizujący zadanie: “na wyprowadzenia W1,W2,W3,W4 podać stan niski – przed pętlą “while(1)” w funkcji “main”
- zmienić główną pętlę “while” na”
1234while (1) {seg7Show4Cyfry();_delay_ms(10);} - przygotować funkcję “seg7Show4Cyfry()”, która pozwala wyświetlić na wyświetlaczu liczbę z zakresu 0-9999
- wykorzystać przerwanie do zwiększania wartości liczby jaką wyświetlamy (dopisać kod do funkcji “ISR(TIMER1_OVF_vect)”)
4. Zegarek na wyświetlaczu 7 segmentowym
Należy przygotować program, który będzie realizował funkcje zegarka – sekundy odmierzane z wykorzystaniem przerwania wewnętrznego. Czas wyświetlany na wyświetlaczu 7 segmentowym.
Zadanie 4.1
- do odmierzania czasu należy wykorzystać przerwanie pochodzące od TIMER1 (skonfigurować przerwanie aby było wywoływane z okresem 1 sekundy)
- w funkcji przerwania “ISR(TIMER1_OVF_vect)” należy odpowiednio operować na zmiennych “minuty” i “sekundy” w celu uzyskania prawidłowo odmierzania czasu
- wykorzystać funkcję z poprzedniego zadania “seg7Show4Cyfry()” (wpisywać odpowiednią wartość do zmiennej “liczba7Seg”) i zaprezentować aktualny czas na wyświetlaczu 7 segmentowym
5. Zadanie domowe
- schemat podłączenia wyświetlacza 7 segmentowego do mikrokontrolera
Zadania na ocenę 5,5:
- przygotować funkcję “seg7Show4Litery()” – do tablicy “znaki[4]” -wpisujemy dowolne cyfry, liczby i funkcja wyświetla zawartość na wyświetlaczu 7-segmentowym
- przepisać funkcję odpowiedzialną za multipleksowanie do przerwania – tak aby w pętli głównej programu operacje nie blokowały wyświetlacza
Zagadnienia na przyszłe zajęcia:
- przetwornik ADC