关于STM32 ADC内部温度传感 器的问题
时间:10-02
整理:3721RD
点击:
小生最近想调试一下STM32的内部温度传感器,用于对比内外温度相差多少 。可是开启ADC后,发现读到的数据不对,想请问下是否有人遇到过类似问题,望指点一二。下面为ADC的程序。
void Adc_init(void)
{
//先初始化IO口
RCC->APB2ENR|=1<<9; //ADC1时钟使能
RCC->APB2RSTR|=1<<9; //ADC1复位
RCC->APB2RSTR&=~(1<<9);//复位结束
RCC->CFGR&=~(3<<14); //分频因子清零
RCC->CFGR|=2<<14;
ADC1->CR1&=0XF0FFFF; //工作模式清零
ADC1->CR1|=0<<16; //独立工作模式
ADC1->CR1&=~(1<<8); //非扫描模式
ADC1->CR2&=~(1<<1); //单次转换模式
ADC1->CR2&=~(7<<17);
ADC1->CR2|=7<<17; //软件控制转换
ADC1->CR2|=1<<20; //使用用外部触发(SWSTART)! 必须使用一个事件来触发
ADC1->CR2&=~(1<<11); //右对齐
ADC1->SQR1&=~(0XF<<20);
ADC1->SQR1&=0<<20; //1个转换在规则序列中 也就是只转换规则序列1
ADC1->SMPR1&=~(7<<18); //清除通道16原来的设置
ADC1->SMPR1|=7<<18; //通道16 239.5周期,提高采样时间可以提高精确度
ADC1->SMPR2&=0XFFFFFF0F;//通道1采样时间清空
ADC1->SMPR2|=7<<3; //通道1 239.5周期,提高采样时间可以提高精确度
ADC1->CR2|=1<<23; //使能温度传感器
ADC1->CR2|=1<<0; //开启AD转换器
ADC1->CR2|=1<<3; //使能复位校准
while(ADC1->CR2&1<<3); //等待校准结束
//该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。
ADC1->CR2|=1<<2; //开启AD校准
while(ADC1->CR2&1<<2); //等待校准结束
}
//获得ADC值
//ch:通道值 0~3 //ADC规则序列寄存器 3(ADC_SQR3)
u16 Get_Adc(u8 ch)
{
u16 re;
//设置转换序列
ADC1->SQR3&=0xfffffff0;//规则序列1 通道ch
ADC1->SQR3|=ch;
ADC1->CR2|=1<<22; //启动规则转换通
while(!(ADC1->SR&1<<1));//等待转换结束
re= ADC1->DR;
ADC1->SR|=~(1<<1);
return re; //返回adc值
}
u16 Get_Temperature(void)
{
u16 temp=0;
u8 t;
for(t=0;t<10;t++)
{
temp+=Get_Adc(16);
delay_ms(5);
}
return temp=temp/10;
}
void show_ADC_TEMP(void)
{
u16 tem;
u8 g,bai,shi,ge,c,d,e;
float a,b;
tem=Get_Temperature();
delay_ms(50);
tem&=0X00ff; //不加这一句,只显示0,加之后,个位及小数位才有变化,可是数据也不对
a=(float)tem*(3.3/4096);
b=a;
b=(1.43-b)/0.0043+25;
b=b*10000;
bai=(u16)b/1000000;
shi= (u16)b%1000000/100000;
ge= (u16)b%100000/10000;
g= (u16)b%10000/1000;
c=(u16)b%1000/100;
d=(u16)b%100/10;
e=(u16)b%10;
lcd_wcmd(0x80);//这些为LCD显示部分
lcd_wdat(bai+0x30);
lcd_wdat(shi+0x30);
lcd_wdat(ge+0x30);
lcd_wdat('.');
lcd_wdat(g+0x30);
lcd_wdat(c+0x30);
lcd_wdat(d+0x30);
lcd_wdat(e+0x30);
}
void Adc_init(void)
{
//先初始化IO口
RCC->APB2ENR|=1<<9; //ADC1时钟使能
RCC->APB2RSTR|=1<<9; //ADC1复位
RCC->APB2RSTR&=~(1<<9);//复位结束
RCC->CFGR&=~(3<<14); //分频因子清零
RCC->CFGR|=2<<14;
ADC1->CR1&=0XF0FFFF; //工作模式清零
ADC1->CR1|=0<<16; //独立工作模式
ADC1->CR1&=~(1<<8); //非扫描模式
ADC1->CR2&=~(1<<1); //单次转换模式
ADC1->CR2&=~(7<<17);
ADC1->CR2|=7<<17; //软件控制转换
ADC1->CR2|=1<<20; //使用用外部触发(SWSTART)! 必须使用一个事件来触发
ADC1->CR2&=~(1<<11); //右对齐
ADC1->SQR1&=~(0XF<<20);
ADC1->SQR1&=0<<20; //1个转换在规则序列中 也就是只转换规则序列1
ADC1->SMPR1&=~(7<<18); //清除通道16原来的设置
ADC1->SMPR1|=7<<18; //通道16 239.5周期,提高采样时间可以提高精确度
ADC1->SMPR2&=0XFFFFFF0F;//通道1采样时间清空
ADC1->SMPR2|=7<<3; //通道1 239.5周期,提高采样时间可以提高精确度
ADC1->CR2|=1<<23; //使能温度传感器
ADC1->CR2|=1<<0; //开启AD转换器
ADC1->CR2|=1<<3; //使能复位校准
while(ADC1->CR2&1<<3); //等待校准结束
//该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。
ADC1->CR2|=1<<2; //开启AD校准
while(ADC1->CR2&1<<2); //等待校准结束
}
//获得ADC值
//ch:通道值 0~3 //ADC规则序列寄存器 3(ADC_SQR3)
u16 Get_Adc(u8 ch)
{
u16 re;
//设置转换序列
ADC1->SQR3&=0xfffffff0;//规则序列1 通道ch
ADC1->SQR3|=ch;
ADC1->CR2|=1<<22; //启动规则转换通
while(!(ADC1->SR&1<<1));//等待转换结束
re= ADC1->DR;
ADC1->SR|=~(1<<1);
return re; //返回adc值
}
u16 Get_Temperature(void)
{
u16 temp=0;
u8 t;
for(t=0;t<10;t++)
{
temp+=Get_Adc(16);
delay_ms(5);
}
return temp=temp/10;
}
void show_ADC_TEMP(void)
{
u16 tem;
u8 g,bai,shi,ge,c,d,e;
float a,b;
tem=Get_Temperature();
delay_ms(50);
tem&=0X00ff; //不加这一句,只显示0,加之后,个位及小数位才有变化,可是数据也不对
a=(float)tem*(3.3/4096);
b=a;
b=(1.43-b)/0.0043+25;
b=b*10000;
bai=(u16)b/1000000;
shi= (u16)b%1000000/100000;
ge= (u16)b%100000/10000;
g= (u16)b%10000/1000;
c=(u16)b%1000/100;
d=(u16)b%100/10;
e=(u16)b%10;
lcd_wcmd(0x80);//这些为LCD显示部分
lcd_wdat(bai+0x30);
lcd_wdat(shi+0x30);
lcd_wdat(ge+0x30);
lcd_wdat('.');
lcd_wdat(g+0x30);
lcd_wdat(c+0x30);
lcd_wdat(d+0x30);
lcd_wdat(e+0x30);
}
Get_Adc 倒数第二句
ADC1->SR|=~(1<<1);
应为
ADC1->SR &= ~(1<<1);
你的程序主要是数值精度丢失的问题:
Get_Temperature 返回的ADC读数最大为4095,最小为1
a=(float)tem*(3.3/4096);
这句里面的常数(3.3/4096)是个很小的数值,用浮点数表示这个常数表示这么小的数值,本身就没多少精度可言;运算后a的数值在1/4096到3.3之间,对于浮点数来说,已经丢失了很多数值精度;
建议你不要用浮点数,直接用读取的温度值转成u32或u64类型×1000000来计算,这样肯定不会丢失精度;
祝你好运
谢谢,我会参考此方法再验证一下,看看能否得到正确的结果,那再问一下:
tem&=0X00ff; //不加这一句,只显示0,加之后,个位及小数位才有变化,可是数据也不对
要加上这一句的原因也是精度问题导致的吗?
【电子产品研发交流】:(323764552) 欢迎来群里共同探讨!
小编这个只是读取ADC->DR寄存器的值,并没有将这个数值与温度关联起来,所以,你得到的数据并不是温度,所以你的数据显示个十百千是没有什么意义的 ,将DR寄存器的值和温度关联还需要一些步骤,具体的步骤手册上有,在A.7.16 Temperature computation code example。