Ich versuche aktuell, die Formel für die Berechnung der Temperatur des internen Sensors zu verstehen. Den Wert, den ich vom ADC zurückbekomme ist 1733. Die Formel lautet: ((V25-Vsense) / Slope) + 25 V25 ist 1.43V, Vsense wäre: 1733 * 3.0/4096 = 1.27V ((1.43V-1.27V)*1000 / 4.3mV/°C) + 25°C = 62°C Das ist schon recht weit von der Wirklichkeit entfernt, hab ich irgendwas in meinen Berechnung vergessen / übersehen? Sind 3.0V nun die Referenzspannung? Wenn ich Channel 17 messe, der laut dieser Application Note mit Vrefint verbunden ist (http://www.st.com/content/ccc/resource/technical/document/application_note/b9/21/44/4e/cf/6f/46/fa/DM00035957.pdf/files/DM00035957.pdf/jcr:content/translations/en.DM00035957.pdf) bekomme ich den Wert 2080 zurück. Damit kann ich doch jetzt nicht viel anfangen, da ich die Referenzspannung nicht weiß und somit nicht auf die tatsächliche Spannung schließen kann? Im selben Abschnitt ist noch diese Formel gegeben: Val_VREFINT = VREFINT 2^12 / VREF+ = VREFINT x 4096 / VDDA Von der kenne ich aber Vref+ und VDDA nicht? Ich blick da nicht durch.
:
Bearbeitet durch User
Fuer modernere STM32 als den F1 gibt es im "ROM" Kalibarationswerte, die bei Chiptest bei 30 und 110 und 3.3V gemessen wurden. Setzt man die Werte aus dem Rom in die Formel ein, bekommt man deutlich realistischere Werte. Fuer den F103 finde ich keine Hinweis, dass diese Kalibrationswerte verfuegbar sind. Wenn Du nur die typischen Datenblattwerte nimmt, musst Du mit grossen Toleranzen leben, kannst aber immer noch Tendenzen sehen. Zwischen V25 Max und Min liegen 180 mV, bei Min Avg-Slope 4 mV sind das 45 (+/- 22.5) Grad moegliche Abweichung. Ausserdem musst Du die Samplezeiten fuer den Temperaturkanal sehr lang waehlen, den richtigen Kanal wahlen und TSVREFE richtig gesetzt haben. Viel raum also fuer Fehler. Lass Dir doch erstmal nur die Spannung des Temperatursensor ausgeben und schau ob die Werte ungefaehr passen.
Uwe B. schrieb: > Ausserdem musst Du die Samplezeiten fuer den Temperaturkanal sehr lang > waehlen, den richtigen Kanal wahlen und TSVREFE richtig gesetzt haben. > Viel raum also fuer Fehler. So sieht die ADC-Initialisierung aus:
1 | RCC->APB2ENR |= (1<<9); //Enable ADC1 Clock |
2 | RCC->CFGR |= (0b10<<14); //set ADC Prescaler '6' |
3 | ADC1->SMPR1 |= (0b100<<18); //41.5 cycles sample time |
4 | ADC1->CR2 |= (1<<23); //Enable Temperature Sensor & Vref |
5 | |
6 | ADC1->CR2 |= (1<<0); //Enable ADC and start conversion |
7 | |
8 | ADC1->CR2 |= (1<<3); //Initialize calibration register |
9 | while(ADC1->CR2 & (1<<3)){ //Wait until calibration register initialized |
10 | ; |
11 | } |
12 | |
13 | ADC1->CR2 |= (1<<2); //Enable calibration |
14 | while(ADC1->CR2 & (1<<2)){ //Wait until calibration completed |
15 | ; |
16 | } |
und so das Auslesen:
1 | uint32_t getADCTempValue(uint16_t channel){ |
2 | ADC1->SQR3 |= (channel<<0); |
3 | ADC1->CR2 |= (1<<0); //Enable ADC and start conversion |
4 | while(!(ADC1->SR & (1<<1))){ //Wait until end of conversion |
5 | ; |
6 | } |
7 | return ADC1->DR; |
8 | } |
Uwe B. schrieb: > Lass Dir doch erstmal nur die Spannung des > Temperatursensor ausgeben Die Spannung direkt bekomme ich doch nicht, oder? Sondern nur einen Wert, den ich mit der Formel: adc_value * Vref / (2^12) in eine Spannung umrechnen kann.
:
Bearbeitet durch User
Max M. schrieb: > RCC->CFGR |= (0b10<<14); //set ADC Prescaler '6' > ADC1->SMPR1 |= (0b100<<18); //41.5 cycles sample time Gibt das die in rm0008 geforderten mindestens 17.1 us? ( > Die Spannung direkt bekomme ich doch nicht, oder? Sondern nur einen > Wert, den ich mit der Formel: > > adc_value * Vref / (2^12) > > in eine Spannung umrechnen kann. Ja, genau, lass der den ADC Wert als Spannung oder einfach nur als Wert ausgeben und schau als erstes, ob der Wert der Erwartung entspricht. Mit mit "finger drauf" und/oder Kaeltespray kanns Du dann die Chiptemperatur veraendern un dem Wert beobachten.
Uwe B. schrieb: > Ja, genau, lass der den ADC Wert als Spannung oder einfach nur als Wert > ausgeben und schau als erstes, ob der Wert der Erwartung entspricht. Ich hab den Wert 1750 bekommen, laut diversen Tutorials im Internet entspräche ein Wert von 1750 ca. 25°C (darauf komm ich rechnerisch auch, wenn 3.3V Vref wäre). Der Wert würde also ungefähr passen (gefühlt sind es aber eher 23°C). Das Board unter eine Glühlampe zu halten, senkt den Wert. Uwe B. schrieb: > Gibt das die in rm0008 geforderten mindestens 17.1 us? Der ADC Prescaler ist auuf 6, also wäre die Frequenz: 72MHz / 6 = 12MHz. Das sind 12 * 10^6 Cycles pro Sekunde. Jeder Cycle braucht also 12us, wenn 41.5 cycles gewartet wird, entspricht das 498u us, müsste also rein rechnerisch passen, oder? Edit: Das stimmt ja gar nicht, ein Cycle braucht 1 / 12MHz, also 8.3*(10^-8)s. 41.5 cycles brauchen also 3.46us.
:
Bearbeitet durch User
Max M. schrieb: > 41.5 cycles brauchen also 3.46us. Das ist zu kurz. Setze doch erst einmal auf maximale Sampledauer (111 statt 100) in ADC_SMPRx.
Uwe B. schrieb: > Setze doch erst einmal auf maximale Sampledauer (111 statt 100) in > ADC_SMPRx. Hab ich gemacht, jetzt hat sich der Wert leicht nach oben korrigiert, auf 1755. Ich hab inzwischen eine Vermutung aufgestellt, wie die Formel funktionieren könnte. Um die Spannung zu bekommen, die der Temperatursensor liefert, muss man diesen mit der Referenzspannung und der Auflösung des ADC verrechnen (wie oben schon angemerkt). Dann läuft das so: (V25 - Vtemp) * 1000 / 4.3 + 25 Soweit ich das sehe, bekommt man aber den richtigen Wert von V25 nicht raus, da mein STM32F103 keinen Referenzpin hat, er liegt aber wohl im Bereich zwischen 1.34V und 1.52V. Mit der oben genannten Formel komme ich dann auf ~25°C.
Hm, kenne mich ja nur mit AVRs aus, aber wenn ich beim STM32F103 in's Datenblatt schaue, kann ich die interne Temperatur-Erfassung mit 12 Bit Auflösung nicht sooo toll finden: Guckt man tiefer in's Datenblatt: 2.3.28 Temperature sensor ------------------------- The temperature sensor has to generate a voltage that varies linearly with temperature. The conversion range is between 2 V < V DDA < 3.6 V. Erkenntnis 1: ============= 2 V ... 3,6 V an V_DDA macht einen großen Unterschied - Da sollte man schon mal wissen, was an V_DDA anliegt - und in die Berechnung einfließen lassen. 5.3.21 Temperature sensor characteristics ----------------------------------------- Für 25 °C liefert der Sensor 1,34...1,52 V Die Änderung für 1 °C ist 4,0 mV/°C ... 4,6 mV/°C Bei 4,3 mV / °C entspricht die Spanne von 1,52 V - 1,34 V = 0,18 V = 180 mV, einer Unsicherheits-Spanne von 180 mV / 4,3 mV/°C = 41 °C Erkenntnis 2: ============= 25 °C +/- 20,5 °C sind für Absolut-Messung SEHR ungeeignet. Ohne eine Kalibrierung ist also nur Müll zu messen.... Fazit: ====== Deine schlechten Testergebnisse zeigen einfach nur die grottenschlechte Temperaturerfassung des STM32F103.
Jakob schrieb: > The temperature sensor has to generate a voltage that varies > linearly with temperature. The conversion range is between > 2 V < V DDA < 3.6 V. > > Erkenntnis 1: > ============= > 2 V ... 3,6 V an V_DDA macht einen großen Unterschied > - Da sollte man schon mal wissen, was an V_DDA anliegt - und > in die Berechnung einfließen lassen. Das hast du falsch verstanden: Vdda, die Versorgungsspannung für den Analogbereich des µCs, muss innherhalb von 2V bis 3,6V liegen, damit der Temperatursensor spezifikationsgemäß funktioniert. Wo Vdda innerhalb dieses Bereichs genau liegt, ist nicht so spannend: Zuerst misst Du den Wert der internen Referenz. Deren Wert kennst Du relativ genau, daraus kannst Du dann den aktuellen Wert von Vdda zurückrechnen. Und damit liest Du nun den Temperatursensor aus.
:
Bearbeitet durch User
Gerd E. schrieb: > Zuerst misst Du den Wert der internen Referenz. Deren Wert kennst Du > relativ genau, daraus kannst Du dann den aktuellen Wert von Vdda > zurückrechnen Dafür hatte ich ja diese Formel: Val_Vrefint = Vrefint * 4096 / Vdda Vdda (also die Versorgungsspannung) ist in meinem Fall 3.3V. Der gemessene Wert von Channel 17 (Val_Vrefint nach: http://www.st.com/content/ccc/resource/technical/document/application_note/b9/21/44/4e/cf/6f/46/fa/DM00035957.pdf/files/DM00035957.pdf/jcr:content/translations/en.DM00035957.pdf) schwankt zwischen diesen Werten:
1 | 1983 |
2 | 2189 |
3 | 2008 |
4 | 2199 |
5 | 2016 |
6 | 2202 |
Vrefint = Val_Vrefint * Vdda / 4096 Mit einem Wert von z.B. 2060 für Val_Vrefint: Vrefint = 2060 * 3.3V / 4096 = 1.66V Kommt mir irgendwie wenig vor? Gerd E. schrieb: > daraus kannst Du dann den aktuellen Wert von Vdda > zurückrechnen. Okay, wie würde das funktionieren?
:
Bearbeitet durch User
Wenn du im Ref.Manual mal ganz unten schaust sollte es ein Code-Beispiel geben, das dir das ganze auch direkt in °C umrechnet. Die Rechnung ist echt Hahnebüchen, aber funktioniert.
Here we go.
1 | #define TEMP110_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7C2))
|
2 | #define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7B8))
|
3 | #define VDD_CALIB ((uint16_t) (330))
|
4 | #define VDD_APPLI ((uint16_t) (300))
|
5 | int32_t temperature; /* will contain the temperature in degree Celsius */ |
6 | temperature = (((int32_t) ADC1->DR * VDD_APPLI / VDD_CALIB) - (int32_t) *TEMP30_CAL_ADDR ); |
7 | temperature = temperature * (int32_t)(110 - 30); |
8 | temperature = temperature / (int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR); |
9 | temperature = temperature + 30; |
Max M. schrieb: > Vdda (also die Versorgungsspannung) ist in meinem Fall 3.3V. Konstant, z.B. mit Spannungsregler? > Der > gemessene Wert von Channel 17 (Val_Vrefint)... > schwankt zwischen diesen Werten: > >
1 | > 1983 |
2 | > 2189 |
3 | > 2008 |
4 | > 2199 |
5 | > 2016 |
6 | > 2202 |
7 | > |
Während Du konstante 3.3V an Vdda anliegen hast? Dann ist schon an der Stelle was ziemlich faul: Spannungsversorgung mit Kondensatoren nach Datenblatt genau des verwendeten Controllers abgeblockt? Siehe u.a. Fig. 14 im Datenblatt. ADC nach jedem Booten des µC kalibriert? ADC läuft die ganzen 17.1µs für das Sampeln der Vrefint? Den richtigen ADC verwendet? Lt. Refman ist der Vrefint nur an ADC1 verfügbar. Geh auch nochmal das Errata-Sheet durch, vielleicht gibt es irgendwelche Pins bei deren Benutzung der ADC empfindlich reagiert. So ähnlich wie PC13, PC14, PC15. Die Vrefint muss lt. Datenblatt Tabelle 5.3.4 zwischen 1.16V und 1.24V liegen. Bei 3,3V und 1,2V kommt da 1487 raus, Dein Wert sollte da irgendwo in der Nähe liegen.
Gerd E. schrieb: > Konstant, z.B. mit Spannungsregler? Hm, der Strom kommt von einem USB / UART Konverter, auf dem Board (dieses: http://img.dxcdn.com/productimages/sku_395848_2.jpg) ist einer drauf. Gerd E. schrieb: > Während Du konstante 3.3V an Vdda anliegen hast? Okay, gerade nachgemessen: Es sind 3.24V Gerd E. schrieb: > Spannungsversorgung mit Kondensatoren nach Datenblatt genau des > verwendeten Controllers abgeblockt? Siehe u.a. Fig. 14 im Datenblatt. Ich benutze ein fertiges Board, ich gehe mal davon aus, dass es richtig verschaltet ist, auch wenn es Chinaware ist. Gerd E. schrieb: > ADC nach jedem Booten des µC kalibriert? > > ADC läuft die ganzen 17.1µs für das Sampeln der Vrefint? > > Den richtigen ADC verwendet? Lt. Refman ist der Vrefint nur an ADC1 > verfügbar. Nicht böse gemeint, aber mein Code steht hier: Beitrag "Re: STM32F103 interner Temperatursensor" Der erfüllt, denke ich, die Anforderungen. Die Anzahl der Wartezyklen wurde inzwischen auf 239.5 cycles erhöht, das dürfte passen (Nach 5.3.18 entsprechen 239.5 cycles 17.1us bei 14MHz ADC-Frequenz, da mein Prescaler bei 6 liegt, ist die Frequenz 12 MHz). Gerd E. schrieb: > Die Vrefint muss lt. Datenblatt Tabelle 5.3.4 zwischen 1.16V und 1.24V > liegen. Bei 3,3V und 1,2V kommt da 1487 raus, Dein Wert sollte da > irgendwo in der Nähe liegen. Ich hab gerade mal debugged. Wenn ich durchsteppe, bekomme ich auf dem Terminal Window auf einmal eine ziemlich stabile Zahl um 1513. Warum ändert sich der Wert auf über 2000 wenn ich den Controller nicht debugge? Mit einem Wert von 1513 und 3.24V kommt man auf 1.20V.
:
Bearbeitet durch User
Max M. schrieb: >> Konstant, z.B. mit Spannungsregler? > > Hm, der Strom kommt von einem USB / UART Konverter, auf dem Board > (dieses: http://img.dxcdn.com/productimages/sku_395848_2.jpg) ist einer > drauf. Vielleicht nicht perfekt, verursacht aber vermutlich nicht solche Sprünge. Häng es vielleicht aber zur Sicherheit dennoch mal an nen anderen USB-Hub, USB-Port oder PC. Ich hatte schon einen USB-Hub mit einem Netzteil, dessen Kondensatoren defekt waren. Das machte ähnliche Effekte schon unter leichter Last. >> Spannungsversorgung mit Kondensatoren nach Datenblatt genau des >> verwendeten Controllers abgeblockt? Siehe u.a. Fig. 14 im Datenblatt. > > Ich benutze ein fertiges Board, ich gehe mal davon aus, dass es richtig > verschaltet ist, auch wenn es Chinaware ist. Da hab ich so meine Zweifel. Kontrolliere das bitte. Vor allem wenn Du solche Fehler siehst. Kerkos nachmessen oder gegen welche tauschen bei denen Du Dir wegen der Werte sicher bist. > Ich hab gerade mal debugged. Wenn ich durchsteppe, bekomme ich auf dem > Terminal Window auf einmal eine ziemlich stabile Zahl um 1513. So sollte der Wert sein. > Warum > ändert sich der Wert auf über 2000 wenn ich den Controller nicht > debugge? Es gibt 2 Möglichkeiten: a) Software Dein Programm macht im Hintergrund (Interrupts, PWM,...) irgendetwas, was den ADC durcheinanderbringt. Beim Debuggen läuft das nicht, oder nur so langsam, daß es keinen Schaden anrichtet. b) Hardware Beim Debuggen zieht der µC nicht kontinuierliche Peaks aus den falsch dimensionierten Kondensatoren, sondern zwischen den Debugger-Steps haben die genug Zeit sich wieder aufzuladen. oder Beim Debuggen wartet der µC meist auf den nächsten Befehl, dadurch entstehen nicht so starke Schwankungen auf Masse / Vcc. Die bringen den ADC durchandender wg. schlechtem Routing oder ähnlichem.
:
Bearbeitet durch User
Gerd E. (robberknight) schrieb:
> das hast du falsch verstanden...
Dass der Grundwert für 25 °C mit (typically) +/-20,5 °C Unsicherheit
belastet ist, muss man nur als Pipifax abtun...
Schon hat man: Endlosen Spaß beim weiteren Schwafeln!
Jakob schrieb: > Gerd E. (robberknight) schrieb: > >> das hast du falsch verstanden... > > Dass der Grundwert für 25 °C mit (typically) +/-20,5 °C Unsicherheit > belastet ist, muss man nur als Pipifax abtun... Wo habe ich das geschrieben oder angedeutet? Ich bin nur auf Deine "Erkenntnis 1" eingegangen, weil die meiner Meinung nach nicht korrekt war. Das sagt nichts über Deine "Erkenntnis 2" aus.
:
Bearbeitet durch User
Gerd E. schrieb: > a) Software > > Dein Programm macht im Hintergrund (Interrupts, PWM,...) irgendetwas, > was den ADC durcheinanderbringt. Beim Debuggen läuft das nicht, oder nur > so langsam, daß es keinen Schaden anrichtet. Hm, Interrupts und PWM hab ich nicht im Code. Fällt euch da etwas auf?
1 | #include "stm32f10x_gpio.h" |
2 | #include <stdio.h> |
3 | #include <string.h> |
4 | |
5 | void delay(long cycles); |
6 | void delay(long cycles){ |
7 | while(cycles > 0) |
8 | cycles--; |
9 | } |
10 | |
11 | void initADC(){ |
12 | RCC->APB2ENR |= (1<<9); //Enable ADC1 Clock |
13 | RCC->CFGR |= (0b11<<14); //set ADC Prescaler '8' |
14 | |
15 | ADC1->SMPR1 |= (0b111<<18); //239.5 cycles sample time |
16 | ADC1->CR2 |= (1<<23); //Enable Temperature Sensor & Vref |
17 | ADC1->CR2 |= (1<<0); //Enable ADC and start conversion |
18 | ADC1->CR2 |= (1<<3); //Initialize calibration register |
19 | while(ADC1->CR2 & (1<<3)){ //Wait until calibration register initialized |
20 | ; |
21 | } |
22 | |
23 | ADC1->CR2 |= (1<<2); //Enable calibration |
24 | while(ADC1->CR2 & (1<<2)){ //Wait until calibration completed |
25 | ; |
26 | } |
27 | } |
28 | |
29 | uint32_t getADCTempValue(uint16_t channel){ |
30 | ADC1->SQR3 |= (channel<<0); |
31 | ADC1->CR2 |= (1<<0); //Enable ADC and start conversion |
32 | while(!(ADC1->SR & (1<<1))){ //Wait until end of conversion |
33 | ; |
34 | } |
35 | return ADC1->DR; |
36 | } |
37 | |
38 | void initUART(){ |
39 | RCC->APB2ENR |= (1<<2); //Port A clock enable |
40 | |
41 | GPIOA->CRH |= (0xB << 4); //Pin A9 as Alternative PP & 50MHz Output mode |
42 | |
43 | RCC->APB2ENR |= (1<<14); //USART1 Clock enable |
44 | |
45 | USART1->CR1 |= (1<<13); //Enable UART |
46 | USART1->BRR = 72000000 / 9600; //72MHZ / 9600 BAUD |
47 | USART1->CR1 |= (1<<3); //Enable Transmitter |
48 | } |
49 | |
50 | void sendChar(char c){ |
51 | while(!(USART1->SR & (1<<7))){ //Wait until data is transferred to shift register |
52 | ; |
53 | } |
54 | USART1->DR = c; |
55 | while(!(USART1->SR & (1<<6))){ //Wait until transmission is complete |
56 | ; |
57 | } |
58 | } |
59 | |
60 | void sendString(const char *str){ |
61 | while(*str){ |
62 | sendChar(*str++); |
63 | } |
64 | } |
65 | |
66 | int main(void){ |
67 | initUART(); |
68 | initADC(); |
69 | char buffer[100]; |
70 | uint32_t adcVal = 0; |
71 | while(1){ |
72 | adcVal = getADCTempValue(17); |
73 | itoa((int)adcVal,buffer,10); |
74 | sendString("ADC-Value: "); |
75 | sendString(buffer); |
76 | |
77 | sendChar('\n'); |
78 | delay(500000); |
79 | } |
80 | } |
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.