| Weitere Artikel aus dem Elo-Magazin |
Min/Max-Thermometer mit bis zu 10 Messtellen
Temperaturmessung per OneWire-Sensoren mit der Ping-Pong-Platine
von Bernhard Kaiser
Es können bis zu 10 OneWire-Temperatursensoren des Typs DS1820 des Herstellers Maxim angeschlossen werden. Der Messbereich dieser Sensoren liegt im Bereich von -55 ... +125°C, die Auflösung beträgt 0,5°C. Auf der LED-Anzeige wird die Temperatur des per Poti angewählten Sensors angezeigt. Dabei kann eingestellt werden, ob der minmale, der aktuelle oder der maximale Messwert des ausgewählten Sensors angezeigt werden soll. Zusätzlich ist ein Scanbetrieb möglich, bei dem die Sensoren automatisch der Reihe nach durchgeschaltet werden und für jeweils ca. 3 Sekunden angezeigt werden.
Ganzen Artikel lesen...

OneWire-Temperatursensoren des Typs DS1820. Diese haben 3 Pins: VCC, GND, sowie Data. Data wird an PORTC.4 (also Pad C4) angeschlossen. Es können bis zu 10 Sensoren angeschlossen werden, diese werden einfach alle parallel geschaltet. An PORTC.4 muss zusätzlich ein Pull-Up-Widerstand von 4K7 gegen VCC geschaltet werden. Optional, damit ein Reset des Min-/Maxspeichers erfolgen kann: Ein zusätzlicher Taster (1-poliger Schließer), der zwischen PortD.3 (also Lötpad D3) und GND angeschlossen wird. Der benötigte Pullup-Widerstand wird im Controller intern hinzugeschaltet.
In der obersten LED-Zeile wird angezeigt, wieviele Sensoren angeschlossen sind sowie welcher Sensor aktuell angewählt ist. Die maximal 10 möglichen Sensoren werden durch die entsprechende Anzahl leuchtender LEDs beginnend von links her angezeigt. Die LED des angewählten Sensors blinkt hierbei. Der Scanbetrieb wird durch eine zusätzliche blinkende LED ganz rechts angezeigt.
Mit dem rechten Poti wird der anzuzeigende Sensor ausgewählt. Der Einstellbereich wird hierzu in (Anzahl Sensoren + 1) Teile aufgeteilt. Der Bereich am linken Anschlag entspricht Sensor 1, bei Drehung nach rechts im Uhrzeigersinn werden die weiteren Sensoren der Reihe nach ausgewählt. Der Bereich am rechten Anschlag wählt den Scanbetrieb aus.
Mit dem linken Poti oberhalb des Münzschlitzes kann ausgewählt werden, ob der Minimalwert, der aktuelle Wert oder der Maximalwert der Temperatur des ausgewählten Sensors angezeigt werden soll. Der Einstellbereich des Potis ist hierzu in 3 Teile unterteilt:
- Bereich am linken Anschlag: minimaler Temperaturwert, symbolisiert durch einen 4 Pixel breiten LED-Balken links in der untersten LED-Zeile
- Mittelstellung: aktueller Temperaturwert, symbolisiert durch einen 4 Pixel breiten LED-Balken mittig in der untersten LED-Zeile
- Bereich am rechten Anschlag: maximaler Temperaturwert, symbolisiert durch einen 4 Pixel breiten LED-Balken rechts in der untersten LED-Zeile
Durch kurzen Druck auf den optionalen Taster kann der Min- / Maxwert-Speicher zurückgesetzt werden. Die Anzeige des Temperaturwerts erfolgt in folgendem Format:
-55 ... -10°C: -xx
-9,9 ... -0,1°C: -x.x
0 ... 99,9°C: xx.x
100 ... 125°C: xxx
Download: Quelltext und Hex-File
/*****************************************************
Compiler : CodeVisionAVR 2.04.6 Evaluation
Chip type : ATmega8
Clock frequency : 8 MHz (int. RC-OSC)
*****************************************************/
//***************************************************
// Tmeperaturanzeige für 1-Wire Temperatursensoren
// auf Basis des Franzis-Pingpong
// http://www.elo-web.de/ping-pong-start
//***************************************************
#include <mega8.h>
#include <stdio.h>
#include <delay.h>
#include <sleep.h>
// 1 Wire Bus functions
#asm
.equ __w1_port=0x15 ;PORTC.4 für OneWire
.equ __w1_bit=4
#endasm
#include <1wire.h>
// DS1820 Temperature Sensor functions
#include <ds1820.h>
#define P_CLK PORTB.3
#define P_DATA PORTB.4
#define P_STROBE PORTB.2
#define PIN_COIN PIND.2
#define PULLUP_COIN PORTD.2
#define DIR_COIN DDRD.2
#define COIN_INSERTED (PIN_COIN == 0)
#define PIN_KEY PIND.3
#define PULLUP_KEY PORTD.3
#define KEY_PRESSED (PIN_KEY == 0)
#define WIDTH 12 // number of fields in horizontal direction
#define HEIGHT 10 // number of fields in vertical direction
unsigned int leds[WIDTH]; // current state of each LED (organized in columns)
unsigned int ledsBlink[WIDTH]; // current blink state of each LED (organized in columns)
bit bKeypressed = 0;
bit bTimerInt = 0;
/* maximum number of DS1820/DS18S20 connected to the bus */
#define MAX_DEVICES 10
/* DS1820/DS18S20 devices ROM code storage area, 9 bytes are used for each device
(see the w1_search function description),
but only the first 8 bytes contain the ROM code
and CRC */
unsigned char rom_codes[MAX_DEVICES][9]; //jeder DS1820 besitzt eine eindeutige 8Byte-Serielnummer, diese wird hier übergeben
unsigned char devices; // Devices = Anzahl angeschlossener Sensoren
signed int tempminmax; //temp=Temperaturwert
#define NOF_SENSORS (MAX_DEVICES)
signed int tempSensor[NOF_SENSORS]; // Speichervariable für aktuelle Temperatur, angelegt für 10 Sensoren
signed int temp_min[NOF_SENSORS]; // Speichervariable für Mindesttemperatur, angelegt für 10 Sensoren
signed int temp_max[NOF_SENSORS]; // Speichervariable für Maximaltemperatur, angelegt für 10 Sensoren
unsigned int scancount = 0;
flash unsigned char decimals[] =
{
0x1F, 0x11, 0x1F, // 0
0x00, 0x00, 0x1F, // 1
0x1D, 0x15, 0x17, // 2
0x15, 0x15, 0x1F, // 3
0x07, 0x04, 0x1F, // 4
0x17, 0x15, 0x1D, // 5
0x1F, 0x15, 0x1D, // 6
0x01, 0x01, 0x1F, // 7
0x1F, 0x15, 0x1F, // 8
0x17, 0x15, 0x1f, // 9
0x04, 0x04, 0x04, // -
0x07, 0x05, 0x07, // °
0x00, 0x00, 0x00 // Leerzeichen
};
// clear the whole screen, all LEDs off
void clearScreen(void)
{
unsigned char i;
for(i = 0; i < (WIDTH); i++)
{
leds[i] = 0;
}
}
// Timer 2 overflow interrupt service routine
// multiplexing of LEDs
// approx. every 1ms
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
static unsigned char count = 0;
unsigned char cValue, cValue2;
static unsigned char cBlink = 0x00;
static unsigned char cBlinkcnt = 0;
scancount++;
cBlinkcnt++;
if(cBlinkcnt >= 250)
{
cBlinkcnt = 0;
cBlink = ~cBlink;
}
count++;
if(count >= 12)
{
count = 0;
P_DATA = 0;
if(KEY_PRESSED)
{
bKeypressed = 1;
}
}
else
{
P_DATA = 1;
}
P_CLK = 1;
P_CLK = 0;
PORTC &= (~0x0F);
PORTD &= (~0xF0);
PORTB &= (~0x03);
P_STROBE = 1;
P_STROBE = 0;
cValue = (unsigned char)leds[count] & 0x0F;
cValue2 = (unsigned char)ledsBlink[count] & cBlink;
cValue &= (~cValue2);
PORTC |= cValue;
cValue = (unsigned char)leds[count] & 0xF0;
cValue &= (~cValue2);
PORTD |= cValue;
cValue = (unsigned char)(leds[count]>>8) & 0x03;
cValue2 = (unsigned char)(ledsBlink[count]>>8) & cBlink;
cValue &= (~cValue2);
PORTB |= cValue;
bTimerInt = 1;
}
// initialization of Timer2
void initTimer2(void)
{
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 250,000 kHz
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x03;
TCNT2=0x00;
OCR2=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;
}
// initialization of ports
void init(void)
{
PORTB = 0;
DDRB = 0x1F;
PORTC = 0;
DDRC = 0x0F;
PORTD = 0;
DDRD = 0xF4;
PULLUP_KEY = 1;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
}
#define ADC_VREF_TYPE 0x00
// initialization of ADC
void initADC(void)
{
// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AREF pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x86;
}
// Read the AD conversion result
// adc_input: ADC channel (0..7)
// return: ADC value (0..1023)
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}
// select sensor to be displayed
// return: selected sensor index (0...(devices-1), 0xFF=scan mode)
unsigned char selectSensor(void)
{
unsigned char x;
if(devices == 0)
return(0);
x = devices - (read_adc(7) / (1023/(devices+1) + 1));
if(x == devices)
x = 0xFF;
return(x);
}
// select value to be displayed
// return: selected value (0=min, 1=current, 2=max)
unsigned char selectDisplayValue(void)
{
unsigned char x;
x = (read_adc(6) / 342);
return(x);
}
// display sensor temperature
// x: number of selected sensor
// select: selected value (0=min, 1=current, 2=max)
void displaySensorTemp(unsigned char x, unsigned char select)
{
signed int temp;
unsigned char i, j, d, value;
bit bDecimalPoint = 0;
char buf[10];
static unsigned char scanx = 0;
bit bScan = 0;
unsigned int ledsLocal[WIDTH];
if(scancount >= 3000)
{
scancount = 0;
if(x == 0xFF)
{
scanx++;
if(scanx == devices)
scanx = 0;
}
}
if(x == 0xFF)
{
bScan = 1;
x = scanx;
}
if(select == 0)
temp = temp_min[x];
else if(select == 2)
temp = temp_max[x];
else
temp = tempSensor[x];
if(temp < 0)
{ // negative Temperatur
if(temp <= -100)
sprintf(buf, "%2d", (temp/10)%100); // Temp <= -10° => -xx
else
{
sprintf(buf, "-%d%d", (-1*temp)/10, (-1*temp)%10); // -10 < Temp < 0° => -x.x
bDecimalPoint = 1;
}
}
else
{ // positive Temperatur
if(temp < 1000)
{
sprintf(buf, "%2d%d", (temp/10), temp%10); // 0 <= Temp < 100° => xx.x
bDecimalPoint = 1;
}
else
sprintf(buf, "%3d", (temp/10)%1000); // Temp >= 100° => xxx
}
i = 0;
for(d = 0; d < 3; d++)
{
value = buf[d];
if(value == '-')
value = 10;
else if(value == '°')
value = 11;
else if(value == ' ')
value = 12;
else
value -= '0';
for(j = 0; j < 3; j++)
{
ledsLocal[i++] = ((unsigned int)decimals[value*3 + j] << 2);
}
ledsLocal[i++] = 0;
}
if(bDecimalPoint)
{
ledsLocal[7] |= 0x080;
}
for(i = 0; i < 10; i++)
{
if(devices > i)
ledsLocal[i] |= 0x001;
if(i != x)
ledsBlink[i] &= (~0x001);
}
ledsBlink[x] |= 0x001;
if(bScan)
{
ledsLocal[11] |= 0x001;
ledsBlink[11] |= 0x001;
}
for(i = select*4; i < (select+1)*4; i++)
{
ledsLocal[i] |= 0x200;
}
for(i = 0; i < WIDTH; i++)
{
leds[i] = ledsLocal[i];
}
}
// Init Temp-Min/Max-Register
void resetMinMax(void)
{
unsigned char k;
for (k=0; k < NOF_SENSORS; k++)
{
temp_min[k] = 1250;
temp_max[k] = -550;
}
}
void oneWire_write(unsigned char c)
{
bTimerInt = 0;
while(!bTimerInt);
#asm("cli")
w1_write(c);
#asm("sei")
}
unsigned char oneWire_read(void)
{
unsigned char x;
bTimerInt = 0;
while(!bTimerInt);
#asm("cli")
x = w1_read();
#asm("sei")
return(x);
}
void oneWire_init(void)
{
bTimerInt = 0;
while(!bTimerInt);
#asm("cli")
w1_init();
#asm("sei")
}
// main routine
void main(void)
{
unsigned char x, k, i, value;
signed int iTemp;
unsigned char scratchpad[9];
init();
initTimer2();
initADC();
clearScreen();
resetMinMax();
// 1 Wire Bus initialization
w1_init();
/* detect how many DS1820/DS18S20 devices are connected to the bus and
store their ROM codes in the rom_codes array */
devices = w1_search(0xf0,rom_codes);
#asm("sei") // Global enable interrupts
while(1)
{
oneWire_init();
oneWire_write(0xCC); // Skip ROM
oneWire_write(0x44); // Convert temperature
for(k = 0; k < 80; k++)
{ // > 800ms (mind. 750ms) warten, bis Temperaturmessung beendet
x = selectSensor();
value = selectDisplayValue();
displaySensorTemp(x, value);
delay_ms(10);
}
//Auslesen und Anzeige der Temperatur je Sensor
for (k = 0; k < devices; k++) //k="Sensor-Zähler"
{
oneWire_init();
oneWire_write(0x55); // Match ROM
for(i = 0; i < 8; i++)
{
oneWire_write(rom_codes[k][i]);
}
oneWire_write(0xBE); // Read scratchpad
for(i = 0; i < 9; i++)
{
scratchpad[i] = oneWire_read();
}
oneWire_init();
iTemp = (scratchpad[0] | ((unsigned int)scratchpad[1] << 8));
tempSensor[k] = iTemp * 5;
tempminmax=tempSensor[k]; //erster Messwert = 85°C, für Max-Temp nicht brauchbar, deshalb weitere Variable
if (temp_min[k] > tempminmax) // wenn gespeicherte Temp größer ist, dann neuer, kleinerer Wert zuweisen
{
temp_min[k] = tempminmax;
}
if (temp_max[k] < tempminmax) //
{
temp_max[k] = tempminmax;
}
x = selectSensor();
value = selectDisplayValue();
displaySensorTemp(x, value);
}
if(bKeypressed)
{
bKeypressed = 0;
resetMinMax();
}
x = selectSensor();
value = selectDisplayValue();
displaySensorTemp(x, value);
}
}












