kramann.info
© Guido Kramann

Login: Passwort:










Mikrocontroller
1 Einfuehrung
..1.1 Entwicklungsgeschichtliches
..1.2 Maschinensprache
..1.3 Assemblerbeispiel
..1.4 Sprachwahl
..1.5 Praxis
....1.5.1 Digital_IO
....1.5.2 Byteoperationen
....1.5.3 AVR_Studio
....1.5.4 Testboard
....1.5.5 Aufgaben
....1.5.6 Do_it_yourself
......1.5.6.1 Ampel
......1.5.6.2 Programmierer
..1.6 Literatur
..1.7 Programmierer
....1.7.1 Bauverlauf
....1.7.2 KurzreferenzLow
....1.7.2 Kurzreferenz_16PU
..1.8 Uebung1
..1.9 BoardAtHome
....1.9.1 Software
....1.9.2 Hardware
....1.9.3 Knoppix
....1.9.4 Aufbau
....1.9.5 LED
2 Oszillator
..2.1 Assembler
..2.2 Interner_RC
..2.3 Quarz
..2.4 Taktgenerator
3 DigitalIO
..3.1 Elektrische_Eigenschaften
..3.2 Pullup_Widerstaende
..3.3 Bitmasken_Eingang
..3.4 Bitmasken_Ausgang
..3.5 Tic_Tac_Toe
....3.5.1 DuoLEDs
....3.5.2 Schaltplan
....3.5.3 Spielfeld
....3.5.4 Anwahl
....3.5.5 Kontrolle
..3.6 Laboruebung2
..3.7 Laboruebung2_alt
4 PWM
..4.1 Prinzip
..4.2 Nutzen
..4.3 Generierung
..4.4 Programmierung
..4.5 Servos
..4.7 Laboruebung3
..4.8 LoesungUE3
..4.9 Uebung6
5 LichtKlangKugeln
..5.1 LED
..5.2 RGB
..5.3 Sensoren
..5.4 lautsprecher
..5.5 tonerzeugung
6 UART
..6.1 Bussysteme
..6.2 UART
..6.3 RS232
..6.4 Hardware
..6.5 Senden
..6.6 Hyperterminal
..6.7 Empfangen
..6.8 Broadcast
..6.9 Uebung4
7 Infrarot
..7.1 schalten
..7.2 seriell
..7.3 Uebung
8 OOP
..8.1 Probleme
..8.2 Konzept
..8.3 Statisch
..8.4 Datentypen
..8.5 RS232
....8.5.1 Prozedural
....8.5.2 Analyse
....8.5.3 Umsetzung
....8.5.4 Vererbung
....8.5.5 Statisch
....8.5.6 Performance
..8.6 Fahrzeug
9 ADW
..9.1 ADW
..9.2 Zaehler
10 Peripherie
..10.1 RS232Menue
..10.2 ASCIIDisplay
..10.3 Tastenmatrix
..10.4 Schrittmotor
..10.5 Zaehler
..10.6 Uebung7
11 SPI
..11.1 Testanordnung
..11.2 Register
..11.3 Test1
..11.4 Test2_Interrupt
..11.5 Test3_2Slaves
..11.6 Laboruebung
12 EEPROM
13 I2C
..13.1 MasterSendByte
..13.2 MasterSend2Bytes
..13.3 MasterReceiveByte
..13.4 MasterReceive2Bytes
14 Anwendungen
..14.1 Mechatroniklabor
....14.1.1 Biegelinie
....14.1.2 Ausbruchsicherung
....14.1.3 Einachser
....14.1.4 AV
....14.1.5 Vierradlenkung
....14.1.6 Kommunikation
..14.2 Sinuserzeugung
....14.2.1 Variante1
....14.2.2 Variante2
....14.2.3 Variante3
....14.2.4 Variante4
..14.3 Laboruebung8
..14.4 Loesung_Ue8
..14.5 SPI_Nachtrag
20 Xubuntu

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