1) Biblioteki AVR – co naprawdę robią?
Biblioteki AVR nie są frameworkiem jak Arduino. One głównie:
- definiują adresy rejestrów sprzętowych,
- udostępniają nazwy bitów (PB0, PD2, itp.),
- dodają kilka funkcji pomocniczych (np. delay).
#include <avr/io.h>
Kluczowe
avr/io.h to mapa sprzętu – bez niej nie ma GPIO, timerów ani ADC.
Najczęściej używane nagłówki
#include <avr/io.h> // rejestry i piny
#include <util/delay.h> // opóźnienia
#include <stdint.h> // uint8_t, uint16_t
#include <avr/interrupt.h> // przerwania (później)
2) GPIO od strony sprzętu: DDRx, PORTx, PINx
Każdy pin mikrokontrolera to 1 bit w trzech rejestrach.
- DDRx – kierunek (0 = wejście, 1 = wyjście)
- PORTx – stan wyjścia / pull-up
- PINx – odczyt stanu pinu
// PB0 jako wyjście
DDRB |= (1 << PB0);
// LED ON
PORTB |= (1 << PB0);
// LED OFF
PORTB &= ~(1 << PB0);
3) Maski bitowe – absolutny fundament AVR
Maska bitowa to liczba, w której ustawiony jest tylko jeden (lub kilka) bitów. Dzięki niej możesz manipulować konkretnymi pinami bez ruszania reszty rejestru.
Tworzenie maski
(1 << PB0) // 00000001
(1 << PB3) // 00001000
Cztery podstawowe operacje (MUSISZ ZNAĆ)
// SET – ustaw bit
X |= maska;
// CLEAR – skasuj bit
X &= ~maska;
// TOGGLE – przełącz bit
X ^= maska;
// READ – sprawdź bit
if (X & maska) { ... }
Zapamiętaj
90% programowania AVR to operacje na maskach bitowych.
4) #define – dlaczego i jak go używać?
#define to makro preprocesora – działa zanim kod zostanie skompilowany. W embedded używa się go bardzo często do:
- numerów pinów,
- masek bitowych,
- konfiguracji sprzętu.
Przykład – czytelny kod GPIO
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB0
LED_DDR |= (1 << LED_PIN);
LED_PORT |= (1 << LED_PIN);
Dlaczego tak?
Zmiana pinu LED wymaga zmiany jednej linijki, a nie całego programu.
#define vs const
- #define – do pinów i masek
- const – do wartości logicznych (czas, progi)
#define BUTTON_PIN PD2
const uint16_t debounce_ms = 20;
5) Pull-up i logika odwrócona
// wejście
DDRD &= ~(1 << PD2);
// pull-up ON
PORTD |= (1 << PD2);
Przy pull-up:
- przycisk puszczony → stan wysoki (1)
- przycisk wciśnięty → stan niski (0)
Błąd uczniów
Zapominają o ! w warunku:
if (!(PIND & (1 << PD2)))
6) Pełny wzorzec programu GPIO
#include <avr/io.h>
#include <util/delay.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB0
#define BTN_PORT PORTD
#define BTN_DDR DDRD
#define BTN_PIN PD2
int main(void)
{
LED_DDR |= (1 << LED_PIN);
BTN_DDR &= ~(1 << BTN_PIN);
BTN_PORT |= (1 << BTN_PIN);
while (1)
{
if (!(PIND & (1 << BTN_PIN)))
LED_PORT |= (1 << LED_PIN);
else
LED_PORT &= ~(1 << LED_PIN);
_delay_ms(20);
}
}
To jest wzorzec
Na tym schemacie będziemy budować wszystkie kolejne projekty.
7) Co MUSISZ umieć po tej lekcji
- rozumieć rolę avr/io.h
- używać DDRx / PORTx / PINx
- stosować maski bitowe
- czytelnie używać #define
- napisać własny kod GPIO bez Arduino