Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
microcontrollertechnik:9_uart_und_terminal [2021/10/24 02:06] tfischer |
microcontrollertechnik:9_uart_und_terminal [2024/03/11 00:04] (aktuell) mexleadmin |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== 9. UART und Terminal ====== | + | ====== 9 UART und Terminal ====== |
< | < | ||
Zeile 24: | Zeile 24: | ||
</ | </ | ||
==== Video ==== | ==== Video ==== | ||
- | + | ||
+ | {{youtube> | ||
+ | |||
+ | <WRAP hide> | ||
{{youtube> | {{youtube> | ||
{{youtube> | {{youtube> | ||
+ | </ | ||
</ | </ | ||
Zeile 36: | Zeile 40: | ||
< | < | ||
</ | </ | ||
- | {{drawio> | + | {{drawio> |
</ | </ | ||
+ | --> I. Vorarbeiten # | ||
+ | - Laden Sie folgende Datei herunter: | ||
+ | - {{microcontrollertechnik: | ||
+ | - {{microcontrollertechnik: | ||
+ | - {{microcontrollertechnik: | ||
+ | <callout type=" | ||
- | ==== Code ==== | + | **Beachten Sie folgendes** |
+ | * Es wird nun ein ATmega328 genutzt, d.h. das Programm ist nicht mehr kompatibel mit dem MiniMEXLE! | ||
+ | * Überprüfen Sie die Pins und Ports des Displays. | ||
+ | * Überprüfen Sie die Taktfrequenz. | ||
+ | |||
+ | </ | ||
+ | |||
+ | <-- | ||
+ | |||
+ | --> Code mit Polling # | ||
+ | ==== Code mit Polling | ||
Dieses Unterkapitel ist z.Zt. in einem provisorischem Zustand. | Dieses Unterkapitel ist z.Zt. in einem provisorischem Zustand. | ||
- | - {{microcontrollertechnik: | + | Variante mit Polling: |
- | - Variante mit Polling: {{microcontrollertechnik: | + | |
- | - Variante | + | <sxh c; first-line: 1> |
+ | /* ---------------------------------------------------------------------------- | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | AVR-USB-PROGI Ver. 2.0 | ||
+ | |||
+ | | ||
+ | C-Compiler: | ||
+ | |||
+ | | ||
+ | Maximaltemperatur im Betriebszeitraum in °C mit 1/10 Grad. | ||
+ | Keine Tastenbedienung | ||
+ | |||
+ | | ||
+ | | ||
+ | |- Experiment 8 -| |Temp. | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | Fuses im uC: | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | 2) AD-Wandlung (Takt: 100 ms) | ||
+ | 3) Umrechnung fuer Temperatur | ||
+ | 4) Anzeigetreiber (Takt: 1 s) | ||
+ | |||
+ | 1) Das Modul " | ||
+ | und Umrechnung und einen zusaetzlichen Takt von 1 s fuer die Anzeige. | ||
+ | |||
+ | Verwendung von Hardware-Timer 0 und T0 Overflow-Interrupt. | ||
+ | Frequenzen: | ||
+ | Timer-Vorteiler / | ||
+ | Hardware-Timer | ||
+ | Software-Vorteiler / 60 => 100 Hz / 10 ms | ||
+ | Hundertstel-Zaehler / | ||
+ | Zehntel-Zaehler / | ||
+ | |||
+ | 2) Das Modul " | ||
+ | Der AD-Wandler wird mit einem internen Takt von 96 kHz betrieben. | ||
+ | Im Modul wird eine einzelne AD-Wandlung des Kanals ADC0 mit 10 Bit | ||
+ | Aufloesung gestartet. Dort ist der NTC des Boards mit Vorwiderstand | ||
+ | als temperaturabhaengiger Spannungsteiler bzw. Potentiometer angeschlossen. | ||
+ | Als Referenzspannung wird die 5V-Versorgung verwendet. | ||
+ | Das Ergebnis wird in der globalen Variable ad_wert gespeichert. | ||
+ | |||
+ | 3) Das Modul " | ||
+ | Der Ergebniswert des Moduls " | ||
+ | einen entsprechenden Temperaturwert umgerechnet. In der Tabelle sind | ||
+ | Temperaturwerte ueber aequidistante (Abstand = 16) AD-Werte aufgetragen. | ||
+ | Die Werte dazwischen werden mit linearer Interpolation ermittelt. | ||
+ | Weiterhin wird im Modul jede aktuelle Temperatur mit der gespeicherten | ||
+ | maximalen Temperatur verglichen und der Maximalwert optional angepasst. | ||
+ | |||
+ | 4) Das Modul " | ||
+ | zu schnelles Umschalten der Anzeigewerte vermieden. Das Modul gibt die | ||
+ | Werte der aktuellen und der maximalen Temperatur in 1/10 °C aus. | ||
+ | |||
+ | Zwischen AD-Wandlung / Umrechnung und Anzeige kann spaeter noch eine | ||
+ | | ||
+ | |||
+ | Die Kopplung der Module wird ueber global definierte Variable realisiert: | ||
+ | |||
+ | | ||
+ | | ||
+ | Takt | ||
+ | |||
+ | 16-Bit-Variable: | ||
+ | t-wert Umrechnung => Anzeige | ||
+ | tmax-wert Umrechnung => Anzeige | ||
+ | |||
+ | // ----------------------------------------------------------------------------*/ | ||
+ | |||
+ | // Deklarationen ============================================================== | ||
+ | |||
+ | // Festlegung der Quarzfrequenz | ||
+ | #ifndef F_CPU // | ||
+ | #define F_CPU 8000000L // Simulation mit 8 MHz Quarz | ||
+ | # | ||
+ | |||
+ | // Include von Header-Dateien | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | #include < | ||
+ | |||
+ | // Konstanten | ||
+ | #define VORTEILER_WERT 60 | ||
+ | #define HUNDERTSTEL_WERT 10 | ||
+ | #define ZEHNTEL_WERT 10 | ||
+ | |||
+ | #define ASC_NULL | ||
+ | #define ASC_FULL_STOP | ||
+ | |||
+ | #define UART_BUFFER_SIZE 10 // Buffersize für übertrgene Daten | ||
+ | #define BAUD_RATE 9600L | ||
+ | |||
+ | // Berechnungen für die Baudrate | ||
+ | #define UBRR_VAL | ||
+ | #define BAUD_REAL (F_CPU/ | ||
+ | #define BAUD_ERROR ((BAUD_REAL*1000)/ | ||
+ | |||
+ | // Überprüfung der Baudrate und ob Fehler zu groß ist | ||
+ | #if ((BAUD_ERROR> | ||
+ | #error Systematischer Fehler der Baudrate zu hoch! | ||
+ | #endif | ||
+ | |||
+ | |||
+ | const int TEMP[45] = {521, | ||
+ | 338, | ||
+ | 193, | ||
+ | 48, | ||
+ | -145, | ||
+ | |||
+ | // Die Tabellenwerte sind in 1/10 °C angegeben | ||
+ | // Der erste Tabellenwert entspricht einem AD-Wert | ||
+ | // von 256. Die Abstaende der AD-Werte sind 16 | ||
+ | |||
+ | // Variable | ||
+ | unsigned char vorteiler = VORTEILER_WERT; | ||
+ | unsigned char hundertstel = HUNDERTSTEL_WERT; | ||
+ | unsigned char zehntel = ZEHNTEL_WERT; | ||
+ | |||
+ | unsigned int adcValue = 0; // Variable fuer den AD-Wandlungswert | ||
+ | int tValue = 0; // Variable fuer die Temperatur (in 1/10 °C) | ||
+ | int tValueMax =-300; | ||
+ | |||
+ | bool takt10ms; | ||
+ | bool takt100ms; | ||
+ | bool takt1s; | ||
+ | |||
+ | char wort[UART_BUFFER_SIZE]; | ||
+ | |||
+ | |||
+ | // | ||
+ | void initTimer0 (void); | ||
+ | void initAdc (void); | ||
+ | void initDisplay (void); | ||
+ | void doAdc (void); | ||
+ | void calculateTemp (void); | ||
+ | void refreshDisplayTemp(int tempValue, char line, char pos); | ||
+ | void refreshDisplay (void); | ||
+ | |||
+ | void initUart(void); | ||
+ | void putData(char *daten); | ||
+ | uint8_t getData(void); | ||
+ | |||
+ | // Hauptprogramm ============================================================== | ||
+ | int main () | ||
+ | { | ||
+ | uint8_t bufferFilled = 0; // Flag für vollen Puffer | ||
+ | |||
+ | initDisplay(); | ||
+ | initTimer0(); | ||
+ | initAdc(); | ||
+ | |||
+ | initUart(); | ||
+ | sei(); | ||
+ | |||
+ | // Hauptprogrammschleife __________________________________________________ | ||
+ | |||
+ | while(1) // | ||
+ | // Funktionen abhaengig von Taktbotschaften | ||
+ | { | ||
+ | if(takt10ms) | ||
+ | { | ||
+ | takt10ms = 0; // Taktbotschaft zuruecksetzen | ||
+ | |||
+ | if(getData()==' | ||
+ | |||
+ | if (bufferFilled==1) // Bei verfügbarer Zeichenkette | ||
+ | { | ||
+ | putData(wort); | ||
+ | bufferFilled=0; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | if(takt100ms) // | ||
+ | { | ||
+ | takt100ms = 0; // Taktbotschaft zuruecksetzen | ||
+ | doAdc(); | ||
+ | calculateTemp(); | ||
+ | } | ||
+ | |||
+ | if(takt1s) // | ||
+ | { | ||
+ | takt1s = 0; // Taktbotschaft zuruecksetzen | ||
+ | |||
+ | refreshDisplay(); | ||
+ | wort[5] = ' | ||
+ | wort[6] = ' | ||
+ | wort[7] = ' | ||
+ | wort[8] = ' | ||
+ | wort[9] = 0; // Endzeichen | ||
+ | bufferFilled=1; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | // Timer-Initialisierung ============================================================== | ||
+ | // | ||
+ | // Initialisierung des Timer0 zur Erzeugung eines getakteten Interrupts. | ||
+ | // Er dient dazu, die benoetigten Taktbotschaften zu erzeugen. | ||
+ | void initTimer0() | ||
+ | { | ||
+ | TCCR0A |= (0<< | ||
+ | | (0<< | ||
+ | TCCR0B |= (0<< | ||
+ | | (1<< | ||
+ | TIMSK0 |= (1<< | ||
+ | } | ||
+ | |||
+ | // Timer-Initialisierung ============================================================== | ||
+ | // | ||
+ | // Initialisierung des A/ | ||
+ | // Vorteiler = 128 => interner Takt = 96 kHz | ||
+ | // Abfrage des ADC0 (NTC-Spannungsteiler) | ||
+ | // Referenzspannung = analoge Versorgung Avcc | ||
+ | void initAdc () | ||
+ | { | ||
+ | ADMUX | ||
+ | | (1<< | ||
+ | | (1<< | ||
+ | |||
+ | ADCSRA |= (1<< | ||
+ | | (1<< | ||
+ | | (1<< | ||
+ | | (1<< | ||
+ | } | ||
+ | |||
+ | |||
+ | // Timer-Initialisierung ============================================================== | ||
+ | // | ||
+ | // In der Interrupt-Routine sind die Softwareteiler realisiert, die die Takt- | ||
+ | // botschaften (10ms, 100ms, 1s) fuer die Module erzeugen. Die Interrupts | ||
+ | // werden von Timer 0 ausgeloest (Interrupt Nr. 1) | ||
+ | // | ||
+ | // Veraenderte Variable: | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | // Ausgangsvariable: | ||
+ | // | ||
+ | // | ||
+ | |||
+ | ISR (TIMER0_OVF_vect) | ||
+ | { | ||
+ | --vorteiler; | ||
+ | if (vorteiler==0) // | ||
+ | { | ||
+ | vorteiler = VORTEILER_WERT; | ||
+ | takt10ms = true; // Botschaft 10ms senden | ||
+ | --hundertstel; | ||
+ | |||
+ | if (hundertstel==0) // | ||
+ | { | ||
+ | hundertstel = HUNDERTSTEL_WERT; | ||
+ | takt100ms = true; // Botschaft 100ms senden | ||
+ | --zehntel; | ||
+ | |||
+ | if (zehntel==0) // | ||
+ | { | ||
+ | zehntel = ZEHNTEL_WERT; | ||
+ | takt1s = true; // Botschaft 1s senden | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ADWandlung ============================================================== | ||
+ | // | ||
+ | // Durchfuehrung einer Einzelwandlung der am NTC-Spannungsteiler anstehenden | ||
+ | // Spannung in einen digitalen 10-bit-Wert (einmal pro 100 ms). | ||
+ | void doAdc() | ||
+ | { | ||
+ | ADCSRA |= (1<< | ||
+ | while (ADCSRA & (1<< | ||
+ | |||
+ | adcValue = ADCL + (ADCH<< | ||
+ | // | ||
+ | // | ||
+ | } | ||
+ | |||
+ | // Umrechnung ============================================================== | ||
+ | // | ||
+ | // (wird alle 100 ms aufgerufen) | ||
+ | void calculateTemp () | ||
+ | { | ||
+ | unsigned char index; | ||
+ | unsigned char steps; | ||
+ | // | ||
+ | |||
+ | index = (adcValue-256)/ | ||
+ | steps = (adcValue-256)%16; | ||
+ | |||
+ | tValue = steps * (TEMP[index+1] - TEMP[index])/ | ||
+ | // | ||
+ | |||
+ | if(tValue> | ||
+ | { | ||
+ | tValueMax = tValue; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Anzeigetreiber fuer Temperaturanzeige ============================================================== | ||
+ | // | ||
+ | // Beschreiben der Anzeige mit dem erstellten Temperaturwert | ||
+ | // und mit dem maximalen Wert (wird alle 1 s aufgerufen). | ||
+ | // | ||
+ | // Umrechnung der Zahlenwerte (1/10 °C) in Anzeigewerte wie folgt: | ||
+ | // Hunderter: einfache Integer-Teilung (/100). | ||
+ | // Zehner: Modulo-Ermittlung (%100), d.h. Rest bei der Teilung durch 100 | ||
+ | // dann nochmals Integer-Teilung (/10) dieses Restes. | ||
+ | // Einer: | ||
+ | // | ||
+ | // Umrechnung in ASCII-Werte fuer die Anzeige durch Addition von 0x30. | ||
+ | void refreshDisplayTemp(int tempValue, char line, char pos) | ||
+ | { | ||
+ | lcd_gotoxy(line, | ||
+ | if (tempValue> | ||
+ | { | ||
+ | wort[0] = ' '; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | wort[0] = ' | ||
+ | tempValue = -tempValue; | ||
+ | } | ||
+ | wort[1] = tempValue/ | ||
+ | tempValue = tempValue%100; | ||
+ | wort[2] = tempValue/ | ||
+ | wort[3] = ASC_FULL_STOP; | ||
+ | wort[4] = tempValue%10 + ASC_NULL; | ||
+ | wort[5] = 0; | ||
+ | lcd_putstr | ||
+ | } | ||
+ | |||
+ | // Anzeigefunktion ============================================================== | ||
+ | // | ||
+ | // Der aktuelle Temperatur und die maximale Temperatur werden ausgegeben | ||
+ | void refreshDisplay() | ||
+ | { | ||
+ | refreshDisplayTemp(tValueMax, | ||
+ | refreshDisplayTemp(tValue, | ||
+ | } | ||
+ | |||
+ | // Initialisierung Display-Anzeige ============================================================== | ||
+ | // | ||
+ | void initDisplay() // | ||
+ | { | ||
+ | lcd_init(); | ||
+ | |||
+ | lcd_displayMessage(" | ||
+ | lcd_displayMessage(" | ||
+ | |||
+ | _delay_ms(2000); | ||
+ | |||
+ | lcd_displayMessage(" | ||
+ | lcd_displayMessage(" | ||
+ | // | ||
+ | } // | ||
+ | |||
+ | void initUart (void) // Initialisierung der UART-Register | ||
+ | { | ||
+ | UBRR0H = UBRR_VAL >> 8; // High-Baudraten-Register beschreiben | ||
+ | UBRR0L = UBRR_VAL & 0xFF; // Low-Baudraten-Register beschreiben | ||
+ | UCSR0B = (1<< | ||
+ | UCSR0C = (1<< | ||
+ | } | ||
+ | |||
+ | |||
+ | /* puts ist unabhaengig vom Controllertyp */ | ||
+ | void putData (char *data) | ||
+ | { | ||
+ | while (*data) | ||
+ | { /* so lange *s != ' | ||
+ | while (!(UCSR0A & (1<< | ||
+ | UDR0 = *data; | ||
+ | data++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | uint8_t getData(void) // | ||
+ | { | ||
+ | if (UCSR0A & (1<< | ||
+ | { | ||
+ | return UDR0; // Zeichen aus UDR an Aufrufer zurueckgeben | ||
+ | }else{ | ||
+ | return 0; | ||
+ | }; | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | <-- | ||
+ | |||
+ | --> Code mit Interrupt # | ||
+ | ==== Code mit Interrupt==== | ||
+ | |||
+ | Variante mit Interrupt: {{microcontrollertechnik: | ||
+ | <sxh c; first-line: 1> | ||
+ | /* ---------------------------------------------------------------------------- | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | AVR-USB-PROGI Ver. 2.0 | ||
+ | |||
+ | | ||
+ | C-Compiler: | ||
+ | |||
+ | | ||
+ | Maximaltemperatur im Betriebszeitraum in °C mit 1/10 Grad. | ||
+ | Keine Tastenbedienung | ||
+ | |||
+ | | ||
+ | | ||
+ | |- Experiment 8 -| |Temp. | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | Fuses im uC: | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | 2) AD-Wandlung (Takt: 100 ms) | ||
+ | 3) Umrechnung fuer Temperatur | ||
+ | 4) Anzeigetreiber (Takt: 1 s) | ||
+ | |||
+ | 1) Das Modul " | ||
+ | und Umrechnung und einen zusaetzlichen Takt von 1 s fuer die Anzeige. | ||
+ | |||
+ | Verwendung von Hardware-Timer 0 und T0 Overflow-Interrupt. | ||
+ | Frequenzen: Quarzfrequenz 12,288 MHz. | ||
+ | Timer-Vorteiler / | ||
+ | Hardware-Timer | ||
+ | Software-Vorteiler / 60 => 100 Hz / 10 ms | ||
+ | Hundertstel-Zaehler / | ||
+ | Zehntel-Zaehler / | ||
+ | |||
+ | 2) Das Modul " | ||
+ | Der AD-Wandler wird mit einem internen Takt von 96 kHz betrieben. | ||
+ | Im Modul wird eine einzelne AD-Wandlung des Kanals ADC0 mit 10 Bit | ||
+ | Aufloesung gestartet. Dort ist der NTC des Boards mit Vorwiderstand | ||
+ | als temperaturabhaengiger Spannungsteiler bzw. Potentiometer angeschlossen. | ||
+ | Als Referenzspannung wird die 5V-Versorgung verwendet. | ||
+ | Das Ergebnis wird in der globalen Variable ad_wert gespeichert. | ||
+ | |||
+ | 3) Das Modul " | ||
+ | Der Ergebniswert des Moduls " | ||
+ | einen entsprechenden Temperaturwert umgerechnet. In der Tabelle sind | ||
+ | Temperaturwerte ueber aequidistante (Abstand = 16) AD-Werte aufgetragen. | ||
+ | Die Werte dazwischen werden mit linearer Interpolation ermittelt. | ||
+ | Weiterhin wird im Modul jede aktuelle Temperatur mit der gespeicherten | ||
+ | maximalen Temperatur verglichen und der Maximalwert optional angepasst. | ||
+ | |||
+ | 4) Das Modul " | ||
+ | zu schnelles Umschalten der Anzeigewerte vermieden. Das Modul gibt die | ||
+ | Werte der aktuellen und der maximalen Temperatur in 1/10 °C aus. | ||
+ | |||
+ | Zwischen AD-Wandlung / Umrechnung und Anzeige kann spaeter noch eine | ||
+ | | ||
+ | |||
+ | Die Kopplung der Module wird ueber global definierte Variable realisiert: | ||
+ | |||
+ | | ||
+ | | ||
+ | Takt | ||
+ | |||
+ | 16-Bit-Variable: | ||
+ | t-wert Umrechnung => Anzeige | ||
+ | tmax-wert Umrechnung => Anzeige | ||
+ | |||
+ | // ----------------------------------------------------------------------------*/ | ||
+ | |||
+ | // Deklarationen ============================================================== | ||
+ | |||
+ | // Festlegung der Quarzfrequenz | ||
+ | #ifndef F_CPU // | ||
+ | #define F_CPU 8000000L // | ||
+ | # | ||
+ | |||
+ | // Include von Header-Dateien | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | #include < | ||
+ | |||
+ | // Konstanten | ||
+ | #define VORTEILER_WERT 60 | ||
+ | #define HUNDERTSTEL_WERT 10 | ||
+ | #define ZEHNTEL_WERT 10 | ||
+ | |||
+ | #define ASC_NULL | ||
+ | #define ASC_FULL_STOP | ||
+ | |||
+ | #define UART_BUFFER_SIZE 10 // Buffersize fuer uebertragene Daten | ||
+ | #define BAUD_RATE 9600L | ||
+ | |||
+ | // Berechnungen für die Baudrate | ||
+ | #define UBRR_VAL | ||
+ | #define BAUD_REAL (F_CPU/ | ||
+ | #define BAUD_ERROR ((BAUD_REAL*1000)/ | ||
+ | |||
+ | // Überprüfung der Baudrate und ob Fehler zu groß ist | ||
+ | #if ((BAUD_ERROR> | ||
+ | #error Systematischer Fehler der Baudrate zu hoch! | ||
+ | #endif | ||
+ | |||
+ | |||
+ | const int TEMP[45] = {521, | ||
+ | 338, | ||
+ | 193, | ||
+ | 48, | ||
+ | -145, | ||
+ | |||
+ | // Die Tabellenwerte sind in 1/10 °C angegeben | ||
+ | // Der erste Tabellenwert entspricht einem AD-Wert | ||
+ | // von 256. Die Abstaende der AD-Werte sind 16 | ||
+ | |||
+ | // Variable | ||
+ | unsigned char vorteiler = VORTEILER_WERT; | ||
+ | unsigned char hundertstel = HUNDERTSTEL_WERT; | ||
+ | unsigned char zehntel = ZEHNTEL_WERT; | ||
+ | |||
+ | unsigned int adcValue = 0; // Variable fuer den AD-Wandlungswert | ||
+ | int tValue = 0; // Variable fuer die Temperatur (in 1/10 °C) | ||
+ | int tValueMax =-300; | ||
+ | |||
+ | bool takt10ms; | ||
+ | bool takt100ms; | ||
+ | bool takt1s; | ||
+ | |||
+ | volatile uint8_t uart_rx_flag = 0; // Flag für vollständig empfangene Daten | ||
+ | volatile uint8_t DataTransferFinished = 1; // Flag für vollständig gesendete Daten | ||
+ | char uart_rx_buffer[UART_BUFFER_SIZE]; | ||
+ | char uart_tx_buffer[UART_BUFFER_SIZE]; | ||
+ | char wort[UART_BUFFER_SIZE]; | ||
+ | |||
+ | |||
+ | // | ||
+ | void initTimer0 (void); | ||
+ | void initAdc (void); | ||
+ | void initDisplay (void); | ||
+ | void doAdc (void); | ||
+ | void calculateTemp (void); | ||
+ | void refreshDisplayTemp(int tempValue, char line, char pos); | ||
+ | void refreshDisplay (void); | ||
+ | |||
+ | void initUart (void); | ||
+ | void putData(char *data); // Daten senden | ||
+ | |||
+ | // Hauptprogramm ============================================================== | ||
+ | int main () | ||
+ | { | ||
+ | uint8_t bufferFilled = 0; // Flag für vollen Puffer | ||
+ | |||
+ | initDisplay(); | ||
+ | initTimer0(); | ||
+ | initAdc(); | ||
+ | |||
+ | initUart(); | ||
+ | sei(); | ||
+ | UDR0 = 0; // Work around für Probleme bei Simulide <= R941 : ohne diese Zeile is kein Senden möglich | ||
+ | |||
+ | // Hauptprogrammschleife __________________________________________________ | ||
+ | |||
+ | while(1) // | ||
+ | // Funktionen abhaengig von Taktbotschaften | ||
+ | { | ||
+ | if(takt10ms) | ||
+ | { | ||
+ | takt10ms = 0; | ||
+ | if (DataTransferFinished==1 && bufferFilled==1) // Bei abgeschlossener Sendung und verfügbarer Zeichenkette | ||
+ | { | ||
+ | bufferFilled=0; | ||
+ | putData(wort); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | if(takt100ms) // | ||
+ | { | ||
+ | takt100ms = 0; // Taktbotschaft zuruecksetzen | ||
+ | doAdc(); | ||
+ | calculateTemp(); | ||
+ | } | ||
+ | |||
+ | if(takt1s) // | ||
+ | { | ||
+ | takt1s = 0; // Taktbotschaft zuruecksetzen | ||
+ | refreshDisplay(); | ||
+ | wort[5] = ' | ||
+ | wort[6] = ' | ||
+ | wort[7] = ' | ||
+ | wort[8] = ' | ||
+ | wort[9] = 0; // Endzeichen | ||
+ | bufferFilled=1; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | // Timer-Initialisierung ============================================================== | ||
+ | // | ||
+ | // Initialisierung des Timer0 zur Erzeugung eines getakteten Interrupts. | ||
+ | // Er dient dazu, die benoetigten Taktbotschaften zu erzeugen. | ||
+ | void initTimer0() | ||
+ | { | ||
+ | TCCR0A |= (0<< | ||
+ | | (0<< | ||
+ | TCCR0B |= (0<< | ||
+ | | (1<< | ||
+ | TIMSK0 |= (1<< | ||
+ | } | ||
+ | |||
+ | // Timer-Initialisierung ============================================================== | ||
+ | // | ||
+ | // Initialisierung des A/ | ||
+ | // Vorteiler = 128 => interner Takt = 96 kHz | ||
+ | // Abfrage des ADC0 (NTC-Spannungsteiler) | ||
+ | // Referenzspannung = analoge Versorgung Avcc | ||
+ | void initAdc () | ||
+ | { | ||
+ | ADMUX | ||
+ | | (1<< | ||
+ | | (1<< | ||
+ | |||
+ | ADCSRA |= (1<< | ||
+ | | (1<< | ||
+ | | (1<< | ||
+ | | (1<< | ||
+ | } | ||
+ | |||
+ | |||
+ | // Timer-Initialisierung ============================================================== | ||
+ | // | ||
+ | // In der Interrupt-Routine sind die Softwareteiler realisiert, die die Takt- | ||
+ | // botschaften (10ms, 100ms, 1s) fuer die Module erzeugen. Die Interrupts | ||
+ | // werden von Timer 0 ausgeloest (Interrupt Nr. 1) | ||
+ | // | ||
+ | // Veraenderte Variable: | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | // Ausgangsvariable: | ||
+ | // | ||
+ | // | ||
+ | |||
+ | ISR (TIMER0_OVF_vect) | ||
+ | { | ||
+ | --vorteiler; | ||
+ | if (vorteiler==0) // | ||
+ | { | ||
+ | vorteiler = VORTEILER_WERT; | ||
+ | takt10ms = true; // Botschaft 10ms senden | ||
+ | --hundertstel; | ||
+ | |||
+ | if (hundertstel==0) // | ||
+ | { | ||
+ | hundertstel = HUNDERTSTEL_WERT; | ||
+ | takt100ms = true; // Botschaft 100ms senden | ||
+ | --zehntel; | ||
+ | |||
+ | if (zehntel==0) // | ||
+ | { | ||
+ | zehntel = ZEHNTEL_WERT; | ||
+ | takt1s = true; // Botschaft 1s senden | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // ADWandlung ============================================================== | ||
+ | // | ||
+ | // Durchfuehrung einer Einzelwandlung der am NTC-Spannungsteiler anstehenden | ||
+ | // Spannung in einen digitalen 10-bit-Wert (einmal pro 100 ms). | ||
+ | void doAdc() | ||
+ | { | ||
+ | ADCSRA |= (1<< | ||
+ | while (ADCSRA & (1<< | ||
+ | |||
+ | adcValue = ADCL + (ADCH<< | ||
+ | // | ||
+ | // | ||
+ | } | ||
+ | |||
+ | // Umrechnung ============================================================== | ||
+ | // | ||
+ | // (wird alle 100 ms aufgerufen) | ||
+ | void calculateTemp () | ||
+ | { | ||
+ | unsigned char index; | ||
+ | unsigned char steps; | ||
+ | // | ||
+ | |||
+ | index = (adcValue-256)/ | ||
+ | steps = (adcValue-256)%16; | ||
+ | |||
+ | tValue = steps * (TEMP[index+1] - TEMP[index])/ | ||
+ | // | ||
+ | |||
+ | if(tValue> | ||
+ | { | ||
+ | tValueMax = tValue; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Anzeigetreiber fuer Temperaturanzeige ============================================================== | ||
+ | // | ||
+ | // Beschreiben der Anzeige mit dem erstellten Temperaturwert | ||
+ | // und mit dem maximalen Wert (wird alle 1 s aufgerufen). | ||
+ | // | ||
+ | // Umrechnung der Zahlenwerte (1/10 °C) in Anzeigewerte wie folgt: | ||
+ | // Hunderter: einfache Integer-Teilung (/100). | ||
+ | // Zehner: Modulo-Ermittlung (%100), d.h. Rest bei der Teilung durch 100 | ||
+ | // dann nochmals Integer-Teilung (/10) dieses Restes. | ||
+ | // Einer: | ||
+ | // | ||
+ | // Umrechnung in ASCII-Werte fuer die Anzeige durch Addition von 0x30. | ||
+ | void refreshDisplayTemp(int tempValue, char line, char pos) | ||
+ | { | ||
+ | lcd_gotoxy(line, | ||
+ | if (tempValue> | ||
+ | { | ||
+ | wort[0] = ' '; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | wort[0] = ' | ||
+ | tempValue = -tempValue; | ||
+ | } | ||
+ | wort[1] = tempValue/ | ||
+ | tempValue = tempValue%100; | ||
+ | wort[2] = tempValue/ | ||
+ | wort[3] = ASC_FULL_STOP; | ||
+ | wort[4] = tempValue%10 + ASC_NULL; | ||
+ | wort[5] = 0; | ||
+ | lcd_putstr | ||
+ | } | ||
+ | |||
+ | // Anzeigefunktion ============================================================== | ||
+ | // | ||
+ | // Der aktuelle Temperatur und die maximale Temperatur werden ausgegeben | ||
+ | void refreshDisplay() | ||
+ | { | ||
+ | refreshDisplayTemp(tValueMax, | ||
+ | refreshDisplayTemp(tValue, | ||
+ | } | ||
+ | |||
+ | // Initialisierung Display-Anzeige ============================================================== | ||
+ | // | ||
+ | void initDisplay() // | ||
+ | { | ||
+ | lcd_init(); | ||
+ | |||
+ | lcd_displayMessage(" | ||
+ | lcd_displayMessage(" | ||
+ | |||
+ | _delay_ms(2000); | ||
+ | |||
+ | lcd_displayMessage(" | ||
+ | lcd_displayMessage(" | ||
+ | // | ||
+ | } // | ||
+ | |||
+ | void initUart (void) // Initialisierung der UART-Register | ||
+ | { | ||
+ | UBRR0H = UBRR_VAL >> 8; // High-Baudraten-Register beschreiben | ||
+ | UBRR0L = UBRR_VAL & 0xFF; // Low-Baudraten-Register beschreiben | ||
+ | |||
+ | UCSR0B = (1<< | ||
+ | UCSR0C = (1<< | ||
+ | } | ||
+ | |||
+ | |||
+ | ISR(USART_RX_vect) // Interrupt Routine für das Empfangen | ||
+ | { | ||
+ | char data = UDR0; // Daten auslesen, um Interruptflag zu loeschen | ||
+ | if (data==' | ||
+ | } | ||
+ | |||
+ | ISR(USART_UDRE_vect) // Interrupt Routine für das Senden | ||
+ | { | ||
+ | static char* uart_tx_p = uart_tx_buffer; | ||
+ | char data = *uart_tx_p++; | ||
+ | |||
+ | if (data==0 ) // Am Ende der Eingabe | ||
+ | { | ||
+ | UCSR0B &= ~(1<< | ||
+ | uart_tx_p = uart_tx_buffer; | ||
+ | DataTransferFinished = 1; // Flag für Senden setzen | ||
+ | } | ||
+ | else UDR0 = data; | ||
+ | } | ||
+ | |||
+ | void putData(char *data) // Daten senden | ||
+ | { | ||
+ | if (DataTransferFinished==1) // | ||
+ | { | ||
+ | DataTransferFinished = 0; // Flag für Senden löschen | ||
+ | strcpy(uart_tx_buffer, | ||
+ | UCSR0B |= (1<< | ||
+ | } | ||
+ | }</ | ||
+ | |||
+ | <-- | ||
+ | |||
+ | |||
+ | <WRAP onlyprint> | ||
+ | Unvollständige [[http:// | ||
+ | |||
+ | </ | ||
+ | |||
+ | Bitte arbeiten Sie folgende Aufgaben durch: | ||
+ | |||
+ | --> Aufgabe# | ||
+ | |||
+ | Versuchen Sie die folgenden Zeitverlauf des UART Signals zu entschlüsseln - es kam vom vorliegenden Programm. \\ Welche neun Zeichen wurden gesendet? | ||
+ | |||
+ | <-- | ||
- | Zu Beachten: | ||
- | * Display an einem anderen Port --> muss in lcd_lib geändert werden |