2021-08-08 11:00 AM
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);
}
}
2021-08-08 12:14 PM
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:
Edit: also note that taking a longer term averages are how temperature measurements are typically made rather than relying on a single sample.
2021-08-08 01:57 PM
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?
2021-08-08 03:51 PM
Take many samples and use the average.