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
intmain(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
>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.
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
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.
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
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)
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
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.
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?
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.
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.
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
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
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
;-)
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 ;)
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
intmain(void)
18
{
19
//INIT 1-wire
20
voidonewire_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
voidoww_eins(){
28
intA=6;
29
intB=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
voidoww_null(){
37
//Master-Write 0
38
intC=60;
39
intD=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
voidoww(intcommand){
47
for(inti=7;i>=0;--i){
48
if((command>>i)&0x01){
49
oww_eins();
50
}else{
51
oww_null();
52
}
53
}
54
}
55
charowr(){
56
intA,E,F;
57
A=6;
58
E=9;
59
F=55;
60
intret=0b00;
61
for(inti=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
chara[8];
71
itoa(ret,a,2);
72
message(a);
73
message(" ");
74
returnret;
75
}
76
77
inta,b;
78
charowi_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
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. ;-)
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.
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);)
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
voidonewire_init(){
2
intG=0;
3
intH=480;
4
intI=70;
5
intJ=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
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?
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