PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ansteuerung eines DS18S20



Bumbum
25.07.2013, 16: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

Bumbum
26.07.2013, 08:21
Guten morgen,

hier mal ein Bild vom Aufbau:

26086

Alles noch auf dem STK mit kurzen Kabeln, um Fehler mit zu langen Kabeln, etc. während der Entwicklung vorzubeugen. Der DS18S20 bekommt seine Spannungsversorgung ebenfalls über das STK. Den Zwei-Draht-Anschluss inkl. Versorgungsspannung über die Datenleitung möchte ich erst probieren, wenn die Kommunikation läuft.

Viele Grüße
Andreas

Bumbum
28.07.2013, 12:15
Hallo,

ich habe die Ursache des Problems gefunden. Nur der vollständigkeit halber, falls jemand anderes ein ähniches Problem haben sollte:

Ich habe den ATtiny45 mit dem internen RC-Oszillator und gesetztem CKDIV8 Bit laufen lassen. Also FCPU = ca. 1 MHz. Das ist aber scheinbar zuwenig, um die Delays, die der DS18S20 benötgit genau genug einzuhalten. Nach dem löschen des CKDIV8-Bits und einer Run-Time-Geschwindigkeit von 8MHz läuft das Ganze nun einwandfrei.

Viele Grüße
Andreas