Forum: Mikrocontroller und Digitale Elektronik 1-wire mit Atmega8


von Matthias (Gast)


Lesenswert?

Hallo,

ich probiere gerade einen DS18S20 über 1-wire mit dem Atmega8 
anzusteuern.
Noch vorab: ja ich habe das Forum durchsucht, ja ich weiß das es ganz 
viele funktionierende Beispiele gibt. Aber genau das will ich nicht ... 
kopieren und mich freuen das es geht weil ich STRG+C und STRG+V drücken 
kann.
Ich will das selber schreiben und anschließend wissen was ich gemacht 
habe und wieso, sonst habe ich ja nichts gelernt ;)

Schaltung nach Datenblatt habe ich umgesetzt und mehrfach kontrolliert, 
die ist korrekt ... VCC=3,3V weil ich den Atmega8 über ein Raspberry Pi 
B+ mit avrdude flashe (Atmega8 also auch mit 3,3V betrieben). VCC_min 
laut Datenblatt sind 3V, sollte also kein Problem darstellen ... 
47k-Widerstand von Busleitung zu VCC ist auch drin, also keine 
parasitäre Versorgung.

Hier jetzt mein C-Code
1
#include <avr/io.h>
2
3
#ifndef F_CPU
4
#define F_CPU 1000000UL
5
#endif
6
#include <util/delay.h>
7
#include "LCD.h"
8
9
int main(void)
10
{  
11
    while(1)
12
    {
13
    init();          //LCD initialisieren
14
    message("Test");    //"Test" auf LCD schreiben
15
    cmd(0xC0,0);      //Zeilenumbruch
16
    
17
    DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
18
    PORTD = (0<<PD5);    //Bus-Master PullDown
19
    _delay_us(480);      //warte 480uS - auch mit 500 und 550 versucht
20
    DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
21
    _delay_us(60);      //warte 60uS - auch mit 45 und 55 versucht
22
                //in der Zeit sollte 47k-R den Bus auf HIGH ziehen
23
    if(PIND & (0<<PD5)){  //Wurde PD5 auf LOW gezogen?
24
      message("ja");
25
    }else{
26
      message("nein");
27
    }
28
    _delay_ms(1000);    //warte damit Display nicht so flackert
29
    }
30
}

Ich habe mit Kommentaren dran geschrieben was ich mir dabei gedacht 
habe.
Kann mir jemand sagen was falsch ist und wieso das falsch ist?

grüße...
Matthias

von Tobi (Gast)


Lesenswert?

Meintest du eventuell einen 4k7 Widerstand?

Mfg

von Matthias (Gast)


Lesenswert?

ja meine ich, danke für den Hinweis

von holger (Gast)


Lesenswert?

>Noch vorab: ja ich habe das Forum durchsucht, ja ich weiß das es ganz
>viele funktionierende Beispiele gibt. Aber genau das will ich nicht ...

Das sind aber super Nachschlagewerke die zeigen wie es richtig geht.
Wenn bei dir was nicht funktioniert siehst du dort rein
und schaust nach was du anders machst. Bessere Erklärungen
wirst du hier auch nicht bekommen.

von Steffen (Gast)


Lesenswert?

Tobi schrieb:
> Meintest du eventuell einen 4k7 Widerstand?

Versuch ruhig einen kleineren Widerstand, ich nehme bei den DS Sensoren 
bei 3V auf 1,5k. bei 5V 2,2k

von Max H. (hartl192)


Lesenswert?

Matthias schrieb:
> _delay_us(60);
Versuchs mal mit 70µs.

https://www.maximintegrated.com/en/app-notes/index.mvp/id/126
Parameter 'I'

von Bobesch (Gast)


Lesenswert?

> (0<<PD5)
?

von Tuxi (Gast)


Lesenswert?

Über die 0<<PD5 solltest du nochmal gut nachdenken ... ;)

von Max H. (hartl192)


Lesenswert?

Matthias schrieb:
> if(PIND & (0<<PD5)){  //Wurde PD5 auf LOW gezogen?
Das ist immer flasch.
(0 << PD5) ist das gleiche wie (0 << 5) und das ist 0.
0 & irgendetwas ist 0 und 0 ist in C falsch, es wird also immer der 
else Zweig ausgeführt.

von Matthias (Gast)


Lesenswert?

Max H. schrieb:
> Versuchs mal mit 70µs.

Keine Veränderung

Steffen schrieb:
> Versuch ruhig einen kleineren Widerstand, ich nehme bei den DS Sensoren
> bei 3V auf 1,5k. bei 5V 2,2k

Ich habe keine "Reserven" da .... nur 10k oder 330 ...
5*330 in Reihe = 1,65k
Hat auch keinen Effekt

Bobesch schrieb:
>> (0<<PD5)
> ?

Welche Zeile meinst du? das kommt ja öfter vor.
Grundlegend habe ich das so gefunden um die PINs einzeln ansprechen zu 
können

von Bobesch (Gast)


Lesenswert?

> das kommt ja öfter vor
Eben. So viele Nullen.

von Matthias (Gast)


Lesenswert?

Max H. schrieb:
>> if(PIND & (0<<PD5)){  //Wurde PD5 auf LOW gezogen?
> Das ist immer flasch.
> (0 << PD5) ist das gleiche wie (0 << 5) und das ist 0.
> 0 & irgendetwas ist 0 und 0 ist in C falsch, es wird also immer der
> else Zweig ausgeführt.

Ich verstehe was du schreibst aber nicht das wieso.
Wenn ich den Ausgang beschalte nehme ich doch die gleiche Syntax also 
"Port&(wert<<pin)

von Steffen (Gast)


Lesenswert?

Matthias schrieb:
> Ich habe keine "Reserven" da .... nur 10k oder 330 ...
> 5*330 in Reihe = 1,65k
> Hat auch keinen Effekt

ja das klappt erst wenn der Rest geht.

Matthias schrieb:
> Bobesch schrieb:
>>> (0<<PD5)
>> ?
>
> Welche Zeile meinst du? das kommt ja öfter vor.
> Grundlegend habe ich das so gefunden um die PINs einzeln ansprechen zu
> können

wenn ich nix über sehen haben dann so:
1
DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
2
PORTD &= ~(1<<PD5);    //Bus-Master PullDown
3
_delay_us(480);      //warte 480uS - auch mit 500 und 550 versucht
4
DDRD &= ~(1<<PD5);    //PD5 als Eingang setzen
5
_delay_us(60);      //warte 60uS - auch mit 45 und 55 versucht
6
              //in der Zeit sollte 47k-R den Bus auf HIGH ziehen
7
if(!(PIND & (1<<PD5))){  //Wurde PD5 auf LOW gezogen?

von Steffen (Gast)


Lesenswert?

Noch ein Tip, versuch erstmal eine LED zu schalten damit du mit den 
Zuständen klar kommst. 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
Mach erst dann die 1-Wire Sachen. Das ist nicht ganz so Simpel wie du 
denkst. Ich selber arbeite schon seit Jahren mit diesen Sensoren, am 
Anfang war es auch recht tricky, wenn man aber einiges versucht und 
einhält klappt es ganz gut.

von Matthias (Gast)


Lesenswert?

Steffen schrieb:
> if(!(PIND & (1<<PD5))){  //Wurde PD5 auf LOW gezogen?

damit funktioniert es ....
wie genau muss ich die Zeile denn lesen?

Ich könnte mir Vorstellen:
- 1 = 0b0000 0001
- (1<<PD5) heist dann "schiebe 5 stellen nach Links"
- 0b0010 0000

ist das soweit korrekt?
Wie kommt die &-Verknüpfung ins Spiel und wieso funktioniert das mit der 
0 nicht?
Haben die beiden Fragen die gleiche Antwort?

Oder anders formuliert:
Wie muss ich "PIND" interpretieren?

von Max H. (hartl192)


Lesenswert?

Matthias schrieb:
> Wenn ich den Ausgang beschalte nehme ich doch die gleiche Syntax also
> "Port&(wert<<pin)
Sow ie hier?
> DDRD &= ~(0<<PD5);
Das macht aber nichts:
(0<<PD5) = (0<<5) = 0
~0 = 0xFF

DDRD &= ~(0<<PD5) entspricht DDRD &= 0xFF und das
DDRD = DDRD & 0xFF was dann das geliche ist wie DDRD = DDRD.

von Max H. (hartl192)


Lesenswert?

Matthias schrieb:
> Wie kommt die &-Verknüpfung ins Spiel und wieso funktioniert das mit der
> 0 nicht?
Die berechnet das bitweise UND* zwischen 0b0010 0000 und PIND. Wenn du
PIND & 0
berechnest, dann wird immer 0 herauskommen, weil 0 & x = 0

*https://de.wikipedia.org/wiki/Konjunktion_%28Logik%29

Wie muss ich "PIND" interpretieren?
In PIND stehen die züstande der PINs an PORTD. Wenn du z.B. an PORTD 
anlegst:
PD0 = 3.3V, PD1 = 3.3V, PD2 = 3.3V, PD3 = 3.3V,
PD4 =   0V, PD5 =   0V, PD6 = 3.3V, PD7 = 000V
dann steht in PIND 0b01001111.

: Bearbeitet durch User
von Jens (Gast)


Lesenswert?

Bei 1-wire ist das Timing recht kritisch.

Vielleicht liest(!) und probierst Du doch erstmal die Application note 
AVR318 von Atmel [1].
Mir hat die damals (tm) ganz gut geholfen, auch wenn ich das Protokoll 
nicht auf einem Atmel-Chip implementiert habe.

Jens

[1] Dallas 1-Wire master on tinyAVR and megaAVR devices:
http://www.atmel.com/images/doc2579.pdf

von Matthias (Gast)


Lesenswert?

Max H. schrieb:
>> Wie kommt die &-Verknüpfung ins Spiel und wieso funktioniert das mit der
>> 0 nicht?
> Die berechent das bitweise UND* zwischen 0b0010 0000 und PIND. Wenn du
> PIND & 0
> bechenset, dann wird immer 0 herauskommen, weil 0 & x = 0
>
> *https://de.wikipedia.org/wiki/Konjunktion_%28Logik%29

Ich musste gerade kurz die Hände über dem Kopf zusammen schlagen.
DAS war etwas dumm von mir ;)

Danke für die geduldigen und zielführenden Antworten!

lg
Matthias

von Steffen (Gast)


Lesenswert?

Matthias schrieb:
> Steffen schrieb:
>> if(!(PIND & (1<<PD5))){  //Wurde PD5 auf LOW gezogen?
>
> damit funktioniert es ....
> wie genau muss ich die Zeile denn lesen?

Es gibt zwei zustände, gesetzt oder nicht gesetzt. mit PIND & (1<<PD5) 
prüfst du ob das Bit gesetzt ist. mit ! prüfst du wenn es nicht gesetzt 
ist. ganz einfach.

Steffen schrieb:
> Noch ein Tip, versuch erstmal eine LED zu schalten damit du mit den
> Zuständen klar kommst.
> http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

;-)

von Matthias (Gast)


Lesenswert?

Steffen schrieb:
> Steffen schrieb:
>> Noch ein Tip, versuch erstmal eine LED zu schalten damit du mit den
>> Zuständen klar kommst.
>> http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
>
> ;-)

habe ich vorher, auch mit Taster.
Das LCD-Display funktioniert ja auch ...
da musste ich aber keinen PIN einlesen sondern nur schreiben ;)

von Matthias (Gast)


Lesenswert?

so, bin deutlich weiter gekommen, funktionieren tut es natürlich noch 
nicht ;)

Der aktuelle Code:
1
/*
2
 * onewire.c
3
 *
4
 * Created: 15.09.2015 22:02:57
5
 *  Author: Matthias
6
 */ 
7
8
#include <avr/io.h>
9
#include <stdlib.h>
10
11
#ifndef F_CPU
12
#define F_CPU 1000000UL
13
#endif
14
#include <util/delay.h>
15
#include "LCD.h"
16
17
int main(void)
18
{  
19
  //INIT 1-wire
20
  void onewire_init(){
21
    DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
22
    PORTD = (0<<PD5);    //Bus-Master PullDown
23
    _delay_us(480);      //warte 480uS - auch mit 500 und 550 versucht
24
    DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
25
    _delay_us(15);      //warte 60uS - auch mit 45 und 55 versucht
26
  }
27
  void oww_eins(){
28
    int A=6;
29
    int B=64;
30
    DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
31
    PORTD = (0<<PD5);    //Bus-Master PullDown
32
    _delay_us(A);
33
    DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
34
    _delay_us(B);
35
  }
36
  void oww_null(){
37
    //Master-Write 0
38
    int C=60;
39
    int D=10;
40
    DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
41
    PORTD = (0<<PD5);    //Bus-Master PullDown
42
    _delay_us(C);
43
    DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
44
    _delay_us(D);
45
  }
46
  void oww(int command){
47
    for(int i=7; i>=0; --i){
48
      if((command>>i) & 0x01){
49
        oww_eins();
50
      }else{
51
        oww_null();
52
      }
53
    }
54
  }
55
  char owr(){
56
    int A,E,F;
57
    A=6;
58
    E=9;
59
    F=55;
60
    int ret=0b00;
61
    for(int i=7; i>=0; i--){
62
      DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
63
      PORTD = (0<<PD5);    //Bus-Master PullDown
64
      _delay_us(A);
65
      DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
66
      _delay_us(E);
67
      ret += ((PIND>>PD5) & 1)<<i;
68
      _delay_us(F);
69
    }
70
    char a[8];
71
    itoa(ret,a,2);
72
    message(a);
73
    message(" ");
74
    return ret;
75
  }
76
  
77
  int a,b;
78
  char owi_s[8];
79
  
80
    while(1)
81
    {
82
    init();          //LCD initialisieren
83
    
84
    onewire_init();
85
    oww(0xCC);
86
    oww(0x44);
87
    while(!(PIND & (1<<PD5))){
88
      _delay_us(1);
89
    }
90
    _delay_us(10);
91
    
92
    onewire_init();
93
    oww(0xCC);
94
    oww(0xBE);
95
    
96
    a = owr();
97
    b = owr();
98
99
    _delay_ms(5000);    //warte damit Display nicht so flackert
100
    }
101
}

bei den beiden Bytes die ich auslese würde ich 0x00 und etwas in 
Richtung 0x30 erwarten, kommt natürlich nicht. Ausgabe ist "11111111 0".

Am liebsten würde ich ein Oszi dran klemmen, ich habe aber keins.
Also wäre eine Simulation gut.
Gibt es da Möglichkeiten? Immerhin müsste ja der "simulierte DS18S20" in 
der Simulation auch mal reagieren ...

Liege Grüße
Matthias

von (prx) A. K. (prx)


Lesenswert?

Matthias schrieb:
>   void oww_eins(){
>     int A=6;
>     int B=64;
>     DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
>     PORTD = (0<<PD5);    //Bus-Master PullDown
>     _delay_us(A);
>     DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
>     _delay_us(B);
>   }

Bei 1MHz wird die Low-Zeit deutlich länger als 6µs sein. 1MHz ist für 
1-W Timing auf der knappen Seite und setzt voraus, dass man die vom 
Compiler generierten Befehlstakte abzählt.

NB: Gratuliere: Das ist der erste reale C Code mit lokalen Funktionen, 
den ich zu Gesicht bekam. ;-)

von Bobesch (Gast)


Lesenswert?

Ist das dein Ernst? Noch immer die vielen Nullen (0<<PD5)?

> DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
Max H. schrieb:
> Das macht aber nichts:
> (0<<PD5) = (0<<5) = 0
> ~0 = 0xFF
> DDRD &= ~(0<<PD5) entspricht DDRD &= 0xFF und das
> DDRD = DDRD & 0xFF was dann das geliche ist wie DDRD = DDRD.

von Steffen (Gast)


Lesenswert?

Matthias schrieb:
> so, bin deutlich weiter gekommen, funktionieren tut es natürlich noch
> nicht ;)

sieht aber nicht so aus. Den Teil mit den Nullen musst du noch lernen 
((0<<PD5);)

von (prx) A. K. (prx)


Lesenswert?


von Matthias (Gast)


Lesenswert?

Bobesch schrieb:
> Ist das dein Ernst? Noch immer die vielen Nullen (0<<PD5)?
>
>> DDRD &= ~(0<<PD5);    //PD5 als Eingang setzen
> Max H. schrieb:
>> Das macht aber nichts:
>> (0<<PD5) = (0<<5) = 0
>> ~0 = 0xFF
>> DDRD &= ~(0<<PD5) entspricht DDRD &= 0xFF und das
>> DDRD = DDRD & 0xFF was dann das geliche ist wie DDRD = DDRD.

Den Teil hatte ich offensichtlich übersehen.
1
void onewire_init(){
2
    int G=0;
3
    int H=480;
4
    int I=70;
5
    int J=410;
6
    _delay_us(G);
7
    DDRD |= (1<<PD5);    //PD5 als Ausgang setzen
8
    PORTD &= ~(1<<PD5);    //Bus-Master PullDown
9
    _delay_us(H);      //warte 480uS - auch mit 500 und 550 versucht
10
    DDRD &= ~(1<<PD5);    //PD5 als Eingang setzen
11
    _delay_us(I);      //warte 60uS - auch mit 45 und 55 versucht
12
    _delay_us(J);
13
  }

von Matthias (Gast)


Lesenswert?

A. K. schrieb:
> Bei 1MHz wird die Low-Zeit deutlich länger als 6µs sein. 1MHz ist für
> 1-W Timing auf der knappen Seite und setzt voraus, dass man die vom
> Compiler generierten Befehlstakte abzählt.

Muss ich das wirklich zählen?
Also rein in den Debugger und den Cycle Counter beobachten?
Oder gibt es auch ein Timing-Diagramm oder etwas in der Art, wo man es 
ablesen kann?

von Amateur (Gast)


Lesenswert?

Du solltest Dir würglich mal durch die Birne gehen lassen, was die 
Schiebebefehle machen.
Bit-Pos:   76543210
Ausgang:          0
PD5 = 5:     0<<<<<
(0<<PD5)   00000000  = 0
~(0<<PD5)  11111111  = FF

Zusammen mit PORTD = (0<<PD5)
             PORTD = 00  falls irgendein Bit vorher etwas anderes
                         behauptete: Jetzt sind alle 0
             PORTD = ~(0<<PD5)
             PORTD = FF  falls irgendein Bit vorher etwas anderes
                         behauptete: Jetzt sind alle 1

von Jens (Gast)


Lesenswert?

Matthias schrieb:
> oder etwas in der Art, wo man es
> ablesen kann?
Besorg Dir ein Oszi, oder besuche mal jemanden, der eins hat...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.