|
Externer Quarz
- Als weitere Option bringen die Mikrocontroller der AVR-Famile die Möglichkeit mit, extern einen Quarz anzuschließen.
- Dabei wird zwischen Quarzen niedriger (z.B. 32768Hz - Uhrquarz), mittlerer (z.B. 9216000Hz - günstig für RS232) und hoher Frequenz (20MHz - höchst mögliche Taktrate) unterschieden.
- Je nach Frequenzbereich müssen außen andere Keramikkondensatoren mitgeschaltet werden (s.u.) und intern andere Fuse-Bits gesetzt werden.
|
Prinzip Quarz-Oszillator
- Schwingquarze verformen sich bei Anlegen einer Spannung und die Rückverformung erzeugt wiederum eine Spannung.
- Für diesen Vorgang gibt es eine Resonnanzfrequenz, die sehr unabhängig von Umgebungstemperatur und angelegter Spannung ist.
- Mit Schwingquarzen aufgebaute Oszillatoren, werden durch den Quarz in die Quarzfrequenz "gezwungen".
- Wie bereits im vorangehenden Kapitel erwähnt, liefern Oszillatoren, die mit Schwingquarzen aufgebaut sind ihre Frequenzen mit einer Toleranz, die geringer als 0,003% ist.
|
Verschiedene Bauformen von Quarzen
Bild 0-1: Quarzbauformen
Beschaltung bei der Verwendung eines externen Quarzes
Bild 0-2: Anschluß an ATmega32
- Nicht nur die Höhe der Taktrate ist wichtig bei der Auswahl eines Quarzes, oft sind es auch die Primfaktoren der Quarzfrequenz:
|
Das Uhrquarz mit 32768Hz
- Dieser Quarz ist für den Anschluß an einen Mikrocontroller nicht so gut geeignet, weil er hierfür eine verhältnismäßig niedrige Taktrate hat.
- Jedoch spielt dieser Quarz bei der Herstellung von Zeitgebern eine große Rolle.
- Seine Frequenz beträgt 32768Hz, das sind genau 215Hz.
- Somit erhält man durch 15 maliges teilen der Taktrate durch zwei eine Frequenz von exakt 1Hz.
|
Quarz für die Serielle Schnittstelle mit 9216000Hz
- Bei der seriellen Schnittstelle zum PC (RS232) können folgende Übertragungsraten eingestellt werden:
- in Baud (Anzahl der 8-Bit-Worte pro Sekunde): 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
- Für die Einrichtung einer Verbindung mit dem PC über die serielle Schnittstelle, ist es nötig in das Register UBRR einen Wert zu schreiben, der sich folgendermaßen ergibt: Taktfrequenz/8/Baudrate - 1
- Damit eine Verbindung zwischen PC und Mikrocontroller gut funktioniert, muß das Ergebnis dieser Berechnung möglichst ganzzahlig sein.
- Mit dem Quarz für 9216000Hz und einer baudrate 115200, ergibt sich genau 9216000/8/115200 - 1 = 9
|
Höchste Taktrate 20MHz bedeutet auch höchsten Stromverbrauch!
- Insbesondere bei Batterie betriebenen Mikrocontroller-Anwendungen spielt der Aspekt des Energieverbrauchs eine nicht unwichtige Rolle.
- Je höher die Taktrate, desto höher der Stromverbrauch. Wird eine hohe Rechenleistung nicht gebraucht, sollte man den Mikrocontroller auch nicht unnötig hoch takten.
- Beispiel: 100kHz => 0,4mA Stromaufnahme, 16MHz => 20mA Stromaufnahme.
- Darüber hinaus erhöht sich auch die Leistungsaufnahme mit jeder aktivierten Peripherie (AD-Wandler, Komparator, etc.).
|
Überprüfung der Taktrate via Assemblerprogramm mit bekannter Taktzyklenanzahl
- Mit dem Programm aus dem vorangegangenen Kapitel und einem Oszilloskop, kann auch für die Taktgebung durch Quarz die aktuelle Taktrate nachvollzogen werden.
|
Beispielprogramm: Daten an den PC senden via RS232 - Übertragung von Meßdaten an den PC
Programmteil von muecA für RS232
- Daten, die bei muecA (oberer Mikrocontroller auf Testboard - für 7-Segmentanzeige) an Port A anliegen, sollen als Zahlenwerte an einen PC gesendet werden.
|
#include <avr/io.h>
#define TAKTFREQUENZ 9216000
#define BAUDRATE 115200
void initRS232()
{
unsigned int baudregister = TAKTFREQUENZ/8/BAUDRATE-1;
//setzen der Baudrate
UBRRH = (unsigned char) (baudregister>>8); //Setzen des HIGH-Bytes des Baudraten-Registers
UBRRL = (unsigned char) baudregister; //Setzen des LOW -Bytes des Baudraten-Registers
//Einschalten des Senders und des Empfängers
UCSRB = (1<<TXEN) | (1<<RXEN);
//Setzen des Nachrichtenformats: 8 Datenbits, 2 Stopbits
//UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ0)|(1<<UCSZ1);
//Setzen des Nachrichtenformats: 8 Datenbits, 1 Stopbits
UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);
UCSRA = (1<<U2X);
}
void zeigeZahlDezimal(unsigned char akku)
{
unsigned char l,m,r; //Variablen für Anzeige links, mitte, rechts
l= akku / 100; //links = Inhalt von akku dividiert mit 100
m= (akku % 100) / 10; //mitte = Inhalt von akku modulo mit 100 , anschließend dividiert mit 10
r= akku % 10; //rechts = Inhalt von akku modulo mit 10
while( !(UCSRA & (1<<UDRE)) ); //Warten bis der Uebertragungspuffer leer ist
UDR = l+48;
while( !(UCSRA & (1<<UDRE)) ); //Daten in den Puffer schreiben und übertragen
UDR = m+48;
while( !(UCSRA & (1<<UDRE)) );
UDR = r+48;
while( !(UCSRA & (1<<UDRE)) );
UDR = '\n';
while( !(UCSRA & (1<<UDRE)) );
UDR = '\r';
}
int main(void)
{
unsigned char zahl;
DDRA = 0x00; //PORT A als Eingang
DDRB = 0xFF; //PORT B als Ausgang
DDRC = 0xFF; //PORT C als Ausgang
DDRD = 0xFF; //PORT D BIT 2 bis 8 als Ausgang
initRS232();
zahl = 0;
while(true)
{
zahl = PINA;
zeigeZahlDezimal(zahl);
}
return 0;
}
Code 0-1: Kontinuierliches Senden der Bytes, die an Port A anliegen via RS232 an einen PC.
Bild 0-1: Testboard mit Infrarot-Entfernungssensor
Programm-Download
Zuordnung
- Das .hex-File aus dem Projekt mueca wird auf den Mikrocontroller A übertragen.
- Das .hex-File aus dem Projekt muecb wird auf den Mikrocontroller B übertragen.
|
#include <avr/io.h>
void initADwandler()
{
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
//ADEN
// 1 AD-Wandler eingeschaltet
//ADSC
// 1 Konvertierung starten
//ADATE
// 0 Auto-Trigger aus
//ADIF (Interrupt-Flag)
//ADIE
// 0 Interrupt ausgeschaltet
//ADPS 2 1 0 Vorteilung der Taktrate (sollte zwischen 50..200kHz liegen, also bei 9,216MHz Teilung=92 ~ 128)
//ADPS 2 1 0 Vorteilung der Taktrate (sollte zwischen 50..200kHz liegen, also bei 9,216MHz 144kHz Teilung=64)
// 0 0 0 2
// 0 0 1 2
// 0 1 0 4
// 0 1 1 8
// 1 0 0 16
// 1 0 1 32
// 1 1 0 64 (ausgewählt)
// 1 1 1 128
//Freilaufmode auswählen:
SFIOR &= 255 - ((1<<ADTS2) | (1<<ADTS1) | (1<<ADTS0));
//ACHTUNG: verwendete Pins von PORTA als Eingang wählen!
//AD-Wandler einstellen und aktivieren:
//PA0,1,2,3 als Eingänge (DDRA=0b11110000)
//REFS1 REFS0
// 0 0 externe Referenzspannung
//ADLAR
// 1 Ergebnis in ADCH und ADCL links ausgerichtet (so kann man leicht die höhren 8 Bits lesen)
//MUX 4 3 2 1 0
// 0 0 0 0 0 ADC0 //hier ausgewählt
// 0 0 0 0 1 ADC1
// 0 0 0 1 0 ADC2
// 0 0 0 1 1 ADC3
// 0 0 1 0 0 ADC4
// 0 0 1 0 1 ADC5
// 0 0 1 1 0 ADC6
// 0 0 1 1 1 ADC7
//AD0 / Pin 40 als Eingang wählen
ADMUX = (0<<REFS1) | (0<<REFS0) | (1<<ADLAR) | (0<<MUX4) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
}
int main(void)
{
unsigned char akku,akku2;
int i,k;
long int x;
DDRC = 0b11111111; //PORTC alle Bits als Ausgang
DDRD = 0b00000000; //PORTD alle Bits als Eingang
initADwandler();
while(true)
{
x = 0;
for(i=0;i<100;i++)
{
akku2 = ADCH; //muss erst ausgelesen werden, damit ADCL verfügbar ist.
akku = ADCL;
x+=akku2;
for(k=0;k<100;k++);
}
x/=100;
PORTC = (unsigned char)x;
}
return 0;
}
Code 0-1: Quellcode muecb.cpp
|