Hallo

machs besser
Würde ich ja gerne, wenn ich's könnte. Da ich aber AVR und c Neuling bin, verwirrt mich dieses Bitgeschiebe etwas. Ich würde das ganz traditionell durch binäre Schreibweise ersetzen, dann würde auch der Zusammenhang zwischen Bitnummer und Port erkennbar sein. Du machst das ja auch so in deinem ersten Beispiel:

DDRD =DDRD | (1<<6);

würde ich dann so schreiben:

DDRD =DDRD | 0b01000000;

was als Einstieg aber immer noch viel zu kompliziert ist.

Erstmal muss man wissen, dass DDRD für das Datenrichtungsregister des Port D steht und irgendwo (in der io.h?) per #define definiert wurde. Nach dem Reset sind alle Ports auf Eingang gesetzt (offenbar sind sie es nicht, siehe unten) und müssen, je nach Bedarf, als Ausgang geschaltet werden. Um den 7. Pin als Ausgang zu definieren, genügt ein

DDRD=0b01000000; // binaere Schreibweise

wobei man beachten muss, dass die Zählung der Bits bei 0 beginnt. Allerdings werden mit diesem Befehl auch die anderen Richtungsbits beeinflust, dies ist aber meist nicht gewünscht. Um gezielt ein bestimmtes Bit zu setzen (ein 1 reinschreiben), muss man eine oder-Verküpfung anwenden, die nur das gewünschte Bit verändert und den Rest unbeeinflusst läst:

DDRD=DDRD | 0b01000000;

Das Setzen eines Ausgangs funktioniert dann nach dem selben Schema, nur das man dabei auf das Datenregister zugreift, das als PORTD definiert wurde. Wiederum mit einer oder-Verknüpfung, um die anderen Ports nicht zu beeinflussen, sieht das Setzen die 7. Ports (Portbit6!) dann so aus:

PORTD=PORTD | 0b01000000;

Das Rücksetzen des Ausgangs funktioniert nun ähnlich, mit dem Unterschied, dass wir eine und-Verknüpfung anwenden müssen, um die anderen Portbits nicht zu beeinflussen. Das würde dann so aussehen:

PORTD=PORTD & 0b10111111;

und läst sich mit dem ~-Operator noch wunderbar vereinfachen, weil dieser einen Wert bitweise negiert, also aus einer 0 eine 1 macht und aus einer 1 eine 0. Man kann also einfach auch

PORTD=PORTD & ~0b01000000;

schreiben. So wird beim Lesen gleich klar, welches Bit eigentlich gemeint ist, dem AVR ist es aber egal, er setzt beidesmal das Portbit auf 0.

Na wunderbar, scheinbar habe wenigstens ich es jetzt kapiert. Hier mein allererstes selbstgeschriebenes Programm, das OHNE die asuro-Lib direkt auf die Ports zugreift. Weil meine umgebaute FrontLED unsichtbares IR-Licht aussendet, setze ich völlig unspektakulär die StatusLED auf rot:

Code:
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
	DDRB=0; // nicht benoetigte Ports auf Eingang setzen
	DDRC=0;
	DDRD=0b00000100; //rote StatusLED haengt an PD2(= Port D, Bit2)
	PORTD=0b00000100; // Ausgang setzen
	while(1);
	return(0);
}
Mit #include <avr/io.h> werden, je nach Compilerdirektive, die #defines für den entsprechenden Mikrokontroller eingebunden. In unserem Fall eben die Definitionen für den ATMega8.
Mit #include <avr/interrupt.h> werden noch die Default-Interruptroutinen eingebunden, ohne verabschiedet sich der Prozessor nach dem Programmstarts ins Nirwana.

Da ich mir das nun selbst erarbeitet habe, bin ich ziemlich stolz auf das Ergebniss. Natürlich werden die AVR-Profis unter euch darüber schmunzeln, aber jeder fängt eben mal klein an. Die "Bitschiebereien" habe ich natürlich kapiert, aber für den Einstieg finde ich es so verständlicher.

Gruß

mic

[Edit]
Abschließend noch zum Thema Tastenabfrage:
Code:
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
	DDRB=0; // nicht benoetigte Ports auf Eingang setzen
	DDRC=0;
	DDRD=0b00000100; //rote StatusLED haengt an PD2(= Port D, Bit2)
	while(1)
	{
/*
Die Tasten haengen an PortC Bit4. Wenn keine Taste gedrueckt ist,
wird ueber R23 VCC an diesen Pin gelegt. Das ergibt eine 1 beim Einlesen.

Wenn man dann eine Taste drueckt, ergibt sich ein Spannungsteiler,
bei dem der Pin dann deutlich, bei K6 1000K zu 68K, nach 0V gezogen wird.
Das ergibt eine 0 am Eingang.

Den C7 kann man ignorieren, R24 ebenfalls, weil PD3 als Eingang (ohne Pullup?)
geschaltet ist.
*/

		if (PINC & 0b00010000) // PortC Bit4 ist der Tasteneingang
		{
			PORTD=0b00000100; // StatusLED rot setzen
		}
		else
		{
			PORTD=0b00000000; // StatusLED ausschalten
		}

/*
Spätestens jetzt wird auch mir klar, dass die Bitschieberei effektiver ist:

   PORTD=((PINC & (1<<PC4))  >> 2);

*/
	}
	return(0);
}
Wenn man eine Taste drückt, geht die StatusLED aus.