kramann.info
© Guido Kramann

Login: Passwort:










2.3 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

BILDBESCHREIBUNG

Bild 2.3-1: Quarzbauformen

Beschaltung bei der Verwendung eines externen Quarzes

BILDBESCHREIBUNG

Bild 2.3-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 2.3-1: Kontinuierliches Senden der Bytes, die an Port A anliegen via RS232 an einen PC.

Testboard mit Sensor

Bild 2.3-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 2.3-1: Quellcode muecb.cpp