Lectura del sensor de temperatura interna STM32

Estoy tratando de leer el sensor de temperatura interna. Cada vez, el valor de la conversión ADC es 296, lo que da como resultado una temperatura negativa. ¿Debo agregar algo al código a continuación, habilitar algún periférico o mis cálculos son incorrectos?

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

--EDITAR

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

Fórmula de cálculo de temperatura Valores de calibración

Configuración ADC:

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

Obtengo la salida alrededor de 35 grados. ¿Está bien tener una compensación tan grande?

¿Cuáles son las definiciones de ADC_REFERENCE_VOLTAGE_MV y las otras constantes?
ADC_REFERENCE_VOLTAGE_MV es un voltaje de banda prohibida = 1210mV; ADC_MAX_OUTPUT_VALUE = 4095; TEMP_SENSOR_VOLTAJE_MV_AT_25 = 760mV; TEMP_SENSOR_AVG_SLOPE_MV_PER_CELSIUS = 2,5 mV/C;
Gracias, pero ¿puede publicar las declaraciones #define reales? Puede ser un error firmado/sin firmar o algo similar. Puede editarlos en su pregunta.
Este es un buen código. Sin embargo, preguntar cómo se debe mejorar su código o algo que se debe agregar no es algo que podamos decir porque este es su proyecto. Pero puede preguntarnos si hay algo más que desee agregar, pero no está seguro de cómo escribir tal cosa. Averiguar cómo tomar medidas (como la temperatura) es algo que debe averiguar por su cuenta, a menos que haya intentado algo pero hay algo mal y no puede averiguar qué es lo que está mal. No olvide consultar el registro de errores si ocurre algo.
@VIPPER siempre menciona el modelo
es STM32F429ZIT6
Agregue toda la configuración de ADC.
Tienes un error en la fórmula. Debe ser en su lugar (ver el último paréntesis):temperature = (int32_t)((TEMP110 - TEMP30) / ((float)(*TEMP110_CAL_VALUE) - (float)(*TEMP30_CAL_VALUE)) * (sensorValue - (float)(*TEMP30_CAL_VALUE))) + TEMP30;
Tenga en cuenta que ST proporciona una macro para calcular la temperatura en el stm32xxxx_hal_adc.hnombre__HAL_ADC_CALC_TEMPERATURE

Respuestas (2)

Como señaló PeterJ, el primer defecto es que tienes que configurar el ADC_CCR_TSVREFEbit y no restablecerlo.

No tengo idea de cómo configura la muestra y el tiempo de espera, pero espero que sea correcto. Tiene que ser de al menos 10 µs para una medición precisa (sección de la hoja de datos sobre el sensor de temperatura).

Su próxima gran falla está en pensar que el voltaje de referencia es 1.21 V. Ese es el valor nominal para el V r mi F i norte t . Este voltaje no es el voltaje de referencia para el ADC. El voltaje de referencia suele ser V D D A o un voltaje diferente suministrado externamente en el V R mi F + -alfiler. Pero no puede ser más alto que V D D A ni puede ser inferior a V D D A -1,2 V.

Con su resultado de conversión de 950, y tomando 3,3 V, terminaría con 27,2 °C, lo que parece un buen comienzo. Si tiene 3 V, sería -0.6 °C, lo que también parece estar bien.

¿Por qué considero que -0,6 °C es un buen valor? Porque el cálculo usando los valores promedio es una mierda.

No sé por qué, pero STM no promociona mucho sus valores calibrados. Cada dispositivo tiene dos valores brutos de ADC tomados a 30 °C y 110 °C a 3,3 V almacenados internamente. Usando esos valores, termina con valores de temperatura más razonables sin realizar la calibración.


Algo a lo largo de estas líneas debería hacer:

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

Estoy acostumbrado a C ++, por lo que tal vez no sea su estilo de codificación, pero eso no debería ser un gran problema.

Encontré estos valores de calibración en el manual de referencia de STM32F0. Esto es realmente extraño que en el manual de referencia STM32F4 no pude encontrarlo. Además, describieron el procedimiento de lectura del valor del sensor de temperatura con ADC y no mencionaron ningún valor de calibración. Sin embargo, estos valores aparecen en la hoja de datos... desde mi punto de vista, es un pequeño lío en sus documentos.
Con respecto a la nota de la aplicación STM32L1 AN3964, el voltaje de referencia de calibración es de 3 V, no de 3,3 V como mencionó anteriormente. ¿Es eso correcto?
No tengo idea de cómo llegaste a 27.2 grados :D
@VIPPER no estoy seguro de por qué te interesa el STM32L1, pero sí, en ese dispositivo la calibración se realiza a 3 V. En el F429 se realiza a 3,3 V. En cuanto a los 27,2 °C: utilicé tus fórmulas con 950 como valor ADC pero cambió el voltaje de referencia del ADC de 1210 mV a 3300 mV.
Y para su edición: obtuvimos una desviación de hasta 6 K con el sensor interno. Si es más, algo parece estar mal (mida Vdda para asegurarse de que sea 3,3 V, por ejemplo)
// Disable Vbat signal from input channel and wake up temp sensor from power down mode
ADC->CCR &= ~(ADC_CCR_TSVREFE);

En realidad está justo enfrente :)

Lectura de la temperatura Para usar el sensor: 3. Seleccione el canal de entrada ADC1_IN18. 4. Seleccione un tiempo de muestreo mayor que el tiempo de muestreo mínimo especificado en la hoja de datos. 5. Establezca el bit TSVREFE en el registro ADC_CCR para despertar el sensor de temperatura del modo de apagado 6. Inicie la conversión ADC configurando el bit SWSTART (o mediante un disparador externo) 7. Lea los datos V SENSE resultantes en el registro de datos ADC 8. Calcule la temperatura usando la siguiente fórmula: Temperatura (en °C) = {(V SENSE – V 25 ) / Avg_Slope} + 25 Donde: – V 25 = valor V SENSE para 25° C – Avg_Slope = pendiente promedio de la temperatura frente a la curva V SENSE (dada en mV/°C o µV/°C) Consulte la sección de características eléctricas de la hoja de datos para conocer los valores reales de V 25 y Avg_Slope.

Gracias, tienes razón. Ahora puedo leer un valor más alto después de la conversión, alrededor de 950, lo que da como resultado -166 grados... pero esto es un progreso: D
¿Por qué no inicializa correctamente el ADC? Después del encendido, puede hacer esto cuando programa los registros, pero no usa HAL