Lesen des internen Temperatursensors STM32

Ich versuche, den internen Temperatursensor zu lesen. Der Wert der ADC-Konvertierung beträgt jedes Mal 296, was zu einer negativen Temperatur führt. Sollte ich dem Code unten etwas hinzufügen, einige Peripheriegeräte aktivieren oder meine Berechnungen sind falsch?

#define TEMP_SENSOR_AVG_SLOPE_MV_PER_CELSIUS                        2.5f
#define TEMP_SENSOR_VOLTAGE_MV_AT_25                                760.0f
#define ADC_REFERENCE_VOLTAGE_MV                                    1210.0f
#define ADC_MAX_OUTPUT_VALUE                                        4095.0f

int32_t sensorValue, temperature;

__HAL_ADC_ENABLE(&hadc1);

// Disable Vbat signal from input channel and wake up temp sensor from power down mode
ADC->CCR &= ~(ADC_CCR_TSVREFE);


HAL_ADC_Start(&hadc1);
if(HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
{
    sensorValue = (int32_t)HAL_ADC_GetValue(&hadc1);
    HAL_ADC_Stop(&hadc1);
    sensorValue = sensorValue * ADC_REFERENCE_VOLTAGE_MV / ADC_MAX_OUTPUT_VALUE;
    temperature = (int32_t)((sensorValue - TEMP_SENSOR_VOLTAGE_MV_AT_25) / TEMP_SENSOR_AVG_SLOPE_MV_PER_CELSIUS + 25);
}
else
{
    temperature = -273;
}

return temperature;

--BEARBEITEN

#define TEMP_SENSOR_AVG_SLOPE_MV_PER_CELSIUS                        2.5f
#define TEMP_SENSOR_VOLTAGE_MV_AT_25                                760.0f
#define ADC_REFERENCE_VOLTAGE_MV                                    3300.0f
#define ADC_MAX_OUTPUT_VALUE                                        4095.0f
#define TEMP110_CAL_VALUE                                           ((uint16_t*)((uint32_t)0x1FFF7A2E))
#define TEMP30_CAL_VALUE                                            ((uint16_t*)((uint32_t)0x1FFF7A2C))
#define TEMP110                                                     110.0f
#define TEMP30                                                      30.0f

int32_t temperature;
float sensorValue;
float adcCalValue30 = (float)(*TEMP30_CAL_VALUE);
float adcCalValue110 = (float)(*TEMP110_CAL_VALUE);

__HAL_ADC_ENABLE(&hadc1);

// Disable Vbat signal from input channel and wake up temp sensor from power down mode
ADC->CCR |= ADC_CCR_TSVREFE;
ADC->CCR &= ~ADC_CCR_VBATE ;


HAL_ADC_Start(&hadc1);
if(HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
{
    sensorValue = (float)HAL_ADC_GetValue(&hadc1);
    HAL_ADC_Stop(&hadc1);
    temperature = (int32_t)((TEMP110 - TEMP30) / ((float)(*TEMP110_CAL_VALUE) - (float)(*TEMP30_CAL_VALUE)) * (sensorValue - (float)(*TEMP30_CAL_VALUE)) + TEMP30);
}
else
{
    temperature = -273;
}

return temperature;

Formel zur Berechnung der Temperatur Kalibrierwerte

ADC-Konfiguration:

  ADC_ChannelConfTypeDef sConfig;

    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
    */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
    */
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

Ich bekomme die Ausgabe um 35 Grad. Ist es in Ordnung, einen so großen Versatz zu haben?

Was sind die Definitionen von ADC_REFERENCE_VOLTAGE_MV und den anderen Konstanten?
ADC_REFERENCE_VOLTAGE_MV ist eine Bandlückenspannung = 1210 mV; ADC_MAX_OUTPUT_VALUE = 4095; TEMP_SENSOR_VOLTAGE_MV_AT_25 = 760mV; TEMP_SENSOR_AVG_SLOPE_MV_PER_CELSIUS = 2,5 mV/C;
Vielen Dank, aber können Sie die eigentlichen #define-Anweisungen posten? Es kann ein signierter/unsignierter Fehler oder etwas Ähnliches sein. Sie können sie in Ihrer Frage bearbeiten.
Das ist guter Code. Die Frage, wie man Ihren Code verbessern oder etwas hinzufügen sollte, können wir jedoch nicht beantworten, da dies Ihr Projekt ist. Aber Sie können uns fragen, ob Sie noch etwas hinzufügen möchten, aber Sie sind sich nicht sicher, wie Sie so etwas schreiben. Herauszufinden, wie man Messungen (wie Temperatur) durchführt, ist etwas, das Sie selbst herausfinden müssen, es sei denn, Sie haben etwas versucht, aber etwas stimmt nicht und Sie können nicht herausfinden, was falsch ist. Vergessen Sie nicht, das Fehlerprotokoll zu überprüfen, wenn etwas passiert.
@VIPPER erwähnt immer das Modell
Es ist STM32F429ZIT6
Fügen Sie die gesamte ADC-Konfiguration hinzu.
Sie haben einen Fehler in der Formel. Muss stattdessen sein (beachten Sie die letzte Klammer):temperature = (int32_t)((TEMP110 - TEMP30) / ((float)(*TEMP110_CAL_VALUE) - (float)(*TEMP30_CAL_VALUE)) * (sensorValue - (float)(*TEMP30_CAL_VALUE))) + TEMP30;
Beachten Sie, dass ST ein Makro bereitstellt, um die Temperatur in stm32xxxx_hal_adc.hnamed zu berechnen__HAL_ADC_CALC_TEMPERATURE

Antworten (2)

Wie PeterJ betonte, besteht der erste Fehler darin, dass Sie das ADC_CCR_TSVREFEBit setzen und nicht zurücksetzen müssen.

Ich habe keine Ahnung, wie Sie die Abtast- und Haltezeit eingestellt haben, aber ich hoffe, es ist richtig. Sie muss für eine genaue Messung mindestens 10 µs betragen (Datenblattabschnitt Temperatursensor).

Ihr nächster großer Denkfehler ist, dass die Referenzspannung 1,21 V beträgt. Das ist der Nennwert für die v R e F ich N T . Diese Spannung ist nicht die Referenzspannung für den ADC. Die Referenzspannung ist in der Regel v D D A oder eine andere extern zugeführte Spannung an der v R E F + -Stift. Aber höher darf es nicht sein v D D A es kann auch nicht niedriger sein als v D D A -1,2 V.

Mit Ihrem Umrechnungsergebnis von 950 und 3,3 V würden Sie am Ende 27,2 ° C erhalten, was wie ein guter Anfang erscheint. Wenn Sie 3 V haben, wären es -0,6 ° C, was auch in Ordnung zu sein scheint.

Warum halte ich -0,6 °C für einen guten Wert? Denn die Berechnung mit den Durchschnittswerten ist Mist.

Ich weiß nicht warum, aber STM bewirbt ihre kalibrierten Werte nicht sehr. Jedes Gerät hat zwei ADC-Rohwerte, die bei 30 °C und 110 °C bei 3,3 V aufgenommen wurden, intern gespeichert. Wenn Sie diese Werte verwenden, erhalten Sie sinnvollere Temperaturwerte, ohne eine Kalibrierung durchzuführen.


Etwas in dieser Richtung sollte tun:

// see datasheet for position of the calibration values, this is for STM32F429
const uint16_t* const ADC_TEMP_3V3_30C =  reinterpret_cast<uint16_t*>(0x1FFF7A2C);
const uint16_t* const ADC_TEMP_3V3_110C =  reinterpret_cast<uint16_t*>(0x1FFF7A2E);
const float CALIBRATION_REFERENCE_VOLTAGE = 3.3F;

const float REFERENCE_VOLTAGE = 3.0F; // supplied with Vref+ or VDDA

// scale constants to current reference voltage
float adcCalTemp30C = static_cast<float>(*ADC_TEMP_3V3_30C) * (REFERENCE_VOLTAGE/CALIBRATION_REFERENCE_VOLTAGE);
float adcCalTemp110C = static_cast<float>(*ADC_TEMP_3V3_110C) * (REFERENCE_VOLTAGE/CALIBRATION_REFERENCE_VOLTAGE);

uint16_t adcTempValue = SAMPLED VALUE;

float temperature = (static_cast<float>(adcTempValue) - adcCalTemp30C)/(adcCalTemp110C - adcCalTemp30C) * (110.0F - 30.0F) + 30.0F;

Ich bin an C++ gewöhnt, also vielleicht nicht Ihr Programmierstil, aber das sollte kein großes Problem sein.

Ich habe diese Kalibrierungswerte im Referenzhandbuch des STM32F0 gefunden. Das ist wirklich seltsam, dass ich es im STM32F4-Referenzhandbuch nicht finden konnte. Darüber hinaus beschrieben sie das Verfahren zum Lesen des Temperatursensorwerts mit ADC und erwähnten keine Kalibrierwerte. Diese Werte erscheinen jedoch im Datenblatt ... aus meiner Sicht ist es ein kleines Durcheinander in ihren Dokumenten.
In Bezug auf den App-Hinweis STM32L1 AN3964 beträgt die Kalibrierungsreferenzspannung 3 V und nicht 3,3 V, wie Sie oben erwähnt haben. Ist das korrekt?
Ich habe keine Ahnung, wie du auf 27,2 Grad gekommen bist :D
@VIPPER nicht sicher, warum Sie sich für den STM32L1 interessieren, aber ja, in diesem Gerät erfolgt die Kalibrierung bei 3 V. Beim F429 erfolgt sie bei 3,3 V. Was die 27,2 ° C betrifft: Ich habe Ihre Formeln mit 950 als ADC-Wert verwendet aber die ADC-Referenzspannung von 1210 mV auf 3300 mV geändert.
Und für Ihre Bearbeitung: Wir haben mit dem internen Sensor eine Abweichung von bis zu 6 K erhalten. Wenn es mehr ist, scheint etwas nicht in Ordnung zu sein (messen Sie Vdda, um sicherzustellen, dass es zum Beispiel 3,3 V ist)
// Disable Vbat signal from input channel and wake up temp sensor from power down mode
ADC->CCR &= ~(ADC_CCR_TSVREFE);

Es ist eigentlich genau gegenüber :)

Ablesen der Temperatur So verwenden Sie den Sensor: 3. Wählen Sie den Eingangskanal ADC1_IN18. 4. Wählen Sie eine Abtastzeit, die größer ist als die im Datenblatt angegebene Mindestabtastzeit. 5. Setzen Sie das TSVREFE-Bit im ADC_CCR-Register, um den Temperatursensor aus dem Abschaltmodus aufzuwecken. 6. Starten Sie die ADC-Umwandlung durch Setzen des SWSTART-Bits (oder durch externen Trigger). 7. Lesen Sie die resultierenden V SENSE-Daten im ADC-Datenregister 8. Berechnen Sie die Temperatur mit der folgenden Formel: Temperatur (in °C) = {(V SENSE – V 25 ) / Avg_Slope} + 25 Dabei gilt: – V 25 = V SENSE-Wert für 25 °C – Avg_Slope = durchschnittliche Steigung des Temperatur vs. V SENSE-Kurve (angegeben in mV/°C oder µV/°C) Die tatsächlichen Werte von V 25 und Avg_Slope finden Sie im Abschnitt zu den elektrischen Eigenschaften des Datenblatts.

Danke, du hast recht. Jetzt kann ich nach der Konvertierung einen höheren Wert lesen, etwa 950, was -166 Grad ergibt ... aber das ist ein Fortschritt: D
Warum initialisieren Sie den ADC nicht richtig? Nach dem Einschalten können Sie dies tun, wenn Sie die Register programmieren, aber nicht mit HAL