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/22 11:04] 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: $T \rightarrow R_{NTC}$\\ Umwandlung der physikalischen Größe in ein Messsignal \\ \\ | + | - Sensor: $T \rightarrow R_{\rm NTC}$\\ Umwandlung der physikalischen Größe in ein Messsignal \\ \\ |
- | - Sensorschaltung: | + | - Sensorschaltung: |
- | - ADC: $V_{NTC} \rightarrow adcValue$\\ Digitalisierung in ein Zahlenwert im Code \\ \\ | + | - ADC: $V_{\rm NTC} \rightarrow adcValue$\\ Digitalisierung in ein Zahlenwert im Code \\ \\ |
- Aufbereitung im Code $adcValue \rightarrow tValue$ \\ um ein Abbild des Sensorwerts zu erhalten \\ \\ | - Aufbereitung im Code $adcValue \rightarrow tValue$ \\ um ein Abbild des Sensorwerts zu erhalten \\ \\ | ||
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$ |
- | | ... | ... | | + | | ... |
</ | </ | ||
</ | </ | ||
Zeile 49: | Zeile 57: | ||
< | < | ||
^ADC-Wert \\ $adcValue$ ^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. | ||
Zeile 89: | 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 104: | 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} |
Daraus ergibt sich der digitalisierte Wert zu | Daraus ergibt sich der digitalisierte Wert zu | ||
- | \begin{align} ADCwert = round \left({{V_{NTC}}\over{V_{CC}}} \cdot 1024 \right) \tag{8.2} \end{align} | + | \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: | Diese Relation muss nun im Analyse-Tool abgebildet werden und wurde in {{microcontrollertechnik: | ||
Zeile 119: | Zeile 125: | ||
* 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 '' | * 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 === | + | ==== 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°C, 50°C]$ sein. | + | |
+ | 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 == | == direkte Verwendung der Datenblattwerte == | ||
<WRAP group>< | <WRAP group>< | ||
Zeile 131: | Zeile 136: | ||
<sxh c; first-line: 42> | <sxh c; first-line: 42> | ||
- | # | + | # |
const int TEMP[MAX_INDEX] | 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}; | 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 | + | // Datenwerte aus dem Datenblatt |
- | // TEMP[] enthaelt die Temperaturen | + | // TEMP[] enthaelt die Temperaturen |
- | // In ADC_VAL[] sind die den Temperaturen | + | // In ADC_VAL[] sind die den Temperaturen |
- | // entsprechenden ADC-Werte abgespeichert | + | // entsprechenden ADC-Werte abgespeichert |
... | ... | ||
for(int index=0; index< | for(int index=0; index< | ||
- | { // suche den Index, bei dem der gemessene | + | { |
- | // Wert zum ersten mal darueber liegt | + | |
if (tValue >= ADC_VAL[index]) break; // wenn gefunden, breche ab | if (tValue >= ADC_VAL[index]) break; // wenn gefunden, breche ab | ||
- | }; // (index zeigt auf untere Temperatur) | + | }; |
- | int tValue = TEMP[index]; | + | int tValue = TEMP[index];// |
- | ... | + | ... |
</ | </ | ||
- | Nachteil dabei ist, dass die Ausführung unterschiedlich lange benötigt und die Auflösung nur 5°C beträgt. | ||
</ | </ | ||
Zeile 155: | Zeile 159: | ||
< | < | ||
</ | </ | ||
- | {{drawio> | + | {{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 == | + | \\ \\ |
+ | === direkte Verwendung der Datenblattwerte mit Interpolation | ||
<WRAP group> | <WRAP group> | ||
Zeile 168: | Zeile 174: | ||
<sxh c; first-line: 42> | <sxh c; first-line: 42> | ||
- | # | ||
- | const int TEMP[MAX_INDEX] = { -30, -25, -20, -15, -10, -5, | + | # |
- | const int ADC_VAL[MAX_INDEX] | + | |
- | // Datenwerte aus dem Datenblatt | + | const int TEMP[MAX_INDEX] |
- | // TEMP[] enthaelt die Temperaturen | + | const int ADC_VAL[MAX_INDEX] ={ 968, 950, 927, 899, 866, 827, 783, 734, 681, 625, 568, 512, 456, 404, 356, 311, 271}; |
- | // In ADC_VAL[] sind die den Temperaturen entsprechenden ADC-Werte abgespeichert | + | // Datenwerte aus dem Datenblatt |
+ | // TEMP[] enthaelt die Temperaturen | ||
+ | // In ADC_VAL[] sind die den Temperaturen | ||
+ | // | ||
... | ... | ||
- | for(int index=0; index< | + | for(int index=0; index< |
- | { // suche den Index, bei dem der gemessene Wert zum ersten mal darueber liegt | + | { |
- | if (tValue >= ADC_VAL[index]) break; | + | |
- | }; | + | if (tValue >= ADC_VAL[index]) break; // wenn gefunden, breche ab |
- | int t_uW = TEMP[index]; | + | }; |
- | int t_oW = TEMP[index+1]; | + | int t_uW = TEMP[index]; |
+ | | ||
+ | int t_oW = TEMP[index+1];// | ||
+ | | ||
- | int ADC_uW = ADC_VAL[index]; | + | int ADC_uW = ADC_VAL[index];// |
- | int ADC_oW = ADC_VAL[index+1]; | + | |
+ | int ADC_oW = ADC_VAL[index+1];// | ||
+ | | ||
- | float tValue = TEMP[index] + 5 * (tValue -ADC_uW ) / (ADC_oW - ADC_uW ) ; // lineare Interpolation | + | float tValue = TEMP[index] + |
- | // zum unteren Temperaturwert wird ein Bruchteil entsprechend der | + | 5 * (tValue - ADC_uW ) / (ADC_oW - ADC_uW ) ; |
- | // Differenz von tValue zum unteren ADC Wert ADC_uW hinzuaddiert | + | |
+ | | ||
+ | | ||
+ | | ||
... | ... | ||
</ | </ | ||
- | Die Auflösung ist nun sehr genau. Nachteile sind aber, dass die Ausführung immernoch unterschiedlich lange benötigt und die ein float-Wert relativ viel Speicher und CPU-Zeit bei weiteren Berechnungen benötigt. | ||
- | |||
- | Der float-Wert kann umgangen werden, wenn im gesamten Programm die Temperaturwerte in Zehntel-Grad geschrieben werden. Also 37,5°C $\rightarrow$ 375. Dann kann ein tValueals signed integer geschrieben werden. | ||
</ | </ | ||
<WRAP column 35%> | <WRAP column 35%> | ||
< | < | ||
</ | </ | ||
- | {{drawio> | + | {{drawio> |
</ | </ | ||
</ | </ | ||
- | == Umrechnung der Datenblattwerte == | + | 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%> | ||
- | <WRAP group>< | ||
Eine geschicktere Option ist es, den Temperatur-Array '' | Eine geschicktere Option ist es, den Temperatur-Array '' | ||
* Betrachtet man die obige Tabelle '' | * Betrachtet man die obige Tabelle '' | ||
Zeile 212: | Zeile 232: | ||
Der Index kann damit als '' | Der Index kann damit als '' | ||
- | </ | + | |
+ | </ | ||
+ | <WRAP column 35%> | ||
< | < | ||
</ | </ | ||
- | {{drawio> | + | {{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: ''# | ||
+ | |||
+ | </ | ||
+ | \\ \\ | ||
+ | |||
+ | |||
<-- | <-- | ||
Zeile 241: | Zeile 281: | ||
<-- | <-- | ||
- | --> 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, Fakultaet T1) | + | |
- | D. Chilachava (Georgische Technische Universitaet) | + | |
- | | + | |
- | Datum : 01.05.2020 | + | |
- | | ||
- | |||
- | | ||
- | AVR-USB-PROGI Ver. 2.0 | ||
- | |||
- | | ||
- | C-Compiler: | ||
- | |||
| | ||
- | Maximaltemperatur im Betriebszeitraum in °C mit 1/10 Grad. | + | |
- | Keine Tastenbedienung | + | Keine Tastenbedienung |
- | + | ||
- | | + | |
- | +----------------+ +----------------+ | + | |
- | |- Experiment 8 -| |Temp. | + | |
- | | Temperature | + | |
- | +----------------+ +----------------+ | + | |
- | + | ||
- | | + | |
- | + | ||
- | | + | |
- | + | ||
- | Fuses im uC: CKDIV8: Aus (keine generelle Vorteilung des Takts) | + | Fuses im uC: |
- | + | ||
- | | + | |
- | + | ||
- | | + | |
- | 2) AD-Wandlung (Takt: 100 ms) | + | 2) AD-Wandlung (Takt: 100 ms) |
- | 3) Umrechnung fuer Temperatur | + | 3) Umrechnung fuer Temperatur |
- | 4) Anzeigetreiber (Takt: 1 s) | + | 4) Anzeigetreiber (Takt: 1 s) |
+ | |||
1) Das Modul " | 1) Das Modul " | ||
- | | + | |
- | + | ||
- | Verwendung von Hardware-Timer 0 und T0 Overflow-Interrupt. | + | Verwendung von Hardware-Timer 0 und T0 Overflow-Interrupt. |
- | Frequenzen: Quarzfrequenz | + | Frequenzen: Quarzfrequenz |
- | Timer-Vorteiler / 8 => | + | Timer-Vorteiler |
- | Hardware-Timer | + | Hardware-Timer |
- | Software-Vorteiler | + | Software-Vorteiler |
- | Hundertstel-Zaehler / | + | Hundertstel-Zaehler / 10 => 10 Hz / 100 ms |
- | Zehntel-Zaehler / 10 => | + | 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. | ||
- | | + | |
Aufloesung gestartet. Dort ist der NTC des Boards mit Vorwiderstand | Aufloesung gestartet. Dort ist der NTC des Boards mit Vorwiderstand | ||
als temperaturabhaengiger Spannungsteiler bzw. Potentiometer angeschlossen. | als temperaturabhaengiger Spannungsteiler bzw. Potentiometer angeschlossen. | ||
Als Referenzspannung wird die 5V-Versorgung verwendet. | Als Referenzspannung wird die 5V-Versorgung verwendet. | ||
Das Ergebnis wird in der globalen Variable tValue gespeichert. | Das Ergebnis wird in der globalen Variable tValue gespeichert. | ||
+ | |||
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 ueber aequidistante (Abstand = 16) AD-Werte aufgetragen. | Temperaturwerte ueber aequidistante (Abstand = 16) AD-Werte aufgetragen. | ||
- | | + | |
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 noch eine |
- | | + | Mittelwertsbildung mit 10 Werten eingefuegt werden. |
+ | |||
+ | 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 ueber 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 " |
+ | |||
// Konstanten | // Konstanten | ||
- | # | + | # |
- | # | + | # |
- | # | + | # |
#define ASC_NULL | #define ASC_NULL | ||
#define ASC_FULL_STOP | #define ASC_FULL_STOP | ||
- | + | ||
- | const int TEMP[45] | + | const int |
- | 338, | + | 338, |
- | 193, | + | 193, |
- | 48, | + | 48, |
- | -145, | + | -145, |
- | + | ||
- | // Die Tabellenwerte sind in 1/10 °C angegeben | + | // Die Tabellenwerte sind in 1/10 °C angegeben |
- | // Der erste Tabellenwert entspricht einem AD-Wert | + | // Der erste Tabellenwert entspricht einem AD-Wert |
- | // von 256. Die Abstaende der AD-Werte sind 16 | + | // von 256. Die Abstaende der AD-Werte sind 16 |
+ | |||
// Variable | // Variable | ||
- | unsigned char vorteiler = VORTEILER_WERT; // Zaehlvariable Vorteiler | + | unsigned char softwarePrescaler |
- | unsigned char hundertstel = HUNDERTSTEL_WERT; | + | unsigned char cycle10msCount |
- | unsigned char zehntel | + | unsigned char cycle100msCount |
- | + | ||
- | unsigned int adcValue = 0; // Variable fuer den AD-Wandlungswert | + | unsigned int adcValue |
- | int tValue = 0; // Variable fuer die Temperatur (in 1/10 °C) | + | int |
- | int tValueMax =-300; | + | int |
- | + | ||
- | 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); | ||
Zeile 385: | Zeile 428: | ||
void refreshDisplayTemp(int tempValue, char line, char pos); | void refreshDisplayTemp(int tempValue, char line, char pos); | ||
void refreshDisplay (void); | void refreshDisplay (void); | ||
+ | |||
// Hauptprogramm ============================================================== | // Hauptprogramm ============================================================== | ||
int main () | int main () | ||
{ | { | ||
- | initDisplay(); | + | |
- | initTimer0(); | + | initTimer0(); |
- | initAdc(); | + | initAdc(); |
- | + | ||
- | sei(); // generell Interrupts einschalten | + | sei(); |
- | + | | |
- | // Hauptprogrammschleife __________________________________________________ | + | // Hauptprogrammschleife __________________________________________________ |
- | + | ||
- | while(1) // unendliche Warteschleife mit Aufruf der | + | while(1) |
- | // Funktionen abhaengig von Taktbotschaften | + | // Funktionen abhaengig von Taktbotschaften |
- | { | + | { |
- | if(takt100ms) // Durchfuehrung der Funktion einmal pro 100ms | + | if(cycle100msActive) // Durchfuehrung der Funktion einmal pro 100ms |
- | { | + | { |
- | takt100ms | + | |
- | doAdc(); // Ausfuehrung des Modules der A/ | + | doAdc(); |
- | calculateTemp(); | + | calculateTemp(); |
- | } | + | } |
- | + | ||
- | if(takt1s) // Durchfuehrung der Anzeige einmal pro 1s | + | if(cycle1sActive) |
- | { | + | { |
- | takt1s | + | |
- | refreshDisplay(); | + | refreshDisplay(); |
- | } | + | } |
- | } | + | } |
} | } | ||
- | + | ||
+ | |||
// Timer Initialisierung ============================================================== | // Timer Initialisierung ============================================================== | ||
// | // | ||
Zeile 422: | Zeile 465: | ||
void initTimer0() | void initTimer0() | ||
{ | { | ||
- | TCCR0A |= (0<< | + | |
- | | (0<< | + | | (0<< |
- | TCCR0B |= (0<< | + | TCCR0B |
- | | (1<< | + | | (1<< |
- | TIMSK0 |= (1<< | + | TIMSK0 |
} | } | ||
+ | |||
// ADC-Initialisierung ============================================================== | // ADC-Initialisierung ============================================================== | ||
// | // | ||
Zeile 435: | Zeile 478: | ||
// Abfrage des ADC0 (NTC-Spannungsteiler) | // Abfrage des ADC0 (NTC-Spannungsteiler) | ||
// Referenzspannung = analoge Versorgung Avcc | // Referenzspannung = analoge Versorgung Avcc | ||
- | void initAdc () | + | void initAdc() |
{ | { | ||
- | ADMUX |= (1<< | + | |
- | + | ||
- | ADCSRA |= (1<< | + | ADCSRA |
- | | (1<< | + | | (1<< |
- | | (1<< | + | | (1<< |
- | | (1<< | + | | (1<< |
+ | (void) ADCH; // erster Wert ist " | ||
} | } | ||
- | + | ||
+ | |||
// Timer-Service Routine ============================================================== | // Timer-Service Routine ============================================================== | ||
// | // | ||
Zeile 452: | Zeile 496: | ||
// werden von Timer 0 ausgeloest (Interrupt Nr. 1) | // werden von Timer 0 ausgeloest (Interrupt Nr. 1) | ||
// | // | ||
- | // Veraenderte Variable: | + | // Veraenderte Variable: |
- | // hunderstel | + | // hunderstel |
- | // zehntel | + | // zehntel |
// | // | ||
- | // Ausgangsvariable: | + | // Ausgangsvariable: |
- | // takt100ms | + | // takt100ms |
- | // takt1s | + | // takt1s |
+ | |||
ISR (TIMER0_OVF_vect) | 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; // Hundertstelzaehler dekrementieren | + | --cycle10msCount; // Hundertstelzaehler dekrementieren |
- | + | ||
- | if (hundertstel==0) // wenn 0 erreicht: 100ms abgelaufen | + | if (cycle10msCount==0) // wenn 0 erreicht: 100ms abgelaufen |
- | { | + | { |
- | hundertstel | + | |
- | takt100ms | + | |
- | --zehntel; | + | --cycle100msCount; |
- | + | ||
- | if (zehntel==0) // Zehntelzaehler dekrementieren | + | if (cycle100msCount==0) |
- | { | + | { |
- | zehntel | + | |
- | takt1s | + | |
- | } | + | } |
- | } | + | } |
- | } | + | } |
} | } | ||
+ | |||
// ADWandlung ============================================================== | // ADWandlung ============================================================== | ||
// | // | ||
Zeile 490: | Zeile 534: | ||
void doAdc() | void doAdc() | ||
{ | { | ||
- | ADCSRA |= (1<< | + | |
- | while (ADCSRA & (1<< | + | while (ADCSRA & (1<< |
- | + | ||
- | adcValue = ADCL + (ADCH<< | + | adcValue = ADCL + (ADCH<< |
// | // | ||
// | // | ||
} | } | ||
+ | |||
// Umrechnung ============================================================== | // Umrechnung ============================================================== | ||
// | // | ||
Zeile 503: | Zeile 547: | ||
void calculateTemp () | void calculateTemp () | ||
{ | { | ||
- | unsigned char index; // Tabellenindex fuer Temperaturtabelle | + | |
- | unsigned char steps; // Abstand zum naechstkleineren Wert | + | unsigned char steps; |
- | // der AD-Werte der Temperaturtabelle | + | // der AD-Werte der Temperaturtabelle |
- | + | | |
- | index = (adcValue-256)/ | + | index |
- | steps = (adcValue-256)%16; | + | steps |
- | + | | |
- | tValue = steps * (TEMP[index+1] - TEMP[index])/ | + | tValue = steps * (TEMP[index+1] - TEMP[index])/ |
- | // Temperaturwert berechnen | + | // Temperaturwert berechnen |
- | + | ||
- | if(tValue> | + | if(tValue> |
- | { | + | { |
- | tValueMax = tValue; // vergleichen und ggf. ersetzen | + | tValueMax = tValue; |
- | } | + | } |
} | } | ||
+ | |||
// Anzeigefunktion ============================================================== | // Anzeigefunktion ============================================================== | ||
// | // | ||
Zeile 524: | Zeile 568: | ||
void refreshDisplay() | void refreshDisplay() | ||
{ | { | ||
- | refreshDisplayTemp(tValue, | + | |
- | refreshDisplayTemp(tValueMax, | + | refreshDisplayTemp(tValueMax, |
} | } | ||
+ | |||
// Anzeigetreiber fuer Temperaturanzeige ============================================================== | // Anzeigetreiber fuer Temperaturanzeige ============================================================== | ||
// | // | ||
Zeile 536: | 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: | ||
// | // | ||
Zeile 542: | Zeile 586: | ||
void refreshDisplayTemp(int tempValue, char line, char pos) | void refreshDisplayTemp(int tempValue, char line, char pos) | ||
{ | { | ||
- | lcd_gotoxy(line, | + | |
- | if (tempValue> | + | if (tempValue> |
- | { | + | { |
- | lcd_putc(' | + | lcd_putc(' |
- | } | + | } |
- | else | + | else |
- | { | + | { |
- | lcd_putc(' | + | lcd_putc(' |
- | tempValue = -tempValue; | + | tempValue = -tempValue; |
- | } | + | } |
- | lcd_putc | + | lcd_putc |
- | tempValue = tempValue%100; | + | tempValue = tempValue%100; |
- | lcd_putc | + | lcd_putc |
- | lcd_putc | + | lcd_putc |
- | lcd_putc | + | lcd_putc |
} | } | ||
+ | |||
// Initialisierung Display-Anzeige ============================================================== | // Initialisierung Display-Anzeige ============================================================== | ||
// | // | ||
- | void initDisplay() // Start der Funktion | + | void initDisplay() |
{ | { | ||
- | lcd_init(); | + | |
- | + | | |
- | lcd_displayMessage(" | + | lcd_displayMessage(" |
- | lcd_displayMessage(" | + | lcd_displayMessage(" |
- | + | ||
- | _delay_ms(2000); | + | _delay_ms(2000); |
- | + | ||
- | lcd_displayMessage(" | + | lcd_displayMessage(" |
- | lcd_displayMessage(" | + | lcd_displayMessage(" |
- | // " | + | // " |
- | } // Ende der Funktion | + | } |
</ | </ | ||
</ | </ | ||
Zeile 585: | Zeile 628: | ||
- 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. \\ \\ \\ \\ \\ | ||
- | - Die Konstanten entsprechen denen der letzten Programme. \\ \\ \\ \\ | + | - Die Konstanten entsprechen denen der letzten Programme. |
- | - Es wird eine zusätzliches Array '' | + | - Es wird eine zusätzliches Array '' |
- | - Bei den Variablen entsprechen einige denen der letzten Programme. | + | - Bei den Variablen entsprechen einige denen der letzten Programme. \\ \\ \\ \\ |
- Die Variable '' | - Die Variable '' | ||
- Die Variable '' | - Die Variable '' | ||
- Die Variable '' | - Die Variable '' | ||
- | - Bei den Funktionsprototypen sind einige bekannte Unterprogramme vorhanden. Details werden weiter unten erklärt. \\ \\ \\ \\ | + | - 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]], wobei die Initialisierung des Timers in eine Unterfunktion '' | + | - 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 $100ms$ (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 $1s$ (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 '' |
- | '' | + | '' |
- | - Die Timer Initialisierung ist dem Programm [[4._up_down_counter|Up/Down Counter]] entlehnt und wird hier nicht weiter erklärt. | + | - Die Timer Initialisierung ist dem Programm [[4_up_down_counter|Up/Down Counter]] entlehnt und wird hier nicht weiter erklärt. |
- | '' | + | '' |
- | - Über den Multiplexer '' | + | |
- | - '' | + | |
- | '' | + | - Über den Multiplexer |
- | - DieTimer-Service Routine ist dem Programm [[4._up_down_counter|Up/ | + | |
+ | - WICHTIG: der erste digitalisierte Wert nach Initialisierung | ||
- | '' | + | <WRAP 470px> |
- | \\ \\ | + | < |
+ | </ | ||
+ | {{drawio> | ||
+ | </ | ||
+ | \\ | ||
+ | '' | ||
+ | - Die Timer-Service Routine ist dem Programm [[4_up_down_counter|Up/ | ||
+ | |||
+ | '' | ||
- Das Bit '' | - Das Bit '' | ||
- Während die AD-Wandlung läuft bleibt das Bit '' | - Während die AD-Wandlung läuft bleibt das Bit '' | ||
- Das Register '' | - Das Register '' | ||
- immer erst ADCL auslesen, dann ADCH. | - immer erst ADCL auslesen, dann ADCH. | ||
- | - immer auch ADCH auslesen, selbst wenn es nicht benötigt wird. \\ | + | - immer auch ADCH auslesen, selbst wenn es nicht benötigt wird. \\ \\ |
'' | '' | ||
Zeile 622: | Zeile 672: | ||
- '' | - '' | ||
- In '' | - In '' | ||
- | \\ \\ \\ \\ \\ \\ | + | \\ \\ \\ \\ \\ |
'' | '' | ||
- Da zwei Temperaturen ausgegeben werden müssen, ruft die Anzeigefunktion eine weitere Unterfunktion auf, welche mit unterschiedlichen Werten gespeist wird | - 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 \\ \\ \\ \\ | - 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. \\ \\ \\ | + | - 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. \\ \\ |
'' | '' |