La ecuación de cálculo de temperatura de STM32L4 muestra resultados inapropiados

0

Mientras utilizo el ADC de STM32L4 para medir sus datos del sensor de temperatura interno, estoy enfrentando un problema.

La ecuación proporcionada en el manual de referencia de STM32L4 parece mostrar resultados impropios.

La ecuación es:

* Temperatura = ((110-30) * (TS_DATA - TS_CAL_1) / (TS_CAL_2 - TS_CAL_1)) + 30 *

donde, TS_DATA = 945 (datos de ADC sin procesar para la temperatura), TS_CAL_1 = 1035 (punto de calibración leído desde la dirección de memoria predefinida), TS_CAL_2 = 1373 (punto de calibración leído de una dirección de memoria predefinida)

Esto resulta en 'Temperatura = 8.69' a temperatura ambiente (alrededor de 26 grados Celsius), lo cual es claramente incorrecto.

Mi código para el mismo es:

#define TS30    ((uint16_t*)((uint32_t)0x1FFF75A8))
#define TS110   ((uint16_t*)((uint32_t)0x1FFF75CA))
uint32_t ADC_Value;
double temperature;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
   ADC_Value = HAL_ADC_GetValue(&hadc1);
   temperature = (double)ADC_Value - (uint32_t)*TS30;
   temperature *= (double)((uint32_t)110 - (uint32_t)30);
   temperature /= (double)(int32_t)((uint32_t)*TS110 - (uint32_t)*TS30);
   temperature += 30;
}
int main(){           /**Main Loop**/
 MX_ADC1_Init();
   HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
   HAL_ADC_Start_IT(&hadc1);

   while(1) {
     HAL_Delay(400);
     HAL_ADC_Start_IT(&hadc1);
   }
}
static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig;
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.NbrOfDiscConversion = 1;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK){
    _Error_Handler(__FILE__, __LINE__);
  }

  /**Configure Regular Channel**/
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){
   _Error_Handler(__FILE__, __LINE__);
  }
}

Por favor revisa el código y ayúdame.

    
pregunta Maunik Patel

2 respuestas

0

Debe aplicar una escala porque su voltaje de referencia es diferente del voltaje de referencia cuando se calibran las partes.

Utilizan una referencia de 3 V durante la calibración, usted usa una referencia de 3.3 V.

Por lo tanto, el valor absoluto del sensor de temperatura no cambiará, por lo que el valor ADC que obtenga será más pequeño que el que obtuvo durante la calibración.

Por lo tanto, su valor de ADC debe escalarse en un factor de 3.3 V / 3.0 V o 1.1.

Si ingresa eso en la fórmula (y usa las temperaturas de calibración correctas de 130 y 30 ° C), terminará con 31 ° C. Todavía un poco fuera de tus 26 ° C, pero eso podría deberse a que tu electrónica es en realidad más cálida, e incluso con los valores calibrados medimos hasta una desviación de 6 K en nuestras pruebas, por lo que consideraría que está bien.

( respuesta similar con un pequeño fragmento de código, pero allí estaba 110 y 30 ° C)

    
respondido por el Arsenal
3
  

Por favor revisa el código y ayúdame.

Lo haré; menos enfoque en el estilo de código de lo que usualmente hago; más enfoque en el aspecto tecnológico de las cosas, ya que estamos en una plataforma de EE, no en programmers.stackexchange.com:

$$ {\ frac {\ text {TS_CAL2_TEMP} - \ text {TS_CAL1_TEMP}} {\ text {TS_CAL2} - \ text {TS_CAL1}}} (\ text {TS_DATA} - \ text {TS_CAL1)) + 30 \, ^ ° \ texto {C} $$

Matemáticas de punto flotante

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
   ADC_Value = HAL_ADC_GetValue(&hadc1);
   temperature = (double)ADC_Value - (uint32_t)*TS30;
   temperature *= (double)((uint32_t)110 - (uint32_t)30);
   temperature /= (double)(int32_t)((uint32_t)*TS110 - (uint32_t)*TS30);
   temperature += 30;
}

¡Oh!

Entonces, primero que todo: double es totalmente exagerado aquí. Su procesador tiene una unidad de punto flotante, pero solo para números de punto flotante de precisión simple, y usted no gana absolutamente nada si calcula esto con doble precisión. No es como si obtuvieras 16 dígitos significativos en cualquier lugar de esta fórmula.

De todos modos, a menos que sepa muy bien lo que está haciendo, ¡no use la FPU en una rutina de interrupción! Hay una razón simple para eso: los registros de estado de FPU generalmente no se guardan / restauran al cambiar de contexto en la mayoría de las plataformas (y AFAIK, esto se aplica especialmente a ARM). Entonces, estás mezclando las cosas. Además, la propia FPU puede generar excepciones (por ejemplo, cuando se realiza una operación matemática ilegal), y usted realmente no desea excepciones anidadas aquí.

Haz esto en un punto fijo. No hay absolutamente ninguna razón para usar un punto flotante aquí.

No hagas los cálculos en el ISR

Entonces, casi ninguno de estos cálculos debe realizarse en la rutina de interrupción. Precalcular el factor \ $ f \ $ (es decir, la fracción de la manual de referencia, p.446 ) y el valor agregado \ $ s \ $ :

\ begin {align} T & = \ underbrace {\ frac {\ text {TS_CAL2_TEMP} - \ text {TS_CAL1_TEMP}} {\ text {TS_CAL2} - \ text {TS_CAL1}}} _f (\ text {TS_DATA} - \ text {TS_CAL1}) + 30 \, ^ ° \ text {C} \\ & = f \ cdot \ text {TS_DATA} + \ underbrace {(- f \ cdot \ text {TS_CAL2} + 30)} _ s \\ & = f \ cdot \ text {TS_DATA} + s \ end {align}

Para que solo tengas que hacer una multiplicación y una suma en el ISR.

Haciéndolo en un punto fijo

Tenga en cuenta que su \ $ f \ $ puede que no se pueda representar correctamente como entero; pero siempre recuerde que la elección de la temperatura de medición en ° C es arbitraria; también podría multiplicar \ $ f \ $ y \ $ s \ $ con 1000 y tener un valor en ° mC, que puede convertir a ° C cuando lo necesite, sin perder precisión, ya que su ADC, su sensor, el ruido natural y el fenómeno observado no tienen aproximadamente 10 bits de información.

Misc

Además, ¿no olvidó registrar su devolución de llamada de conversión de ADC completa?

    
respondido por el Marcus Müller

Lea otras preguntas en las etiquetas