关于STM32 ADC内部温度传感 器的问题

2019-07-16 08:15发布

小生最近想调试一下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);
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
woodmice
1楼-- · 2019-07-16 08:33
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来计算,这样肯定不会丢失精度;
祝你好运
mominglin
2楼-- · 2019-07-16 09:45
谢谢,我会参考此方法再验证一下,看看能否得到正确的结果,那再问一下:
  tem&=0X00ff;    //不加这一句,只显示0,加之后,个位及小数位才有变化,可是数据也不对
要加上这一句的原因也是精度问题导致的吗?
p1105583274
3楼-- · 2019-07-16 09:53
 精彩回答 2  元偷偷看……
w23pp32
4楼-- · 2019-07-16 15:07
楼主这个只是读取ADC->DR寄存器的值,并没有将这个数值与温度关联起来,所以,你得到的数据并不是温度,所以你的数据显示个十百千是没有什么意义的 ,将DR寄存器的值和温度关联还需要一些步骤,具体的步骤手册上有,在A.7.16 Temperature computation code example。

一周热门 更多>