2019-03-18 02:48 PM
I want to read data from PT1000 thermistor. After succeeding in communicating with the TouchGFX model and displaying the content I wanted, I now want to be able to read real time temp. For this job I have PT1000 sensor. I have made the ADC to work, but the problem I'm experiencing, is, that the values I get are very inaccurate. I'm getting every second different values in the range from 17 to 24 degrees, which is pretty bad. I aim for accuracy of +- 1 degree or even 0.1. Now it is quite miserable. I have placed 10uF capacitor to filter out noise, coded to get average of 10 convertions (excluding the lowest and highest values), but nothing helped, I mean, they have improoved the amplitudes, but not with the margin I expected. Before it was worse than 17-25. I really don't know what the reason could be. I have read a lot and watched and everyone has steady reading (for example 1723-1727 (12bit value straight from ADC)), I get fluctuations like 1723-2023. Maybe there is something wrong with my code, maybe there is problem with my channel, maybe it is EMI, but God this is one pretty big amplitude.
Please, help me with this problem, any suggestions are highly appreciated. This is my first contact with MCUs.
Here is my code. It is pretty dirty, in the end I was just hard trying stuff... :D
#define ADCx ADC1
#define ADCx_CLK_ENABLE() __HAL_RCC_ADC1_CLK_ENABLE()
#define ADCx_CHANNEL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define ADCx_FORCE_RESET() __HAL_RCC_ADC_FORCE_RESET()
#define ADCx_RELEASE_RESET() __HAL_RCC_ADC_RELEASE_RESET()
/* Definition for ADCx Channel Pin */
#define ADCx_CHANNEL_PIN GPIO_PIN_6
#define ADCx_CHANNEL_GPIO_PORT GPIOA
/* Definition for ADCx's Channel */
#define ADCx_CHANNEL ADC_CHANNEL_6
#define SAMPLINGTIME ADC_SAMPLETIME_480CYCLES
xQueueHandle msgQueueUI;
static void ADCTask(void* params)
{
ADC_HandleTypeDef AdcHandle;
/*
* Initialize ADC
*/
AdcHandle.Instance = ADCx;
if (HAL_ADC_DeInit(&AdcHandle) != HAL_OK)
{
/* ADC de-initialization Error */
while (1) {};
}
AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
AdcHandle.Init.ScanConvMode = DISABLE;
AdcHandle.Init.EOCSelection = DISABLE;
AdcHandle.Init.ContinuousConvMode = DISABLE;
AdcHandle.Init.NbrOfConversion = 1;
AdcHandle.Init.DiscontinuousConvMode = DISABLE;
AdcHandle.Init.NbrOfDiscConversion = 0;
AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
AdcHandle.Init.DMAContinuousRequests = DISABLE;
if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
{
/* ADC initialization Error */
while (1) {};
}
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* ADC Periph clock enable */
ADCx_CLK_ENABLE();
/* Enable GPIO clock ****************************************/
ADCx_CHANNEL_GPIO_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* ADC Channel GPIO pin configuration */
GPIO_InitStruct.Pin = ADCx_CHANNEL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(ADCx_CHANNEL_GPIO_PORT, &GPIO_InitStruct);
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = ADCx_CHANNEL; /* Sampled channel number */
sConfig.Rank = 1; /* Rank of sampled channel number ADCx_CHANNEL */
sConfig.SamplingTime = SAMPLINGTIME; /* Sampling time (number of clock cycles unit) */
sConfig.Offset = 0; /* Parameter discarded because offset correction is disabled */
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
/* Channel Configuration Error */
while (1) {};
}
float A=3.9083E-3; /* PT1000 consts */
float B=-5.775E-7; /* PT1000 consts */
float R = 1000; /* PT1000 consts */
float averageRead[10]; /* hard trying to improve accuracy */
while (1)
{
vTaskDelay(1000); //Approx 10 Hz
// Start Conversation Error
HAL_ADC_Start(&AdcHandle);
for(int i =0; i<10; i++){
HAL_ADC_PollForConversion(&AdcHandle, 10);
averageRead[i] = HAL_ADC_GetValue(&AdcHandle);
}
float maxValue = averageRead[0];
for(int i=1;i < 10;i++){
if(averageRead[i] > maxValue){
maxValue = averageRead[i];
}
}
float minValue = averageRead[0];
for(int i=1;i < 10;i++){
if(averageRead[i] > minValue){
minValue = averageRead[i];
}
}
float sum = 0;
for (int i=0;i<10;i++){
sum += averageRead[i];
}
float adcValue = (sum - minValue - maxValue)/8;
// Get the converted value of regular channel
float adcVoltage = adcValue*(3.3/4096);
float adcResistance = ((3.3*2200)-(adcVoltage * 2200)) / adcVoltage;
float adcTemp = ((R * A * (-1)) + sqrt((R * R * A * A) - (4 * R * B * (R - adcResistance))))/(2 * R * B); /* PT1000 formula */
xQueueSendToBack(msgQueueUI, &adcTemp, 0); /* sending value to model in TouchGFX */
}
}
P.s my question was posted empty at first, so I had to rewrite it, sorry
P.s. Degrees are in Celsius :)
P.s. Sorry for bad English
Solved! Go to Solution.
2019-03-18 11:49 PM
2019-03-18 05:16 PM
I don't use HAL but usually random values from an ADC means you are reading the ADC value before conversion is complete.
Does HAL_ADC_PollForConversion(...) simply not return until conversion is done, or are you supposed to check it repeatedly for being true before using HAL_ADC_GetValue(...) ??
2019-03-18 11:36 PM
> I want to read data from PT1000 thermistor.
How do you do it, exactly ?
You can't measure resistance directly with an ADC, perhaps you review your analog circuitry to interface the PT1000.
The ADC needs a low-impedance input for proper conversion, and a high enough voltage for proper accuracy.
The sensor needs a minimal transverse current, or else it will self-heat and distort the measurement.
Verify a proper function of your analog circuitry before attaching the ADC.
2019-03-18 11:49 PM
2019-03-19 12:19 PM
In the end I see, that the error has become smaller, but still bigger than desired. Maybe I can shorten somehow the range, since I'm not going to read temps below -10 and above 180 degrees. So I will have 4095 across 190 points, instead of 600 or more hundreds. The problem though is that I have no idea how to do it and if it will improve accuracy. It is logically to do so, but who knows...
P.s I don't think that current is high, since overnight it showed the same values in the morning as midnight. I have measured it with multimeter, it showed 1000uA, but I don't know if it is that accurate and thrustful.
2019-03-19 12:28 PM
1. White wire is Vref (3.3V)
2 Red wire is one end of thermistor (connected to white wire)
3 Blue wire is other end of thermistor
4 Resistor going to ground is 2k2Ohm (connected to blue)
5 Resistor going to brown is 10kOhm (connected to blue)
6 Brown wire is going to ADC
7 Capacitor is 150nF ceramic going to ground as well (connected to brown)
8 Black wire is connected to ground pin