Forum: Compiler & IDEs Problem mit Atmega8 und Temperaturberechnung


von Florian K. (koellsch)


Lesenswert?

Moin,

Ich bin gerade dabei ein Programm für den Atmega8 zu schreiben, welches 
eine gemessene Temperatur auf einer 7-Segment-Anzeige ausgibt. Sprich 
ein Thermometer ;-)
Ich hab auch alles mehr oder weniger hinbekommen (soweit ist das mit dem 
AVR Studio simulieren kann), nur bei der Umrechnung des ADC-Wertes in 
die Temperatur hab ich Probleme.
Zuerst hab ichs mit ner Formel probiert, das hat aber nicht geklappt. Da 
hat er mir immer 000 ausgegeben.
Dann hab ich mir ne Liste zusammengestellt, die für jeden ADC-Wert die 
Temperatur enthält. Das klappt allerdings nur, wenn ich den ADC-Wert als 
Zahl per Hand eintrage, nicht aber, wenn ichs per Variable versuche.

Hier der Ausschnitt aus meinem Programm:
1
int main (void) {
2
  
3
  int tmax = -100, tmin = 200, d, T, s1, s2, s3;
4
  int tlist[] = {-
5
300, -299, -299, -298, -297, -297, -296, -295, -295, -294, -293, -293, -292, -291, -291, -290, -289, -289, -288, -287, -287, -286, 
6
7
-285, -285, -284, -283, -283, -282, -281, -281, -280, -279, -279, -278, -277, -277, -276, -275, -275, -274, -273, -272, -272, -
8
9
271, -270, -270, -269, -268, -268, -267, -266, -266, -265, -264, -264, -263, -262, -261, -261, -260, -259, -259, -258, -257, -257, 
10
11
-256, -255, -254, -254, -253, -252, -252, -251, -250, -250, -249, -248, -247, -247, -246, -245, -245, -244, -243, -242, -242, -
12
13
241, -240, -240, -239, -238, -237, -237, -236, -235, -235, -234, -233, -232, -232, -231, -230, -230, -229, -228, -227, -227, -226, 
14
15
-225, -225, -224, -223, -222, -222, -221, -220, -219, -219, -218, -217, -217, -216, -215, -214, -214, -213, -212, -211, -211, -
16
17
210, -209, -208, -208, -207, -206, -205, -205, -204, -203, -202, -202, -201, -200, -199, -199, -198, -197, -196, -196, -195, -194, 
18
19
-193, -193, -192, -191, -190, -190, -189, -188, -187, -187, -186, -185, -184, -184, -183, -182, -181, -181, -180, -179, -178, -
20
21
177, -177, -176, -175, -174, -174, -173, -172, -171, -171, -170, -169, -168, -167, -167, -166, -165, -164, -164, -163, -162, -161, 
22
23
-160, -160, -159, -158, -157, -156, -156, -155, -154, -153, -153, -152, -151, -150, -149, -149, -148, -147, -146, -145, -145, -
24
25
144, -143, -142, -141, -141, -140, -139, -138, -137, -137, -136, -135, -134, -133, -133, -132, -131, -130, -129, -128, -128, -127, 
26
27
-126, -125, -124, -124, -123, -122, -121, -120, -119, -119, -118, -117, -116, -115, -114, -114, -113, -112, -111, -110, -110, -
28
29
109, -108, -107, -106, -105, -104, -104, -103, -102, -101, -100, -99.4, -98.6, -97.8, -96.9, -96.1, -95.2, -94.4, -93.5, -92.7, -
30
31
91.8, -91, -90.1, -89.3, -88.4, -87.6, -86.7, -85.8, -85, -84.1, -83.3, -82.4, -81.5, -80.7, -79.8, -79, -78.1, -77.2, -76.4, -
32
33
75.5, -74.6, -73.8, -72.9, -72, -71.1, -70.3, -69.4, -68.5, -67.7, -66.8, -65.9, -65, -64.1, -63.3, -62.4, -61.5, -60.6, -59.7, -
34
35
58.9, -58, -57.1, -56.2, -55.3, -54.4, -53.5, -52.6, -51.7, -50.9, -50, -49.1, -48.2, -47.3, -46.4, -
36
45.5, -44.6, -43.7,-42.8, -41.9, -41, -40.1, -39.2, -38.3, -37.4, -36.4, -35.5, -34.6, -33.7, -32.8, -31.9, -31, -30.1, -29.1, -
37
38
28.2, -27.3, -26.4, -25.5, -24.6, -23.6, -22.7, -21.8, -20.9, -19.9, -19, -18.1, -17.2, -16.2, -15.3, -14.4, -13.4, -12.5, -11.6, 
39
40
-10.6, -9.69, -8.75, -7.81, -6.87, -5.93, -4.99, -4.05, -3.1, -2.16, -1.21, -0.266, 0.682, 1.63, 2.58, 3.53, 4.48, 5.44, 6.39, 
41
42
7.35, 8.3, 9.26, 10.2, 11.2, 12.1, 13.1, 14.1, 15, 16, 17, 17.9, 18.9, 19.9, 20.8, 21.8, 22.8, 23.8, 24.7, 25.7, 26.7, 27.7, 28.6, 
43
44
29.6, 30.6, 31.6, 32.6, 33.6, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 
45
46
50.5, 51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.6, 60.6, 61.6, 62.6, 63.6, 64.6, 65.7, 66.7, 67.7, 68.7, 69.8, 70.8, 
47
48
71.8, 72.9, 73.9, 74.9, 76, 77, 78, 79.1, 80.1, 81.1, 82.2, 83.2, 84.3, 85.3, 86.4, 87.4, 88.5, 89.5, 90.6, 91.6, 92.7, 93.7, 
49
50
94.8, 95.8, 96.9, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 
51
52
123, 124, 125, 126, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 
53
54
152, 153, 154, 155, 156, 157, 158, 159, 161, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173, 174, 176, 177, 178, 179, 180, 
55
56
181, 183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 197, 198, 199, 200, 201, 203, 204, 205, 206, 207, 209, 210, 211, 
57
58
212, 213, 215, 216, 217, 218, 219, 221, 222, 223, 224, 226, 227, 228, 229, 230, 232, 233, 234, 235, 237, 238, 239, 240, 242, 243, 
59
60
244, 245, 247, 248, 249, 250, 252, 253, 254, 255, 257, 258, 259, 260, 262, 263, 264, 266, 267, 268, 269, 271, 272, 273, 275, 276, 
61
62
277, 278, 280, 281, 282, 284, 285, 286, 288, 289, 290, 292, 293, 294, 295, 297, 298, 299, 301, 302, 303, 305, 306, 307, 309, 310, 
63
64
311, 313, 314, 316, 317, 318, 320, 321, 322, 324, 325, 326, 328, 329, 331, 332, 333, 335, 336, 337, 339, 340, 342, 343, 344, 346, 
65
66
347, 349, 350, 351, 353, 354, 356, 357, 358, 360, 361, 363, 364, 365, 367, 368, 370, 371, 373, 374, 376, 377, 378
67
, 380, 381, 383, 384, 386, 387, 389, 390, 392, 393, 394, 396, 397, 399, 400, 402, 403, 405, 406, 408, 409, 411, 412, 414, 415, 
68
69
417, 418, 420, 421, 423, 424, 426, 427, 429, 430, 432, 433, 435, 437, 438, 440, 441, 443, 444, 446, 447, 449, 450, 452, 454, 455, 
70
71
457, 458, 460, 461, 463, 465, 466, 468, 469, 471, 473, 474, 476, 477, 479, 481, 482, 484, 485, 487, 489, 490, 492, 494, 495, 497, 
72
73
498, 500, 502, 503, 505, 507, 508, 510, 512, 513, 515, 517, 518, 520, 522, 523, 525, 527, 528, 530, 532, 533, 535, 537, 539, 540, 
74
75
542, 544, 545, 547, 549, 551, 552, 554, 556, 558, 559, 561, 563, 565, 566, 568, 570, 572, 573, 575, 577, 579, 580, 582, 584, 586, 
76
77
588, 589, 591, 593, 595, 597, 598, 600, 602, 604, 606, 608, 609, 611, 613, 615, 617, 619, 620, 622, 624, 626, 628, 630, 632, 634, 
78
79
635, 637, 639, 641, 643, 645, 647, 649, 651, 653, 654, 656, 658, 660, 662, 664, 666, 668, 670, 672, 674, 676, 678, 680, 682, 684, 
80
81
686, 688, 690, 692, 694, 696, 698, 700, 702, 704, 706, 708, 710, 712, 714, 716, 718, 720, 722, 724, 726, 728, 730, 732, 734, 736, 
82
83
738, 741, 743, 745, 747, 749, 751, 753, 755, 757, 760, 762, 764, 766, 768, 770, 772, 775, 777, 779, 781, 783, 785, 788, 790, 792, 
84
85
794, 796, 799, 801, 803, 805, 807, 810, 812, 814, 816, 819, 821, 823, 825, 828, 830, 832, 835, 837, 839, 841, 844, 846, 848, 851, 
86
87
853, 855, 858, 860, 862, 865, 867, 869, 872, 874, 877, 879, 881, 884, 886, 888, 891, 893, 896, 898, 901, 903, 905, 908, 910, 913, 
88
89
915, 918, 920, 923, 925, 928, 930, 933, 935, 938, 940, 943, 945, 948, 950, 953, 955, 958, 961, 963, 966, 968, 971, 974, 976, 979, 
90
91
981, 984, 987, 989, 992, 995, 997, 100};
92
93
94
  DDRB = 0xff; //Port B (Anzeige) als Ausgang
95
  DDRC = 0x00; //PORT C (Knöpfe) als Eingang
96
  DDRD = 0xff; //PORT D (Segmente) als Ausgang
97
98
  ADMUX = 0x00; //External Ref und Eingang ADC0
99
100
101
  while (1) {
102
103
    //Auslesen der Temp//
104
105
    ADCSRA |= 0b10000000; //ADC enable
106
    ADCSRA |= 0b01000000; //Start Conversion
107
108
    while (ADCSRA & (1<<ADSC)) {
109
      }
110
  
111
112
    //Ermitteln der Temp//
113
114
    T = tlist[ADC];

Wenn ich in der letzten Zeile T = tlist[500] schreibe, dann klappt das.
So wies jetzt da steht, bekomme ich, wenn die einzelnen Zahlen angezeigt 
werden sollen, die Fehler:

AVR Simulator: Stack Overflow at 0x0090
AVR Simulator: Stack Overflow at 0x00e1

Woran kann das liegen, dass das mit Zahlen funktioniert, nicht aber mit 
ADC?

Gruß
koellsch

von Gast (Gast)


Lesenswert?

Du schiebst in einen "int" Sachen wie dies hier hinein "56.5".
Ob das so funktioniert?

von Anonymous (Gast)


Lesenswert?

rechne doch mal nach: int hat 2 byte, deine liste hat 1023 einträge...

->das kann nicht gut gehen.

warum es per "hand" funktionieren könnte:

gcc optimiert dein array weg: da der berechnete wert ja schon zur 
compilezeit bekannt ist und das riesen-array nicht gebraucht wird.

verrate doch mal deine formel. eventuell können wir sie so umstellen, 
dass sie funktioniert. 0 als Ergebnis klingt verdächtig nach einem 
integer Rundungsfehler, weil du eine Weil ein Zwischenergebnis zu 0 
gerundet wird.

von Karl H. (kbuchegg)


Lesenswert?

Was Anonymous (Gast)
da schreibt ist erst mal vernünftig. Solange es keinen wirklich guten 
Grund gibt, ist diese Tabelle nicht unbedingt der Weisheit letzter 
Schluss.

Schon alleine aus folgender Überlegung heraus:
Deine Tabelle umfasst 1024 int Werte (ich hab jetzt nicht nachgezählt, 
ob es wirklich 1024 sind). Ein int benötigt 2 Bytes Speicher. Deine 
komplette Tabelle benötigt daher 2KByte SRAM-Speicher. Der Mega8 hat 
aber nur 1KByte!

von Florian K. (koellsch)


Lesenswert?

Hab mir schon gedacht, dass das was mit dem Speicher zu tun hat.
Meine Formel sieht folgendermaßen aus:

T = 
-(0.668*(10^(-2))*(2.169*(10^9)*adc-3.511*(10^12)+2*sqrt(-3.145*(10^17)* 
(adc^2)-8.278*(10^20)*adc+2.165*(10^24))))/(78125*adc-1.265*(10^8))

für adc = 0 kommt -30° und für adc = 1024 100° raus. Das soll auch so 
sein. Die Variable adc ist als uint16_t deklariert und nimmt die Werte 
von ADC an.
Der Rest bleibt so.

Was die Deklarierung von Variablen betrifft bzw. die einzelnen Typen, da 
hab ich eh nicht so die große Ahnung von.

Gruß
koellsch

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dazu kommt, daß das Array als automatische Variable auf dem Stack 
angelegt wird.

Da es sich hier um Konstanten handelt, ist es sinnvoll, das Array im 
Flash-ROM abzulegen. Dafür ist beim AVR der pgmspace.h - Kram 
erforderlich, bei von-Neumann-Maschinen würde ein schlichtes const 
genügen.

von Florian K. (koellsch)


Lesenswert?

Wenn du mir jetzt noch sagst, wie ich das anwende...
Scheint ja mit #define PROGMEM   _ATTR_PROGMEM_ zu funktionieren, aber 
ich weiß nicht, wie ich das anwenden soll.

Wäre aber trotzdem nicht verkehrt, wenn irgendwer die Funktion zum 
Laufen kriegen würde.

von Karl H. (kbuchegg)


Lesenswert?

Der erste (und wahrscheinlich wichtigste) Punkt in deiner Formel ist:
^ ist nicht die Potenzfunktion, sondern bitweises XOR

Was du suchst nennt sich pow() und steckt in math.h (genauso wie auch 
sqrt)

Wo hast du die Formel her?
Da scheinen sich einige Fehler beim Abschreiben eingeschlichen zu haben


T =
   -(   0.668*(10^(-2))*     // 10 ^ -2   ergibt 0.001
        (2.169*(10^9)*adc    // 10 ^ 9    ergibt aber schon 1000000000
         -
         3.511*(10^12)       // 10 ^ 12   ist irrsinnig hoch, 12 Nullen
         +
         2*sqrt(-3.145*(10^17)*(adc^2)   // und 10 ^ 17 erst
            -
            8.278*(10^20)*adc
            +
             2.165*(10^24)
         )
        )
     ) / (78125*adc-1.265*(10^8))    // 10^8

vom Zähler bleibt im wesentlichen nur 2.165 * 10^24 übrig. Im Vergleich 
zur Größe dieser Zahl, sind alle anderen Terme nur Peanuts.
Im Nenner steht im wesentlichen -1.265 * 10^8. Dass von 100 Millionen 
noch 78125*adc abgezogen wird, kann vernachlässigt werden. selbst wenn 
adc den Wert 1024 hat, bleiben immer noch -20 Millionen übrig.

Fazit. Mit der Formel dürfte einiges nicht stimmen.

von Harry (Gast)


Lesenswert?

Warum macht ihr euch alle das Leben so schwer? Nimm nen DS18B20 Sensor, 
der ist bereits kalibriert und über 1wire kinderleicht anzubinden.

von Peter D. (peda)


Lesenswert?

Deine Tabelle sieht interessant aus. Allerdings wird Dich jeder 
auslachen, wenn Dein Thermometer -300°C anzeigen können soll.

Ich bezweifle auch, daß es überhaupt Sensoren gibt, die -273 ... +1000°C 
abkönnen.
Es gibt haufenweise Sensoren-Datenblätter und da stehen der 
Arbeitsbereich und auch die richtige Formel drin.

Da Tiefsttemperatursensoren nicht billig sind, nimmt man da auch keinen 
10Bit-ADC mehr sondern 16..24Bit.


Peter

von Markus B. (diskman)


Lesenswert?

Das sehe ich genauso wie Karl Heinz.

Wenn dein Temperatursensor dennoch ein solch seltsames Verhalten über 
den gesamten Temperaturbereich aufweist, würde ich dir zunächst einmal 
empfehlen zu schauen welche Kurvenform da rauskommt. Selbst wenn das 
Verhalten über den gesamten Bereich nicht linear ist, so könntest du in 
bestimmten Bereichen eine erste lineare Annäherung vornehmen. Soll 
heißen, von z.B. ADC=0 bis ADC=75 gilt ungefähr f(ADC)=-30 * 0,4*ADC für 
ADC=71 bis ADC=223 gilt ungefähr f(x)=0,7*ADC und so weiter. So musst du 
nicht so viele Daten hinterlegen und der Rechenaufwand sinkt erheblich, 
nur eine Gleitpunkt-multiplikation. Außerdem wird der Code leichter 
lesbar:

if(ADC<75) .....
else if(ADC<223)...

usw.

Versuchs mal mit dem Ansatz.

von Markus B. (diskman)


Lesenswert?

Ups Schreibfehler! Soll natürlich

ADC=0 bis ADC=75 gilt ungefähr f(ADC)=-30 + 0,4*ADC
ADC=71 bis ADC=223 gilt ungefähr f(x)=0,7*ADC und so weiter

heißen.

von B e r n d W. (smiley46)


Lesenswert?

Hallo  Florian

Darf man erfahren, um welchen Temperaturfühler es sich handelt?
Vielleicht haben wir dann ja einen besseren Hinweis/Idee.

Gruß, Bernd

von Florian K. (koellsch)


Lesenswert?

Erstmal danke für die ganzen Antworten.

Also, der Temperaturfühler (KTY81, welcher genau das ist, weiß ich 
nicht, da ich nur die Software mache) ist vorgegeben und kann nicht 
verändert werden.

Die Temperaturwerte in der Tabelle sind so groß, weil das die Temperatur 
* 10 ist. Sprich die geht von -30 bis 100 in 1025 Schritten. Und das ist 
ja realistisch.

Die Formel kommt durch ne Regressionsanalyse zustande. Sprich ich hab 
folgende Gleichungen:
1. R(t) = 2000,1 + 15.751*(t-25) + 0.03745*(t-25)^2
2. adc/1024 = -4097 + 0,5187 + 0,5187*4097*((2000+R(t))/2000*R(t))

1 nach t aufgelöst, 2 nach R(t) und eingesetzt. Das ganze mit Maple 
durchrechnen lassen und so weit wie möglich vereinfacht (durch Maple).

Also mit pow() anstatt ^ (was ich natürlich nicht wusste, danke Karl 
Heinz) klappts fast, für den adc 500 rechnet er 16, anstatt 12 aus. 
Evtl. kriegt man die Formel ja auch noch einfacher.

von Falk B. (falk)


Lesenswert?

@  Florian K. (koellsch)

>1 nach t aufgelöst, 2 nach R(t) und eingesetzt. Das ganze mit Maple
>durchrechnen lassen und so weit wie möglich vereinfacht (durch Maple).

Früher(tm) hat man das BESTENFALL mit einem Polynom 2. Grades angenähert 
und gut ist. Heute muss jeder Fliegenschiss mit CAD modeliert werden . . 
.

von Florian K. (koellsch)


Lesenswert?

Ok, ich hatte da noch n Fehler drin, jetzt passts mit der Temperatur.
Die fertige Formel sieht so aus:

T = -(0.00668 * (2.169 * pow(10, 9) * adc - 3.511 * pow(10, 12) + 2 * 
sqrt(-3.145 * pow(10, 17) * pow(adc, 2) - 8.278 * pow(10, 20) * adc + 
2.165 * pow(10, 24))))/(78125 * adc - 1.265 * pow(10, 8))

Mag kompliziert sein, klappt aber. Und ich denke, ich werde das jetzt so 
benutzen.

Vielen Dank an alle für die Hilfe.

@Falk Brunner

Wenn mans kann, dann geht das bestimmt. Ich bin zwar recht gut in Mathe, 
aber das hab ich dann lieber doch mit Maple gemacht. Wie gesagt, falls 
die Formel noch einfacher geht, dann bin ich für jede Hilfe dankbar. 
Aber es läuft ja...

von Martin (Gast)


Lesenswert?

Da kann aber was nicht stimmen. Kein Mensch wertet einen simplen 
Temperatursensor mit so einer Monsterformel aus.

von Florian K. (koellsch)


Lesenswert?

Es handelt sich bei der ganzen Aktion um ein Projekt und da haben wir 
den Auftrag bekommen, die Formel so zu erstellen. Auch wenn man mit 
Kanonen auf Spatzen schießt.

von B e r n d W. (smiley46)


Angehängte Dateien:

Lesenswert?

Hallo Florian

Wenn man den KTY81 nicht an einer Stromquelle, sondern an z.B. 5Volt 
über einen Vorwiderstand von 5600 Ohm betreibt, wird die Kurve nahezu 
linear. Damit habe ich bisher sehr gute Erfahrungen gemacht, und zwar 
Bessere, als den Fühler mit Stromquelle zu betreiben.

Obwohl man die Kurve im Bereich von 0 - 50°C als nahezu linear annehmen 
kann, hab ich hier mal die Korrektur per Polynom 2ter Ordnung 
beschrieben. Die Berechnung findet in (long) statt.

int t = (long)-adc*adc/30941 + (long)1412*adc/1000 - 1554;

Im Ganzzahl-Ergebnis steckt eine Nachkommastelle.

Nachteil:
Der Messbereich erstreckt sich von 910 - 1886mV. Schaltungstechnisch 
könnte dies jedoch noch optimiert werden.

Gruß, Bernd

von Florian K. (koellsch)


Angehängte Dateien:

Lesenswert?

Hi Bernd,
da ich mich mit der Software beschäftigt hab, kenn ich mich nicht so 
genau mit der Hardware aus, aber ich denke, der KTY ist über ne 
Messbrücke und nem OP mit dem atmega verbunden. Eagleschaltplan häng ich 
mal an.

von Gast (Gast)


Lesenswert?

Das wollt ich auch schon immer mal schreiben :)

 Bildformate

von B e r n d W. (smiley46)


Lesenswert?

Hallo Florian

Eagle kann ich leider nicht lesen, gibts das auch als jpg oder pdf?

Gruß, Bernd

von Michael U. (amiga)


Angehängte Dateien:

Lesenswert?

Hallo,

darf es auch png sein?

Gruß aus Berlin
Michael

von Florian K. (koellsch)


Lesenswert?

Danke Michael, ich hätte es nicht besser machen können ;-)

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.