www.mikrocontroller.net

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


Autor: OMarohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
#ifndef F_CPU 
#define F_CPU 16000000
#endif


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include "uart.h"

#define BAUD 19200

#define READ_ROM  0x33

uint8_t ow_buffer[10];
char msg[10];

#define T_PORT PORTA
#define T_DDR  DDRA
#define T_PIN  PINA
#define T_DQ   PA1

#define T_INPUT  T_DDR&=~(1<<T_DQ)
#define T_OUTPUT T_DDR|=(1<<T_DQ)
#define T_LOW    T_PORT&=~(1<<T_DQ)
#define T_HIGH   T_PORT|=(1<<T_DQ)


inline unsigned char owReset()
{
  uint8_t r = 0;
  T_OUTPUT;
      T_LOW;
  _delay_us(480);  // 480us warten
  
  T_INPUT;                // als eingang setzen
  _delay_us(70);      // auch warten, das der sensor den bus wieder auf low zieht

  r = (bit_is_clear(T_PIN, T_DQ) ? 1 : 0);        // bit clear also muss der DS18B20 den pin  auf low gezogen haben

  T_OUTPUT;                 // als ausgang setzen
  _delay_us(410);
  return(r);
}

inline void owWriteBit(uint8_t bit_value)
{
  cli();
  T_OUTPUT;

  if (bit_value)            // Write 1
  {
    T_LOW;        // jetzt auf low ziehen
    _delay_us(6);          // 6 us auf Low lassen
    T_INPUT;            // als eingang setzen
    _delay_us(64);          // 64us warten
  }
  else                // Write 0
  {
    _delay_us(60);          // 60us auf Low lassen
    T_INPUT;            // als eingang setzen
    _delay_us(10);
  }
  sei();
}

void owWriteByte(unsigned char byte_value)
{
  uint8_t i = 8;

  while(i--)
  {
    owWriteBit(byte_value & 0x01);    // das rechts stehende Bit senden
    byte_value = byte_value >> 1;    // um 1 Stelle nach rechts schieben
  }
}

inline uint8_t owReadBit(void)
{
  uint8_t r=0;
  cli();

  T_OUTPUT;
  T_LOW;        // jetzt auf low ziehen
  _delay_us(6);    // 6 us warten
  
  T_INPUT;            // als eingang setzen
  _delay_us(9);    // warten und dann messen

  //r = (bit_is_set(T_PIN, T_DQ) ? 1 : 0);
  if (T_PIN&(1<<T_DQ)) r = 1;

  _delay_us(55);

  sei();
  return (r);
}

uint8_t owReadByte(void)
{
  uint8_t i = 8;
  uint8_t data = 0;
  while(i--)
  {
    data >>= 1;  //bits schieben
    if (owReadBit()) data |= 0x80; // Bit 7 setzen
  }
  return(data);
}

void owReadROMCode(void)
{
  uint8_t i;

  owReset();
  owWriteByte(READ_ROM);
  for (i = 0; i < 8; i++) ow_buffer[i] = owReadByte();  // nun steht der ROM-Code in ow_buffer
  uart_putc(13);
  for (i = 0; i < 8; i++)               // ROM-Code ausgeben
  {
    uart_puts(utoa(ow_buffer[i], msg, 16));
    uart_putc(' ');
  }
}

int main( void )
{

  uint8_t i = 0;
  uint8_t tmp = 0;
  uint16_t T = 0;
  uint16_t T1 = 0;

  uart_init((UART_BAUD_SELECT((BAUD),F_CPU)));
  
  sei();
  
  uart_puts_P( "\rVersuch eines 1 Wire Protokolls\r" );
  uart_puts_P( "-------------------------------------------\r" );

  while(1)
  {
    owReset();
    owWriteByte(0xCC);
    owWriteByte(0x44);

    _delay_ms(1000);

    owWriteByte(0xCC);
    owWriteByte(0xBE);

    for (i = 0; i < 9; i++) ow_buffer[i] = owReadByte(); 
    for (i = 0; i < 9; i++)   
    {
      uart_puts(utoa(ow_buffer[i], msg, 16));
      uart_putc(' ');
    }
    uart_putc(13);
  }
}

und in BASCOM
// BASCOM
$regfile = "m16def.dat"
$crystal = 16000000
$baud = 38400

Config 1wire = Porta.1

Dim Daten(9) As Byte
Dim I As Byte
Dim Tmp As Byte
Dim Crc As Byte
Dim T As Integer
Dim T1 As Integer


Lblmain:

1wreset
1wwrite &H33
Daten(1) = 1wread(8)
For I = 1 To 8n
   Print Hex(daten(i));
   Print " ";
Next

1wreset
1wwrite &HCC
1wwrite &H44

Waitms 1000

1wreset
1wwrite &HCC
1wwrite &HBE

Daten(1) = 1wread(9)

Tmp = Daten(1) And 1                                       
If Tmp = 1 Then Decr Daten(1)
T = Makeint(daten(1) , Daten(2))
T = T * 50
T = T - 25
T1 = Daten(8) - Daten(7)
T1 = T1 * 100
T1 = T1 / Daten(8)
T = T + T1
T = T / 10


Print "Temp := ";
Print T

Goto Lblmain

Autor: Stefan B. (stefan) Benutzerseite
Datum:

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

Autor: OMarohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Stefan B. (stefan) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: OMarohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Oliver M. (oliver_m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Stefan,

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

Oliver

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.