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; }