Forum: Compiler & IDEs DS1820 & ATMega32


von ATMegaNoob (Gast)


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 ###
1
#include <util/delay.h>
2
#ifndef THERMO_H_
3
#define THERMO_H_
4
#endif /* THERMO_H_ */
5
6
/* Thermometer Connections (At your choice) */
7
#define THERM_PORT           PORTD
8
#define THERM_DDR            DDRD
9
#define THERM_PIN            PIND
10
#define THERM_DQ             PD7
11
#define delayA         _delay_us(6);
12
#define delayB         _delay_us(64);
13
#define delayC         _delay_us(60);
14
#define delayD         _delay_us(10);
15
#define delayE         _delay_us(9);
16
#define delayF         _delay_us(55);
17
#define delayG         _delay_us(0);
18
#define delayH         _delay_us(480);
19
#define delayI         _delay_us(70);
20
#define delayJ         _delay_us(410);
21
22
/* Utils */
23
#define BUS_INPUT_MODE()  THERM_DDR&=~(1<<THERM_DQ)
24
#define BUS_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
25
#define BUS_LOW()         THERM_PORT&=~(1<<THERM_DQ)
26
#define BUS_HIGH()        THERM_PORT|=(1<<THERM_DQ)
27
28
#define THERM_DECIMAL_STEPS_12BIT 625 //.0625
29
#define THERM_CMD_CONVERTTEMP   0x44
30
#define THERM_CMD_RSCRATCHPAD   0xbe
31
#define THERM_CMD_WSCRATCHPAD   0x4e
32
#define THERM_CMD_CPYSCRATCHPAD 0x48
33
#define THERM_CMD_RECEEPROM     0xb8
34
#define THERM_CMD_RPWRSUPPLY    0xb4
35
#define THERM_CMD_SEARCHROM     0xf0
36
#define THERM_CMD_READROM       0x33
37
#define THERM_CMD_MATCHROM      0x55
38
#define THERM_CMD_SKIPROM       0xcc
39
#define THERM_CMD_ALARMSEARCH   0xec


### thermo.c ###
1
#include "thermo.h"
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <inttypes.h>
5
#include "lcd.h"
6
7
8
void printIntAsBin(uint8_t integer)
9
{
10
  //lcd_clear();
11
  //set_cursor(0, 2);
12
  int i=7;
13
  lcd_string("0b");
14
  while(i>=0){
15
    if (integer & 1 << i){
16
      lcd_string("1");
17
    }else{
18
      lcd_string("0");
19
    }
20
    i--;
21
  }
22
  lcd_stringf(" %i",integer);
23
}
24
25
uint8_t reset()
26
{
27
  uint8_t i;
28
  delayG;
29
  BUS_LOW();
30
  BUS_OUTPUT_MODE();
31
  delayH;
32
  BUS_INPUT_MODE();
33
  BUS_HIGH();
34
  delayI;
35
  i = (THERM_PIN & (1 << THERM_DQ));
36
  delayJ;
37
  return i;
38
}
39
40
uint8_t readbit()
41
{
42
  uint8_t result;
43
  BUS_LOW();
44
  BUS_OUTPUT_MODE();
45
  delayA;
46
  BUS_INPUT_MODE();
47
  BUS_HIGH();
48
  delayE;
49
50
  result = THERM_PIN & (1<<THERM_DQ);
51
  delayF;
52
  return result;
53
}
54
55
uint8_t readbyte(void)
56
{
57
  int loop, result = 0;
58
  for(loop = 0; loop < 8; loop++){
59
    result >>= 1;
60
    if(readbit())
61
      result |= 0x80;
62
  }
63
  return result;
64
}
65
66
void writebit(uint8_t bit)
67
{
68
  if(bit){
69
    BUS_LOW();
70
    BUS_OUTPUT_MODE();
71
    delayA;
72
    BUS_INPUT_MODE();
73
    BUS_HIGH();
74
    delayB;
75
  }else{
76
    BUS_LOW();
77
    BUS_OUTPUT_MODE();
78
    delayC;
79
    BUS_INPUT_MODE();
80
    BUS_HIGH();
81
    delayD;
82
  }
83
}
84
85
void writebyte(uint8_t byte)
86
{
87
  int loop, result = 0;
88
89
  for(loop = 0; loop < 8; loop++)
90
  {
91
    result >>= 1;
92
    if(byte & 0x01){
93
      if(readbit())
94
        result |= 0x80;
95
    }
96
    else
97
      writebit(0);
98
    byte >>= 1;
99
  }
100
}
101
102
void getTemp(void)
103
{
104
  uint8_t get[10];
105
  uint8_t temp_lsb, temp_msb;
106
  int k;
107
  uint8_t temp_f, temp_c;
108
  reset();
109
  writebyte(0xCC);
110
  writebyte(0x44);
111
  reset();
112
  writebyte(0xCC);
113
  writebyte(0xBE);
114
  for(k=0;k<9;k++)
115
  {
116
    get[k]=readbyte();
117
  }
118
  lcd_clear();
119
  //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] );
120
  temp_lsb = get[0];
121
  temp_msb = get[1];
122
  lcd_string("Temp_LSB:");
123
  printIntAsBin(temp_lsb);
124
  set_cursor(0, 2);
125
  lcd_string("Temp_MSB:");
126
  printIntAsBin(temp_msb);
127
128
  if (temp_msb <= 0x80){temp_lsb = (temp_lsb/2);} // shift to get whole degree
129
  temp_msb = temp_msb & 0x80; // mask all but the sign bit
130
  if (temp_msb >= 0x80) {temp_lsb = (~temp_lsb)+1;} // twos complement
131
  if (temp_msb >= 0x80) {temp_lsb = (temp_lsb/2);}// shift to get whole degree
132
  if (temp_msb >= 0x80) {temp_lsb = ((-1)*temp_lsb);} // add sign bit
133
  //lcd_stringf( "TempC= %d degrees C", (int)temp_lsb ); // print temp. C
134
  temp_c = temp_lsb;  // ready for conversion to Fahrenheit
135
  temp_f = (((int)temp_c)* 9)/5 + 32;
136
  //lcd_stringf( "TempF= %d degrees F", (int)temp_f ); // print temp. F
137
}

### main.c part ###
1
ISR(INT0_vect)
2
{
3
  uint8_t erg = reset();
4
  if (erg == 0b00000000)
5
  {
6
    lcd_clear();
7
    lcd_string("Thrm gefunden, Messe...");
8
    set_cursor(0, 2);
9
    getTemp();
10
    reset();
11
}

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 ;)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

ATMegaNoob schrieb:

> ### main.c part ###
>
1
> ISR(INT0_vect)
2
> {
3
>   uint8_t erg = reset();
4
>   if (erg == 0b00000000)
5
>   {
6
>     lcd_clear();
7
>     lcd_string("Thrm gefunden, Messe...");
8
>     set_cursor(0, 2);
9
>     getTemp();
10
>     reset();
11
> }
12
>
>
> 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.

von ATMegaNoob (Gast)


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?

von chester (Gast)


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..." ?

von Stefan B. (stefan) Benutzerseite


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.

von ATMegaNoob (Gast)


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

von Stefan B. (stefan) Benutzerseite


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).

von chester (Gast)


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
1
uint8_t reset()
2
{
3
  uint8_t i;
4
  delayG;
5
  BUS_LOW();
6
  BUS_OUTPUT_MODE();
7
  delayH;
8
  BUS_INPUT_MODE();
9
  BUS_HIGH();
10
  delayI;
11
  i = (THERM_PIN & (1 << THERM_DQ));
12
  delayJ;
13
  return i | !THERM_PIN;
14
}

Man beachte die Zeile mit dem return.

von chester (Gast)


Lesenswert?

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

von ATMegaNoob (Gast)


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

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.