Wir werden in zukünftigen Übungen in die Situation kommen, dass wir
Informationen vom Controller auswerten bzw. anzeigen müssen wobei es vielleicht
dann nicht mehr reicht, ein paar Leuchtdioden anzusteuern.
Somit brauchen wir eine Verbindung vom AVR zu unserem PC, und dies am besten
über die serielle Schnittstelle.
Einige AVR-Controller haben einen vollduplexfähigen UART (Universal Asynchronous Receiver and Transmitter) schon eingebaut. Dies ist eine wirklich feine Sache, haben wir doch damit schon das nötige Werkzeug, um mit anderen Geräten, welche über eine serielle Schnittstelle verfügen (insbesondere mit unserem PC), zu kommunizieren.
Übrigens: Vollduplex heisst nichts anderes, als dass der Baustein gleichzeitig senden und empfangen kann.
Der UART wird über vier separate Register angesprochen:
UCR |
UART Control Register.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
USR |
UART Status Register. Hier teilt uns der UART mit, was er gerade so macht.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
UDR | UART Data Register. Hier werden Daten zwischen UART und CPU übertragen. Da der UART im Vollduplexbetrieb gleichzeitig empfangen und senden kann handelt es sich hier physikalisch um 2 Register, die aber über die gleiche I/O-Adresse angesprochen werden. Je nachdem, ob ein Lese- oder ein Schreibzugriff auf den UART erfolgt wird automatisch das richtige UDR angesprochen. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
UBRR | UART Baud Rate Register. In diesem Register müssen wir dem UART mitteilen, wie schnell wir gerne kommunizieren möchten. Der Wert, der in dieses Register geschrieben werden muss, errechnet sich nach folgender Formel: UBRR = Taktfrequenz / (Baudrate * 16) - 1 Es sind Baudraten bis zu 115200 Baud und höher möglich. |
Der UART basiert auf normalem TTL-Pegel mit 0V (LOW) und 5V (HIGH). Die Schnittstellenspezifikation für RS232 definiert jedoch -3V ... -12V (LOW) und +3 ... +12V (HIGH). Zudem muss der Signalaustausch zwischen AVR und Partnergerät invertiert werden. Für die Anpassung der Pegel und das Invertieren der Signale gibt es fertige Schnittstellenbausteine. Der bekannteste davon ist wohl der MAX232. Allerdings kostet der auch wieder Geld und benötigt zusätzlich immerhin 4 externe Elkos.
Die in den PC eingebauten Schnittstellen vertragen ohne Klagen auch den TTL-Pegel vom AVR. Allerdings müssen wir immer noch die Signale invertieren. Im einfachtesn Fall verwenden wir dazu jeweils einen einfachen NPN-Transistor und 2 Widerstände. Näheres dazu erfahrt ihr in den folgenden Übungen.
Wir wollen nun Daten mit dem UART auf die serielle Schnittstelle ausgeben.
Dazu müssen wir den UART zuerst mal initialisieren. Dazu setzen wir je nach
gewünschter Funkstionsweise die
benötigten Bits im UART Control Register.
Da wir vorerst nur senden möchten und (noch) keine Interrupts auswerten wollen
gestaltet sich die Initialisierung wirklich sehr einfach, da wir lediglich das Transmitter
Enable Bit setzen müssen:
outp ((1 << TXEN), UCR);
Nun müssen wir noch die Baudrate festlegen. Gemäss unserer Formel brauchen wir dazu die Taktfrequenz des angeschlossenen Oszillators bzw. Quarz in die Formel einzufügen und das Resultat der Berechnung in das Baudratenregister des UART einzuschreiben:
#define F_CPU 4000000
// Zum Beispiel 4Mhz-Quarz
#define UART_BAUD_RATE 9600 // Wir versuchen mal mit 9600 Baud
outp (F_CPU / (UART_BAUD_RATE * 16L) - 1, UBRR);
Um nun ein Zeichen auf die Schnittstelle auszugeben müssen wir dasselbe lediglich in das UART Daten Register schreiben.
outp ('x', UDR); // Schreibt das Zeichen x auf die Schnittstelle
Wenn wir nun mehrere, aufeinanderfolgende Zeichen auf die Schnittstelle
ausgeben wollen, dann müssen wir mit dem nächsten Zeichen warten, bis das
vorhergehende jeweils aus dem Datenregister in das Sende-Schieberegister
übernommen wurde.
Zu diesem Zweck können wir uns für's Erste eine einfache Funktion basteln:
void SendeString (char *szBuf)
{
while (*szBuf++) {
outp (*szBuf, UDR);
loop_until_bit_is_set (USR, UDRE);
}
}
Das ist jetzt insofern etwas kritisch, dass wir während dem Senden des
Strings nicht mehr auf andere Ereignisse reagieren können. Dies wird aber
ohnehin erst dann ein Thema, wenn wir mit unserem Programm gleichzeitig Senden
und Empfangen wollen.
Wir werden zu einem späteren Zeitpunkt Lösung für dieses Problem finden.
|