lukaszrc.files.wordpress.com · Web viewZmienna ms dodawana co 10ms, jeśli 10ms x 100 da nam...
Transcript of lukaszrc.files.wordpress.com · Web viewZmienna ms dodawana co 10ms, jeśli 10ms x 100 da nam...
Spis treściInformacje ogólne........................................................................................................................................2
przerwania...................................................................................................................................................3
Używanie przerwań..............................................................................................................................7
Timery sprzętowe.........................................................................................................................................7
tryby pracy...........................................................................................................................................9
We/wy........................................................................................................................................................10
BV...............................................................................................................................................................10
operacje bitowe.........................................................................................................................................10
if-else..........................................................................................................................................................13
dyrektywa define........................................................................................................................................14
Zmienna static............................................................................................................................................15
Funkcja static..............................................................................................................................................16
Funkcja inline.............................................................................................................................................16
Zmienna register........................................................................................................................................17
ifdef/ ifndef................................................................................................................................................17
volatile........................................................................................................................................................17
register.......................................................................................................................................................17
zapis tylko na FLASH...................................................................................................................................18
maskowanie bitów.....................................................................................................................................19
obsługa lcd 44780.......................................................................................................................................19
różne..........................................................................................................................................................20
Informacje ogólneKupować Atmega88 zamiast atmega8. Zgodne z atmega328 i atmega128. Piny zgodne ze sobą. Można je zamieniać (pamięć flash, eeprom itd.)
w większych obudowach: atmega644, atmega16, atmega32
dobre przewody połączeniowe do płytki
dobra pęseta
gniazdo kanda, wyprowadzenia pod kątem
książki:
mikrokontrolery AVR, język C. podstawy programowania
avrdude -p m8 -c usbasp
rst 10k do zasilania
kondensatory
dławik do avcc 10, 22uh
uwaga: podłączenie masy GND wymagane programatora, nawet jeśli zasilanie zewnętrzne!!!
polecana przetwornica atb-pwr3
reset – biorę kabelek do 1, druga końcówka do masy
warto kupić:
wyświetlacz 2x16
lepsza rodzina atmega48, np. atmega48_88 niż zwykłe atmega8
lepsze atmega88 lub atmega168
ustawienia dla toolchain eclipse
przykładowy stabilizator: we 8v, wy 5v
przerwaniaMamy przerwania zewnętrzne (można wywoływać z zewnątrz poprzez wywoływanie pewnych stanów na pinach) i wewnętrzne
Wewnętrzne: Przerwania synchroniczne (ściśle określony czas, w pewnym takcie) i asynchroniczne
Przerwania zewnętrzne: int0 int1
Dodatkowe wejscia int2 int3 mogą być na innych atmegach
Mogą być wywolywane na zmiane stanów – zbocze narastajace, opadajace, poziomem logicznym lub dowolną zmianą stanu (możliwości sprawdzać w nocie )
Przerwania wewnętrzne
Mogą być generowane poprzez timery (liczniki sprzętowe)
Globalne zezwolenie na przerwania sei();
Uproszczony schemat:
Prześledzenie co będzie się działo
W pętli głównej
Licznik nie musimy zerowac uint8_t to się sam zeruje
Jak zrobić żeby dioda co sekunde się zapalała
Zaprzęgamy timer, ustawienie np. co 10ms, zgłoszenie do cpu jednostki co 10ms
np. w drugim kroku może wywolac się przerwanie z timera/ nastąpi przerwanie i skok do procedury programu obsługującego przerwanie.
Makro ISR
Zmienna static, ona będzie w przerwaniu ciągle
Zmienna ms dodawana co 10ms, jeśli 10ms x 100 da nam 1ssprawdzamy czy minęła 1s, jeśli tak to migamy diodą led na pinie pb7
Procesor zapamiętał miejsce w którym skończył program (adres) zapamiętany na stosie pamięci RAM (2 bajty pamięci ram – adres 16 bitowy)
Po przerwaniu program rozpocznie od kolejnej linii
W trakcie delay(500) nastąpi 50 przerwań. Delay to pełno linijek w asm
Niezależnie otrzymamy zmiany stanów diody co 1s
Przerwanie (szczególnie synchronicznie) powinno trwać jak najkrócej
Jeśli avr jest w procedurze przerwania to wyłącza inne przerwania, ustawiane są flagi przerwań – efekt zamulenia mikrokontrolera
Nie używamy _delaye nie używamy (długotrwałe) w przerwaniu
Pętle, iteracje oczekujące na coś
Operacje wyświetlania na lcd
W przerwaniu jak tylko zmiana stanu pinu, krótkie obliczenia na nie liczbach zmiennoprzecinkowych, nie trzeba wyliczać przerwań co do milisekund
Nie wywołujemy funkcji w przerwaniach,z umiarem, czas i przepełnienie pamięci ram (stos), wejście w obszar zm globalnych
Volatile – zmienna i w przerwaniu i w pętli głównej to używać ten specyfikator
Przerwania zewnętrzne PCINT
Stan wysoki – vcc (napięcie zasilania, 5v lub 3.3v lub 3v)
Stan niski – gnd
Na wejście przerwania (część cyfrowa)
Układy cyfrowe (przerwania) potrafią reagować na zbocza narastające i opadające
Przebiegi prostokątne, np. poprzez przycisk podłączony do pinu podciągniętego do vcc, poprzez kliknięcie stan niski (odradzanie podciągania do gnd ). podciągnięcie do vcc mamy możliwość programowego podciągania – programowe podciąganie linii do vcc – stany wysokiej impedancji
Przerwanie zewnętrzne może reagować:- na zbocze opadające- na zbocze narastające- wyzwalanie poziomem nie jest zalecane (dla początkujących), bo tak długo jak będzie ten stan, np. 1s, gdzie procedura np. 0.1s to przerwanie będzie wykonywane wielokrotnie – obsługiwanie tylko przerwania
- wyzwalanie dowolną zmianą stanu
Uwalnia nam te przerwania poniższe rejestry:
Należy odblokować działanie przerwań na konkretnych pinach
Ustawić, że te konkretne piny mogą generować przerwania zewnętrzne
Opisanie procedury przerwaniaw przerwaniu sprawdzić możemy na którym pinie zero
Część 3
Ważna nota pdf
Do poprawnego działania przy zezwoleniu na przerwania należy stworzyć wektor przerwań (nawet pusty). Inaczej procek może się resetować
Czy przerwanie może tylko jedne dzialac za jednym razem?
Problem:
Do sprawdzenia
EMPTY_INTERRUPT(nazwa przerwania);
sei;
cli;
Używanie przerwań
W funkcji mainsei(); // włączenie globalnego zezwolenia na przerwania
ISR(TIMER0_COMP_vect){}
Interesują nas przerwania zakończone _vect
Timery sprzętoweAtmega 32: różne timery 8 lub 16 bitowe
Sprzętowy licznik impulsów
impulsy biorą się z preskalera – sprzętowy dzielnik częstotliwości taktowania
preskaler ustawiamy za pomocą rejestrów
clk – częstotliwość taktowania procesora, tą częstotliwość dzieli preskaler. Może potem podać do timera
timery 8 bitowe (zliczanie do 256 28) i 16 bitowe (do 216)
rejestr TCCR0 - podstawowy rejestr kontrolny, ustawienie trybów pracy za pomocą bitów WGMxx. (na podstawie atmega 32)
Tryb Normal jest domyślnie ustawiony
Ustawienie na tryb CTC:
TCCR0 |= (1<<WGM01); // tryb CTC
Taktowanie timera, dzielnik częstotliwości, preskaler
Bity CSxx rejestru TCCR0 Domyślnie bity zerowe – timer nie działa, można zatrzymać zerując bity CSxx Dzielniki wybieramy ustawiając odpowiednio bity
OCR0 – rejestr z którym jest porównywany timer. Jeśli jest równy to następuje przerwanie (tryb CTC)
Jest on porównywany z rejestrem TCNTx, gdzie jest aktualna wartość timera
TIMSK umożliwia przerwania generowane poprzez timerBit OCIE0 trybu CTCBit TOIE0 trybu Normal
Kod na tryb CTC// ustawienie TIMER0TCCR0 |= (1<<WGM01); // tryb CTCTCCR0 |= (1<<CS02)|(1<<CS00); // preskaler = 1024//OCR0 = 38; // dodatkowy
podział przez 39 (rej. przepełnienia)
TIMSK |= (1<<OCIE0); // zezwolenie na przerwanie CompareMatch
tryby pracy
Tryb licznika
Każdy timer może pracować w tym trybie
Mozemy kontrolować czas wykonywania się programu, np. do przerwania podawać moment przepełnienia się timera
Licznik można zmieniać, zerować, odczytywać stan
Dostęp do licznika poprzez rejestr TCNTx, x – numer timera
Tryb CTC
Porównywanie wartości licznika z wartością zadaną w specjalnym rejestrze
Zerowanie, ustawianie bitow _BV* _BV(numer_bitu); //ustawienie bitu
DDRC |= (1 << PC7);
* ~_BV(numer_bitu); //zgaszenie bitu
DDRC &= ~(1 << PC6);
Sprawdzanie stanu bitubit_is_set()
bit_is_clear()
operacje bitowebitowa alternatywa*operator "|" - bitowa alternatywa (OR)
0 1 0 1 0 1 0 1
|
0 0 1 1 0 0 1 1
=
0 1 1 1 0 1 1 1
koniunkcjaoperator "&" - bitowa koniunkcja (AND)
0 1 0 1 0 1 0 1
&
0 0 1 1 0 0 1 1
=
0 0 0 1 0 0 0 1
Alternatywa wykluczajaca xor*operator "^" - bitowa alternatywa wykluczająca (XOR)
0 1 0 1 0 1 0 1
^
0 0 1 1 0 0 1 1
=
0 1 1 0 0 1 1 0
*===========================================
operator przesuniecia* PORTC |= (1<<3)|(1<<5)|(1<<7);
* (1<<3) = 0000 1000
bitowe OR
(1<<5) = 0010 0000
bitowe OR
(1<<7) = 1000 0000
-------------
1010 1000
operator "<<" - przesunięcie w lewo 1 0 0 1 1 0 0 1 << 3 = 1 1 0 0 1 0 0 0operator ">>" - przesunięcie w prawo 1 0 0 1 1 0 0 1 >> 5 = 0 0 0 0 0 1 0 0
*===============================================
Zerowanie bitowPORTD &= 0xaa; /* zeruje bity nr. 0,2,4,6
PORTD 1 1 1 1 1 1 1 1
bitowe AND
0xAA 1 0 1 0 1 0 1 0
=
1 0 1 0 1 0 1 0 -> PORTD
*===============================================
Odwracanie bitow
*PORTD ^= 0x0f; /* "odwraca" bity nr. 0..3
*
*PORTD 1 0 1 0 1 0 1 0
bitowe XOR
0x0f 0 0 0 0 1 1 1 1
=
1 0 1 0 0 1 0 1 -> PORTD
*===============================================
Dopelnienie jedynkoweoperator "~" - dopełnienie jedynkowe ~1 0 0 1 1 0 0 1 = 0 1 1 0 0 1 1 0
*/
1 << PC0 //ustawienie 1 na PC0PORTC |= _BV(0)|_BV(1); //podciagniecie do vcc, ustawienie PC0 i PC1
if-elseif( wartość_logiczna PRAWDA/FAŁSZ ) /* Instrukcja wykonywana jeśli PRAWDA */ else /* Instrukcja wykonywana jeśli FAŁSZ */
Część "else" , czyli instrukcje wykonywaną gdy FAŁSZ można pominąć.if( wartość_logiczna PRAWDA/FAŁSZ ) /* Instrukcja wykonywana jeśli PRAWDA */
Obejmując fragment kodu parą klamrowych nawiasów "{","}" tworzymy tzw. blok instrukcji, blok w "if-else" jest traktowany jako pojedyncza instrukcja.
if( wartość_logiczna PRAWDA/FAŁSZ ) { /* Blok instrukcji wykonywany jeśli PRAWDA */ } else { /* Blok instrukcji wykonywany jeśli FAŁSZ */ }
Chcąc sprawdzić czy jeden lub grupa bitów jednocześnie w rejestrze I/0 ma wartość "1" można to zrobić z użyciem instrukcji "if" w następujący sposób:if(REJESTR_I0 & MASKA) { /* Blok instrukcji wykonywany jeśli warunek spełniony */ }
Gdzie "REJESTR_IO" to nazwa rejestru, a "MASKA" to stała wartość z ustawionymi tymi bitami, które potrzeba testować Przykłady:/* Jeśli bit nr. 3 rejestru PINC ma wartość "1" */ if(PINC & 0x08){} /* Jeśli bity 0 lub 1 w PIND mają wartość "1" */ if(PIND & 0x03){}
Na zawartości rejestru wykonywana jest operacja bitowa AND z wartością stałej stojącej po prawej stronie operatora "&". I jeśli wynik tej operacji będzie różnił się od zera, to całe wyrażenie w nawiasach okrągłych będzie uznane jako wartość logiczną "PRAWDA" i wykonane zostaną instrukcje objęte nawiasami klamrowymi po "if"; w przeciwnym przypadku instrukcje te zostaną pominięte. W języku C, jeżeli jakieś wyrażenie po obliczeniu jest różne od zera, to ma wartość logiczną "PRAWDA", a jeżeli wyrażenie jest równe zero, to ma wartość logiczną "FAŁSZ".
A po co na wartości odczytanej z rejestru wykonywana jest bitową operację AND? Żeby przysłonić te bity rejestru, których wartości nas nie interesują. Przykład:Interesuje na stan bitu nr 3 rejestru REJESTR_I0 0 1 0 1 1 1 1 1 (0x5f) bitowe AND 0 0 0 0 1 0 0 0 (0x08) ----------------------------- = 0 0 0 0 1 0 0 0 (0x08) REJESTR_I0 0 1 0 0 0 1 0 1 (0x45) bitowe AND 0 0 0 0 1 0 0 0 (0x08) ----------------------------- = 0 0 0 0 0 0 0 0 (0x00)
Jednak na schemacie przyciski przyłączono do portów we/wy uC w taki sposób, że przy wciśniętym przycisku odczytujemy z rejestru wartość bitu "0", a nie "1".Tak można sprawdzić czy jeden lub grupa bitów w rejestrze I/0 ma wartość "0":if(!(REJESTR_IO & MASKA)) { /* Blok instrukcji wykonywany jeśli warunek spełniony */ }
dyrektywa define
W C istnieje tylko jedna
dyrektywa sluZ4ca do tworzenia stalych licz-bowych, symbolicznych, znakowych, a nawet
calych makr. Dyrektywa ta to #define. Jest
ona przetwarzana przez preproeesor (czyli
jeszcze zanim rozpocznie sip kompilacja).
Jefli gdzieS w kodzie pojawi sip nazwa,kt6ra
zostala za jej pomoc4 zdefiniowana, zostanie
ona automatycznie zast4piona przez odpo-wiedni ci4g znak6w. To wa2ne: nie bpdzie to
liczba, nie bgdzie to tekst. U2ycie slowa klu-czowego, kt6re wcze6niej zdefiniowaliSmy,
jest praktycznie r6wnowa2ne z wpisaniem
w edytorze odpowiedniego ci4gu znak6w
(z pominigciem komentarzy).
Zmienna staticPozwala na zdefiniowanie zmiennej statycznej. "Statyczność" polega na zachowaniu wartości pomiędzy kolejnymi definicjami tej samej zmiennej. Jest to przede wszystkim przydatne w funkcjach. Gdy zdefiniujemy zmienną w ciele funkcji, to zmienna ta będzie od nowa definiowana wraz z domyślną wartością (jeżeli taką podano). W wypadku zmiennej określonej jako statyczna, jej wartość się nie zmieni przy ponownym wywołaniu funkcji
ISR(TIMER0_COMP_vect){
static uint8_t licznik=1; // zmienna do przełączania kolejno anod wyrwietlacza
ANODY_PORT = (ANODY_PORT & 0xF0); // wygaszenie wszystkich wyświetlaczy
if(licznik==1) LED_DATA = pgm_read_byte( &cyfry[cy1] ); // gdy zapalony wyśw.1 podaj stan zmiennej c1
else if(licznik==2) LED_DATA = pgm_read_byte( &cyfry[cy2] ); // gdy zapalony wyśw.2 podaj stan zmiennej c2
else if(licznik==4) LED_DATA = pgm_read_byte( &cyfry[cy3] ); // gdy zapalony wyśw.3 podaj stan zmiennej c3
else if(licznik==8) LED_DATA = pgm_read_byte( &cyfry[cy4] ); // gdy zapalony wyśw.4 podaj stan zmiennej c4
ANODY_PORT = (ANODY_PORT & 0xF0) | (~licznik & 0x0F); // cykliczne przełączanie kolejnej anody w każdym przerwaniu
// operacje cyklicznego przesuwania bitu zapalającego anody w zmiennej licznik
licznik <<= 1; // przesunięcie zawartości bitów licznika o 1 w lewo
if(licznik>8) licznik = 1; // jeśli licznik większy niż 8 to ustaw na 1}
Funkcja staticOdwrotne działanie ma słowo kluczowe static użyte w tym kontekście (użyte wewnątrz bloku tworzy zmienną statyczną, więcej informacji w rozdziale Zmienne). Może ono odnosić się zarówno do zmiennych jak i do funkcji globalnych. Powoduje, że dana zmienna lub funkcja jest niedostępna na zewnątrz biblioteki[1]. Możemy dzięki temu ukryć np. funkcje, które używane są przez samą bibliotekę, by nie dało się ich wykorzystać przez extern
Funkcje można deklarować i definiować z modyfikatorem static. Znaczenie tego modyfikatora jest jednak zupełnie inne dla funkcji globalnych, a więc nie będących składowymi klas, i dla funkcji składowych klas.
Wszystkie funkcje globalne są widoczne nie tylko w module, gdzie zostały zdefiniowane, ale we wszystkich tych modułach składających się na program, w których pojawia się ich deklaracja.
Natomiast funkcja globalna zadeklarowana i zdefiniowana w pewnym module z modyfikatorem static nie jest „eksportowana”: może być użyta tylko w tym module, podobnie jak to miało miejsce dla globalnych zmiennych statycznych - patrz rozdział o klasach pamięci . Dzięki temu w innym module programu można użyć tej samej nazwy dla zupełnie innej funkcji statycznej: kolizji nazw nie będzie, bo w każdym module znana będzie tylko jedna funkcja o tej nazwie - ta pochodząca z tego modułu.
ifdef/ ifndefAfa
zapis tylko na FLASH
#include <avr/pgmspace.h>
tablica wpisana tylko do pamięci flash
// definicja tablicy zawierającej definicje bitowe cyfr LED
const uint8_t cyfry[15] PROGMEM = {
~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F), // 0
~(SEG_B|SEG_C), // 1
~(SEG_A|SEG_B|SEG_D|SEG_E|SEG_G), // 2
~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_G), // 3
~(SEG_B|SEG_C|SEG_F|SEG_G), // 4
~(SEG_A|SEG_C|SEG_D|SEG_F|SEG_G), // 5
~(SEG_A|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G), // 6
~(SEG_A|SEG_B|SEG_C|SEG_F), // 7
~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G), // 8
~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_F|SEG_G), // 9
0xFF // NIC (puste miejsce)
};
odczyt:
LED_DATA = pgm_read_byte( &cyfry[cy1] );
Bez użycia tego kompilator i tak niewidocznie zapisze tablice do pamięci FLASH, korzystać również będzie z pamięci RAM
maskowanie bitówdefinicja napisów w pamięci FLASH
makro PSTR()
parametrem jest napis
kompilator definiuje tablicę znaków typu char, bez żadnej nazwy
makro zwraca adres pierwszego elementu
obsługa lcd 44780
1. RS - (Register Secelct) wejście sterujące określające czy wysyłany pakiet danych jest to dana
do wyświetlenia na ekranie czy komenda sterująca wyświetlaczem. (Stan wysoki - Dane, Stan
niski - Komenda)
2. R/W - (Read / Write) Wejście określające kierunek przepływu informacji. Czy dane są
wysyłane do wyświetlacza czy odczytywane z niego (Stan wysoki - Odczyt, Stan niski -
Zapis)
3. E - (Enable) Wejście sterujące służące do wpisywania danych do wyświetlacza lub
odczytu aktywne stanem wysokim
różne
stan wysokiej impedancji Hi-Z
programowanie ISP
w miarę możliwości nie wykorzystywać pinów ISP do innych celów
1 << PC0 //ustawienie 1 na PC0PORTC |= _BV(0)|_BV(1); //podciagniecie do vcc, ustawienie PC0 i PC1
przesuwanie bitów w lewo – mnożenie przez 2
przesuwanie bitów w prawo – dzielenie przez 2
Wazne jest to, ze operator << ma wyzszy piorytetni niż operator sumy logicznej |