NTC热敏电阻温度采集与adc转换

前言:
ntc热敏电阻的R值是10k,B值是3950
使用的是STM32F103RCT6的ADC

文章目录

    • 1.电路理论
    • 2. NTC热敏电阻阻值与温度之间的转换
    • 3.NTC热敏电阻温度采集与adc转换

其中最主要的是
温度变化,引起了热敏电阻的变化,然后导致的电压的变化,从而导致了adc的值发生改变,所以核心变成了,怎样根据adc值得到温度值

1.电路理论

NTC热敏电阻温度采集与adc转换_第1张图片
不要问我图为啥是这个样子,这是硬件工程师画的板子
其中R_ntc指的是热敏电阻,R1是个平衡电阻,电容不知道干啥子用的,觉得是起个保护作用,但是电容并不影响理解,v_out就是ADC的输出
每次热敏电阻检测到温度变化的时候,输出电压都会随之改变,通常使用分压器
由于是串联电路,电流相等,分压,因此可得到公式

V o u t / R n t c = V C C / ( R n t c + R 1 ) V_{out} /R_{ntc} = V_{CC}/(R_{ntc}+R_{1}) Vout/Rntc=VCC/(Rntc+R1)

由此可以得到:
V C C / V o u t = ( R n t c + R 1 ) / R n t c V_{CC}/V_{out} = (R_{ntc} + R_{1})/R_{ntc} VCC/Vout=(Rntc+R1)/Rntc

在数学上成立下式:
D m a x / D o u t = ( R n t c + R 1 ) / R n t c D_{max}/D_{out} = (R_{ntc} + R_{1})/R_{ntc} Dmax/Dout=(Rntc+R1)/Rntc

其中Dmax指的是最大的ADC值也就是在3.3V的时候ADC等于4096,Dout也就是实际电压输出的ADC值。

所以我们要得到的就变成了电阻与温度之间的对应关系

2. NTC热敏电阻阻值与温度之间的转换

有一个这样子的公式
R t = R ∗ e ( B ∗ ( 1 / T 1 − 1 / T 2 ) ) Rt = R*e^{(B*{(1/T1-1/T2)})} Rt=Re(B(1/T11/T2))

其中:
Rt就是随着温度变化阻值
R就是25℃时的阻值,也就是开头说的10k
B值等于3950
T1:指的时开尔文温度等于273.15+热敏电阻当前阻值对应的摄氏度
T2:273.25+25

看到网上有很多种办法,最常规的一种就是写代码,加一个math库
但是最后发现最好的办法其实是EXCEL表,如下
NTC热敏电阻温度采集与adc转换_第2张图片
最上面红色方框是公式,下面红色框中可以发现当25摄氏度时,阻值等于10k,温度与阻值的变化曲线如下:
NTC热敏电阻温度采集与adc转换_第3张图片
看看大致曲线就行了,其实灵敏度就没那么好

电阻值与ADC的对应关系就是
D m a x / D o u t = ( R n t c + R 1 ) / R n t c D_{max}/D_{out} = (R_{ntc} + R_{1})/R_{ntc} Dmax/Dout=(Rntc+R1)/Rntc

所以就得到了ADC值对应的温度。ADC值得到的方式也是通过excel表计算得到
NTC热敏电阻温度采集与adc转换_第4张图片
关系曲线如下:
NTC热敏电阻温度采集与adc转换_第5张图片
有大佬能指点指点我也行呀,我一直不确定这个变化趋势是不是对的

3.NTC热敏电阻温度采集与adc转换

这里是重点部分了
首先是ADC相关函数,这里我用的是PC4端口,主要是想用用新的,对应的通道关系如下:
NTC热敏电阻温度采集与adc转换_第6张图片
所以PC4对应的通道14,使用的是ADC1,关于ADC的配置方式可以看我的另一篇博客【STM32】学习笔记之ADC(模拟/数字转换)

下面是我的adc.c文件中的内容:(将温度与adc值的对应关系保存在数组中,得到adc值之后只要在数组中查找,没有考虑复杂度,要优化的话,查找算法可以改成更快的二分法查找,快速查找等等,如果得到的adc值在数组中没有对应温度,就取那个相近的温度值)

#include "adc.h"
#include "delay.h"

const u16 ADC_NTC[NTC_ADC_MAX] =
{
     
    2048 ,2043 ,2039 ,2034 ,2030 ,2025 ,2021 ,2016 ,2012 ,2007,  //25-25.9
    2003 ,1998 ,1994 ,1989 ,1985 ,1980 ,1976 ,1971 ,1967 ,1962,  //26-26.9
    1958 ,1953 ,1949 ,1944 ,1940 ,1935 ,1931 ,1926 ,1922 ,1917,  //27-27.9
    1913 ,1909 ,1904 ,1900 ,1895 ,1891 ,1886 ,1882 ,1878 ,1873,  //28-28.9
    1869 ,1864 ,1860 ,1856 ,1851 ,1847 ,1843 ,1838 ,1834 ,1829,  //29-29.9
    1825 ,1821 ,1816 ,1812 ,1808 ,1803 ,1799 ,1795 ,1790 ,1786,  //30-30.9
    1782 ,1778 ,1773 ,1769 ,1765 ,1760 ,1756 ,1752 ,1748 ,1743,  //31-31.9
    1739 ,1735 ,1731 ,1726 ,1722 ,1718 ,1714 ,1710 ,1705 ,1701,  //32-32.9
    1697 ,1693 ,1689 ,1684 ,1680 ,1676 ,1672 ,1668 ,1664 ,1660,  //33-33.9
    1655 ,1651 ,1647 ,1643 ,1639 ,1635 ,1631 ,1627 ,1623 ,1618,  //34-34.9
    1614 ,1610 ,1606 ,1602 ,1598 ,1594 ,1590 ,1586 ,1582 ,1578,  //35-35.9
    1574 ,1570 ,1566 ,1562 ,1558 ,1554 ,1550 ,1546 ,1542 ,1538,  //36-36.9
    1534 ,1530 ,1526 ,1523 ,1519 ,1515 ,1511 ,1507 ,1503 ,1499,  //37-37.9
    1495 ,1491 ,1488 ,1484 ,1480 ,1476 ,1472 ,1468 ,1464 ,1461,  //38-38.9
    1457 ,1453 ,1449 ,1445 ,1442 ,1438 ,1434 ,1430 ,1427 ,1423,  //39-39.9
    1419 ,1415 ,1412 ,1408 ,1404 ,1401 ,1397 ,1393 ,1389 ,1386,  //40-40.9
    1382 ,1378 ,1375 ,1371 ,1368 ,1364 ,1360 ,1357 ,1353 ,1349,  //41-41.9
    1346 ,1342 ,1339 ,1335 ,1332 ,1328 ,1324 ,1321 ,1317 ,1314,  //42-42.9
    1310 ,1307 ,1303 ,1300 ,1296 ,1293 ,1289 ,1286 ,1282 ,1279,  //43-43.9
    1275 ,1272 ,1269 ,1265 ,1262 ,1258 ,1255 ,1251 ,1248 ,1245   //44-44.9
};

void Adc_Init(void)
{
     
	ADC_InitTypeDef ADC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1 , ENABLE ); //使能 ADC1 通道时钟
	RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置 ADC 分频因子 6 ,72M/6=12,ADC 最大时间不能超过 14M

	//PA1 作为模拟通道输入引脚
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
	GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化 GPIOC.4

	ADC_DeInit(ADC1); //复位 ADC1,将外设 ADC1 的全部寄存器重设为缺省值
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC 独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE; //单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC 数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC 通道的数目
	ADC_Init(ADC1, &ADC_InitStructure); //根据指定的参数初始化外设 ADCx

	ADC_Cmd(ADC1, ENABLE); //使能指定的 ADC1
	ADC_ResetCalibration(ADC1); //开启复位校准
	while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
	ADC_StartCalibration(ADC1); //开启 AD 校准
	while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
}

//获得 ADC 值
u16 Get_Adc(u8 ch)
{
     
	//设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
	//通道 1,规则采样顺序值为 1,采样时间为 239.5 周期
	ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能软件转换功能
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
	return ADC_GetConversionValue(ADC1); //返回最近一次 ADC1 规则组的转换结果
}

//多取几次,取平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
     
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
     
		temp_val+=Get_Adc(ch);
		delay_ms(5);
	}
	return temp_val/times;
}

//这是一个ADC值转温度值的函数
float Get_temper(u16 adc_value)
{
     
    int i;
    for(i=0;i<NTC_ADC_MAX;i++)
    {
     
        if(adc_value >= ADC_NTC[i]) //当没有ADC值对应温度的时候,就取相近的,也就是大于的情况
        {
     
            return 0.1*i+25;
            break;
        }
    }
    return 65;
}

main函数不想贴上来了,因为我用的是工业级的屏幕,结果如下:
NTC热敏电阻温度采集与adc转换_第7张图片
因为加了其他的外设,不方便把整个屏幕露出来

有问题记得给我指出来呀

你可能感兴趣的:(STM32,java,linux,pda,单片机,嵌入式)