Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
microcontrollertechnik:8_temperatur [2020/10/18 16:02] tfischer |
microcontrollertechnik:8_temperatur [2024/04/23 01:23] (aktuell) mexleadmin |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== 8. Temperatur-Messung und Analog-Digital-Wandler ====== | + | ====== 8 Temperatur-Messung und Analog-Digital-Wandler ====== |
- | ===== ADC - wie kommt mehr als nur ein Bit über einen Pin? ===== | ||
<WRAP group> | <WRAP group> | ||
<WRAP column 30%> | <WRAP column 30%> | ||
- | ==== Ziele ==== | + | ===== Ziele ===== |
Nach dieser Lektion sollten Sie: | Nach dieser Lektion sollten Sie: | ||
Zeile 11: | Zeile 10: | ||
- wissen, wie ein ADC genutzt wird | - wissen, wie ein ADC genutzt wird | ||
- | ==== weiterführende Links ==== | + | ===== weiterführende Links ===== |
- | * Eine [[http://katgym.by.lo-net2.de/c.wolfseher/ | + | * Eine [[https://www.katharinengymnasium.de/wolf/ |
- | </ | + | </ |
- | ==== Video ==== | + | ===== Video ===== |
+ | {{youtube> | ||
+ | |||
+ | <WRAP hide> | ||
{{youtube> | {{youtube> | ||
+ | </ | ||
</ | </ | ||
- | ==== Messsignal-Digitalisierung und Auswertung ==== | + | <WRAP > |
+ | < | ||
+ | </ | ||
+ | {{drawio> | ||
+ | </ | ||
+ | ===== Messsignal-Digitalisierung und Auswertung | ||
<WRAP right> | <WRAP right> | ||
< | < | ||
</ | </ | ||
- | {{drawio> | + | {{drawio> |
</ | </ | ||
Um Sensorwerte in C sinnvoll nutzen zu können sind einige Schritte zwischen dem passiven Sensor über den ADC bis in den Code umzusetzen (siehe <imgref BildNr1> | Um Sensorwerte in C sinnvoll nutzen zu können sind einige Schritte zwischen dem passiven Sensor über den ADC bis in den Code umzusetzen (siehe <imgref BildNr1> | ||
- | - Sensor: \\ Umwandlung der physikalischen Größe in ein Messsignal | + | - Sensor: |
- | - Sensorschaltung: | + | - Sensorschaltung: |
- | - ADC: \\ Digitalisierung in ein Zahlenwert im Code | + | - ADC: $V_{\rm NTC} \rightarrow adcValue$\\ Digitalisierung in ein Zahlenwert im Code \\ \\ |
- | - Aufbereitung im Code \\ um ein Abbild des Sensorwerts zu erhalten | + | - Aufbereitung im Code $adcValue \rightarrow tValue$ |
~~PAGEBREAK~~ ~~CLEARFIX~~ | ~~PAGEBREAK~~ ~~CLEARFIX~~ | ||
Zeile 39: | Zeile 47: | ||
<WRAP group>< | <WRAP group>< | ||
< | < | ||
- | ^Temperatur\\ $T$ ^Widerstandswert $R_{NTC}$^ | + | ^Temperatur\\ $T$ ^Widerstandswert $R_{\rm NTC}$^ |
- | |$5°C$ | + | |$5° \rm C$ |
- | |$10°C$ |$9,34k\Omega$ | + | |$10°\rm C$ |
- | |$15°C$ |$7,37k\Omega$ | + | |$15°\rm C$ |
- | | ... | ... | | + | | ... |
</ | </ | ||
</ | </ | ||
< | < | ||
- | ^ADC-Wert \\ $ad_wert$ ^Temperatur \\ $T$ ^ | + | ^ADC-Wert \\ $adcValue$ ^Temperatur \\ $T$ ^ |
- | |$256$ | + | |$256$ |
- | |$272$ | + | |$272$ |
- | |$288$ | + | |$288$ |
- | | ... | ... | | + | | ... | ... | |
</ | </ | ||
</ | </ | ||
Zeile 65: | Zeile 73: | ||
~~PAGEBREAK~~ ~~CLEARFIX~~ | ~~PAGEBREAK~~ ~~CLEARFIX~~ | ||
- | === 1.a Umwandlung der physikalischen Größe in ein Messsignal (Sensorwert zu Widerstandswert) === | + | ==== 1.a Umwandlung der physikalischen Größe in ein Messsignal (Sensorwert zu Widerstandswert) |
* Bei vielen passiven Sensoren wird der Sensorwert in eine Widerstandsänderung umgewandelt. Die Relation von Sensorwert zu Widerstandswert ist im Datenblatt des Sensors angegeben. | * Bei vielen passiven Sensoren wird der Sensorwert in eine Widerstandsänderung umgewandelt. Die Relation von Sensorwert zu Widerstandswert ist im Datenblatt des Sensors angegeben. | ||
* Das Datenblatt der gewünschten Komponente (hier: {{vishay_bccomponents-238164066103-datasheet.pdf|Thermistors 2381 640 6472}}) ist im Internet zu finden. | * Das Datenblatt der gewünschten Komponente (hier: {{vishay_bccomponents-238164066103-datasheet.pdf|Thermistors 2381 640 6472}}) ist im Internet zu finden. | ||
- | * Suchen Sie dort nach dem gewünschten Komponente (hier Thermistor 2381 640 6472). Beachten Sie, das manche Datenblätter eine andere Sortierung / Benamung nutzen, als sie von den Distributoren genutzt wird. Im konkreten Fall hilft eine Suche nach den letzten drei Ziffern " | + | |
+ | | ||
<callout title=" | <callout title=" | ||
Zeile 87: | Zeile 96: | ||
</ | </ | ||
- | === 2. + 3. Relation von Widerstandswert zu ADC-Wert === | + | ==== 2. + 3. Relation von Widerstandswert zu ADC-Wert |
<WRAP right> | <WRAP right> | ||
< | < | ||
</ | </ | ||
- | {{drawio> | + | {{drawio> |
</ | </ | ||
Zeile 101: | Zeile 110: | ||
Die Spannung am ADC lässt sich leicht über den Widerstandswert berechnen: | Die Spannung am ADC lässt sich leicht über den Widerstandswert berechnen: | ||
- | \begin{align} {{V_{NTC}} \over {V_{CC}}} = {{R_{NTC}}\over{R_{NTC} + R_{pullup}}} \tag{8.1} \end{align} | + | \begin{align} {{V_{\rm NTC}} \over {V_{\rm CC}}} = {{R_{\rm NTC}}\over{R_{\rm NTC} + R_{\rm pullup}}} \tag{8.1} \end{align} |
- | \begin{align} ADCwert = round \left({{V_{NTC}}\over{V_{CC}}} \cdot 1024 \right) \tag{8.2} \end{align} | + | Daraus ergibt sich der digitalisierte Wert zu |
+ | |||
+ | \begin{align} ADCwert = {\rm round} \left({{V_{\rm NTC}}\over{V_{\rm CC}}} \cdot 1024 \right) \tag{8.2} \end{align} | ||
aus $(8.1)$ und $(8.2)$ ergibt sich | aus $(8.1)$ und $(8.2)$ ergibt sich | ||
- | \begin{align} ADCwert = round \left({{R_{NTC}}\over{R_{NTC} + R_{pullup}}} \cdot 1024 \right) \tag{8.3} \end{align} | + | \begin{align} ADCwert = {\rm round} \left({{R_{\rm NTC}}\over{R_{\rm NTC} + R_{\rm pullup}}} \cdot 1024 \right) \tag{8.3} \end{align} |
- | + | ||
+ | Diese Relation muss nun im Analyse-Tool abgebildet werden und wurde in {{microcontrollertechnik: | ||
+ | * Benamung von Zellen und Bereichen: Für viele Zellen wurden Namen vergeben, z.B. Zelle J2 in Tabelle 1 erhielt die Benamung $V\_CC$ oder der Bereich E7:E45 die Benamung $R\_NTC$. | ||
+ | * Rechnen mit Bereichen: In den Zellen F7 und G7 in Tabelle 1 wurden mit Angabe der Bereichsnamen Formeln eingefügt. Damit entfällt das Auffüllen der weiteren Zeilen | ||
+ | * Einfügen einer Trendlinie: Für das Diagramm wurde ADCval als x-Werte und $R\_NTC$ als y-Werte verwendet. Für die Trendlinie wurde ein Polynom 4. Grades genutzt. Mit Anzeige der Trendlinien-Formel wird die Relation von Widerstandswert zu ADC-Wert sichtbar. Die Zahl-Eigenschaft der Trendlinienbeschriftung sollte dabei auf '' | ||
+ | |||
+ | ==== 4. Aufbereitung der des ADC-Werts im Code ==== | ||
+ | |||
+ | Mit den bisherigen Betrachtungen ist zwar klar, wie die Relation von Widerstandswert zu ADC-Wert aussieht, aber diese ist noch nicht im Code umgesetzt. Zunächst sollte der notwendige Wertebereich geklärt werden: In welchem Bereich werden Messwerte erwartet? In diesem Konkreten Fall geht es um die Innenraumtemperatur. Damit wird die Temperatur im Bereich $[-30°\rm C, 50°\rm C]$ sein. | ||
+ | |||
+ | \\ \\ | ||
+ | == direkte Verwendung der Datenblattwerte == | ||
+ | <WRAP group>< | ||
+ | Die einfachste Variante wäre die vorhandenen Daten aus dem Datenblatt direkt zu nehmen und zu prüfen, ob der eingelesene tValue zwischen zwei bekannten Werten liegt. | ||
+ | |||
+ | <sxh c; first-line: 42> | ||
+ | |||
+ | # | ||
+ | |||
+ | const int TEMP[MAX_INDEX] | ||
+ | const int ADC_VAL[MAX_INDEX] ={ 968, 950, 927, 899, 866, 827, 783, 734, 681, 625, 568, 512, 456, 404, 356, 311, 271}; | ||
+ | // Datenwerte aus dem Datenblatt | ||
+ | // TEMP[] enthaelt die Temperaturen | ||
+ | // In ADC_VAL[] sind die den Temperaturen | ||
+ | // entsprechenden ADC-Werte abgespeichert | ||
+ | ... | ||
+ | for(int index=0; index< | ||
+ | { | ||
+ | | ||
+ | if (tValue >= ADC_VAL[index]) break; // wenn gefunden, breche ab | ||
+ | }; | ||
+ | int tValue = TEMP[index];// | ||
+ | ... // gefundenen index wird zugewiesen | ||
+ | </ | ||
+ | |||
+ | |||
+ | </ | ||
+ | <WRAP column 35%> | ||
+ | < | ||
+ | </ | ||
+ | {{drawio> | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Nachteil dabei ist, dass die Ausführung unterschiedlich lange benötigt und die Auflösung nur 5°C beträgt (vgl. <imgref BildNr2> | ||
+ | |||
+ | \\ \\ | ||
+ | === direkte Verwendung der Datenblattwerte mit Interpolation === | ||
+ | |||
+ | <WRAP group> | ||
+ | <WRAP column 60%> | ||
+ | In einem weiteren Schritt könnte eine Interpolation zwischen den Werten umgesetzt werden | ||
+ | |||
+ | <sxh c; first-line: 42> | ||
+ | |||
+ | |||
+ | # | ||
+ | |||
+ | const int TEMP[MAX_INDEX] | ||
+ | const int ADC_VAL[MAX_INDEX] ={ 968, 950, 927, 899, 866, 827, 783, 734, 681, 625, 568, 512, 456, 404, 356, 311, 271}; | ||
+ | // Datenwerte aus dem Datenblatt | ||
+ | // TEMP[] enthaelt die Temperaturen | ||
+ | // In ADC_VAL[] sind die den Temperaturen | ||
+ | // entsprechenden ADC-Werte abgespeichert | ||
+ | ... | ||
+ | for(int index=0; index< | ||
+ | { | ||
+ | | ||
+ | if (tValue >= ADC_VAL[index]) break; // wenn gefunden, breche ab | ||
+ | }; | ||
+ | int t_uW = TEMP[index]; | ||
+ | | ||
+ | int t_oW = TEMP[index+1];// | ||
+ | | ||
+ | |||
+ | int ADC_uW = ADC_VAL[index];// | ||
+ | | ||
+ | int ADC_oW = ADC_VAL[index+1];// | ||
+ | | ||
+ | |||
+ | float tValue = TEMP[index] + | ||
+ | 5 * (tValue - ADC_uW ) / (ADC_oW - ADC_uW ) ; | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | ... | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | <WRAP column 35%> | ||
+ | < | ||
+ | </ | ||
+ | {{drawio> | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Die Auflösung ist nun sehr genau (vgl. <imgref BildNr3> | ||
+ | |||
+ | Der float-Wert kann umgangen werden, wenn im gesamten Programm die Temperaturwerte in Zehntel-Grad geschrieben werden. Also $37,5°\rm C \rightarrow$ 375. Dann kann ein tValue als signed integer geschrieben werden. | ||
+ | |||
+ | \\ \\ | ||
+ | === Umrechnung der Datenblattwerte === | ||
+ | |||
+ | <WRAP group> | ||
+ | <WRAP column 60%> | ||
+ | |||
+ | Eine geschicktere Option ist es, den Temperatur-Array '' | ||
+ | * Betrachtet man die obige Tabelle '' | ||
+ | * Statt die restlichen Werte in Einzelschritten abzuspeichern, | ||
+ | |||
+ | Der Index kann damit als '' | ||
+ | |||
+ | |||
+ | </ | ||
+ | <WRAP column 35%> | ||
+ | < | ||
+ | </ | ||
+ | {{drawio> | ||
+ | </ | ||
+ | </ | ||
+ | |||
~~PAGEBREAK~~ ~~CLEARFIX~~ | ~~PAGEBREAK~~ ~~CLEARFIX~~ | ||
- | ==== Übung ==== | + | ===== Übung |
--> I. Vorarbeiten # | --> I. Vorarbeiten # | ||
- | - Laden Sie folgende Datei herunter: | + | - Laden Sie folgenden Dateien |
- | - {{microcontrollertechnik: | + | - {{microcontrollertechnik: |
- | - {{microcontrollertechnik: | + | - {{microcontrollertechnik: |
- {{microcontrollertechnik: | - {{microcontrollertechnik: | ||
+ | |||
+ | \\ \\ | ||
+ | <callout type=" | ||
+ | |||
+ | **Beachten Sie, folgendes** | ||
+ | * Es wird nun ein ATmega328 genutzt, d.h. das Programm ist nicht mehr kompatibel mit dem MiniMEXLE! | ||
+ | * Das Display ist nunan einem anderen Port um den Analog-Digial-Wandler am Port C zu nutzen. \\ Deshalb muss der Treiber '' | ||
+ | * Zeile 26: ''# | ||
+ | * Zeile 39: ''# | ||
+ | * Zeile 40: ''# | ||
+ | * Zeile 44: ''# | ||
+ | * Zeile 46: ''# | ||
+ | |||
+ | </ | ||
+ | \\ \\ | ||
+ | |||
+ | |||
<-- | <-- | ||
--> II. Analyse des fertigen Programms # | --> II. Analyse des fertigen Programms # | ||
- Initialisieren des Programms | - Initialisieren des Programms | ||
- | - Öffnen Sie SimulIDE und öffnen Sie dort mittels {{microcontrollertechnik: | + | - Öffnen Sie SimulIDE |
- | - Laden Sie '' | + | - Laden Sie '' |
- Zunächst wird eine Startanzeige mit dem Namen des Programms dargestellt. | - Zunächst wird eine Startanzeige mit dem Namen des Programms dargestellt. | ||
- | - Als nächstes | + | - Als nächstes |
- | - Die Tasten '' | + | - Der Drehregler neben dem NTC ermöglicht es die Temperatur des NTC zu verändern. |
<-- | <-- | ||
- | --> III. Eingabe in Atmel Studio # | + | --> III. Eingabe in Microchip |
+ | |||
<WRAP group>< | <WRAP group>< | ||
/* ---------------------------------------------------------------------------- | /* ---------------------------------------------------------------------------- | ||
- | + | ||
- | | + | |
| | ||
+ | |||
| | ||
+ | | ||
+ | | ||
+ | Prof. G. Gruhler | ||
+ | D. Chilachava | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | AVR-USB-PROGI Ver. 2.0 | ||
- | Autoren : Peter Blinzinger | + | Software: |
- | Prof. G. Gruhler (Hochschule Heilbronn, Fakultät T1) | + | |
- | D. Chilachava (Georgische Technische Universität) | + | |
- | | + | |
- | Datum : 01.05.2020 | + | |
- | Version : 1.1 | + | Funktion |
+ | Maximaltemperatur im Betriebszeitraum in °C mit 1/10 Grad. | ||
+ | Keine Tastenbedienung | ||
+ | |||
+ | | ||
+ | | ||
+ | |- Experiment 8 -| | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | 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 | ||
+ | Timer-Vorteiler | ||
+ | Hardware-Timer | ||
+ | Software-Vorteiler | ||
+ | Hundertstel-Zaehler / 10 => 10 Hz / 100 ms | ||
+ | Zehntel-Zaehler | ||
- | | ||
- | 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 für Temperatur | ||
- | 4) Anzeigetreiber (Takt: 1 s) | ||
- | |||
- | 1) Das Modul " | ||
- | und Umrechnung und einen zusätzlichen Takt von 1 s für 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 " | 2) Das Modul " | ||
Der AD-Wandler wird mit einem internen Takt von 96 kHz betrieben. | Der AD-Wandler wird mit einem internen Takt von 96 kHz betrieben. | ||
- | | + | |
- | | + | |
- | als temperaturabhängiger | + | als temperaturabhaengiger |
Als Referenzspannung wird die 5V-Versorgung verwendet. | Als Referenzspannung wird die 5V-Versorgung verwendet. | ||
- | Das Ergebnis wird in der globalen Variable | + | Das Ergebnis wird in der globalen Variable |
+ | |||
3) Das Modul " | 3) Das Modul " | ||
Der Ergebniswert des Moduls " | Der Ergebniswert des Moduls " | ||
einen entsprechenden Temperaturwert umgerechnet. In der Tabelle sind | einen entsprechenden Temperaturwert umgerechnet. In der Tabelle sind | ||
- | Temperaturwerte | + | Temperaturwerte |
- | | + | Die Werte dazwischen werden mit linearer Interpolation ermittelt. |
Weiterhin wird im Modul jede aktuelle Temperatur mit der gespeicherten | Weiterhin wird im Modul jede aktuelle Temperatur mit der gespeicherten | ||
- | | + | |
+ | |||
4) Das Modul " | 4) Das Modul " | ||
zu schnelles Umschalten der Anzeigewerte vermieden. Das Modul gibt die | zu schnelles Umschalten der Anzeigewerte vermieden. Das Modul gibt die | ||
Werte der aktuellen und der maximalen Temperatur in 1/10 °C aus. | Werte der aktuellen und der maximalen Temperatur in 1/10 °C aus. | ||
- | | + | |
- | | + | Zwischen AD-Wandlung / Umrechnung und Anzeige kann spaeter |
- | | + | Mittelwertsbildung mit 10 Werten |
+ | |||
+ | Die Kopplung der Module wird ueber global definierte Variable realisiert: | ||
+ | |||
+ | 1-Bit-Variable: | ||
+ | => Umrechnung | ||
+ | Takt | ||
+ | |||
+ | 16-Bit-Variable: | ||
+ | t-wert | ||
+ | tmax-wert | ||
- | Die Kopplung der Module wird über global definierte Variable realisiert: | ||
- | |||
- | | ||
- | | ||
- | Takt | ||
- | |||
- | 16-Bit-Variable: | ||
- | t-wert Umrechnung => Anzeige | ||
- | tmax-wert Umrechnung => Anzeige | ||
- | |||
// ----------------------------------------------------------------------------*/ | // ----------------------------------------------------------------------------*/ | ||
+ | |||
// Deklarationen ============================================================== | // Deklarationen ============================================================== | ||
+ | |||
// Festlegung der Quarzfrequenz | // Festlegung der Quarzfrequenz | ||
- | #ifndef F_CPU // optional definieren | + | #ifndef F_CPU |
- | #define F_CPU 12288000UL // MiniMEXLE | + | #define F_CPU 12288000UL |
- | #endif | + | # |
+ | |||
// Include von Header-Dateien | // Include von Header-Dateien | ||
- | #include < | + | #include < |
- | #include < | + | #include < |
- | #include < | + | #include < |
- | #include < | + | #include " |
- | #include " | + | |
// Konstanten | // Konstanten | ||
- | # | + | # |
- | # | + | # |
- | # | + | # |
- | const int TEMP[45] = {521, | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | |||
- | // Die Tabellenwerte sind in 1/10 °C angegeben | ||
- | // Der erste Tabellenwert entspricht einem AD-Wert | ||
- | // von 256. Die Abstände der AD-Werte sind 16 | ||
+ | #define ASC_NULL | ||
+ | #define ASC_FULL_STOP | ||
+ | |||
+ | const int | ||
+ | 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 | // Variable | ||
- | unsigned char vorteiler = VORTEILER_WERT; // Zählvariable | + | unsigned char softwarePrescaler |
- | unsigned char hundertstel = HUNDERTSTEL_WERT; | + | unsigned char cycle10msCount |
- | unsigned char zehntel | + | unsigned char cycle100msCount |
- | + | ||
- | unsigned int ad_wert | + | unsigned int |
- | int t_wert=0; // Variable | + | int tValue |
- | int tmax_wert=-300; // Variable | + | int tValueMax |
- | + | ||
- | bool takt10ms; // Bit-Botschaft alle 10 ms | + | bool |
- | bool takt100ms; // Bit-Botschaft alle 100 ms | + | bool |
- | bool takt1s; // Bit-Botschaft alle 1s | + | bool |
+ | |||
// | // | ||
void initTimer0 (void); | void initTimer0 (void); | ||
- | void adWandlerInit (void); | + | void initAdc |
- | void adWandlung (void); | + | |
- | void umrechnung (void); | + | |
- | void anzeigeTreiber | + | |
void initDisplay (void); | void initDisplay (void); | ||
- | + | void doAdc (void); | |
- | // Initialisierung und Hauptprogramm | + | void calculateTemp (void); |
- | // ============================================================================ | + | void refreshDisplayTemp(int tempValue, char line, char pos); |
+ | void refreshDisplay (void); | ||
+ | |||
+ | // Hauptprogramm | ||
int main () | int main () | ||
{ | { | ||
- | initDisplay(); | + | |
- | initTimer0(); | + | initTimer0(); |
- | adWandlerInit(); // Initialisierung des AD-Wandlers | + | |
- | + | ||
- | sei(); // generell Interrupts einschalten | + | sei(); |
- | + | | |
- | + | // Hauptprogrammschleife __________________________________________________ | |
- | // Hauptprogrammschleife __________________________________________________ | + | |
- | + | while(1) | |
- | while(1) // unendliche Warteschleife mit Aufruf der | + | // Funktionen |
- | // Funktionen | + | { |
- | { | + | if(cycle100msActive) // Durchfuehrung |
- | if(takt100ms == true) // Durchführung | + | { |
- | { | + | |
- | takt100ms | + | doAdc(); // Ausfuehrung |
- | adWandlung(); // Ausführung | + | |
- | umrechnung(); // Ausführung | + | } |
- | } | + | |
- | + | if(cycle1sActive) | |
- | if(takt1s == true) // Durchführung | + | { |
- | { | + | |
- | takt1s | + | |
- | anzeigeTreiber(); | + | } |
- | } | + | } |
- | } | + | |
} | } | ||
- | + | ||
- | // Funktionen | + | |
- | + | // Timer Initialisierung | |
- | // Timer-Initialisierung: | + | |
- | // --------------------- | + | |
// | // | ||
// Initialisierung des Timer0 zur Erzeugung eines getakteten Interrupts. | // Initialisierung des Timer0 zur Erzeugung eines getakteten Interrupts. | ||
- | // Er dient dazu, die benötigten | + | // Er dient dazu, die benoetigten |
void initTimer0() | void initTimer0() | ||
{ | { | ||
- | TCCR0A |= (0<< | + | |
- | TCCR0B |= (0<< | + | |
- | TIMSK0 |= (1<< | + | TCCR0B |
+ | | ||
+ | TIMSK0 | ||
} | } | ||
- | + | ||
- | // A/D-Wandler-Initialisierung: | + | // ADC-Initialisierung |
- | // --------------------------- | + | // |
// Initialisierung des A/ | // Initialisierung des A/ | ||
// Vorteiler = 128 => interner Takt = 96 kHz | // Vorteiler = 128 => interner Takt = 96 kHz | ||
// Abfrage des ADC0 (NTC-Spannungsteiler) | // Abfrage des ADC0 (NTC-Spannungsteiler) | ||
// Referenzspannung = analoge Versorgung Avcc | // Referenzspannung = analoge Versorgung Avcc | ||
- | + | void initAdc() | |
- | void adWandlerInit | + | |
{ | { | ||
- | ADMUX |= (1<< | + | |
- | + | ||
- | ADCSRA |= (1<< | + | ADCSRA |
+ | | ||
+ | | ||
+ | | ||
+ | (void) ADCH; // erster Wert ist " | ||
} | } | ||
- | + | ||
- | + | ||
- | // Interrupt-Routine | + | // Timer-Service |
- | // ============================================================================ | + | // |
- | ISR (TIMER0_OVF_vect) | + | |
// In der Interrupt-Routine sind die Softwareteiler realisiert, die die Takt- | // In der Interrupt-Routine sind die Softwareteiler realisiert, die die Takt- | ||
- | // botschaften (10ms, 100ms, 1s) für die Module erzeugen. Die Interrupts | + | // botschaften (10ms, 100ms, 1s) fuer die Module erzeugen. Die Interrupts |
- | // werden von Timer 0 ausgelöst | + | // werden von Timer 0 ausgeloest |
// | // | ||
- | // Veränderte | + | // Veraenderte |
- | // hunderstel | + | // hunderstel |
- | // zehntel | + | // zehntel |
// | // | ||
- | // Ausgangsvariable: | + | // Ausgangsvariable: |
- | // takt100ms | + | // takt100ms |
- | // takt1s | + | // takt1s |
+ | |||
+ | ISR (TIMER0_OVF_vect) | ||
{ | { | ||
- | --vorteiler; // Vorteiler dekrementieren | + | |
- | if (vorteiler==0) // wenn 0 erreicht: 10ms abgelaufen | + | if (softwarePrescaler==0) // wenn 0 erreicht: 10ms abgelaufen |
- | { | + | { |
- | vorteiler | + | |
- | takt10ms | + | |
- | --hundertstel; // Hundertstelzähler | + | --cycle10msCount; // Hundertstelzaehler |
- | + | ||
- | if (hundertstel==0) // wenn 0 erreicht: 100ms abgelaufen | + | if (cycle10msCount==0) // wenn 0 erreicht: 100ms abgelaufen |
- | { | + | { |
- | hundertstel | + | |
- | takt100ms | + | |
- | --zehntel; | + | --cycle100msCount; |
- | + | ||
- | if (zehntel==0) // Zehntelzähler | + | if (cycle100msCount==0) |
- | { | + | { |
- | zehntel | + | |
- | takt1s | + | |
- | } | + | } |
- | } | + | } |
- | } | + | } |
} | } | ||
- | + | ||
- | // Modul ADWandlung: | + | // ADWandlung |
- | // ---------------- | + | // |
- | // Durchführung | + | // Durchfuehrung |
// Spannung in einen digitalen 10-bit-Wert (einmal pro 100 ms). | // Spannung in einen digitalen 10-bit-Wert (einmal pro 100 ms). | ||
- | void adWandlung() | + | void doAdc() |
{ | { | ||
- | ADCSRA |= (1<< | + | |
- | while (ADCSRA & (1<< | + | while (ADCSRA & (1<< |
- | + | ||
- | ad_wert | + | |
// | // | ||
// | // | ||
} | } | ||
- | + | ||
- | // Modul Umrechnung: | + | // Umrechnung |
- | // -------------------- | + | // |
// (wird alle 100 ms aufgerufen) | // (wird alle 100 ms aufgerufen) | ||
- | void umrechnung | + | void calculateTemp |
{ | { | ||
- | unsigned char index; // Tabellenindex | + | |
- | unsigned char abschnitt; // Abstand zum nächstkleineren | + | unsigned char steps; // Abstand zum naechstkleineren |
- | // der AD-Werte der Temperaturtabelle | + | // der AD-Werte der Temperaturtabelle |
- | + | | |
- | index = (ad_wert-256)/16; // Indexberechnung (Zeiger in Tabelle) | + | index |
- | abschnitt | + | |
- | + | | |
- | t_wert | + | |
- | // Temperaturwert berechnen | + | // Temperaturwert berechnen |
- | + | ||
- | if(t_wert>=tmax_wert) // aktueller Wert mit Maximalwert | + | if(tValue>=tValueMax) |
- | { | + | { |
- | tmax_wert | + | |
- | } | + | } |
} | } | ||
- | + | ||
- | // Modul Anzeigetreiber: | + | // Anzeigefunktion ============================================================== |
- | // -------------------- | + | // |
+ | // Der aktuelle Temperatur und die maximale Temperatur werden ausgegeben | ||
+ | void refreshDisplay() | ||
+ | { | ||
+ | refreshDisplayTemp(tValue, | ||
+ | refreshDisplayTemp(tValueMax, | ||
+ | } | ||
+ | |||
+ | // Anzeigetreiber fuer Temperaturanzeige ============================================================== | ||
// | // | ||
// Beschreiben der Anzeige mit dem erstellten Temperaturwert | // Beschreiben der Anzeige mit dem erstellten Temperaturwert | ||
Zeile 414: | Zeile 580: | ||
// Hunderter: einfache Integer-Teilung (/100). | // Hunderter: einfache Integer-Teilung (/100). | ||
// Zehner: Modulo-Ermittlung (%100), d.h. Rest bei der Teilung durch 100 | // Zehner: Modulo-Ermittlung (%100), d.h. Rest bei der Teilung durch 100 | ||
- | // dann nochmals Integer-Teilung (/10) dieses Restes. | + | // |
// Einer: | // Einer: | ||
// | // | ||
- | // Umrechnung in ASCII-Werte | + | // Umrechnung in ASCII-Werte |
- | void tempAnzeige(int ausgabewert, char zeile, char spalte) | + | void refreshDisplayTemp(int tempValue, char line, char pos) |
{ | { | ||
- | int i; | + | |
- | + | if (tempValue> | |
- | i = ausgabewert; | + | { |
- | lcd_gotoxy(zeile, spalte); // Startposition | + | lcd_putc(' |
- | if (i> | + | } |
- | { | + | else |
- | lcd_putc(' | + | { |
- | } | + | lcd_putc(' |
- | else | + | |
- | { | + | } |
- | lcd_putc(' | + | lcd_putc |
- | i = -i; // Vorzeichenumkehr bei negativer Zahl | + | |
- | } | + | lcd_putc |
- | lcd_putc(i/100 + 0x30); // Hunderter ausgeben (°C Zehner) | + | lcd_putc |
- | i = i%100; | + | lcd_putc |
- | lcd_putc(i/10 + 0x30); // Zehner ausgeben (°C Einer) | + | |
- | lcd_putc(0x2E); // Punkt ausgeben | + | |
- | lcd_putc(i%10 + 0x30); // Einer ausgeben (°C Zehntel) | + | |
} | } | ||
- | + | ||
- | // Anzeigefunktion | + | // Initialisierung Display-Anzeige ============================================================== |
- | // --------------- | + | |
// | // | ||
- | // Der aktuelle Temperatur und die maximale Temperatur werden ausgegeben | + | void initDisplay() // Start der Funktion |
- | void anzeigeTreiber() | + | |
{ | { | ||
- | tempAnzeige(t_wert, | + | |
- | tempAnzeige(tmax_wert, | + | |
- | } | + | |
- | + | | |
- | // Initialisierung Display-Anzeige | + | |
- | void initDisplay() // | + | _delay_ms(2000); |
- | { | + | |
- | lcd_init(); | + | |
- | + | | |
- | lcd_gotoxy(0, | + | // " |
- | lcd_putstr("- Experiment 8 -"); // Ausgabe Festtext: 16 Zeichen | + | } |
- | + | ||
- | lcd_gotoxy(1,0); // Cursor auf 2. Zeile, 1. Zeichen | + | |
- | lcd_putstr(" | + | |
- | + | ||
- | _delay_ms(2000); | + | |
- | + | ||
- | lcd_gotoxy(0, | + | |
- | lcd_putstr(" | + | |
- | // " | + | |
- | + | ||
- | lcd_gotoxy(1,0); // Cursor auf 2. Zeile, 1. Zeichen | + | |
- | lcd_putstr(" | + | |
- | // " | + | |
- | } // Ende der Funktion | + | |
</ | </ | ||
</ | </ | ||
Zeile 477: | Zeile 623: | ||
''/ | ''/ | ||
- | Ändern Sie auch hier wieder die Beschreibung am Anfang des C-Files, je nachdem was Sie entwickeln | + | Ändern Sie auch hier wieder die Beschreibung am Anfang des C-Files, je nachdem was Sie entwickeln |
'' | '' | ||
\\ \\ | \\ \\ | ||
- Hier wird wieder geprüft ob die Frequenz des Quarz bereits eingestellt wurde und - falls nicht - dessen Frequenz eingestellt. \\ \\ | - Hier wird wieder geprüft ob die Frequenz des Quarz bereits eingestellt wurde und - falls nicht - dessen Frequenz eingestellt. \\ \\ | ||
- Die Header-Dateien entsprechen denen der letzten Programme. \\ \\ \\ \\ \\ | - Die Header-Dateien entsprechen denen der letzten Programme. \\ \\ \\ \\ \\ | ||
- | - Auch die Makros | + | - Die Konstanten |
- | - Die Konstanten entsprechen denen der letzten Programme. \\ Zusätzlich | + | - Es wird eine zusätzliches Array '' |
- | - Bei den Variablen entsprechen einige denen der letzten Programme. | + | - Bei den Variablen entsprechen einige denen der letzten Programme. \\ \\ \\ \\ |
- | - Für die Uhr werden Stunden, Minuten, Sekunden und Zehntelsekunden mit Anfangswerten deklariert. \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | - Die Variable '' |
- | - Bei den Funktionsprototypen sind einige bekannte Unterprogramme vorhanden. Details werden weiter unten erklärt. \\ \\ \\ | + | - Die Variable '' |
+ | - Die Variable '' | ||
+ | - Bei den Funktionsprototypen sind einige bekannte Unterprogramme vorhanden. Details werden weiter unten erklärt. | ||
'' | '' | ||
- | - Das Hauptprogramm ähnelt sehr stark dem [[4._up_down_counter|Up/Down Counter]]. Entsprechend werden | + | - Das Hauptprogramm ähnelt sehr stark dem [[4_up_down_counter|Up/Down Counter]], wobei die Initialisierung des Timers in eine Unterfunktion '' |
- | - In der Endlosschleife sind auf der ersten Ebene wieder nur If-Abfragen zu den Flags '' | + | - In der Endlosschleife sind auf der ersten Ebene wieder nur If-Abfragen zu den Flags '' |
- | - Alle $10ms$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm '' | + | - Alle $100~\rm ms$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm '' |
- | - Alle $100ms$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm | + | - Alle $1~\rm s$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm '' |
- | - Alle $1s$ (bzw. wenn das entsprechende Flag gesetzt wird) wird das Flag zurückgesetzt und das Unterprogramm '' | + | '' |
- | '' | + | - Die Timer Initialisierung |
- | - Auch die Interrupt Routine | + | |
- | '' | + | '' |
- | - Auch das Einstellen des Data Direction Registers und der Pullups wurde bereits in vorherigen Programmen erklärt. \\ \\ \\ \\ | + | |
- | '' | + | |
- | \\ \\ | + | |
- | - In dieser Funktion werden zunächst die Stellungen aller Taster eingelesen (vgl. '' | + | |
- | - Neu hier ist, dass die Bedienung der Schalter die Variablen für Stunden, Minuten um eins hochsetzen, bzw. bei Überlauf wider zurück auf 0 setzen. Zusätzlich wird bei eine Änderung des Minuten-Werts der Sekunden-Wert auf 0 gesetzt. | + | |
- | '' | + | - Über den Multiplexer |
- | - Hierüber | + | - ''< |
- | - Ähnlich zum Counter werden | + | - WICHTIG: der erste digitalisierte Wert nach Initialisierung und auch nach Kanalwechsel muss ignoriert werden. Bei Änderungen der ADC-Konfiguration entspricht diese bei AVR-Microcontrollern noch keinem validen Wert! |
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
+ | <WRAP 470px> | ||
+ | < | ||
+ | </ | ||
+ | {{drawio> | ||
+ | </ | ||
+ | \\ | ||
+ | '' | ||
+ | - Die Timer-Service Routine ist dem Programm [[4_up_down_counter|Up/ | ||
+ | |||
+ | '' | ||
+ | - Das Bit '' | ||
+ | - Während die AD-Wandlung läuft bleibt das Bit '' | ||
+ | - Das Register '' | ||
+ | - immer erst ADCL auslesen, dann ADCH. | ||
+ | - immer auch ADCH auslesen, selbst wenn es nicht benötigt wird. \\ \\ | ||
+ | |||
+ | '' | ||
+ | - Die Variable '' | ||
+ | - Die Variable '' | ||
+ | - '' | ||
+ | - In '' | ||
+ | \\ \\ \\ \\ \\ \\ \\ | ||
+ | |||
+ | '' | ||
+ | - Da zwei Temperaturen ausgegeben werden müssen, ruft die Anzeigefunktion eine weitere Unterfunktion auf, welche mit unterschiedlichen Werten gespeist wird | ||
+ | \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ | ||
+ | |||
+ | '' | ||
+ | - Auf der ersten Position wird gegebenenfalls ein Vorzeichen angezeigt. Falls die Temperatur negativ ist, muss für den nächsten Schritt der Betrag gebildet werden \\ \\ \\ \\ | ||
+ | - Für die Temperatur wird zunächst die Zehner und die Einer ermittelt und ausgegeben. Im nächsten Schritt folgt das Dezimaltrennzeichen und die Zehntel Grad. \\ \\ | ||
'' | '' | ||
- Die Funktion '' | - Die Funktion '' | ||
- Danach wird der erste Text auf den Bildschirm geschrieben und damit der Programmname dargestellt. | - Danach wird der erste Text auf den Bildschirm geschrieben und damit der Programmname dargestellt. | ||
- | - Nach zwei Sekunden wird der Auswahlbildschirm | + | - Nach zwei Sekunden wird die Display-Vorlage für die Temperatur |
- | + | ||
- | \\ \\ \\ \\ \\ \\ \\ \\ \\ | + | |
- | '' | ||
- | - Die Zähl-Funktion '' | ||
- | - Zunächst wird ein Schaltwechsel am Ausgang mit dem Lautsprecher ausgegeben, um einen Knackton zu erzeugen | ||
- | - Dann werden die Sekunden hochgezählt | ||
- | - ist das Maximum erreicht, so wird der Sekunden-Wert zurückgesetzt und der Minuten-Wert um eins hochgezählt. | ||
- | - ebenso wird beim Maximum des Minuten-Serts dieser zurückgesetzt und der Stundenwert hochgezählt. | ||
- | - beim Maximum des Stunden-Werts wird dieser wieder auf Null gesetzt | ||
</ | </ | ||
Zeile 539: | Zeile 702: | ||
--> Aufgabe# | --> Aufgabe# | ||
- | - Bauen Sie einen " | + | - Die Anzeige am Display scheint |
- | - Es sollen | + | - Entwickeln |
- | - Achten Sie auf die Schaltjahrermittlung | + | |
- | - Erweitern | + | |
- | - Überlegen Sie sich, wie man Ihre Programme testen kann. | + | |
- | - BONUS: Wie kann der Wochentag bestimmt werden? | + | |
<-- | <-- | ||