Spisu treści:

Mikrokontroler AVR. Migacz diod LED za pomocą timera. Przerwania timerów. Tryb timera CTC: 6 kroków
Mikrokontroler AVR. Migacz diod LED za pomocą timera. Przerwania timerów. Tryb timera CTC: 6 kroków

Wideo: Mikrokontroler AVR. Migacz diod LED za pomocą timera. Przerwania timerów. Tryb timera CTC: 6 kroków

Wideo: Mikrokontroler AVR. Migacz diod LED za pomocą timera. Przerwania timerów. Tryb timera CTC: 6 kroków
Wideo: Jak zrobić tekst wyswietlający sie obok zegara 2024, Listopad
Anonim
Image
Image

Cześć wszystkim!

Timery to ważna koncepcja w dziedzinie elektroniki. Każdy element elektroniczny działa na podstawie czasu. Ta podstawa czasu pomaga zsynchronizować całą pracę. Wszystkie mikrokontrolery pracują z określoną częstotliwością zegara, wszystkie mają możliwość ustawienia timerów. AVR może pochwalić się bardzo dokładnym, precyzyjnym i niezawodnym timerem. Oferuje mnóstwo funkcji, dzięki czemu jest obszernym tematem. Najlepsze jest to, że zegar jest całkowicie niezależny od procesora. W ten sposób działa równolegle do procesora i nie ma interwencji procesora, co sprawia, że zegar jest dość dokładny. W tej sekcji wyjaśniam podstawowe pojęcia Timerów AVR. Piszę prosty program w kodzie C do sterowania flasherem LED za pomocą timerów.

Krok 1: Opis

Opis problemu 1: Migajmy najpierw diodę LED (zieloną) co 50 ms
Opis problemu 1: Migajmy najpierw diodę LED (zieloną) co 50 ms

W ATMega328 istnieją trzy rodzaje timerów:

Timer/Counter0 (TC0) - jest 8-bitowym modułem Timer/Counter ogólnego przeznaczenia, z dwoma niezależnymi jednostkami OutputCompare i obsługą PWM;

Timer/Licznik1 (TC1) – 16-bitowy Timer/Licznik umożliwia dokładne synchronizowanie czasu wykonywania programu (zarządzanie zdarzeniami), generowanie fali i pomiar czasu sygnału;

Timer/Counter2 (TC2) - jest uniwersalnym, kanałowym, 8-bitowym modułem Timer/Counter z PWM i pracą asynchroniczną;

Krok 2: Stwierdzenie problemu 1: Migajmy najpierw diodę LED (zieloną) co 50 ms

Opis problemu 1: Migajmy najpierw diodę LED (zieloną) co 50 ms
Opis problemu 1: Migajmy najpierw diodę LED (zieloną) co 50 ms
Opis problemu 1: Migajmy najpierw diodę LED (zieloną) co 50 ms
Opis problemu 1: Migajmy najpierw diodę LED (zieloną) co 50 ms

Metodologia:

- użycie preskalera Timer0 do redukcji sygnału elektrycznego o wysokiej częstotliwości do niższej częstotliwości przez dzielenie liczb całkowitych;

- używanie przerwania za każdym razem, gdy Timer0 się przepełni;

Timer0 (8 bitów) odlicza od 0 do 255 po czym się przepełniają, wartość ta zmienia się przy każdym impulsie zegara.

F_CPU=16MHz: Okres zegara = 1000ms / 16000000Hz = 0,0000625ms

Licznik timera = (Wymagane opóźnienie / Okres czasu zegara)-1 = (50ms / 0,0000625ms) = 799999

Zegar tyka już 799999 razy, co daje opóźnienie tylko 50 ms!

Do zmniejszenia licznika timerów możemy wykorzystać technikę dzielenia częstotliwości, nazywaną prescalingiem. AVR oferuje nam do wyboru następujące wartości preskalerów: 8, 64, 256 i 1024. Zobacz tabelę podsumowującą wyniki zastosowania różnych preskalerów.

Wartość licznika powinna zawsze być liczbą całkowitą. Wybierzmy preskaler 256!

W większości mikrokontrolerów istnieje coś, co nazywa się przerwaniem. To przerwanie może zostać uruchomione, gdy zostaną spełnione określone warunki. Teraz za każdym razem, gdy uruchamiane jest przerwanie, AVR zatrzymuje się i zapisuje wykonanie głównej procedury, obsługuje wywołanie przerwania (wykonując specjalną procedurę, zwaną Interrupt Service Routine, ISR) i po jej zakończeniu powraca do główną rutynę i kontynuuje ją.

Ponieważ wymagane opóźnienie (50ms) jest większe niż maksymalne możliwe opóźnienie: 4, 096ms = 1000ms / 62500Hz * 256, oczywiście timer się przepełni. A ilekroć licznik się przepełni, wywoływane jest przerwanie.

Ile razy powinno być wywoływane przerwanie?

50ms / 4,096ms = 3125 / 256 = 12,207 Jeśli zegar przekroczyłby 12 razy, minęłoby 12 * 4,096 ms = 49,152 ms. W 13. iteracji potrzebujemy opóźnienia 50ms – 49,152ms = 0,848ms.

Przy częstotliwości 62500 Hz (preskaler = 256) każdy tik trwa 0,016 ms. Tak więc, aby osiągnąć opóźnienie 0,848ms, wymagałoby to 0,848ms / 0,016ms = 53 tików. Tak więc w 13. iteracji pozwalamy, aby timer zliczył tylko do 53, a następnie go zresetował.

Zainicjuj Timer0/Licznik (patrz zdjęcie):

TCCR0B |= (1 << CS02) // ustawienie timera z preskalerem = 256 TCNT0 = 0 // inicjalizacja licznika TIMSK0 |= (1 << TOIE0) // włączenie przerwania przepełnienia sei() // włączenie przerwań globalnych tot_overflow = 0 // zainicjuj zmienną licznika przepełnienia

Krok 3: Opis problemu 2: Migajmy drugą diodę LED (niebieską) co 1 s

Opis problemu 2: Migajmy drugą diodę LED (niebieską) co 1 s
Opis problemu 2: Migajmy drugą diodę LED (niebieską) co 1 s
Opis problemu 2: Migajmy drugą diodę LED (niebieską) co 1 s
Opis problemu 2: Migajmy drugą diodę LED (niebieską) co 1 s
Opis problemu 2: Migajmy drugą diodę LED (niebieską) co 1 s
Opis problemu 2: Migajmy drugą diodę LED (niebieską) co 1 s

Metodologia:

- użycie preskalera Timer1 do redukcji sygnału elektrycznego o wysokiej częstotliwości do niższej częstotliwości przez dzielenie liczb całkowitych;

- używanie Clear Timer w trybie porównania (CTC);

- korzystanie z przerwań w trybie CTC;

Timer1 (16 bitów) liczy od 0 do 65534 po czym się przepełnia. Wartość ta zmienia się z każdym impulsem zegara.

F_CPU=16MHz: Okres zegara = 1000ms / 16000000Hz = 0,0000625msLicznik timera = (Wymagane opóźnienie / Okres zegara)-1 = (1000ms / 0,0000625ms) = 15999999

Zegar odmierzył już 15999999 razy, dając opóźnienie 1s!

Do zmniejszenia licznika timerów możemy wykorzystać technikę dzielenia częstotliwości, nazywaną prescalingiem. AVR oferuje nam do wyboru następujące wartości preskalerów: 8, 64, 256 i 1024. Zobacz tabelę podsumowującą wyniki zastosowania różnych preskalerów. Wartość licznika powinna zawsze być liczbą całkowitą. Wybierzmy preskaler 256!

W trybie Clear timer on Compare(CTC) rejestr OCR1A lub ICR1 jest używany do manipulowania rozdzielczością licznika. W trybie CTC licznik jest wyzerowany, gdy wartość licznika (TCNT1) pasuje do OCR1A lub ICR1. OCR1A lub ICR1 określają górną wartość licznika, stąd też jego rozdzielczość. Ten tryb pozwala na większą kontrolę nad częstotliwością wyjściową porównywania wyników. Upraszcza również operację zliczania zdarzeń zewnętrznych. Musimy powiedzieć AVR, aby zresetował Timer1/Licznik, gdy tylko jego wartość osiągnie wartość 62500, aby uzyskać opóźnienie 1s.

Zainicjuj Timer1/Licznik (patrz zdjęcie):

TCCR1B |= (1 << WGM12)|(1 << CS12) // ustawienie timera z preskalerem = 256 i trybem CTC TCNT1 = 0 // inicjalizacja licznika TIMSK1 |= (1 << OCIE1A) // włączenie porównania przerwań OCR1A = 62500 // zainicjuj porównywaną wartość

Krok 4: Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms

Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms
Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms
Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms
Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms
Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms
Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms
Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms
Opis problemu 3: Migajmy trzecią diodę LED (czerwoną) co 16 ms

Metodologia:

- użycie preskalera Timer2 do redukcji sygnału elektrycznego o wysokiej częstotliwości do niższej częstotliwości przez dzielenie liczb całkowitych;

- używanie Clear Timer w trybie porównania (CTC);

- korzystanie ze sprzętowego trybu CTC bez przerwań;

Timer2 (8 bitów) liczy od 0 do 255 po czym się przepełnia. Wartość ta zmienia się z każdym impulsem zegara.

F_CPU=16MHz: Okres zegara = 1000ms / 16000000Hz = 0,0000625ms

Licznik timera = (Wymagane opóźnienie / okres czasu zegara)-1 = (16ms / 0,0000625ms) = 255999

Zegar odmierzył już 255999 razy, dając opóźnienie 16ms!

Zobacz tabelę podsumowującą wyniki stosowania różnych preskalerów. Wartość licznika powinna zawsze być liczbą całkowitą. Wybierzmy preskaler 1024!

W trybie CTC licznik jest wyzerowany, gdy wartość licznika (TCNT2) odpowiada OCR2A lub ICR2. Pin PB3 jest również pinem Output Compare TIMER2 - OC2A (patrz schemat).

Rejestr kontrolny timera/licznika 2 A – TCCR2A Bit 7:6 – COM2A1:0 – Tryb porównania wyjścia dla jednostki porównania A. Ponieważ musimy przełączyć diodę LED, wybieramy opcję: Przełącz OC2A na porównanie Pin OC2A jest automatycznie przełączany. Nie ma potrzeby sprawdzania żadnego bitu flagi, nie ma potrzeby zajmowania się przerwaniami.

Zainicjuj Timer2/Licznik

TCCR2A |= (1 << COM2A0)|(1 << WGM21) // ustaw pin OC2A timera w trybie przełączania i trybie CTC TCCR2B |= (1 << CS22)|(1 << CS21)|(1 << CS20) //ustaw licznik czasu z preskalerem = 1024 TCNT2 = 0 //inicjalizuj licznik OCR2A = 250 //inicjalizuj porównywaną wartość

Krok 5: Pisanie kodu programu w C. Ładowanie pliku HEX do pamięci Flash mikrokontrolera

Pisanie kodu programu w C. Wgrywanie pliku HEX do pamięci Flash mikrokontrolera
Pisanie kodu programu w C. Wgrywanie pliku HEX do pamięci Flash mikrokontrolera
Pisanie kodu programu w C. Wgrywanie pliku HEX do pamięci Flash mikrokontrolera
Pisanie kodu programu w C. Wgrywanie pliku HEX do pamięci Flash mikrokontrolera

Napisanie i zbudowanie aplikacji mikrokontrolera AVR w kodzie C z wykorzystaniem Zintegrowanej Platformy Programistycznej - Atmel Studio.

F_CPU definiuje częstotliwość zegara w hercach i jest powszechny w programach korzystających z biblioteki avr-libc. W tym przypadku jest używany przez procedury opóźniające do określenia sposobu obliczania opóźnień czasowych.

#ifndef F_CPU

#define F_CPU 16000000UL // mówienie częstotliwości kryształu kontrolera (16 MHz AVR ATMega328P) #endif

#include // nagłówek, aby włączyć kontrolę przepływu danych przez piny. Definiuje piny, porty itp.

Pierwszy plik dołączany jest częścią avr-libc i będzie używany w prawie każdym projekcie AVR, nad którym pracujesz. io.h określi, jakiego procesora używasz (dlatego określasz część podczas kompilacji), a następnie dołączy odpowiedni nagłówek definicji IO dla używanego przez nas układu. Po prostu definiuje stałe dla wszystkich twoich pinów, portów, rejestrów specjalnych itp.

#include // nagłówek, aby włączyć przerwanie

nietrwały uint8_t tot_overflow; // zmienna globalna do zliczania przepełnień

Metodologia rozwiązywania problemów: Najpierw miga dioda (zielona) co 50 ms

- użycie preskalera Timer0 do redukcji sygnału elektrycznego o wysokiej częstotliwości do niższej częstotliwości przez dzielenie liczb całkowitych;

- używanie przerwania za każdym razem, gdy Timer0 się przepełni;

void timer0_init() //zainicjuj timer0, przerwanie i zmienną

{ TCCR0B |= (1 << CS02); // ustaw timer z preskalerem = 256 TCNT0 = 0; // zainicjuj licznik TIMSK0 |= (1 << TOIE0); // włącz przepełnienie nterrupt sei(); // włącz globalne przerwania tot_overflow = 0; // zainicjuj zmienną licznika przepełnienia }

Metodologia rozwiązywania problemów: Miga druga dioda LED (niebieska) co 1 s

- użycie preskalera Timer1 do redukcji sygnału elektrycznego o wysokiej częstotliwości do niższej częstotliwości przez dzielenie liczb całkowitych;

- używanie Clear Timer w trybie porównania (CTC);

- korzystanie z przerwań w trybie CTC;

void timer1_init() // zainicjuj timer1, przerwanie i zmienną{ TCCR1B |= (1 << WGM12)|(1 << CS12); // ustaw timer z preskalerem = 256 i trybem CTC TCNT1 = 0; // inicjalizacja licznika OCR1A = 62500; // zainicjuj porównywaną wartość TIMSK1 |= (1 << OCIE1A); // włącz przerwanie porównania}

Metodologia rozwiązywania problemów: Migaj trzecią diodą LED (czerwoną) co 16 ms

- użycie preskalera Timer2 do redukcji sygnału elektrycznego o wysokiej częstotliwości do niższej częstotliwości przez dzielenie liczb całkowitych;

- używanie Clear Timer w trybie porównania (CTC);

- korzystanie ze sprzętowego trybu CTC bez przerwań;

void timer2_init() // zainicjuj timer2{ TCCR2A |= (1 << COM2A0)|(1 << WGM21); // ustaw pin timera OC2A w trybie przełączania i trybie CTC TCCR2B |= (1 << CS22)|(1 << CS21)|(1 << CS20); // ustaw timer z preskalerem = 1024 TCNT2 = 0; // inicjalizacja licznika OCR2A = 250; // zainicjuj porównywaną wartość }

Procedura obsługi przerwań przepełnienia TIMER0 wywoływana za każdym razem, gdy przepełnia się TCNT0:

ISR(TIMER0_OVF_vect)

{ tot_przepełnienie++; // śledź liczbę przepełnień }

Ten ISR jest uruchamiany za każdym razem, gdy pojawia się mecz, dlatego przełącz tutaj sam:

ISR (TIMER1_COMPA_vect){ PORTC ^= (1 << 1); // przełącz tutaj prowadzoną}

int główny (unieważniony)

{ DDRB |= (1 << 0); // podłącz 1 (zielony) led do pinu PB0 DDRC |= (1 << 1); // podłącz 2 (niebieski) led do pinu PC1 DDRB |= (1 << 3); // podłącz 3 (czerwone) diody led do pinu PB3 (OC2A) timer0_init(); // zainicjuj timer0 timer1_init(); // zainicjuj timer1 timer2_init(); // zainicjuj timer2 while(1) // zapętl na zawsze {

Jeśli Timer0 przepełnił się 12 razy, minęłoby 12 * 4,096 ms = 49,152 ms. W 13. iteracji potrzebujemy opóźnienia 50ms – 49,152ms = 0,848ms. Tak więc w 13. iteracji pozwalamy, aby timer zliczył tylko do 53, a następnie go zresetował.

if (tot_overflow >= 12) // sprawdź, czy nie. przepełnień = 12 UWAGA: stosuje się '>='

{ if (TCNT0 >= 53) // sprawdź, czy licznik licznika osiągnął 53 { PORTB ^= (1 << 0); // przełącza diodę TCNT0 = 0; // zresetuj licznik tot_overflow = 0; // zresetuj licznik przepełnienia } } } }

Wgrywanie pliku HEX do pamięci flash mikrokontrolera:

wpisz w oknie wiersza poleceń DOS polecenie:

avrdude –c [nazwa programisty] –p m328p –u –U flash:w:[nazwa twojego pliku hex]W moim przypadku jest to: avrdude –c ISPProgv1 –p m328p –u –U flash:w:Timers.hex

To polecenie zapisuje plik hex do pamięci mikrokontrolera. Obejrzyj film ze szczegółowym opisem wypalania pamięci flash mikrokontrolera:

Nagrywanie pamięci flash mikrokontrolera…

Ok! Teraz mikrokontroler pracuje zgodnie z instrukcjami naszego programu. Sprawdźmy to!

Krok 6: Tworzenie obwodu elektrycznego

Tworzenie obwodu elektrycznego
Tworzenie obwodu elektrycznego
Tworzenie obwodu elektrycznego
Tworzenie obwodu elektrycznego
Tworzenie obwodu elektrycznego
Tworzenie obwodu elektrycznego

Połącz elementy zgodnie ze schematem ideowym.

Zalecana: