Bumbum
25.07.2013, 17:30
Hallo,
ich versuche mich gerade an der Ansteuerung eines DS18S20, es klappt aber nicht. Folgenden Code habe ich mit Hilfe des Datenblattes erstellt:
//Library zur Ansteuerung eines Temperatur-Sensors DS18S20
void DS18S20_init (volatile U8 *DataInPort, volatile U8 *DataOutPort, volatile U8 *DDR, U8 Pin);
bool DS18S20_startTemp (void);
bool DS18S20_waitTemp (void);
bool DS18S20_readMemory (void);
bool DS18S20_getTemp (int *result);
bool DS18S20_resetPulse (void);
void DS18S20_sendByte (U8 dataByte);
bool DS18S20_readBit (void);
U8 DS18S20_readByte (void);
U8 DS18S20_scratchPadCRC (void);
#define DS18S20_skipROM 0xCC
#define DS18S20_convertTemp 0x44
#define DS18S20_readScratchPad 0xBE
volatile U8 *DS18S20inputPort;
volatile U8 *DS18S20ddrPort;
U8 DS18S20dataPin;
U8 scratchPad[10];
#define DS18S20input *DS18S20ddrPort &= ~(1<<DS18S20dataPin)
#define DS18S20output *DS18S20ddrPort |= (1<<DS18S20dataPin)
#define DS18S20dataIn ((*DS18S20inputPort & (1<<DS18S20dataPin)) != 0)
void DS18S20_init (volatile U8 *DataInPort, volatile U8 *DataOutPort, volatile U8 *DDR, U8 Pin)
{
DS18S20inputPort = DataInPort;
DS18S20ddrPort = DDR;
DS18S20dataPin = Pin;
DS18S20input;
*DataOutPort &= ~(1<<Pin); // Pin löschen
}
bool DS18S20_startTemp (void)
{
if (DS18S20_resetPulse ())
{
DS18S20_sendByte (DS18S20_skipROM);
DS18S20_sendByte (DS18S20_convertTemp);
return (TRUE);
}
else
return (FALSE);
}
bool DS18S20_waitTemp (void)
{
U8 timeout = 100;
bool lastBit = FALSE;
while ((!lastBit) & (timeout > 0))
{
_delay_ms (10);
timeout--;
lastBit = DS18S20_readBit ();
}
return (lastBit);
}
bool DS18S20_readMemory (void)
{
if (DS18S20_resetPulse ())
{
DS18S20_sendByte (DS18S20_skipROM);
DS18S20_sendByte (DS18S20_readScratchPad);
U8 i1;
for (i1 = 0; i1 < 9; i1++)
{
scratchPad[i1] = DS18S20_readByte ();
}
return (TRUE);
//return (DS18S20_scratchPadCRC () == scratchPad[8]);
}
else
return (FALSE);
}
bool DS18S20_getTemp (int *result)
{
*result = 0;
if (DS18S20_startTemp ())
if (DS18S20_waitTemp ())
if (DS18S20_readMemory ())
{
*result = scratchPad[1]<<8;
*result = *result + scratchPad[0];
return (TRUE);
}
return (FALSE);
}
bool DS18S20_resetPulse (void)
{
DS18S20output;
_delay_us (500);
DS18S20input;
_delay_us (100);
bool result = !(DS18S20dataIn);
_delay_us (500);
return (result);
}
void DS18S20_sendByte (U8 dataByte)
{
U8 i1;
for (i1 = 0; i1 < 8; i1++)
{
DS18S20output;
_delay_us (5);
if ((dataByte & 1) != 0)
DS18S20input;
dataByte = dataByte>>1;
_delay_us (60);
DS18S20input;
_delay_us (5);
}
}
bool DS18S20_readBit (void)
{
DS18S20output;
_delay_us (5);
DS18S20input;
_delay_us (15);
bool result = DS18S20dataIn;
_delay_us (45);
return (result);
}
U8 DS18S20_readByte (void)
{
U8 result = 0;
U8 i1;
for (i1 = 0; i1 < 8; i1++)
{
result = result>>1;
if (DS18S20_readBit ())
result |= 0x80;
}
return (result);
}
U8 DS18S20_scratchPadCRC (void)
{
U8 ByteCount;
U8 CRC = 0;
for (ByteCount = 0; ByteCount < 8; ByteCount++)
{
U8 PruefByte = scratchPad[ByteCount];
U8 BitCount = 8;
for (BitCount = 0; BitCount < 8; BitCount++)
{
U8 BitWert = (CRC ^ PruefByte) & 0x01;
if (BitWert == 0x01)
CRC = CRC ^ 0x18; // 0x18= X^8+X^5+X^4+X^0
CRC = 0x7F & (CRC>>1);
if (BitWert == 0x01)
CRC = CRC | 0x80;
PruefByte = PruefByte>>1;
}
}
return (CRC);
}
Wenn ich die Funktion DS18S20_readMemory aufrufe, erhalte ich vom Sensor ausschließlich high als Bit-Daten. Ich habe meinen Code schon mit etlichen aus dem Web verglichen, und er ist eigentlich gleich. Wahrscheinlich sehe ich mal wieder den Wald vor lauter Bäumen nicht.
Was funktioniert ist der Reset-Puls und die darauffolgende presence pulse Erkennung. Der Sensor zieht die Leitung auf Low. Wenn ich die Wartezeit für das low zu kurz (10µS), oder zu lange (200µS) mache, wird das low schon nicht mehr erkannt. Wenn ich den Sensor abklemme, bleibt die Leitung natürlich auch high.
Allerdings zieht er die Leitung auch auf low, wenn ich den Reset-Puls z.B. nur 100µS auf low halte. Allerdings nicht immer.
Aber dann wars dass auch schon. Nach dem Reset bekomme ich keine Reaktion mehr vom Sensor. Ich habe keine Ahnung, wo ich noch suchen soll. Mit den Delay-Zeiten habe ich schon stundenlang gespielt. Der Sensor will mir einfach keine Daten senden.
Das ganze läuft auf einem Attiny45 mit internem Takt. Ich lasse eine LED mit _delay_ms (1000) blinken und der Sekundentakt scheint gut zu passen. Der Clock und die delay.h ist also scheinbar richtig konfiguriert. (sonst würde das mit dem Reset-Puls und der presence-Erkennung wohl auch nicht zu funktionieren)
Der Fehler scheint also in den Sende- Und Empfangs-Funktionen zu liegen, aber die habe ich schon 1000x durchgeschaut. Wo könnte ich noch suchen?
Viele Grüße
Andreas
ich versuche mich gerade an der Ansteuerung eines DS18S20, es klappt aber nicht. Folgenden Code habe ich mit Hilfe des Datenblattes erstellt:
//Library zur Ansteuerung eines Temperatur-Sensors DS18S20
void DS18S20_init (volatile U8 *DataInPort, volatile U8 *DataOutPort, volatile U8 *DDR, U8 Pin);
bool DS18S20_startTemp (void);
bool DS18S20_waitTemp (void);
bool DS18S20_readMemory (void);
bool DS18S20_getTemp (int *result);
bool DS18S20_resetPulse (void);
void DS18S20_sendByte (U8 dataByte);
bool DS18S20_readBit (void);
U8 DS18S20_readByte (void);
U8 DS18S20_scratchPadCRC (void);
#define DS18S20_skipROM 0xCC
#define DS18S20_convertTemp 0x44
#define DS18S20_readScratchPad 0xBE
volatile U8 *DS18S20inputPort;
volatile U8 *DS18S20ddrPort;
U8 DS18S20dataPin;
U8 scratchPad[10];
#define DS18S20input *DS18S20ddrPort &= ~(1<<DS18S20dataPin)
#define DS18S20output *DS18S20ddrPort |= (1<<DS18S20dataPin)
#define DS18S20dataIn ((*DS18S20inputPort & (1<<DS18S20dataPin)) != 0)
void DS18S20_init (volatile U8 *DataInPort, volatile U8 *DataOutPort, volatile U8 *DDR, U8 Pin)
{
DS18S20inputPort = DataInPort;
DS18S20ddrPort = DDR;
DS18S20dataPin = Pin;
DS18S20input;
*DataOutPort &= ~(1<<Pin); // Pin löschen
}
bool DS18S20_startTemp (void)
{
if (DS18S20_resetPulse ())
{
DS18S20_sendByte (DS18S20_skipROM);
DS18S20_sendByte (DS18S20_convertTemp);
return (TRUE);
}
else
return (FALSE);
}
bool DS18S20_waitTemp (void)
{
U8 timeout = 100;
bool lastBit = FALSE;
while ((!lastBit) & (timeout > 0))
{
_delay_ms (10);
timeout--;
lastBit = DS18S20_readBit ();
}
return (lastBit);
}
bool DS18S20_readMemory (void)
{
if (DS18S20_resetPulse ())
{
DS18S20_sendByte (DS18S20_skipROM);
DS18S20_sendByte (DS18S20_readScratchPad);
U8 i1;
for (i1 = 0; i1 < 9; i1++)
{
scratchPad[i1] = DS18S20_readByte ();
}
return (TRUE);
//return (DS18S20_scratchPadCRC () == scratchPad[8]);
}
else
return (FALSE);
}
bool DS18S20_getTemp (int *result)
{
*result = 0;
if (DS18S20_startTemp ())
if (DS18S20_waitTemp ())
if (DS18S20_readMemory ())
{
*result = scratchPad[1]<<8;
*result = *result + scratchPad[0];
return (TRUE);
}
return (FALSE);
}
bool DS18S20_resetPulse (void)
{
DS18S20output;
_delay_us (500);
DS18S20input;
_delay_us (100);
bool result = !(DS18S20dataIn);
_delay_us (500);
return (result);
}
void DS18S20_sendByte (U8 dataByte)
{
U8 i1;
for (i1 = 0; i1 < 8; i1++)
{
DS18S20output;
_delay_us (5);
if ((dataByte & 1) != 0)
DS18S20input;
dataByte = dataByte>>1;
_delay_us (60);
DS18S20input;
_delay_us (5);
}
}
bool DS18S20_readBit (void)
{
DS18S20output;
_delay_us (5);
DS18S20input;
_delay_us (15);
bool result = DS18S20dataIn;
_delay_us (45);
return (result);
}
U8 DS18S20_readByte (void)
{
U8 result = 0;
U8 i1;
for (i1 = 0; i1 < 8; i1++)
{
result = result>>1;
if (DS18S20_readBit ())
result |= 0x80;
}
return (result);
}
U8 DS18S20_scratchPadCRC (void)
{
U8 ByteCount;
U8 CRC = 0;
for (ByteCount = 0; ByteCount < 8; ByteCount++)
{
U8 PruefByte = scratchPad[ByteCount];
U8 BitCount = 8;
for (BitCount = 0; BitCount < 8; BitCount++)
{
U8 BitWert = (CRC ^ PruefByte) & 0x01;
if (BitWert == 0x01)
CRC = CRC ^ 0x18; // 0x18= X^8+X^5+X^4+X^0
CRC = 0x7F & (CRC>>1);
if (BitWert == 0x01)
CRC = CRC | 0x80;
PruefByte = PruefByte>>1;
}
}
return (CRC);
}
Wenn ich die Funktion DS18S20_readMemory aufrufe, erhalte ich vom Sensor ausschließlich high als Bit-Daten. Ich habe meinen Code schon mit etlichen aus dem Web verglichen, und er ist eigentlich gleich. Wahrscheinlich sehe ich mal wieder den Wald vor lauter Bäumen nicht.
Was funktioniert ist der Reset-Puls und die darauffolgende presence pulse Erkennung. Der Sensor zieht die Leitung auf Low. Wenn ich die Wartezeit für das low zu kurz (10µS), oder zu lange (200µS) mache, wird das low schon nicht mehr erkannt. Wenn ich den Sensor abklemme, bleibt die Leitung natürlich auch high.
Allerdings zieht er die Leitung auch auf low, wenn ich den Reset-Puls z.B. nur 100µS auf low halte. Allerdings nicht immer.
Aber dann wars dass auch schon. Nach dem Reset bekomme ich keine Reaktion mehr vom Sensor. Ich habe keine Ahnung, wo ich noch suchen soll. Mit den Delay-Zeiten habe ich schon stundenlang gespielt. Der Sensor will mir einfach keine Daten senden.
Das ganze läuft auf einem Attiny45 mit internem Takt. Ich lasse eine LED mit _delay_ms (1000) blinken und der Sekundentakt scheint gut zu passen. Der Clock und die delay.h ist also scheinbar richtig konfiguriert. (sonst würde das mit dem Reset-Puls und der presence-Erkennung wohl auch nicht zu funktionieren)
Der Fehler scheint also in den Sende- Und Empfangs-Funktionen zu liegen, aber die habe ich schon 1000x durchgeschaut. Wo könnte ich noch suchen?
Viele Grüße
Andreas