Forum: Compiler & IDEs 1Wire Problem - mal wieder - mit DS18B20 in C


von OMarohn (Gast)


Lesenswert?

Hallo zusammen,

nachdem ich bisher immer gut aus dem (hier) vorhandenen Know How meine 
Probleme lösen konnte, ist es jetzt so weit, ich finde den Fehler nicht 
und brauche mal 4 bis (x*2) Augen ;-)

Mein Problem ist, das ich die 1wire Kommunikation mit dem DS18B20 trotz 
zahlreicher libs nicht hinbekomme.

Aus Verzweiflung habe ich dann mir auch nochmal die Appnotes von Dallas 
durchgelesen und versucht umzusetzen. Auch das ohne Erfolg.

Der 'Witz' ist, das es mit BASCOM sofort geklappt hat.

Anbei mal der aktuelle Stand, vielleicht kann mir jemand die Tomaten von 
den Augen reißen.

1000 Dank
Oliver
1
#ifndef F_CPU 
2
#define F_CPU 16000000
3
#endif
4
5
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <avr/eeprom.h>
9
#include <util/delay.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <stdint.h>
13
14
#include "uart.h"
15
16
#define BAUD 19200
17
18
#define READ_ROM  0x33
19
20
uint8_t ow_buffer[10];
21
char msg[10];
22
23
#define T_PORT PORTA
24
#define T_DDR  DDRA
25
#define T_PIN  PINA
26
#define T_DQ   PA1
27
28
#define T_INPUT  T_DDR&=~(1<<T_DQ)
29
#define T_OUTPUT T_DDR|=(1<<T_DQ)
30
#define T_LOW    T_PORT&=~(1<<T_DQ)
31
#define T_HIGH   T_PORT|=(1<<T_DQ)
32
33
34
inline unsigned char owReset()
35
{
36
  uint8_t r = 0;
37
  T_OUTPUT;
38
      T_LOW;
39
  _delay_us(480);  // 480us warten
40
  
41
  T_INPUT;                // als eingang setzen
42
  _delay_us(70);      // auch warten, das der sensor den bus wieder auf low zieht
43
44
  r = (bit_is_clear(T_PIN, T_DQ) ? 1 : 0);        // bit clear also muss der DS18B20 den pin  auf low gezogen haben
45
46
  T_OUTPUT;                 // als ausgang setzen
47
  _delay_us(410);
48
  return(r);
49
}
50
51
inline void owWriteBit(uint8_t bit_value)
52
{
53
  cli();
54
  T_OUTPUT;
55
56
  if (bit_value)            // Write 1
57
  {
58
    T_LOW;        // jetzt auf low ziehen
59
    _delay_us(6);          // 6 us auf Low lassen
60
    T_INPUT;            // als eingang setzen
61
    _delay_us(64);          // 64us warten
62
  }
63
  else                // Write 0
64
  {
65
    _delay_us(60);          // 60us auf Low lassen
66
    T_INPUT;            // als eingang setzen
67
    _delay_us(10);
68
  }
69
  sei();
70
}
71
72
void owWriteByte(unsigned char byte_value)
73
{
74
  uint8_t i = 8;
75
76
  while(i--)
77
  {
78
    owWriteBit(byte_value & 0x01);    // das rechts stehende Bit senden
79
    byte_value = byte_value >> 1;    // um 1 Stelle nach rechts schieben
80
  }
81
}
82
83
inline uint8_t owReadBit(void)
84
{
85
  uint8_t r=0;
86
  cli();
87
88
  T_OUTPUT;
89
  T_LOW;        // jetzt auf low ziehen
90
  _delay_us(6);    // 6 us warten
91
  
92
  T_INPUT;            // als eingang setzen
93
  _delay_us(9);    // warten und dann messen
94
95
  //r = (bit_is_set(T_PIN, T_DQ) ? 1 : 0);
96
  if (T_PIN&(1<<T_DQ)) r = 1;
97
98
  _delay_us(55);
99
100
  sei();
101
  return (r);
102
}
103
104
uint8_t owReadByte(void)
105
{
106
  uint8_t i = 8;
107
  uint8_t data = 0;
108
  while(i--)
109
  {
110
    data >>= 1;  //bits schieben
111
    if (owReadBit()) data |= 0x80; // Bit 7 setzen
112
  }
113
  return(data);
114
}
115
116
void owReadROMCode(void)
117
{
118
  uint8_t i;
119
120
  owReset();
121
  owWriteByte(READ_ROM);
122
  for (i = 0; i < 8; i++) ow_buffer[i] = owReadByte();  // nun steht der ROM-Code in ow_buffer
123
  uart_putc(13);
124
  for (i = 0; i < 8; i++)               // ROM-Code ausgeben
125
  {
126
    uart_puts(utoa(ow_buffer[i], msg, 16));
127
    uart_putc(' ');
128
  }
129
}
130
131
int main( void )
132
{
133
134
  uint8_t i = 0;
135
  uint8_t tmp = 0;
136
  uint16_t T = 0;
137
  uint16_t T1 = 0;
138
139
  uart_init((UART_BAUD_SELECT((BAUD),F_CPU)));
140
  
141
  sei();
142
  
143
  uart_puts_P( "\rVersuch eines 1 Wire Protokolls\r" );
144
  uart_puts_P( "-------------------------------------------\r" );
145
146
  while(1)
147
  {
148
    owReset();
149
    owWriteByte(0xCC);
150
    owWriteByte(0x44);
151
152
    _delay_ms(1000);
153
154
    owWriteByte(0xCC);
155
    owWriteByte(0xBE);
156
157
    for (i = 0; i < 9; i++) ow_buffer[i] = owReadByte(); 
158
    for (i = 0; i < 9; i++)   
159
    {
160
      uart_puts(utoa(ow_buffer[i], msg, 16));
161
      uart_putc(' ');
162
    }
163
    uart_putc(13);
164
  }
165
}

und in BASCOM
1
// BASCOM
2
$regfile = "m16def.dat"
3
$crystal = 16000000
4
$baud = 38400
5
6
Config 1wire = Porta.1
7
8
Dim Daten(9) As Byte
9
Dim I As Byte
10
Dim Tmp As Byte
11
Dim Crc As Byte
12
Dim T As Integer
13
Dim T1 As Integer
14
15
16
Lblmain:
17
18
1wreset
19
1wwrite &H33
20
Daten(1) = 1wread(8)
21
For I = 1 To 8n
22
   Print Hex(daten(i));
23
   Print " ";
24
Next
25
26
1wreset
27
1wwrite &HCC
28
1wwrite &H44
29
30
Waitms 1000
31
32
1wreset
33
1wwrite &HCC
34
1wwrite &HBE
35
36
Daten(1) = 1wread(9)
37
38
Tmp = Daten(1) And 1                                       
39
If Tmp = 1 Then Decr Daten(1)
40
T = Makeint(daten(1) , Daten(2))
41
T = T * 50
42
T = T - 25
43
T1 = Daten(8) - Daten(7)
44
T1 = T1 * 100
45
T1 = T1 / Daten(8)
46
T = T + T1
47
T = T / 10
48
49
50
Print "Temp := ";
51
Print T
52
53
Goto Lblmain

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Nach dem 1s Delay fehlt offensichtlich der 1wreset vor der Aufforderung 
an den Sensor die Daten zu senden.

von OMarohn (Gast)


Lesenswert?

Super schnelle Antwort, in der Sache richtig, lößt aber leider mein 
Problem nicht. Habe den Reset eingebaut bekomme aber immernoch nur

ff ff ff ff ff ff .....


Trotzdem vielen Dank!

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Deine Resetfunktion ist buggy, der Rest funktioniert.

Im Anhang ist mein Debugcode mit ein paar Zeitmessungen. Achtung: ich 
musste den 1-Wirepin auf PD2 legen, weil ich mit einem Atmega8 (@ 12 
MHz) getestet habe. Und ich habe 9600 Baud benutzt. Vor dem Testen bitte 
eigene Quellen backuppen.

Die Temperaturberechnung ist quick&dirty zur Plausibilitätsabschätzung 
:) Wie es genau geht hast du ja im BASCOM Code.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ähm noch drei Kommentare zu meiner Debugfunktion

1/ Die ausgegebenen time_reset_... "Zeiten" sind Schätzeisen. Durch den 
Schleifenoverhead sind die tatsächlichen Delays länger. Die Taktrate hat 
da einen großen Einfluß, Aufpassen, wenn es zu niedrigen Taktraten geht.

2/ Die Schleifen sollten besser so geschrieben werden, um den 
Seiteneffekt -- in der Bedingungsabfrage zu vermeiden:

  timeout = xxx;
  while ( timeout && <bedingung2> )
  {
    _delay_us(1);
    timeout--;
  }

3/ Bei der Berechnung des 480 µs Enddelays kann (und tut) ein uint8_t 
Overflow stattfinden (bei meinem Sensor: 480-1-18-67). An der Stelle 
also einen uint16_t für das Ergebnis einsetzen.

von OMarohn (Gast)


Lesenswert?

Hallo Stefen,

vielen Dank für Deine umfangreiche Analyse!
Da hab ich wohl beim Reset was falsch verstanden. Asche über mein Haupt.
Werde ich heute nach der Arbeit mal ausprobieren, und mich wieder 
melden.

Oliver

von Oliver M. (oliver_m)


Lesenswert?

Hallo Stefan,

hat geklappt!
Also nochmal vielen Dank für Deine Hilfe.

Oliver

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.