diyundso.de
Grundlagen AVR-GCC
Standard-Includes
#include <avr/io.h> //Bezeichnungen für Register/Bits
Ausgänge
Soll z.B. der Pin PD4 des AVRs als Ausgang benutzt werden, muss der PIN zunächst im Register DDRD (bei PB2 wäre es dann DDRB usw.) als solcher definiert werden. Dazu wird das 4. Bit von DDRD gesetzt:
DDRD |= (1<<4);
PD4 ist nun ein Ausgang. Um einen HIGH-Level an PD4 zu erzeugen, muss nun das 4. Bit von PORTD gesetzt werden:
PORTD |= (1<<4);
Analog dazu lässt sich auch ein LOW-Level an PD4 erzeugen, dazu muss das 4. Bit von PORTD gelöscht werden:
PORTD &= ~(1<<4);
Eingänge
Soll z.B. der Pin PD4 des AVRs als Eingang benutzt werden, muss der PIN zunächst im Register DDRD (bei PB2 wäre es dann DDRB usw.) als solcher definiert werden. Dazu wird das 4. Bit von DDRD gelöscht:
DDRD &= ~(1<<4);
PD4 ist nun ein Eingang. Um den internen Pullup-Widerstand des AVR an PD4 zu nutzen, muss nun das 4. Bit von PORTD gesetzt werden:
PORTD |= (1<<4);
Ob der Status von PD4 nun HIGH oder LOW ist, lässt sich aus dem 4. Bit des Registers PIND auslesen:
if ( PIND & (1<<4) ){//Status ist HIGH
//...
}
if ( !(PIND & (1<<4) ) ){//Status ist LOW
//...
}
Funktionsweise des Auslesevorgangs (kein Code!)
z.B. PIND = 10010001
ausführen von PIND & (1<<4):
1 = 00000001
Linksshift von 1 um 4 stellen:
(1<<4) = 00010000
verUNDen des PIND-Wertes mit (1<<4):
10010001 & 00010000 = 00010000 //Das Ergebnis ist 16
Da 16 ungleich 0, ist die Bedingung: (PIND&(1<<4)) wahr.
Wird nun PD4 z.B. durch einen Taster auf LOW-Level gezogen, so wird ( PIND & (1<<4) ) zu 0, also falsch.
Die Verneinung ( !( PIND & (1<<4) ) ) ist dann also wahr.
Bitmanipulationen
Bits setzen und löschen
Oben wurde bereits gezeigt wie ein Bit gesetzt/gelöscht wird, hier wird dies noch um das Umschalten eines Bits (toggeln) ergänzt und anschließend genauer erklärt:
DDRD |= (1<<4); //4. Bit setzen
DDRD &= ~(1<<4); //4. Bit löschen
DDRD ^= (1<<4); //4. Bit toggeln
Funktionsweise Bit setzen (kein Code!)
z.B. DDRD = 00100101
ausführen von DDRD |= (1<<4):
1 = 00000001
Linksshift von 1 um 4 stellen:
(1<<4) = 00010000
verODERn des DDRD-Wertes mit (1<<4):
00100101 | 00010000 = 00110101 //4. Bit nun 1
Neuen Wert in das Register DDRD schreiben:
DDRD = DDRD | (1<<4);
DDRD |= (1<<4); //kürzere Schreibweise
Funktionsweise Bit löschen (kein Code!)
z.B. DDRD = 00100101
ausführen von DDRD &= ~(1<<2):
1 = 00000001
Linksshift von 1 um 2 stellen:
(1<<2) = 00000100
Negieren von (1<<2):
~(1<<2) = 11111011
verUNDen des DDRD-Wertes mit ~(1<<2):
00100101 | 11111011 = 00100001 //2. Bit nun 0
Neuen Wert in das Register DDRD schreiben:
DDRD = DDRD & ~(1<<2);
DDRD &= ~(1<<2); //kürzere Schreibweise
Funktionsweise Bit toggeln (kein Code!)
z.B. DDRD = 00100101
ausführen von DDRD ^= (1<<2):
1 = 00000001
Linksshift von 1 um 2 stellen:
(1<<2) = 00000100
verXORen des DDRD-Wertes mit (1<<2):
00100101 | 00000100 = 00100001 //2. Bit nun getoggelt
Neuen Wert in das Register DDRD schreiben:
DDRD = DDRD ^ (1<<4);
DDRD ^= (1<<4); //kürzere Schreibweise
Delays
#define F_CPU 1000000 //CPU-Takt angeben in Hz
#include <util/delay.h>
_delay_ms(100); //100ms Delay
_delay_us(100); //100µs Delay
Beispielcode: PD2 in Endlosschleife an- und ausschalten:
#include <avr/io.h>
#define F_CPU 1000000 //hier CPU-Takt in Hz eintragen
#include <util/delay.h>
int main (void){
DDRD |= (1<<2); //PD2 als Ausgang
while(1){ //Endlosschleife
PORTD ^= (1<<2);
_delay_ms(1000); //Status von PD2 soll alle 1000ms von HIGH auf LOW und umgekehrt wechseln.
}
return 0; }