Podłączenie mikrokontrolera ATmega8: zasilanie 8 i 22 <

Transkrypt

Podłączenie mikrokontrolera ATmega8: zasilanie 8 i 22 <
Podłączenie mikrokontrolera ATmega8:
zasilanie
8 i 22 <- GND (masa)
7
<- VCC (+ zasilania)
programowanie
17 <- MOSI (Master Output Slave Input)
18 <- MISO (Master Input Slave Output)
19 <- SCK
(Serial ClocK)
1 <- RST
(ReSeT)
i przez opornik ~10 kΩ do VCC
Niektóre piny mogą pełnić różne role, zależnie od aktualnej wartości sygnałów sterujących.
Oprogramowanie
CrossPack - https://www.obdev.at/products/crosspack/index.html (do komunikacji z μC) - zainstaluj,
Eclipse C++ Luna - środowisko do programowania, pobierz i rozpakuj (nie trzeba instalować)
ww.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR2/eclipsecpp-luna-SR2-macosx-cocoa-x86_64.tar.gz
Plugin AVR do Eclipse:
Help / Install new software, w polu Work with: http://avr-eclipse.sourceforge.net/updatesite
avrdude - program do komunikacji komputera głównego z mikrokontrolerem, zawarty w CrossPack
polecenie sprawdzenia komunikacji:
avrdude -c rodzajProgramatora -p typMikrokontrolera
avrdude -c usbasp -p m8
// m8 oznacza mikrokontroler ATmega8
Lista mikrokontrolerów obsługiwanych przez avrdude:
http://www.nongnu.org/avrdude/user-manual/avrdude_4.html
zapis programu wykonywalnego moje.hex do pamięci flash μC:
avrdude -c usbasp -p m8 -U flash:w:moje.hex
pobranie programu wykonywalnego z pamięci flash μC i zapis do pliku moje.hex:
avrdude -c usbasp -p m8 -U flash:r:moje.hex
Eclipse - nowy projekt
New / C project / AVR cross target application, podaj nazwę projektu, Next
odznacz opcję Debug (ma zostać tylko Release), Next
wybierz MCU Type: ATmega8 oraz MCU Frequency 1Mhz, Finish
New / File / Source file, w polu Source name wpisz nazwę main.c
#include <avr/io.h>
int main(void) {
DDRD = 0b11111111;
PORTD = 0b00001100;;
while (1) { }
return 0;
}
// ustawienie całego portu D jako wyjscie
// ustawienie pinów PD2 i PD3 na 1, a pozostałych na 0
// pętla bez końca
We właściwościach projektu ustaw rodzaj programatora: USBasp (menu Project / Properties, AVR):
Jeśli w polu wyboru Programmer configuration nie ma nic do wyboru, to kliknij przycisk New,
w oknie Programmer Hardware wybierz USBasp, http://www.fischl.de/usbasp,
w polu Configuration name wpisz jakąś nazwę, może być USBasp, zatwierdź: Apply oraz OK.
Skompiluj kod i zbuduj program wykonywalny .hex: Wybierz menu Project / Build All.
Podłącz programator z mikrokontrolerem,
aby przesłać program do pamięci flash mikrokontrolera kliknij ikonę AVR
lub wybierz z menu:
Zgodnie z programem, na pinie PD3 (nóżka 5) i PD2 (nóżka 4) jest napięcie 5V, a na innych pinach
portu D jest 0V. Przy wyłączonym zasilaniu podłącz do PD2 i PD3 diody (każda przez opornik ~300 Ω),
podłącz zasilanie. Świeci?
Mikrokontroler ATmega8 ma 3 porty do obsługi wejścia/wyjścia:
B - 8 pinów oznaczonych: PB0, PB1, PB2, … , PB7 (piny: 14,15,16,17,18,19, 9 i 10)
C - 7 pinów oznaczonych: PC0, PC1, PC2, …, PC6 (piny: 23, 24, 25, 26, 27, 28 i 1)
D - 8 pinów oznaczonych: PD0, PD1, PD2, …, PD7 (piny: 2, 3, 4, 5, 6, 11, 12, 13)
Każdy pin można skonfigurować niezależnie:
jako wejście (μC będzie czytać sygnał 0 lub 1 z tego pinu)
lub jako wyjście (μC będzie ustawiać sygnał 0 lub 1 na tym pinie).
Każdy port jest kontrolowany przez 3 osobne rejestry 8-bitowe:
DDRx - ustawia kierunek przesyłania danych na pinach portu x (1 – wyjście, 0 – wejście)
PORTx - rejestr danych portu x, zawiera wartość wystawianą na port x
PINx - rejestr wejściowy portu x, pozwala odczytać wartość na pinach portu x
gdzie x ϵ [B,C,D]
Przykład dla x=D:
DDRD = 0b11111111; // wszystkie piny portu D są wyjściami
PORTD = 0b00001100; // na pinach PD2 i PD3 ustaw stan 1, na pozostałych pinach portu D: stan 0
Każdy z pinów we/wy μC ATmega8 może obsłużyć przepływ prądu do 20 mA, co wystarcza do
wysterowania np. diody LED lub małego brzęczyka piezoelektrycznego. Bardziej prądożerne układy
steruje się pośrednio, sygnał z pinu jest podawany na tranzystor, który dopiero steruje układem.
Jak sterować mruganiem diody
Należy okresowo, cyklicznie zmieniać stan sygnału na pinie wyjściowym sterującym diodą: z 1 (świeci)
na 0 (nie świeci).
Do odmierzania interwału czasu użyjemy funkcji _delay_ms(czas w ms), zdefiniowanej w pliku
nagłówkowym util/delay.h. Powoduje ona uśpienie μC na podaną liczbę milisekund.
Umieścimy tę funkcję wewnątrz pętli nieskończonej, aby zapewnić cykliczność operacji.
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
DDRD = 0b11111111;
PORTD = 0b00001100;
while (1) {
_delay_ms(1000);
PORTD = 0b00001000;
_delay_ms(1000);
PORTD = 0b00001100;
}
return 0;
// cały port D jest wyjściem
// na piny PD2 i PD3 podano stan wysoki
// jedna LED na PD2 (pin 4), druga na PD3 (pin 5)
// zgaś LED na PD2, pozostaw zapaloną LED na PD3
// z powrotem zaświeć obie diody
}
Wartości liczbowe można podać binarnie 0b11111111 lub szesnastkowo 0xFF lub dziesiętnie 255. Tu diody będą mrugać na przemian:
#include <avr/io.h>
#include <util/delay.h>
int main() {
DDRD = 255;
// 0b11111111 =
PORTD = 12;
// 0b00001100 =
while(1) {
_delay_ms(1000);
PORTD = 8; // 0b00001000;
_delay_ms(1000);
PORTD = 4; // 0b00000100;
}
return 0;
}
0xFF = 255 dec
0xC = 12 dec
= 0x8 = 8 dec
= 0x4 = 4 dec
Operacje na bitach
Zamiast ustawiać wartości wszystkich bitów w rejestrze kontrolnym portu, nauczmy się ustawiać
wartość pojedynczego, wybranego bitu, nie zmieniając pozostałych. Trzeba znać operacje na bitach:
Aby ustawić n-ty bit w bajcie (lub skasować, lub zmienić na przeciwny, lub tylko sprawdzić czy jest
ustawiony) najpierw trzeba przygotować sobie maskę o rozmiarze 1 bajta, w której n-ty bit jest
ustawiony na 1, a pozostałe bity są skasowane (czyli mają wartości 0).
Robi się to za pomocą operatorów przesunięcia bitowego: << oraz >>
• operacja x << n oznacza przesunięcie wszystkich bitów zmiennej x w lewo o n pozycji, z dopisaniem n zer z prawej strony liczby, czyli n-krotne pomnożenie liczby x przez 2
• operacja x >> n oznacza przesunięcie wszystkich bitów zmiennej x w prawo o n pozycji,
z dopisaniem n zer z lewej strony liczby, czyli n-krotne podzielenie liczby x przez 2.
Cyfry, które w wyniku przesunięcia nie zmieszczą się w bajcie, są odrzucane.
Operator negacji bitowej ~ zmienia wszystkie bity w bajcie x na przeciwne, np jeśli x = 0b00001111, to po wykonaniu operacji x = ~x , x będzie równe 0b11110000.
Operacja M = 1<<n oznacza: w masce M ustaw n-ty bit na wartość 1, a pozostałe bity na 0.
Gdy mamy maskę, wykonujemy operację na aktualnej zawartości rejestru R, w którym chcemy ustawić
(lub skasować, lub zmienić, lub tylko sprawdzić) n-ty bit, nie zmieniając pozostałych bitów tego rejestru:
• suma logiczna: R | M - aby ustawić na 1 ten bit, który jest ustawiony w masce,
• iloczyn logiczny: R & (~M) - aby skasować (na 0) ten bit, który jest ustawiony w masce,
• alternatywa XOR: R ^ M - aby zmienić ten bit, który jest ustawiony w masce (1->0 lub 0->1).
W notacji skróconej operacje na rejestrze R można zapisać tak:
ustaw n-ty bit, na 1:
R |= 1 << n;
skasuj n-ty bit, na 0:
R &= ~(1<<n);
zmień n-ty bit, 0 na 1 lub 1 na 0:
R ^= 1<<n;
sprawdź czy n-ty bit jest ustawiony: if (R &(1<<n) ) { … } ;
Przykład:
Dioda na PD3 mruga 2-krotnie wolniej niż ta na PD2, zmiana stanu PD3 za pomocą operacji: XOR ^
#include <avr/io.h>
#include <util/delay.h>
int main() {
DDRD = 255;
PORTD = 0xC;
_delay_ms(10000);
while(1) {
_delay_ms(1000);
PORTD &= ~(1<<PD2);
_delay_ms(1000);
PORTD |= 1<<PD2;
PORTD ^= (1<<PD3);
}
return 0;
}
// 0b00001100;
12
// skasuj bit PD2 (ustaw na 0), zgaś diodę
// ustaw bit PD2 (na 1), zapal diodę
// zmień bit PD3 na wartość przeciwną niż ma
Przykład: Dioda na PD2 mrugnie 3 razy zanim druga dioda, na PD3, zmieni swój stan.
#include <avr/io.h>
#include <util/delay.h>
int main() {
DDRD = 255;
PORTD = 0xC; // 0b00001100;
_delay_ms(10000);
12
while(1) {
for (int i=0; i<3; i++) {
_delay_ms(1000);
PORTD &= ~(1<<PD2);
_delay_ms(1000);
PORTD |= 1<<PD2;
}
}
}
PORTD ^= (1<<PD3);
// zgaś PD2
// zapal PD2;
// zmień PD3 na przeciwny
return 0;
Przykład: cztery diody, na pinach: PD0, PD1, PD2 i PD3 świecą kolejno po sobie (wędrujące światełko)
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
DDRD = 0xFF;
PORTD = 1;
unsigned maska = 1;
// maska ma ustawiony bit aktualnie świecącej diody
while (1) {
_delay_ms(1000);
PORTD ^= maska;
// skasuj bit aktualnie świecącej diody
maska <<=1;
// ustaw maskę dla następnej diody
if (maska>15) maska = 1; // wróć do pierwszej diody
PORTD ^= maska;
// ustaw bit następnej diody
}
return 0;
}

Podobne dokumenty