www.mikrocontroller.net

Forum: Compiler & IDEs DS1820 & ATMega32


Autor: ATMegaNoob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Habe ein kleines Problem, folgendes:
Habe mir vor schon etwas längerer Zeit 'nen DS1820 besorgt.
Nun habe ich das Vorhaben wieder aufgenommen ihn auszulesen!
Und ja, ich weiß das etliche Beiträge/Infos dazu herrschen,
doch komme ich da absolut auf keinen grünen Zweig! :(

Also ich bekomm' ein Present-Signal, will ich jedoch das Scratchpad nach 
einer Messung auslesen, beomm' ich lauter 0x00's :\

Nutze 'nen ATMega32, dieser ist mit 1MHz getaktet.

Wär'  echt nett, wenn ein etwas Erfahrener mal über meine Funktionen 
schauen könnte!

### thermo.h ###
#include <util/delay.h>
#ifndef THERMO_H_
#define THERMO_H_
#endif /* THERMO_H_ */

/* Thermometer Connections (At your choice) */
#define THERM_PORT           PORTD
#define THERM_DDR            DDRD
#define THERM_PIN            PIND
#define THERM_DQ             PD7
#define delayA         _delay_us(6);
#define delayB         _delay_us(64);
#define delayC         _delay_us(60);
#define delayD         _delay_us(10);
#define delayE         _delay_us(9);
#define delayF         _delay_us(55);
#define delayG         _delay_us(0);
#define delayH         _delay_us(480);
#define delayI         _delay_us(70);
#define delayJ         _delay_us(410);

/* Utils */
#define BUS_INPUT_MODE()  THERM_DDR&=~(1<<THERM_DQ)
#define BUS_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
#define BUS_LOW()         THERM_PORT&=~(1<<THERM_DQ)
#define BUS_HIGH()        THERM_PORT|=(1<<THERM_DQ)

#define THERM_DECIMAL_STEPS_12BIT 625 //.0625
#define THERM_CMD_CONVERTTEMP   0x44
#define THERM_CMD_RSCRATCHPAD   0xbe
#define THERM_CMD_WSCRATCHPAD   0x4e
#define THERM_CMD_CPYSCRATCHPAD 0x48
#define THERM_CMD_RECEEPROM     0xb8
#define THERM_CMD_RPWRSUPPLY    0xb4
#define THERM_CMD_SEARCHROM     0xf0
#define THERM_CMD_READROM       0x33
#define THERM_CMD_MATCHROM      0x55
#define THERM_CMD_SKIPROM       0xcc
#define THERM_CMD_ALARMSEARCH   0xec


### thermo.c ###
#include "thermo.h"
#include <avr/io.h>
#include <util/delay.h>
#include <inttypes.h>
#include "lcd.h"


void printIntAsBin(uint8_t integer)
{
  //lcd_clear();
  //set_cursor(0, 2);
  int i=7;
  lcd_string("0b");
  while(i>=0){
    if (integer & 1 << i){
      lcd_string("1");
    }else{
      lcd_string("0");
    }
    i--;
  }
  lcd_stringf(" %i",integer);
}

uint8_t reset()
{
  uint8_t i;
  delayG;
  BUS_LOW();
  BUS_OUTPUT_MODE();
  delayH;
  BUS_INPUT_MODE();
  BUS_HIGH();
  delayI;
  i = (THERM_PIN & (1 << THERM_DQ));
  delayJ;
  return i;
}

uint8_t readbit()
{
  uint8_t result;
  BUS_LOW();
  BUS_OUTPUT_MODE();
  delayA;
  BUS_INPUT_MODE();
  BUS_HIGH();
  delayE;

  result = THERM_PIN & (1<<THERM_DQ);
  delayF;
  return result;
}

uint8_t readbyte(void)
{
  int loop, result = 0;
  for(loop = 0; loop < 8; loop++){
    result >>= 1;
    if(readbit())
      result |= 0x80;
  }
  return result;
}

void writebit(uint8_t bit)
{
  if(bit){
    BUS_LOW();
    BUS_OUTPUT_MODE();
    delayA;
    BUS_INPUT_MODE();
    BUS_HIGH();
    delayB;
  }else{
    BUS_LOW();
    BUS_OUTPUT_MODE();
    delayC;
    BUS_INPUT_MODE();
    BUS_HIGH();
    delayD;
  }
}

void writebyte(uint8_t byte)
{
  int loop, result = 0;

  for(loop = 0; loop < 8; loop++)
  {
    result >>= 1;
    if(byte & 0x01){
      if(readbit())
        result |= 0x80;
    }
    else
      writebit(0);
    byte >>= 1;
  }
}

void getTemp(void)
{
  uint8_t get[10];
  uint8_t temp_lsb, temp_msb;
  int k;
  uint8_t temp_f, temp_c;
  reset();
  writebyte(0xCC);
  writebyte(0x44);
  reset();
  writebyte(0xCC);
  writebyte(0xBE);
  for(k=0;k<9;k++)
  {
    get[k]=readbyte();
  }
  lcd_clear();
  //lcd_stringf("Data: %X%X%X%X%X", get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0] );
  temp_lsb = get[0];
  temp_msb = get[1];
  lcd_string("Temp_LSB:");
  printIntAsBin(temp_lsb);
  set_cursor(0, 2);
  lcd_string("Temp_MSB:");
  printIntAsBin(temp_msb);

  if (temp_msb <= 0x80){temp_lsb = (temp_lsb/2);} // shift to get whole degree
  temp_msb = temp_msb & 0x80; // mask all but the sign bit
  if (temp_msb >= 0x80) {temp_lsb = (~temp_lsb)+1;} // twos complement
  if (temp_msb >= 0x80) {temp_lsb = (temp_lsb/2);}// shift to get whole degree
  if (temp_msb >= 0x80) {temp_lsb = ((-1)*temp_lsb);} // add sign bit
  //lcd_stringf( "TempC= %d degrees C", (int)temp_lsb ); // print temp. C
  temp_c = temp_lsb;  // ready for conversion to Fahrenheit
  temp_f = (((int)temp_c)* 9)/5 + 32;
  //lcd_stringf( "TempF= %d degrees F", (int)temp_f ); // print temp. F
}

### main.c part ###
ISR(INT0_vect)
{
  uint8_t erg = reset();
  if (erg == 0b00000000)
  {
    lcd_clear();
    lcd_string("Thrm gefunden, Messe...");
    set_cursor(0, 2);
    getTemp();
    reset();
}

Wär' super wenn mir mal Jemand sagen könnte, warum da was nicht so 
funktioniert...
Und bitte fordert mich nicht auf zu googlen etc.
Habe 'ne Menge gesucht, aber nichts von dem vielen Zeug
half mir(ja, erstaunlicher Weise...).
Bis auf das Datenblatt und eine Doku über die 1-Wire
Kommunikation natürlich, jeweils bereitgestellt von Maxim.

Vielleicht geh ich auch irgendwie falsch an die Sache ran.
Wenn noch was von Nöten ist, dann reich ich es gerne nach

Danke schon mal im Voraus für (hoffentlich) die Hilfe! : )
Gruß, der ATMegaNoob ;)

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ATMegaNoob schrieb:

> ### main.c part ###
>
> ISR(INT0_vect)
> {
>   uint8_t erg = reset();
>   if (erg == 0b00000000)
>   {
>     lcd_clear();
>     lcd_string("Thrm gefunden, Messe...");
>     set_cursor(0, 2);
>     getTemp();
>     reset();
> }
> 
>
> Wär' super wenn mir mal Jemand sagen könnte, warum da was nicht so
> funktioniert...

Das sieht nicht so gut aus. Dieser Codefetzen hat Syntaxfehler (ein } 
fehlt) und lange Berechnungen (1Wire-Reset + 1Wire-Abfrage + 
LCD-Ausgabe) in der Interrupt-ISR sind fragwürdig.

Autor: ATMegaNoob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ehm ja, das } ist auf jedenfall da, auf das if folgt ein else mit 
der LCD-Ausgabe "Therm nicht gefunden". Sorry das ich es nicht 
mitkopiert habe, irritiert schon sehr.

Stefan B. schrieb:
> (1Wire-Reset + 1Wire-Abfrage +
> LCD-Ausgabe) in der Interrupt-ISR sind fragwürdig.
warum fragwuerdig?

Autor: chester (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Also ich bekomm' ein Present-Signal, will ich jedoch das Scratchpad nach
> einer Messung auslesen, beomm' ich lauter 0x00's

Bekommst du das Signal tatsächlich (mit Oszilloskop überprüft?)
oder ist die Datenleitung vielleicht immer auf 0 und dein
Programm sagt somit immer "Thrm gefunden, Messe..." ?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn dein Programm sich in der ISR befindet, können keine anderen 
Interrupts abgearbeitet werden.

Das betrifft u.U. die Funktionsfähigkeit der in der ISR aufgerufenen 
Funktionen, z.B. wenn I/O mit Hardwareinterrupts arbeitet (TWI, ADC, 
Timer, UART, ...). In deinem Codefetzen ist das vermutlich nicht 
relevant. Sicher kann ich es nicht sagen, weil nicht alles gezeigt ist.

Das betrifft ausserdem die Zuverlässigkeit bei der Reaktion auf 
Interrupt auslösende Ereignisse. Trifft die interruptauslösende 
Bedingung zu, während das Programm in der ISR ist, wird max. ein solches 
Ereignis in die "Interruptwarteschlange" eingereiht. Weitere Ereignisse 
der gleichen Interruptquelle werden weggeworfen.

Autor: ATMegaNoob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke erstmal fuer eure Antworten!

@Chester: Nein, ein Oszi habe ich nicht, ich habe es aber dahingehend 
gecheckt, dass wenn ich den DS1820 vom Bus nehme die Meldung "Therm 
nicht gefunden" kommt (eben der codefezten, den ich vergessen habe).

Also nehme ich stark an, das es doch der DS1820 ist, der den Bus runter 
drueckt und die Reset-Routine schonmal soweit stimmt.

@Stefan: Ja, das der uC dahingehend "blockiert" ist, ist mir bewusst, 
ueberall wird ja auch vor langen Abarbeitungen in den Interrupt-Routinen 
gewarnt. Da bei mir aber wirklich nichts anderes laeuft [bis auf eine 2. 
ISR fuer den 2. Taster, aber da passiert nichts kritisches 
(Pollin-Board)] denk/hoff ich, dass mir das nicht in die Quere kommen 
duerfte.

Ich kann ja mal mein komplettes "Projekt" (eher Bausteller) in der 
naechsten Zeit hochladen, wenn es erforderlich ist...

Bitte um Feedback dahingehend und natuerlich weiter um Hilfe!
...frustriert naemlich nun schon ziehmlich lol..

Gruss ATMegaNoob

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Solche Frustrationen verringere ich persönlich indem ich mich vom 
Kleinen zum Grossen vortaste.

In deinem Beispiel würde ich zuerst ein "stinknormales" main() mit einer 
Arbeitsschleife benutzen und in der Arbeitsschleife die Abfrage des 
Sensors machen. Der Vorteil - das ganze Interruptgedöns kann nicht 
stören. Tausend potentielle Bugs weniger...

Wenn das funktioniert, würde ich den Interrupt draufpacken. Im Prinzip 
dann also eventgesteuert arbeiten - in der ISR wird ein Flag (volatile) 
gesetzt, dass der INT0 aufgetreten ist und in der Arbeitsschleife wird 
das Flag abgefragt und darauf reagiert (Sensorabfrage und Ausgabe).

Bzw. noch wahrscheinlicher ein ähnliches Projekt mit Interrupt aufsetzen 
bei dem durch den Interrupt nur eine LED (oder die LCD-Anzeige) betätigt 
wird. Mit dieser Projektstufe kann die richtige Initialisierung des INT0 
sowie die grundsätzliche Funktion überprüft werden ohne dass der Sensor 
eine Rolle spielt. Wenn das funktioniert, würde ich versuchen die 
Sensorabfrage draufzupacken.

Wenn du das Projekt hochlädst (was ich für sinnvoll halte), gehe nochmal 
darauf ein, wie du den Sensor angeschlossen hast und was du beim 
Programmlauf beobachtest ("Also ich bekomm' ein Present-Signal..." ???).

Im Moment sieht es für mich so aus, als ob du den DS1820 parasitär 
versorgst und als Pull-Up Widerstand den internen Pullup des PD7 
benutzt. Wenn das so ist:

Im Datenblatt des DS18S20 (S.5 2. Abschnitt) ist aber die Rede davon 
einen starken Pullup (4,7 kOhm) zu benutzen - das ist der interne 
Pullup des PD7 nicht; der ist mit ca. 50 kOhm dafür zu hochohmig 
(schwach). Das würde zum Bild passen, dass durch die zu hohe parasitäre 
Stromaufnahme des DS1820 bei zu hochohmigem AVR-internem Pull-Up die 
DQ-Leitung am PD7-Eingang des AVR nie logisch HIGH wird und du beim 
Lesen des  Scratchpads nur '0'-Bits liest bzw. der Sensor sogar nicht 
arbeitet, da zu wenig Strom (5V/50KOhm = 0,1mA statt bis zu 1 bis 1,5 mA 
wie erforderlich).

Autor: chester (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Also nehme ich stark an, das es doch der DS1820 ist, der den Bus runter
>drueckt und die Reset-Routine schonmal soweit stimmt.

Ich tippe auf ein Timing-Problem, das aber ohne oszi schwer zu
überprüfen ist...

Folgendes würde ich auf jeden Fall einbauen. Nach dem der DS1820 die 
Leitung auf 0 zieht muss er sie auch danach wieder
freigeben, sonst ist da was faul.

also folgendes ausprobieren
uint8_t reset()
{
  uint8_t i;
  delayG;
  BUS_LOW();
  BUS_OUTPUT_MODE();
  delayH;
  BUS_INPUT_MODE();
  BUS_HIGH();
  delayI;
  i = (THERM_PIN & (1 << THERM_DQ));
  delayJ;
  return i | !THERM_PIN;
}

Man beachte die Zeile mit dem return.

Autor: chester (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry, sollte
return i | !(THERM_PIN & (1 << THERM_DQ));
heissen.

Autor: ATMegaNoob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LOL!
Ja ja, die kleinen netten Fehler! ;)
Habe den DS wohl um eine Buchsenreihe verschoben falsch angeschlossen... 
:X
Also folgender Stand: Beim Auslesen des LSB-Bytes kommen tatsaechlich 
Werte raus!
Und wenn ich das Ding mit dem Finger erwaerme, steigt es auch :)
Ich werde das ganze nochmal richtig ueberpruefen(vorallem mit dem 
PullUp), und werd dann ggf. mein komplettes Projekt Up'en, ausser ihr 
seid der Meinung das Forum braucht sowas nichtmehr.
Wie auch immer, wuerde gern Eure Hilfe in Anspruch nehmen, um das Ganze 
zu optimieren.

@Stefan: Ich werd mir das ansehen, und sehr wahrscheinlich auch was von 
deiner potentiellen Vorgehensweise implementieren, das es mir doch auf 
den erstem Blick sympathischer scheint!


Danke fuer Eure Hilfe bis hierhin!
(Nun erstmal reggen :) )

Gruss ATMegaNoob

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.