Es gilt ein einfaches Thermometer, das Temperatur mit großzügiger Toleranz von +/- 2°C im Bereich von 10°C bis 50°C misst, aufzubauen. Die aktuell
gemessene Temperatur soll mithilfe einer 7-Segmentanzeige sichtbar gemacht werden. Die Messung und notwendige Berechnungen soll der Mikrocontroller PIC 12F615
übernehmen. Zusätzlich soll die dazugehörige Schaltung mit einer Warnleuchte (Leuchtdiode) versehen werden, die signalisiert, dass der Rand des festgelegten
Messbereiches unter- oder überschritten wurde.
In der Schaltung geht es vorrangig um die Erfassung eines analogen Wertes und Steuerung eines Schieberegisters mit einem PIC, in diesem Fall PIC12F615. Des
Weiteren wird im Programm auf einfache Weise die Parabel, die die Abhängigkeit des Widerstandes des NTC-Widerstandes von Temperatur beschreibt,
linearisiert.
PIC12F615
Die Wahl eines Mikrocontrollers hängt von der gestellten Aufgabe ab. Eine einfache Temperaturmessung wäre sicher auch mit anderen PICs problemlos
realisierbar. Soll der Mikrocontroller weitere Aufgaben übernehmen, weitere Signale verarbeiten oder weitere Abnehmer schalten, muss man sich nach einem
Mikrocontroller mit größeren Kapazitäten umschauen. Der PIC12F615 mit sechs I/Os ist eher für kleine
Aufgaben gedacht.
Schieberegister 74HC595
Der Mikrocontroller PIC12F615 stellt zu wenig „Beinchen“ zur Verfügung, um eine 7-Segmentanzeige direkt anzusteuern, geschweige mehrere. Da in dem Beispiel
gleich zwei 7-Segmentanzeigen zum Einsatz kommen, bedeutet das, dass 14 Elemente der Anzeigen angesteuert werden müssen. Eine Lösung des Problems, die hier zur
Anwendung kommt, bieten Schieberegister an. Der Schieberegister 74HC595 stellt acht Ausgänge zur Verfügung, womit eine 7-Segmentanzeige problemlos mit Spannung
versorgt werden kann. Die Schieberegister lassen sich nacheinander aufschalten (Kaskadenschaltung), wodurch weitere Steuerleitungen eingespart werden können. In
der Schaltung werden von dem PIC lediglich drei Pins in Anspruch genommen, um alle 14 Elemente der beiden
Anzeigen anzusteuern.
7-Segmentanzeige
Eine 7-Segmentanzeige ist nichts anderes als eine Zusammenstellung von sieben Leuchtdioden, die als kurze Balken in einem Gehäuse ausgeführt werden. Die
einzelnen Balken sind so zueinander angeordnet, dass eine Darstellung von allen Ziffern 0 bis 9 und einigen Buchstaben sowie Sonderzeichen möglich ist. Die
7-Segmentanzeige 5101AH hat zusätzlich noch einen weiteren Anschluss, mit dem die achte Leuchtdiode, die in der Anzeige als Punkt fungiert, aktiviert werden kann.
Diese Erweiterung wird in unserer Schaltung nicht in Anspruch
genommen.
NTC / 10kOhm
NTC ist ein temperaturabhängiger Widerstand. NTC werden sehr oft für Temperaturmessung eingesetzt. NTC hat einen
geringeren Widerstand bei höheren Temperaturen.
Die Messung der Temperatur basiert auf dem temperaturabhängigen Widerstand R16, der in Reihe mit dem Widerstand R15 geschaltet ist. Der
Widerstandswert von R16 ändert sich abhängig von der Temperatur. In diesem Fall handelt es sich um einen NTC, dessen Widerstand mit steigender Temperatur
fällt (Heißleiter). Beide Widerstände, R16 und R15 bilden einen Spannungsteiler. Die Spannung, die zwischen den beiden Widerständen gebildet wird, geht auf
den analogen Eingang des PIC-Mikrocontrollers GP0 und wird direkt zur Bestimmung der Temperatur verwendet.
Die Änderung des Widerstandswertes von R16 bei Temperaturänderungen verläuft nach einer Kurve, die auf dem folgenden Bild
dargestellt ist:
Um aus der ermittelten Spannung die Temperatur exakt abzuleiten, müsste die Grundformel eines NTCs angewendet werden:
In dem Beispiel werden wir diese Formel umgehen und auf Berechnungen mit float-Variablen, die viel Speicherplatz beanspruchen, verzichten. Stattdessen
teilen wir die Kurve in kleine Intervalle von 10°C Breite und linearisieren sie. Je kleiner die Aufteilung, umso genauer die Ergebnisse. Für jeden Abschnitt kann
man dann sagen, dass die Spannung am Spannungsteiler direkt proportional zu der Temperatur ist. Die Temperatur wird dann durch Anwendung der einfachen
Dreisatz-Formel berechnet.
Schaltplan
Schaltplan
Testschaltung
Testschaltung
Programm
// *****************************************************************************************
// Temperaturmessung mit PIC12F615
// MPLAB X IDE v6.00
// XC8-Compiler 2.4
// *****************************************************************************************
// PIC12F615 Configuration Bit Settings
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O
// function on GP4/OSC2/CLKOUT pin, I/O function on
// GP5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is
// digital input, MCLR internally tied to VDD)
#pragma config CP = OFF // Code Protection bit (Program memory code protection
// is disabled)
#pragma config IOSCFS = 4MHZ // Internal Oscillator Frequency Select (4 MHz)
#pragma config BOREN = OFF // Brown-out Reset Selection bits (BOR disabled)
#include <xc.h>// Einbindung der Bibliotheken
#include <stdbool.h>
union { // Struckt-Konstrukt für späteren Bit-Zugriff
unsigned char Ziffer;
struct {
unsigned b0:1;
unsigned b1:1;
unsigned b2:1;
unsigned b3:1;
unsigned b4:1;
unsigned b5:1;
unsigned b6:1;
unsigned b7:1;
};
} byte_u;
#define SH_CP_Pin GPIObits.GP1 // Schieberegister 74HC595 SH_CP
#define ST_CP_Pin GPIObits.GP2 // Schieberegister 74HC595 ST_CP
#define DS_Pin GPIObits.GP4 // Schieberegister 74HC595 DS
#define _XTAL_FREQ 4000000 // Taktfrequenz
int Wert_Analog; // Aktueller Wert am Analogeingang
// Linealisierungsintervalle:
int Intervall; // Interval-Wert
int Anfangswert, Endwert; // Interval-Grenzen
int T_Min; // Intervall-Grundtemperatur
int Temperatur; // Temperaturwert
int Anzeige_Ziffer [2]; // Einzelne Ziffer für 7-Segmentanzeige
// *****************************************************************************************
void Ziffer_Anzeige () { // Bits Übertragung zum Schieberegister
SH_CP_Pin = false; // Startvorbereitung
DS_Pin = byte_u.b0; // Bitwert
SH_CP_Pin = true; // Übernehmen
SH_CP_Pin = false;
DS_Pin = byte_u.b1;
SH_CP_Pin = true;
SH_CP_Pin = false;
DS_Pin = byte_u.b2;
SH_CP_Pin = true;
SH_CP_Pin = false;
DS_Pin = byte_u.b3;
SH_CP_Pin = true;
SH_CP_Pin = false;
DS_Pin = byte_u.b4;
SH_CP_Pin = true;
SH_CP_Pin = false;
DS_Pin = byte_u.b5;
SH_CP_Pin = true;
SH_CP_Pin = false;
DS_Pin = byte_u.b6;
SH_CP_Pin = true;
SH_CP_Pin = false;
DS_Pin = byte_u.b7;
SH_CP_Pin = true;
}
// *****************************************************************************************
void main(void) {
GPIO = 0b00000000; // Alle GPIOs nullen
TRISIO = 0b00001001; // 0-Ausgang 1-Eingang
ANSEL = 0b01010001; // ADC Frequenz mit Fosc/16 = 0b101
ADCON0 = 0b10000001; // GP0 als Analogeingang
while (true) { // Endlosschleife
ADCON0bits.GO_DONE = 1; // GO_DONE Bit setzen
while (ADCON0bits.GO_DONE) { // Schleife Analogwert lesen
Wert_Analog = (ADRESH << 8) + ADRESL; // Variable Wert_Analog beschreiben
}
if (Wert_Analog >= 358) { // Intervall 10-20°C
Anfangswert = 358;
Endwert = 460;
T_Min = 10; }
if (Wert_Analog >= 460) { // Intervall 20-30°C
Anfangswert = 460;
Endwert = 558;
T_Min = 20; }
if (Wert_Analog >= 558) { // Intervall 30-40°C
Anfangswert = 558;
Endwert = 648;
T_Min = 30; }
if (Wert_Analog >= 648) { // Intervall 40-50°C
Anfangswert = 648;
Endwert = 726;
T_Min = 40; }
Intervall = Endwert - Anfangswert; // Temperatur-Berechnung
Temperatur = ((Wert_Analog - Anfangswert) * 10 / Intervall) + T_Min;
GPIObits.GP5 = false; // Warnleuchte AUS
if ((Temperatur < 10) || (Temperatur > 50)) { // T außer Messbereich
GPIObits.GP5 = true; } // Warnleuchte EIN
Anzeige_Ziffer [1] = Temperatur / 10; // Ziffer für 7-Segmentanzeige
Anzeige_Ziffer [0] = Temperatur - (Anzeige_Ziffer [1] * 10);
if (Wert_Analog > 999) {Wert_Analog = 999;}
ST_CP_Pin = false; // Schieberegister ST_CP
for (int i=0; i<2; i++) { // For-Schleife für beide Ziffern
// der Anzeige
int a = Anzeige_Ziffer [i];
switch (a) {
case 0: byte_u.Ziffer = 0b11111100; // Bitbelegung für Elemente der
// 7-Segmentanzeige
Ziffer_Anzeige (); // Unterprogramm aufrufen
// (Schieberegister))
break;
case 1: byte_u.Ziffer = 0b01100000; // usw.
Ziffer_Anzeige ();
break;
case 2: byte_u.Ziffer = 0b11011010;
Ziffer_Anzeige ();
break;
case 3: byte_u.Ziffer = 0b11110010;
Ziffer_Anzeige ();
break;
case 4: byte_u.Ziffer = 0b01100110;
Ziffer_Anzeige ();
break;
case 5: byte_u.Ziffer = 0b10110110;
Ziffer_Anzeige ();
break;
case 6: byte_u.Ziffer = 0b10111110;
Ziffer_Anzeige ();
break;
case 7: byte_u.Ziffer = 0b11100000;
Ziffer_Anzeige ();
break;
case 8: byte_u.Ziffer = 0b11111110;
Ziffer_Anzeige ();
break;
case 9: byte_u.Ziffer = 0b11110110;
Ziffer_Anzeige ();
break;
}
}
ST_CP_Pin = true; // 7-Segmentanzeige aktualisieren
__delay_ms(500); // Wartezeit
}
}
// *****************************************************************************************