Ich habe mich damit auch schon mal befasst. Sollte mal eine Heizungssteuerung werden hat sich dann aber erledigt.
Ich würde mir bei drei mal DS18B20 das mit einem Pin noch einmal überlegen, denn dann gibt es nur die Möglichkeit das über die ID des jeweiligen Sensors eine Zuordung zur Meßstelle zu machen. Das geht nur z.b. über ein Array im Flash/EEPROM und im falle eines Sensordefekts wärst du vermutlich der einzige der diesen wechseln könnte. Im Anhang mal meine damaligen Versuche evtl. ist die CRC - Prüfung da ganz nützlich (entstamt aber nicht von mir aber ist korrekt).
Code
Program Heizung;
{.$NOSHADOW}
{ .$WG} {global Warnings off}
Device = mega328, VCC = 5;
{ $BOOTRST $00C00} {Reset Jump to $00C00}
Import SysTick, I2CPort, LCDport;
From System Import Float;
Define
ProcClock = 8000000; {Hertz}
SysTick = 10; {msec}
StackSize = $0032, iData;
FrameSize = $0032, iData;
LCDport = LcdUserPort;
LCDtype = 44780; {66712}
LCDrows = 4; {2 rows}
LCDcolumns = 20; {20 chars per line}
I2Cport = PortC;{use port C}
I2Cclk = 1;{clock-pin = port C bit 1}
I2Cdat = 2;{data-pin = port C bit 2}
Uses PCF8574_I2C_LCDIOS; // Oder je nach Anschluss PCF8574_TWI_LCDIOS (nicht getestet!!!)
Implementation
{$IDATA}
{--------------------------------------------------------------}
{ Type Declarations }
Type
{--------------------------------------------------------------}
{ Const Declarations }
Const
//dwArr : array[0..6] of string[2]=
//('Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So');
DS1 : Table[0..7] Of Byte = ($10, $8F, $12, $24, $01, $08, $00, $69);
SP : Byte = 1;
SP2 : Byte = 1;
RWSlot : Byte = 80;
LP : Byte = 55;
{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
Var
Y, X : Byte;
crc1, crc2, nc1, nc2, MC : Longint;
DSTimer : Byte;
KSTemp : Float; // Kesseltemperatur
SPTemp : Float; // Speichertemperatur
get : Array[0..8] Of Byte;
Convblock : Boolean; // Convert in OneSecond Blocken
DS1PORT[@Portb, 0] : Bit;
DDS1PORT[@DDRB, 0] : Bit;
DS1INP[@PINB, 0] : Bit;
DS2PORT[@Portb, 1] : Bit;
DDS2PORT[@DDRB, 1] : Bit;
DS2INP[@PINB, 1] : Bit;
LED[@Portc, 5] : Bit;
DDLED[@DDRc, 5] : Bit;
TS[@Portd, 2] : Bit;
DDTS[@DDRd, 2] : Bit;
TSINP[@PINd, 2] : Bit;
MyTemp : Float;
tf : Float;
TB : int8;
Oldsecond : Byte;
{--------------------------------------------------------------}
{ functions }
//------------------------------------------------------------------------------
Function OneWireReset(DSPORT : Byte) : Boolean;
Begin
DisableInts;
Case DSPORT Of
1 :
DDS1PORT := 1; //port is output
DS1PORT := 1; //port is high
|
2 :
DDS2PORT := 1; //port is output
DS2PORT := 1; //port is high
|
Endcase;
uDelay_1(RWSlot); // wait 60us
Case DSPORT Of
1 :
DS1PORT := 0; //port is low
|
2 :
DS2PORT := 0; //port is low
|
Endcase;
uDelay(LP); //wait 480 us
Case DSPORT Of
1 :
DDS1PORT := 0; // port is input
DS1PORT := 1; // pullup on
|
2 :
DDS2PORT := 0; // port is input
DS2PORT := 1; // pullup on
|
Endcase;
uDelay_1(RWSlot); // wait 60us
Case DSPORT Of
1 :
Return(Not DS1INP);
|
2 :
Return(Not DS2INP);
|
Endcase;
ENABLEINTS;
End;
//------------------------------------------------------------------------------
Procedure OneWireWrite_1_Bit(DSPORT : Byte);
Begin
DisableInts;
Case DSPORT Of
1 :
DS1PORT := 0;
DDS1PORT := 1;
uDelay_1(SP);
|
2 :
DS2PORT := 0;
DDS2PORT := 1;
uDelay_1(SP2);
|
Endcase;
Case DSPORT Of
1 :
DDS1PORT := 0;
DS1PORT := 1;
|
2 :
DDS2PORT := 0;
DS2PORT := 1;
|
Endcase;
uDelay_1(RWSlot); //timeslot = 60us
ENABLEINTS;
End;
//------------------------------------------------------------------------------
Procedure OneWireWrite_0_Bit(DSPORT : Byte);
Begin
DisableInts;
Case DSPORT Of
1 :
DS1PORT := 0;
DDS1PORT := 1;
|
2 :
DS2PORT := 0;
DDS2PORT := 1;
|
Endcase;
uDelay_1(RWSlot); //timeslot = 60us
Case DSPORT Of
1 :
DDS1PORT := 0;
DS1PORT := 1;
|
2 :
DDS2PORT := 0;
DS2PORT := 1;
|
Endcase;
ENABLEINTS;
End;
//------------------------------------------------------------------------------
Function OneWireReadBit(DSPORT : Byte) : Boolean;
Begin
DisableInts;
Case DSPORT Of
1 :
DS1PORT := 0;
DDS1PORT := 1;
uDelay_1(SP);
|
2 :
DS2PORT := 0;
DDS2PORT := 1;
uDelay_1(SP2);
|
Endcase;
Case DSPORT Of
1 :
DDS1PORT := 0;
DS1PORT := 1;
uDelay_1(SP);
|
2 :
DDS2PORT := 0;
DS2PORT := 1;
uDelay_1(SP2);
|
Endcase;
ENABLEINTS;
Case DSPORT Of
1 :
Return(DS1INP);
|
2 :
Return(DS2INP);
|
Endcase;
End;
//------------------------------------------------------------------------------
Procedure OneWireWriteByte(DSPORT : Byte; C : Byte);
Var
X : Byte;
Begin
For X := 0 To 7 Do
If Bit(C, X) Then
OneWireWrite_1_Bit(DSPORT);
Else
OneWireWrite_0_Bit(DSPORT);
Endif;
uDelay_1(2);
Endfor;
End;
//------------------------------------------------------------------------------
Function OneWireReadByte(DSPORT : Byte) : Byte;
Var
X, D : Byte;
Begin
For X := 0 To 7 Do
If OneWireReadBit(DSPORT) Then
INCL(D, X);
Else
EXCL(D, X);
Endif;
uDelay_1(RWSlot); //timeslot = 60us
Endfor;
Return(D);
End;
//------------------------------------------------------------------------------
Function ReadTemperature : Byte;
Var
temp_lsb, temp_msb : Byte;
k : Byte;
Temp : Word;
Begin
temp_msb := get[1];// Sign byte + lsbit
temp_lsb := get[0];// Temp data plus lsb
Hi(Temp) := temp_msb;
Lo(Temp) := temp_lsb;
Temp := Temp Shr 4; // 1C Auflösung
Return(Lo(Temp));
End ReadTemperature;
//------------------------------------------------------------------------------
Procedure ReadScratchpad(DSPORT : Byte);
Var
k : Byte;
Begin
OneWireReset(DSPORT);
uDelay(5);
OneWireWriteByte(DSPORT, $CC); //Skip ROM
OneWireWriteByte(DSPORT, $BE); // Read Scratch Pad
For k := 0 To 8 Do
get[k] := OneWireReadByte(DSPORT);
Endfor;
End ReadScratchpad;
//------------------------------------------------------------------------------
Procedure ReadRom(DSPORT : Byte);
Var
k : Byte;
Begin
OneWireWriteByte(DSPORT, $33); // Read Rom
For k := 0 To 7 Do
get[k] := OneWireReadByte(DSPORT);
Endfor;
End ReadRom;
//------------------------------------------------------------------------------
Function Calccrc : Byte;
Const
Poly : Byte = $8C;
Var
CRC : Byte;
I, j : Integer;
Result : Byte;
Begin
CRC := 0;
For I := 0 To 7 Do
CRC := CRC Xor get[I];
For j := 1 To 8 Do
If odd(CRC) Then
CRC := (CRC Shr 1) Xor Poly;
Else CRC := CRC Shr 1;
Endif;
Endfor;
Endfor;
Return(CRC);
End;
//------------------------------------------------------------------------------
Procedure Onsystick(SaveAllRegs);
Begin
If DSTimer > 0 Then
Dec(DSTimer);
Else
Convblock := False;
Endif;
End;
//------------------------------------------------------------------------------
Procedure ReadDS;
Begin
ReadScratchpad(1);
If Calccrc = get[8] Then
TB := Int8(ReadTemperature);
tf := Float(get[7] - get[6]);
KSTemp := Float(TB - 0.25) + (tf / Float(get[7]));
Else
INC(crc1);
Endif;
ReadScratchpad(2);
If Calccrc = get[8] Then
TB := Int8(ReadTemperature);
tf := Float(get[7] - get[6]);
SpTemp := Float(TB - 0.25) + (tf / Float(get[7]));
Else
INC(crc2);
Endif;
End;
//------------------------------------------------------------------------------
Procedure Startconv;
Begin
If OneWireReset(1) Then
uDelay_1(RWSlot);
OneWireWriteByte(1, $CC); // Skip ROM
OneWireWriteByte(1, $44); // Start Convert
Else
INC(nc1);
Endif;
If OneWireReset(2) Then
uDelay_1(RWSlot);
OneWireWriteByte(2, $CC); // Skip ROM
OneWireWriteByte(2, $44); // Start Convert
Else
INC(nc2);
Endif;
DSTimer := 85; // at 10ms Systick 800 mS for Convert
Convblock := True;
Inc(MC);
End;
{--------------------------------------------------------------}
{ Main Program }
{$IDATA}
Begin
ENABLEINTS;
init_lcd($27);
BL_On;
lcdcursor(False, False);
lcdclr;
LCDCharSet(#2, $00, $08, $03, $04, $04, $04, $03, $00);
lcdxy(0, 0);
Convblock := True;
crc1 := 0;
crc2 := 0;
nc1 := 0;
nc2 := 0;
MC := 0;
DDLED := 1;
KSTemp := 0;
Convblock := True;
DSTimer := 0;
OneWireReset(1);
uDelay_1(RWSlot);
OneWireWriteByte(1, $CC); // Skip ROM
OneWireWriteByte(1, $44); // Start Conversion
OneWireReset(2);
OneWireWriteByte(2, $CC); // Skip ROM
OneWireWriteByte(2, $44); // Start Conversion
MDelay(255);
lcdclr;
DSTimer := 85;
Loop
lcdxy(2, 0);
Write(LCDOUT, LongToStr(MC : 6));
If Convblock = False Then
Readds;
Led := False;
Endif;
mDelay(100);
If ((DSTimer = 0)) Then
lcdxy(0, 1);
Write(LCDOUT, 'TK:' + IntToStr(Round(KSTemp) : 5));
LCDOUT(#2);
lcdxy(10, 1);
Write(LCDOUT, 'TS:' + IntToStr(Round(SPTemp) : 5));
LCDOUT(#2);
lcdxy(0, 2);
Write(LCDOUT, 'CRC: '); // CRC Fehler
Write(LCDOUT, LongToStr(crc1 : 6));
Write(LCDOUT, LongToStr(crc2 : 6));
lcdxy(0, 3);
Write(LCDOUT, 'NC : '); // No Connect Fehler
Write(LCDOUT, LongToStr(nc1 : 6));
Write(LCDOUT, LongToStr(nc2 : 6));
Endif;
If ((Convblock = False)) Then
Startconv
;
LED := True;
Endif;
Endloop;
End Heizung.