cancel
Showing results for 
Search instead for 
Did you mean: 

Stm32f103 adc stable conversion

Bicer
Associate II

I am making a ntc thermometer with stm32f103c8 (by writing over registers without using state library). The code works as it is,I did the adc conversion in 7.5 cycles. I used the calibration register and ran the adc in continuous conversion mode. but it is not fully stable, the value in the last step is constantly changing. How can I make adc more stable?.I want the adc value to stay as constant as possible (I used a 10k ntc between 3.3v and a2 pin. I connected a 10k resistor between gnd and a2 pin ).

#include "stm32f10x.h"                  // Device header
#include "math.h"
float heat = 0;
char analog[10];
char analog2[10];
int temp;
int a;
void int2char(int num, char str[])
{
  char lstr[30];
   int cnt = 0;
  int div = 10;
  int j = 0;
 
    
    
while( num >= div)
{
    lstr[cnt] = num % div + 0x30;
    num /= 10;
    cnt++;
}
    lstr[cnt] = num + 0x30;
for(j= cnt ; j >=0;j--)
{
    str[cnt-j] = lstr[j];
}
   
   
}
 
void DelayUs(unsigned long t)
{
    for(;t>0;t--)
        {
         SysTick->LOAD = 72;
       SysTick->VAL = 0;
       while((SysTick->CTRL & 0x00010000) == 0);
        }
}
 
 
void lcd_cmd(unsigned char data)
{
    //pin_output(0,11);
    GPIOA->ODR &=~0x100;//lcd_rs(LOW);
    GPIOA->ODR &=~0x200;//lcd_rw(LOW);
    DelayUs(10);
    GPIOA->ODR |=0x400;//lcd_e(HIGH);
    DelayUs(5);
    GPIOA->ODR &= 0xff0f;
    GPIOA->ODR |= (data & 0x00f0);
    DelayUs(10);
    GPIOA->ODR &=~0x400;//lcd_e(LOW);
    
    DelayUs(20);
    
    GPIOA->ODR |=0x400;//lcd_e(HIGH);
    DelayUs(5);
    GPIOA->ODR &= 0xff0f;
    GPIOA->ODR |= ((data << 4) & 0x00f0);
    DelayUs(10);
    GPIOA->ODR &=~0x400;//lcd_e(LOW);
}
 
void lcd_data(unsigned char data)
{
    //pin_output(4,7);
    GPIOA->ODR |=0x100;//lcd_rs(HIGH);
    GPIOA->ODR &=~0x200;//lcd_rw(LOW);
    DelayUs(10);
    GPIOA->ODR |=0x400;//lcd_e(HIGH);
    DelayUs(5);
    GPIOA->ODR &= 0xff0f;
    GPIOA->ODR |= (data & 0x00f0);
    DelayUs(10);
    GPIOA->ODR &=~0x400;//lcd_e(LOW);
    
    DelayUs(20);
    
    GPIOA->ODR |=0x400;//lcd_e(HIGH)
    DelayUs(5);
    GPIOA->ODR &= 0xff0f;
    GPIOA->ODR |= ((data << 4) & 0x00f0);
    DelayUs(10);
    GPIOA->ODR &=~0x400;//lcd_e(LOW)
}
 
void lcd_send( char str[])
{
    int i = 0;
        while(str[i])
        {
            lcd_data(str[i]);
            i++;
            DelayUs(100);
        }
 
}
 
 
void lcd_msg(unsigned char line_1_2, unsigned char pos_0_16, char msg[])
{
    short pos = 0;
    if(line_1_2==1)
    {
        pos = 0;
    }
    else if(line_1_2==2)
    {
        pos = 0x40;
    }
    lcd_cmd(0x80 +pos + pos_0_16);
    DelayUs(100);
    lcd_send(msg);
}
 
 
 
int main(void)
{
    // initialize the delay function (Must initialize)
    SysTick->CTRL = 0;
    SysTick->LOAD = 0x00FFFFFF;
    SysTick->VAL = 0;
    SysTick->CTRL = 5;
    
    
    //pin_output(4,11);
    RCC->APB2ENR = 0x04; /// port a active
    GPIOA->CRL   = 0x33330000; /// pin a4-a7 
    GPIOA->CRH   = 0x00003333; /// pin a8-a11
 
    DelayUs(20000);
    GPIOA->ODR |=0x100;//lcd_rs(LOW);
    GPIOA->ODR |=0x200;//lcd_rw(LOW);
    DelayUs(10);
    GPIOA->ODR |=0x400;//lcd_e(HIGH);
    DelayUs(5);
    GPIOA->ODR &= 0xff0f;
    GPIOA->ODR |= 0x30; // 8 bit communication mode 
    DelayUs(10);
    GPIOA->ODR &=~0x400;//lcd_e(LOW);
    
    DelayUs(20000);
    
    
    GPIOA->ODR &=~0x100;//lcd_rs(LOW);
    GPIOA->ODR &=~0x200;//lcd_rw(LOW);
    DelayUs(10);
    GPIOA->ODR |=0x400;//lcd_e(HIGH);
    DelayUs(5);
    GPIOA->ODR &= 0xff0f;
    GPIOA->ODR |= 0x20; // 4 bit communication mode 
    DelayUs(10);
    GPIOA->ODR &=~0x400;//lcd_e(LOW);
    
    
    lcd_cmd(0x2C); // 4 bit communication mode / 2 lines
    DelayUs(5000);
    lcd_cmd(0x0C); // Display ON
    DelayUs(5000);
    lcd_cmd(0x01); // Clear Display
    DelayUs(5000);
    lcd_cmd(0x02); // Get back to initial address
    DelayUs(5000);
    
        lcd_msg(1, 0,"Temp(C)");
        RCC->APB2ENR |= 0x201; //ADC 1 interface clock enable
        ADC1->SQR3 = 2;  //first transformation in regular order   
        ADC1->SQR1 &= ~(0xf << 20);//adc channel string length          
    ADC1->SMPR2 |= (0x1);   //7.5 loop
    //12mhz: 7.5+12.5 =20 hz ->3.3us(micro s) 
    ADC1->CR2 &= ~(1 << 11); // right alignment     
    ADC1->CR2 |= 2|1; //adc on and continuous
    ADC1->CR2 |= (1<<3);// reset calibration 
    ADC1->CR2 |= (1<<2);// calibration  
    ADC1->CR2 |=1; //adc on 
    while(1)
    {
  heat = log(((40950000 / ADC1->DR) - 10000));
  heat = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * heat * heat)) * heat);
  temp = (heat - 273.15)*100; 
     int2char(temp,analog);
     lcd_msg(2, 2,analog);
        if(temp<1000)
        {
         a=3;   
        }
        else if(temp<10000)
        {
     a=4;
        }
    else
        {
     a=5;
        }           
     temp=temp%100;
     int2char(temp,analog2);
     lcd_msg(2, a,".");
     lcd_msg(2, a+1,analog2);
     lcd_msg(2, a+3,"     ");
     DelayUs(250000);
    }
    
}

3 REPLIES 3
TDK
Guru

10kOhm is a relatively high resistance. You're going to have some noise in there. The biggest and easiest improvement will probably be maxing out the sampling time. Temperature doesn't change quickly, no need to limit it to 7.5 cycles. You could add a bypass cap to give the circuit some capacitance so the switching doesn't affect things as much.

Some more general tips here:

https://www.st.com/resource/en/application_note/cd00211314-how-to-get-the-best-adc-accuracy-in-stm32-microcontrollers-stmicroelectronics.pdf

Edit: also note that taking a longer term averages are how temperature measurements are typically made rather than relying on a single sample.

If you feel a post has answered your question, please click "Accept as Solution".
Bicer
Associate II

Thanks for your advice. I added a bypass capacitor to the circuit and set the sampling rate to maximum, it got a little better. Do you have a software solution suggestion?

Take many samples and use the average.

If you feel a post has answered your question, please click "Accept as Solution".