Hallo,
Habe Probleme damit einen DS1820 Temperatursensor auszulesen, welcher an
einem Atmega16 hängt.
Er hängt an Port B0, und hat einen 4,7K Ohm-Pullup.
Das Programm sieht zum Reset des DS1820 einen 600us-Low vor, danach
meldet er sich 28uS später mit einem Presence Pulse von 102uS.
Soweit ist alles OK.
Problem ist nun dass egal was ich an ihn Sende z.b. (0xBE für
Read-Scratch-Pad oder 0x33 für Read Rom) er nichts zurück Sendet.
Ich Sende ihm 0en der Länge 85uS, einsen der Länge 9uS und gebe ihm ca
0,5Sek Zeit um die Leitung selbst mal auf Masse zu ziehen.
Aber das tut er ja nicht.
Bei 1-Wire darf der µC nie aktiv den Pin hochziehen, ausser in der
Messphase bei parasitärer Versorgung. Das muss aufgrund der
bidirektionalen Arbeitsweise ein externer Pullup-Widerstand machen.
Also: PORTB.0=0 lassen und DDRB.0=0 für high/input, DDRB.0=1 für low.
Matze schrieb:> Eventuell seht ihr das Problem.
Damit er erkennen kann dass er und nur er gemeint ist, muß er ein Skip
ROM bekommen, es könnten ja mehrere am Draht hängen. Dann muß man
nämlich ein Match ROM mit der zugehörigen Adresse senden.
A. K. schrieb:> Also: PORTB.0=0 lassen und DDRB.0=0 für high/input, DDRB.0=1 für low.
Danke, das hab ich nun erledigt und so geht der Presence auch wirklich
bis 0V.
Route 66 schrieb:> Damit er erkennen kann dass er und nur er gemeint ist, muß er ein Skip> ROM bekommen, es könnten ja mehrere am Draht hängen. Dann muß man> nämlich ein Match ROM mit der zugehörigen Adresse senden.
Stimmt, die würde eich es überhaupt machen wenn ich mehrere DS1820an
einem Bus hätte?
Müsste ich sie mit der Sensior-ID Addressieren die ich vermutlich vor
dem 1. Auslesen mittels Skip-Rom nicht kennen würde?
Das Problem ist jedoch immer noch das selbe, er gibt keine Daten aus.
Wenn ich dem Signalflussdiagramm im Datenblatt folge steht dort zuerst
kommt ein Reset, danach kann ich ein Skip-Rom (0xCC) senden.
Danach hoffe ich die Temperatur wandeln zu können (0x44) und sie
auslesen zu können (0xBE).
Habe den Code auch sonst etwas verbessert:
1
ISR(TIMER0_COMP_vect)
2
{
3
DDRB&=0xFE;//Pin Setzen / Input
4
TCCR0=0x00;//Stoppen
5
Tint=1;
6
}
7
8
intmain(void)
9
{
10
Init();
11
DDRD|=0x40;//Triggerung für Oszi
12
PORTB&=FE;//PORTB.0=0
13
TIMSK|=0x02;//Interrupt Timer0 Enable
14
while(1)
15
{
16
17
One_Wire_Send(0x00,1);//Reset
18
_delay_ms(2);//Zeit für Presence = 500uS
19
One_Wire_Send(0xCC,0);//DS1820Auswählen
20
One_Wire_Send(0x44,0);//Temperatur Wandeln
21
PORTD|=0x40;//Setzen
22
One_Wire_Send(0xBE,0);//Temperatur Zusenden
23
_delay_ms(4);//Zeit zum zusenden
24
PORTD&=0xBF;//Rücksetzen
25
}
26
}
27
28
voidOne_Wire_Send(unsignedshortintByte,intSteuer)
29
{
30
Tint=0;
31
unsignedshortintVergleich=0x80;
32
if(Steuer==1)//Reset des DS1820
33
{
34
TCNT0=0x00;//Anfang des Zählens
35
OCR0=38;//--600uS
36
DDRB|=0x01;//Portpin auf LOW / Ausgang
37
TCCR0=0x03;//Prescaler = 8,Timer Starten --16uS
38
while(Tint!=1)//Warten bis IRQ Ausgelöst
39
{;}
40
}
41
else//Fals Kein Steuersignal übertragen werden soll
> One_Wire_Send(0x44,0); //Temperatur Wandeln> PORTD|=0x40; //Setzen> One_Wire_Send(0xBE,0); //Temperatur Zusenden> _delay_ms(4); //Zeit zum zusenden
He. Moment mal.
Ich hab jetzt die Codes nicht kontrolliert.
Aber nachdem du dem DS befohlen hast, die Temperatur festzustellen,
musst du ihm auch Zeit geben, genau das zu tun.
Ehe da jetzt weiter analysiert wird.
In der Codesammlung gibt es Routinen für den DS1820. Im speziellen
fallen mir die Routinen vom Peter Danegger ein. Hol dir die mal und
studier mal, wie das alles gedacht ist.
Ich hätte nicht gedacht das er 500mS zum Wandeln braucht.
Ein weiteres Problem war dass nicht einfach 0en und 1en gesendet werden,
sondern die Kommunikation in Timeslots abläuft.
Ein Timeslot hat eine länge von 60-120uS.
Folglich müssen im Falle einer gesendeten 1 mit 10uS auf Low, zusätzlich
80uS High folgen bevor das nächste Bit gesendet wird.
Diese Fehler wurden nun Korrigiert.
Eine 0 Besteht aus 80uS LOW und 10uS High.
Eine 1 aus 10uS LOW und 80uS High.
Aber auch das hat am eigentlichen Problem nichts geändert.
Er zieht die Leitung nur auf Low um sein dasein zu bestätigen.
So sieht es nun aus:
1
ISR(TIMER0_COMP_vect)
2
{
3
DDRB&=0xFE;//Pin Setzen / Input
4
TCCR0=0x00;//Stoppen
5
Tint=1;
6
}
7
8
intmain(void)
9
{
10
Init();
11
DDRD|=0x40;//Triggerung für Oszi
12
PORTB&=FE;//PORTB.0=0
13
TIMSK|=0x02;//Interrupt Timer0 Enable
14
while(1)
15
{
16
One_Wire_Send(0x00,1);//Reset
17
_delay_ms(2);//Zeit für Presence = 500uS
18
One_Wire_Send(0xCC,0);//DS1820 Auswählen
19
_delay_ms(1);//Zeit zum Wandeln
20
One_Wire_Send(0x44,0);//Temperatur Wandeln
21
_delay_ms(600*4);//Zeit zum Wandeln 600ms
22
//One_Wire_Send(0xCC,0); //DS1820 Auswählen
23
_delay_ms(2);//Zeit zum Wandeln
24
while(1)
25
{
26
One_Wire_Send(0x00,1);//Reset
27
_delay_ms(2);//Zeit für Presence = 500uS
28
PORTD|=0x40;//Setzen
29
One_Wire_Send(0x33,0);//Temperatur Zusenden
30
_delay_ms(10);//Zeit zum zusenden
31
PORTD&=0xBF;//Rücksetzen
32
}
33
34
}
35
}
36
37
voidOne_Wire_Send(unsignedshortintByte,intSteuer)
38
{
39
40
unsignedshortintVergleich=0x80;
41
if(Steuer==1)//Reset des DS1820
42
{
43
Tint=0;
44
TCNT0=0x00;//Anfang des Zählens
45
OCR0=38;//--600uS
46
DDRB|=0x01;//Portpin auf LOW / Ausgang
47
TCCR0=0x03;//Prescaler = 8,Timer Starten --16uS
48
while(Tint!=1)//Warten bis IRQ Ausgelöst
49
{;}
50
}
51
else//Fals Kein Steuersignal übertragen werden soll
@Klaus
Danke das Projekt ist sehr nützlich,
Darin steht dass der DS1820 die Daten 15uS nach dem beginn des LOWs bei
senden einer 1 abgreift.
Um nun sicher zu gehen dass er auch wirklich eine 1 erkennt, habe ich
das LOW auf 8uS verkürzt.
Ausserdem bin ich nun nur noch bei ca 62uS für einen Timeslot und habe
die Timerinitialisierung ausgelagert.
Laut der Beschreibung des Projekts sendet ein einzelner Slave am Bus,
nach Reset und Empfang von 0x33 für Read Rom seine 64Bit - ID.
Das müsste wohl noch am ehesten Funktionieren.
Soweit ich gelesen habe muss ich beim 1Wire-Bus das LSB zuerst senden?
Aber auch das alles hat mich noch nicht weiter gebracht.
1
ISR(TIMER0_COMP_vect)
2
{
3
DDRB&=0xFE;//Pin Setzen / Input
4
TCCR0=0x00;//Stoppen
5
Tint=1;
6
}
7
8
intmain(void)
9
{
10
Init();
11
DDRD|=0x40;//Triggerung für Oszi
12
PORTB&=FE;//PORTB.0=0
13
TIMSK|=0x02;//Interrupt Timer0 Enable
14
while(1)
15
{
16
One_Wire_Send(0x00,1);//Reset
17
_delay_ms(2);//Zeit für Presence = 500uS
18
PORTD|=0x40;//Setzen
19
One_Wire_Send(0xCC,0);//Temperatur Zusenden
20
_delay_ms(10);//Zeit zum zusenden
21
PORTD&=0xBF;//Rücksetzen
22
_delay_ms(10);//Zeit zum zusenden
23
}
24
}
25
26
voidOne_Wire_Send(unsignedshortintByte,intSteuer)
27
{
28
if(Steuer==1)//Reset des DS1820
29
Timer0(38,0x03,0);
30
else//Fals Kein Steuersignal übertragen werden soll
31
{
32
unsignedshortintVergleich=0x80;
33
for(inti=8;i>=1;Vergleich=Vergleich/2,i--)
34
{
35
if(Byte&Vergleich)//1 Senden
36
{
37
Timer0(0x02,0x01,0);//Pin ist nach 8 uS wieder auf High
Wenn ich nun wie im PDF des 1-Wire Projekts dem DS1820 zuerst ein
1. Reset
2. Skip-Rom
3. Messung
4. Reset
5. Skip-Rom
6. Read Scratscpad-Ram
sende.
Gibt er außer dem Presence nichts her.
Keine Ahnung was ich tun soll?
1
ISR(TIMER0_COMP_vect)
2
{
3
DDRB&=0xFE;//Pin Setzen / Input
4
TCCR0=0x00;//Stoppen
5
Tint=1;
6
}
7
8
intmain(void)
9
{
10
Init();
11
DDRD|=0x40;//Triggerung für Oszi
12
PORTB&=FE;//PORTB.0=0
13
TIMSK|=0x02;//Interrupt Timer0 Enable
14
One_Wire_Send(0x00,1);//Reset
15
_delay_ms(2);//Zeit für Presence = 500uS
16
One_Wire_Send(0x44,0);//Temperatur Wandeln
17
_delay_ms(750*4);//Zeit zum Wandeln 600ms
18
while(1)
19
{
20
One_Wire_Send(0x00,1);//Reset
21
_delay_ms(2);//Zeit für Presence = 500uS
22
PORTD|=0x40;//Setzen
23
One_Wire_Send(0xCC,0);//DS1820 Auswählen
24
One_Wire_Send(0xBE,0);//DS1820 Auswählen
25
_delay_ms(10);//Zeit zum Wandeln
26
PORTD&=0xBF;//Rücksetzen
27
}
28
}
29
30
voidOne_Wire_Send(unsignedshortintByte,intSteuer)
31
{
32
if(Steuer==1)//Reset des DS1820
33
Timer0(2);
34
else//Fals Kein Steuersignal übertragen werden soll
Matze schrieb:> Ich sehe mit dem Oszi das der nichts sendet.> Also brauche ich wohl keine Einleseroutine schreiben.
Bis ein 1-Wire Slave etwas sendet kannst du ewig warten.
Der Master holt es ab.
@Matze
>Er hängt an Port B0, und hat einen 4,7K Ohm-Pullup.
Wo ist der denn in deinem Schaltplan eingezeichnet?
Für mich sieht es eher aus als würde der DS1820 auf dem Port PB3
verbunden zu sein. Korrigier mich!
@ A.K.
Ich wusste nicht das der Master die Daten abholen muss.
In diesem
http://www.atmel.com/Images/doc2579.pdf
Datenblatt steht um Daten zu lesen muss der Master den Pin für 1-15uS
auf LOW ziehen.
Danach kann der Slave die Datenleitung weiterhin aktiv auf LOW ziehenund
dem Master damit 0en senden.
@Klaus
1.
Stimmt im Schaltplan Hängt der DS1820 auf PinB3.
Ich habe den Schaltplan gezeichnet nach dem ich die "Uhr" aufgebaut
hatte.
Dabei hat sich herausgestellt, dass es Layouttechnisch besser ist den
DS1820 auf PB3 zu legen.
Auf dem Lochraster-Prototyp ist er auf PB0.
2.
Stimmt eigentlich kann ich auf den Interrupt verzichten, und es
stattdessen mit einem Delay machen.
Und im uS-Bereich ist das vielleicht auch praktischer.
Wollte es ursprünglich mit Interrupts machen um sicherzustennen das Uhr
mit Zeitmultiplexing nicht stehen bleibt.
3.
Der Codeschnipsel Init tut nichts was momentan wichtig ist.
Das Gesamtprogramm ist nun:
1
intmain(void)
2
{
3
Init();
4
DDRD|=0x40;//Triggerung für Oszi
5
PORTB&=FE;//PORTB.0=0
6
TIMSK|=0x02;//Interrupt Timer0 Enable
7
One_Wire_Send(0x00,1);//Reset
8
_delay_ms(2);//Zeit für Presence = 500uS
9
One_Wire_Send(0x22,0);//Temperatur Wandeln
10
_delay_ms(750*4);//Zeit zum Wandeln 600ms
11
while(1)
12
{
13
One_Wire_Send(0x00,1);//Reset
14
_delay_ms(2);//Zeit für Presence = 500uS
15
One_Wire_Send(0x33,0);//Skip-Rom
16
PORTD&=0xBF;//Rücksetzen
17
One_Wire_Send(0x7D,0);//Daten Lesen
18
PORTD|=0x40;//Setzen
19
One_Wire_Send(0xFF,0);//DS1820 Auswählen
20
PORTD&=0xBF;//Rücksetzen
21
One_Wire_Send(0xFF,0);//DS1820 Auswählen
22
PORTD|=0x40;//Setzen
23
One_Wire_Send(0xFF,0);//DS1820 Auswählen
24
One_Wire_Send(0xFF,0);//DS1820 Auswählen
25
One_Wire_Send(0xFF,0);//DS1820 Auswählen
26
One_Wire_Send(0xFF,0);//DS1820 Auswählen
27
One_Wire_Send(0xFF,0);//DS1820 Auswählen
28
One_Wire_Send(0xFF,0);//DS1820 Auswählen
29
}
30
}
31
32
voidOne_Wire_Send(unsignedshortintByte,intSteuer)
33
{
34
if(Steuer==1)//Reset des DS1820
35
Bit_Senden(2);
36
else//Fals Kein Steuersignal übertragen werden soll
37
{
38
unsignedshortintVergleich=0x80;
39
for(inti=8;i>=1;Vergleich=Vergleich/2,i--)
40
{
41
if(Byte&Vergleich)//1 Senden
42
{
43
Bit_Senden(1);
44
}
45
else//0 Senden
46
{
47
Bit_Senden(0);
48
}
49
}
50
}
51
}
52
53
voidInit()
54
{
55
TCNT1H=0x00;//Timer auf 0
56
TCNT1L=0x00;
57
OCR1A=15624;
58
TCCR1A=0x00;//Kein WPM / Keine Ansteuerung von Pins
59
sei();
60
TIMSK|=(1<<OCIE1A);//Interrupt Enable
61
//TCCR1B=0x0C; //=00001100 / CTC-Modus, Prescaler = 256, Starten
62
DDRA=0xFF;
63
DDRB=0x00;//Eingang
64
DDRC=0xFC;
65
DDRD=0x00;
66
}
Nun Funktioniert es :)
Er gibt mir in den ersten 2 Bytes 01010101 00000000
Nun bin ich mit nur noch nicht so richtig sicher wie ich das
interpretieren soll.
00000000 ist im zum glück positiven Bereich.
Aber 01010101 bedeitet bei +1 Pro 0.5°C für LSB zuletzt 42,5°C
und für LSB zuerst: 85°C.
Beides ist nicht so richtig realistisch.
Denke ich jetzt falsch?
>Der Codeschnipsel Init tut nichts was momentan wichtig ist.
Sag soetwas nicht Leichtsinnig.
Wie sieht den Bit_Senden(1); genau aus.
wird dort das Timing der Zeitschlitze eingehalten.
Ein Beispiel wie es Aussehen könnte wenn du Skip-Rom verwendest.
Hier mal ein Codesipsel von mir.
void DS18S20_readrom (void)
{
uint8_t i;
DS18S20_writebyte(0xCC); // Sende Skip ROM - Command
DS18S20_Init();
DS18S20_writebyte(0x33); // Sende READ-ROM - Command
for(i=0; i<8; i++)
{
DS18S20_ROM[i] = DS18S20_readbyte();
}
}
Als Ergebnis steht dann z.B. in DS18S20_ROM folgendes:
10 0E 61 DD 01 08 00 75 Das ist der Familliencode komplett
So sieht es aus wenn ich die Temperatur auslesen möchte.
DS18S20_writebyte(0xCC); // Sende Skip ROM - Command
DS18S20_Conv_T();
DS18S20_Init();
DS18S20_writebyte(0xCC); // Sende Skip ROM - Command
DS18S20_writebyte(0xBE); // Sende Read Scratchpad Command
for(i=0; i<9; i++)
{
DS18S20_Scratchpad[i] = DS18S20_readbyte();
}
85° stünde für "kein Wert", wie das Datasheet in schönster Klarheit
vermittelt.
Wird der Sensor parasitär versorgt, oder mit separatem Vcc?
Wärs nicht allmählich an der Zeit, mal Code anderer Leute anzusehen?
Mittlerweile ist ohnehin das halbe Programm nicht mehr von dir.
@A.K.
Der Sensor wird Separat versorgt.
Ich kann den Sensor nun auslesen, die Temparatur ausrechnen und
anzeigen.
Habe das Programm nun in eine Main.c und eine DS1820.c sowie DS1820.h
aufgeteilt.
Eine Erkennung für den Fall das sich der DS1820 nach Reset nicht meldet
eingebaut.
Nun möchte ich noch die CRC-Prüfsumme berechnen.
Dann soll er mit der Uhr gemeinsam laufen.
Damit diese ganau wird soll später über I2C ein DS3231 (RTC mit TCXO)
dazukommen.
Mich stört noch das der Sensor 500mS zum wandeln braucht.
Währenddessen soll die Anzeige nicht einfach stehen bleiben, eventuell
lässt sich das mit einem Timer lösen?
Grüße
Matze
Matze schrieb:> Mich stört noch das der Sensor 500mS zum wandeln braucht.> Währenddessen soll die Anzeige nicht einfach stehen bleiben, eventuell> lässt sich das mit einem Timer lösen?
du musst ja nicht warten, während der Sensor misst.
Starte einfach am Anfang die erste Messung.
In der Hauptschleife holst du dann z.B. alle 5-10 Sek. (häufiger ist bei
Temp. eigentlich selten sinnvoll) den letzten Wert ab und startest die
nächste Messung. Dein Messwert ist dann zwar jeweils um 4-9 Sekunden
veraltet, aber das ist wie gesagt bei Temperaturen meistens unwichtig.