Forum: Compiler & IDEs Temperaturmessung Problem


von Daniel F. (Gast)


Lesenswert?

Guten Abend

ich habe ein Problem und bin wohl auf eure Hilfe angewiesen.

Ich beschäftige mich gerade mit einem Temperatursensor.

Benutzt wird ein AD22100.

Ich möchte eine Temperatur auf meinem LCD-Display ausgeben, jedoch 
klappt dies noch nicht so gut. Der Sensor arbeitet jedoch -> gemessen!

Hier mal mein für euch abgespeckter Code, alle anderen #includes etc. 
sind natürlich vorhanden:
1
#include <math.h>
2
#define  _USE_MATH_DEFINES
3
4
int temperatur;
5
int buffer[2];
6
7
/* ADC initialisieren */
8
void ADC_Init(void)
9
{
10
  uint16_t result;
11
  ADMUX = (1<<REFS1) | (1<<REFS0);              // interne Referenzspannung nutzen
12
  ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
13
  ADCSRA |= (1<<ADEN);                         // ADC aktivieren
14
 
15
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
16
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
17
 
18
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
19
  while (ADCSRA & (1<<ADSC) ) {}        // auf Abschluss der Konvertierung    warten
20
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
21
     Wandlung nicht übernommen. */
22
  result = ADCW;
23
}
24
 
25
26
/* ADC Einzelmessung */
27
uint16_t ADC_Read( uint8_t channel )
28
{
29
  // Kanal waehlen, ohne andere Bits zu beeinflußen
30
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
31
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
32
  while (ADCSRA & (1<<ADSC) ) {}  // auf Abschluss der Konvertierung warten
33
  return ADCW;                    // ADC auslesen und zurückgeben
34
}
35
36
int main(void)
37
{
38
while(1)
39
{
40
 ADC_Init();
41
42
 x=5/(1023*0.0225)*(ADC_Read(5)-1.375)/0.0225;
43
44
 sprintf(buffer,"%d",temperatur/1000);
45
 lcd_setcursor (1, 2);
46
 lcd_string(buffer);
47
}
48
}

Auf dem Display erscheint jedoch nur ein -12°C.

Vielleicht sehe ich vor lauter Bäumen den Wald auch schon nicht mehr, 
aber ich hoffe jemand kann mir helfen!
schönen Abend

von Daniel F. (Gast)


Lesenswert?

ach jetzt habe ich auch noch was falsches gepostet.
1
x=5/(1023*0.0225)*(ADC_Read(5)-1.375)/0.0225;

x = temperatur !!

von Fausto B. (fausto)


Lesenswert?

wie wäre es mit eine mathematische trennung punkt vor strich?

x=(5/(1023*0.0225))*((ADC_Read(5)-1.375)/0.0225);

dann den fehler liegt das die initializierung in der while schleife ist 
man man..... du machst immer wieder eine initialisierung

Ciao

von Karl H. (kbuchegg)


Lesenswert?

fang damit an, dir den Wert für
  ADC_Read(5)
ausgeben zu lassen

Dann würde ich mal die Formel etwas umstellen um sie besser lesbar zu 
machen.
Der Faktor 0.0225 ist da schon etwas seltsam in der Verwendung, das 
sieht gefühlsmässig nicht richtig aus.

Die Formel sieht aus, als ob du falsch substituiert hättest. Die nackten 
5 bei 5/.... machen mich stutzig.

Aber erst mal solltest du checken, ob deine ADC Werte plausibel sind.
Dann die ADC Werte in eine Spannung umrechnen (damit du mit einem 
Voltmeter vergleichen kannst)
und erst dann die Volt in eine Temperatur umrechnen.

von Daniel F. (Gast)


Lesenswert?

Hallo Fausto, erstmal danke für deine Hilfe!

Also die init ist nicht in der While(1), das ist mir eben beim 
zusammenkopieren passiert, ebenfalls habe ich ausversehen die 
temperatur-Ausgabe nochmal durch 1000 geteilt, was auch nicht sein 
sollte.

Habe mal deine punkt vor strich trennung befolgt, bekomme nun einen Wert 
von
9863 ausgegeben.

Hier nochmal der untere Code, wie gesagt die ADC_init(); ist natürlich 
nicht in der while!
1
   temperatur=(5/(1023*0.0225))*((ADC_Read(5)-1.375)/0.0225);
2
  
3
4
    sprintf(buffer,"%d",temperatur);
5
    lcd_setcursor (11, 1);
6
    lcd_string(buffer);

Ich sitze heute schon 9 std. an meinem Code, tut mir leid wenn ich nicht 
mehr richtig gucken kann ;D

von Fausto B. (fausto)


Lesenswert?

dann kann es nur an falsche adressierung liegen!! Aber du hast ja eine 
LIB/SDK vom hersteller richtig?

von Daniel F. (Gast)


Lesenswert?

Hallo Karl Heinz,

wenn ich ADC_Read(5) ausgeben lasse, erscheint eine 1023 auf dem 
Display, welche sich nicht ändert. Wenn ich den Sensor erhitze oder 
abkühle, passiert rein garnichts? Mit dem Voltmeter gemessen, ändert 
sich die Sp. jedoch...?

Vll. liegt der Fehler sogar vor der Main?

von Daniel F. (Gast)


Lesenswert?

@Fausto, ich bin noch recht neu in diesem Fachgebiet.

Wenn du mit LIB-Bibliothek meinst und mit SDK den Programmer, dann JA!

von Stefan E. (sternst)


Lesenswert?

1
int buffer[2];
2
...
3
 sprintf(buffer,"%d",temperatur/1000);
int? 2?

von Thorsten (Gast)


Lesenswert?

Wenn ich das richtig sehe, hast du den ADC auf interne Spannungsreferenz 
von 2,56V gestellt, ist das gewollt? Jede Spannung über 2,56V wird somit 
zu 1023 gewandelt. Das würde zu deiner Erklärung passen, dass sich der 
Wert nicht ändert bei Veränderung der Temperatur, falls der 
Spannungswert immer über 2,56V liegt.

von Daniel F. (Gast)


Lesenswert?

Hallo Thorsten,

der Spannungswert liegt um und bei 2,47V.

Wo genau habe ich die interne Spannungsreferenz beim ADC auf 2,56V 
gestellt?

Die Funktionen habe ich von mikrocontroller.net

von Krapao (Gast)


Lesenswert?

> Wo genau habe ich die interne Spannungsreferenz beim ADC auf 2,56V
> gestellt?

hier, an der Stelle bei der der Kommentar zur Referenzspannung steht

>>   ADMUX = (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen

Beim Atmega8 (Table 74. Voltage Reference Selections for ADC in 
Datenblatt Revision 2486T–AVR–05/08) ist diese Bitkombination

REFS1 REFS0 Voltage Reference Selection
1 1 Internal 2.56V Voltage Reference with external capacitor at AREF pin

AVcc = Vcc intern wäre
0 1 AVCC with external capacitor at AREF pin

von Krapao (Gast)


Lesenswert?

Im AVR-GCC-Tutorial hatte jemand das Beispiel von AVCC als Referenz 
auf 2,56V als Referenz umgestellt. Die Originalzeile mit der 01 
Bitkombination war auskommentiert. IMHO ist die AVCC Referenz sinnvoller 
für den Lernenden.

von Daniel F. (Gast)


Lesenswert?

Hallo Leute,

ich habe mein Programm nun soweit zum laufen, es lag erstens an der 
Formel und zweitens an meinem ATmega328P.

Sobald ich einen mega8 mit dem Code bespiele zeigt er mir nun die genaue 
Temperatur an und verändert sich auch.

Woran kann das liegen? hat das was mit dem ADC zu tun, dass es mit dem 
mega328P nicht funktioniert?

Habe schon mal im Datenblass nachgesehen, kann auf anhieb aber nichts 
finden, was dort anders sein könnte!

von Daniel F. (Gast)


Lesenswert?

Ist die Referenzspannung bei diesem denn kleiner als die vom mega 8?

von Daniel F. (Gast)


Lesenswert?

Auch mit einer Referenzsp. von 1,1V bekomme ich keinen vernünftigen Wert 
auf mein Display. Da muss doch irgend etwas Grundlegendes am 328P anders 
sein als am mega8?

von Krapao (Gast)


Lesenswert?

Obacht: Bei einer Referenzspannung von 1.1V und einer Signalspannung von 
2,47V kannst du keinen vernünftigen ADC Wert bekommen!

Der Atmega328P unterscheidet sich vom Atmega8 in der genau dieser 
internen, genauen Referenzspannung, die mit (1<<REFS1) | (1<<REFS0) 
gewählt wird: Atmega8 2,56V und Atemag328P 1,1V.

Leider hat Martin Thomas im AVR-GCC-Tutorial wieder die vermaledeite 
"Interne Referenzspannung" als Voreinstellung für das adc_init() 
Beispiel gewählt. Statt dass man im allerersten (!) Beispiel Genauigkeit 
mal aussen vor lässt und den vollen ADC Eingangsbereich 0..AVcc 
auszunutzt...

Wir werden diese Problematik "Mein ADC misst nur Mist" noch häufiger 
sehen. Ich habe keinen Bock das jedes Mal zu erklären, wenn ich den ADC 
Einsteigern  erkläre "Benutzt für eure ersten ADC Versuche doch die 
bewährten Routinen aus dem AVR-GCC-Tutorial, aber mit der 
Referenzspannung müsst ihr..."

von Karl H. (kbuchegg)


Lesenswert?

Krapao schrieb:

> Statt dass man im allerersten (!) Beispiel Genauigkeit
> mal aussen vor lässt und den vollen ADC Eingangsbereich 0..AVcc
> auszunutzt...

Die sowieso ein Trugschluss ist.
Denn die interne Referenzspannung ist vor allen Dingen eines:
Sie ist zwar stabil, aber keinesfalls immer und bei jedem µC exakt 1.1 
oder 2.5V.

Ich würds auch besser finden, wenn man Anfänger da erst mal nicht 
durchjagt, sondern sie mit der Versorgungsspannung arbeiten lässt. 
Zumindest die einzelnen Varianten als auskommentierte Versionen (so wie 
das früher mal war) in den Source Code mit aufnimmt.

von Daniel F. (Gast)


Lesenswert?

Hallo ihr beiden,

danke erstmal, dass ihr nochmals Stellung zu meinem Problem nimmt.

Die Spannung von 2,47V(Vout) ist Geschichte, da muss ich wohl irgendwie 
mist gemacht haben.

Ich habe Sie nochmals gemessen und Sie liegt bei Zimmertemperatur 
ungefähr bei 1,86V!


Ich habe meine Formel im C-Code schon auf die 1,1 V umgestellt.

Hier mal die Formel:
1
result=ADC_Read(5);
2
A=2560L*result/1023L;
3
temperatur=(u-1375)/0.0225;
4
sprintf(buffer,"Temp=%d",temperatur/1000);

Diese Formel umgeschrieben für den 328P
1
result=ADC_Read(5);
2
A=1100L*result/1023L;
3
B=(u-1375)/0.0225;
4
sprintf(buffer,"Temp=%d",B/1000);

Wie gesagt beim mega8 funktioniert alles beim 328 nicht.

Die Routinen sind ja aus dem GCC-Tutorial, aber irgend einen Unterschied 
zwischen den genannten megas muss es ja geben!

Die weitere Suche im Forum ergab auch keine Treffer...

von Stefan E. (sternst)


Lesenswert?

Daniel F. schrieb:
> Ich habe Sie nochmals gemessen und Sie liegt bei Zimmertemperatur
> ungefähr bei 1,86V!
> ...
> Ich habe meine Formel im C-Code schon auf die 1,1 V umgestellt.
> ...
> Wie gesagt beim mega8 funktioniert alles beim 328 nicht.

Kann es eventuell sein, dass dir nicht klar ist, dass die 
Referenzspannung die obere Grenze der messbaren Spannung darstellt? Bei 
einer Referenzspannung von 1,1V hast du bei jeder Spannung >= 1,1V (also 
auch bei 1,86V) 1023 als Ergebnis.

von Karl H. (kbuchegg)


Lesenswert?

Daniel F. schrieb:

> Ich habe Sie nochmals gemessen und Sie liegt bei Zimmertemperatur
> ungefähr bei 1,86V!
>
>
> Ich habe meine Formel im C-Code schon auf die 1,1 V umgestellt.

Der ADC misst deine Spannung im Prinzip als Prozentwert in Bezug auf die 
Referenzspannung. D.h. der ADC Wert sagt dir, wo im Bereich 0 bis 
Referenzspannung sich deine zu messende Spannung bewegt. Ist die 
Spannung kleiner 0, liefert der ADC auch 0. Ist die Spannung größer als 
die Referenzspannung, kriegst du immer 100%

Das bedeutet aber auch:
Dein Messwert darf den durch die Referenzspannung vorgegebenen 
Messbereich nicht verlassen, sonst kriegst du IMMER die Endwerte 0 bzw. 
100%. Denn mehr als 100% kann der ADC nun mal nicht als Ergebnis 
liefern.

Nur dass der ADC die 100% eben als die Zahl 1023 ausdrückt.

> Die weitere Suche im Forum ergab auch keine Treffer...

Nicht für alles gibt es vorgefertigte Antworten. Du musst schon auch 
mitdenken und dein Wissen darüber wie die Einzelsysteme funktionieren 
zum Einsatz bringen.

Wenn du einen Meterstab hast, der 1 Meter lang ist (der "Referenzwert"), 
dann kannst du durch anlegen an ein Objekt nur dann seine Länge messen, 
wenn das Objekt nicht länger als 1 Meter ist. Darüber kannst du nur noch 
die Aussage treffen: Ist länger. Aber Zahlenwert kannst du keinen mehr 
angeben.

Tu dir selbst einen Gefallen und stell beim ADC die Referenzspannung auf 
die Verwendung von Vcc (also deine 5V Versorgungsspannung) um und 
vergiss die interne Referenzspannung fürs erste. Denn die ist sowieso 
nicht 1.1V oder 2.56V oder ....  Schau ins Datenblatt, die hat ganz 
schön große Toleranzen von µC zu µC! Der Zweck der Referenzspannung ist 
es nicht, auf allen µC die immer gleiche Spannung zur Verfügung zu 
stellen, sondern eine Spannung zur Verfügung zu stellen, die sich auf 
einem µC möglichst wenig ändert! Ob die 1.2V hat oder 1.0V spielt nicht 
so sehr die Rolle (das kann man softwaretechnisch kalibrieren), wichtig 
ist dass die 1.2V sich unter Last, unter wechselnden 
Temperaturbedingungen nicht ändern und bei -20°C bzw +60°C immer noch 
1.2V sind.

von Daniel F. (Gast)


Lesenswert?

Hi Karl Heinz,

wie von dir beschrieben habe ich es gemacht.

ADMUX = (0<<REFS1) | (0<<REFS0);

Zum probieren habe ich erstmal die 5V ohne schnickschnack auf Vref 
gelegt.

Nun bekomme ich jedenfalls schonmal einen Wert heraus der sich ändert. 
Dennoch wird mir nun ein zu kleiner Wert vom ADC ausgegeben.

Bei 20°C habe ich an Vout des AD22100 1,86V.

Wenn ich nun 1023/5V rechne, bekomme ich einen Wert von 204,6.

204,6 * 1,86V = 380<- Wert der aus dem ADC kommen sollte.

Wenn ich ADC_Read auslesen lasse, wird mir aber bei 20°C ein Wert von 
ca. 250 ausgegeben. Wo liegt denn nun schon wieder der Hund begraben?

Das hat ja mit der Umrechnung für die Temperatur nichts zu tun.

von Daniel F. (Gast)


Lesenswert?

Ich habs,

keine Ahnung wie aber auf einmal scheints zu klappen. Habe AVR-Studio 
mal neu gestartet und danach ging es. Da hatte sich wohl irgendwie ein 
Fehler im Programm eingeschlichen, aber egal, Hauptsache es 
funktioniert!

Vielen herzlichen Dank an alle Helfer!!!

schönes Wochenende!

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.