浏览量: 295 次浏览

STM32 AD转换以及获取温度值

2019年5月20日 0 作者 Nie Hen

获取传感器的值通常都需要模电 数电的知识,放大信号 数模转换等等处理。
这篇文章主要讲AD转换 并应用使用热敏电阻通过查表法和计算法获取温度值

应用演示

AD基本原理

ADC 全称:Analog to Digital Concerter,称为模/数转换器或者模拟/数字转换器。是指将连续变化的模拟信号转换为离散的数字信号的器件。
enter description here
常用的ADC有积分型、逐次逼近型、并行比较型/串并行型、Σ -Δ调制型、电容阵列逐次比较型及压频变换型。
我们使用的是 逐次逼近性。
逐次逼近型AD由一个比较器和DA转换器通过逐次比较逻辑构成,从MSB开始,顺序地对每一位将输入电压与内置DA转换器输出进行比较,经n次比较而输出数字值。其电路规模属于中等。其优点是速度较高、功耗低。

逐次逼近型模拟数字转换器
A/D转换器的主要技术指标
A/D完成一次转换所需要的时间。转换时间的倒数为转换速率。
分辨率:
衡量A/D转换器能够分辨出输入模拟量最小变化程度的技术指标。用输出的二进制位数或BCD码位数表示。
量化误差:
量化过程引起的误差称为量化误差。是由于有限位数字量对模拟量进行量化而引起的误差。

AD转换
ADC时钟 : ADC_CLK由 PCLK2经过分频产生,最大是 14M,(分频具体见stm32时钟RCC部分)。一般我们设置 PCLK2=HCLK=72M
采样时间 : 采样周期最小是 1.5 个(ADC_CLK 周期,1/ADC_CLK),即如果我们要达到最快的采样,那么应该设置采样周期为 1.5 个周期。

一般设置 PCLK2=72M,经过 ADC 预分频器(6分频)能分频到最大的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us,这个是最常用的。
数据储存的对齐方式:数据可以左对齐和右对齐,一般使用右对齐。

ADC转换方式选择:查询、中断和DMA

应用 温度检测

P1接热敏电阻(NTC),型号MF52A103G3380。阻值10K,2%精度;B值3380K。

(1)单片机程序采集:
Vx = (ADC1_Value * 3.3) / 4096;
(2)计算Rt实际电阻值:
Rt =(R21* Vx) / (3.3-Vx); //由电路,推出电阻与电压关系
将(1)式代入得Rt=(R21* ADC1_Value)/ (4096-ADC1_Value)
即使Rt=(10000* ADC1_Value)/ (4096-ADC1_Value)
(3)数据处理
查表方式
根据Rt=R0exp{B(1/T-1/T0)}, 可以设计t与Rt之间表格
根据(2)的结果,查表得到温度t。
直接计算,利用”math.h“
温度T与电阻Rt的关系
T=1/(ln(Rt/R0)/B+1/T0)
对应的摄氏温度t=T-273.15=1/(ln(Rt/R0)/B+1/T0)-273.15
enter description here

CubeMx配置
1. 配置时钟 ADC时钟6分频后12M
enter description here
2. 配置ADC 数据左对齐 使能连续转换模式
enter description here

程序设计

使用计算法 :
需要导入 math.h
#include “math.h”
进行转换并计算的代码

uint16_t ADC1temp1(void)
{   uint16_t ADC1_Value;
     float  t,Rt;   
     HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 50);
    if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
     {
       ADC1_Value = HAL_ADC_GetValue(&hadc1);
     Rt=(float)((10000*ADC1_Value)/ (4096-ADC1_Value)); 
     t=1/(log((Rt/10000))/3380+1/(273.15+25))-273.15;  / /t=1/(ln(Rt/R0)/B+1/T0)-273.15  
    return 10*t;//扩大10倍,含1位小数
     }
 }

调用这个函数 获取到的返回值 就是温度的十倍 可以直接放到数码管显示的函数中。
用数码管进行显示温度值。

使用查表法:
根据阻值计算温度计算起来费时间,增加功耗。查表法是将阻值和温度根据该温度传感器对应起来,计算出来阻值根据二分查找法找到对应的温度,并使用线性计算就可以获取温度值。

写出温度和阻值所对应的的数组

float array_Temp[] = {
-40,-30,-20,-10,-5,-3,-1,0,
2,4,6,8,10,13,15,18,
20,22,24,25,26,27,28,29,
30,31,32,33,34,35,36,37,38,
39,40,42,45,48,52,60,65,
70,75,80,85,90,95,100,105,

};
float array_Resis[] = {
201,116,70.03,43.35,34.48,31.52,28.85,27.62,
25.32,23.23,21.34,19.63,18.07,15.98,14.47,13.09,
12.11,11.21,10.39,10.00,9.631,9.277,8.938,8.613,
8.302,8.004,7.718,7.444,7.180,6.928,6.683,6.654,6.230,
6.016,5.810,5.423,4.897,4.429,3.883,3.001,2.582,
2.223,1.921,1.667,1.451,1.268,1.112,0.977,0,8262,

};

使用二分法查找 以及线性计算法

float search_temp(float rsis)
{
int start=0,end=sizeof(array_Temp);
    int j;
while(1)
{
j = (end + start)/2;
if (rsis > array_Resis[j])
{

    end = j-1;
}
else if (rsis == array_Resis[j])
    break;
else 
    start = j+1;
if (end - start <0)
    break;
}

 if (start-end ==1)
{   
    float R = (array_Temp[start]-array_Temp[end])/(array_Resis[start]-array_Resis[end])*(rsis-array_Resis[end])+array_Temp[end];
    //DisplayDigtal(end);
    return R;
}else 
    return array_Temp[j];
}

上面这个函数需要传入阻值
阻值的计算是在ADC计算法那里,最后一步换成调用这个函数。

代码链接