前言:
ntc热敏电阻的R值是10k,B值是3950
使用的是STM32F103RCT6的ADC
其中最主要的是
温度变化,引起了热敏电阻的变化,然后导致的电压的变化,从而导致了adc的值发生改变,所以核心变成了,怎样根据adc值得到温度值
不要问我图为啥是这个样子,这是硬件工程师画的板子
其中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值。
所以我们要得到的就变成了电阻与温度之间的对应关系
有一个这样子的公式
R t = R ∗ e ( B ∗ ( 1 / T 1 − 1 / T 2 ) ) Rt = R*e^{(B*{(1/T1-1/T2)})} Rt=R∗e(B∗(1/T1−1/T2))
其中:
Rt就是随着温度变化阻值
R就是25℃时的阻值,也就是开头说的10k
B值等于3950
T1:指的时开尔文温度等于273.15+热敏电阻当前阻值对应的摄氏度
T2:273.25+25
看到网上有很多种办法,最常规的一种就是写代码,加一个math库
但是最后发现最好的办法其实是EXCEL表,如下
最上面红色方框是公式,下面红色框中可以发现当25摄氏度时,阻值等于10k,温度与阻值的变化曲线如下:
看看大致曲线就行了,其实灵敏度就没那么好
电阻值与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表计算得到
关系曲线如下:
有大佬能指点指点我也行呀,我一直不确定这个变化趋势是不是对的
这里是重点部分了
首先是ADC相关函数,这里我用的是PC4端口,主要是想用用新的,对应的通道关系如下:
所以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函数不想贴上来了,因为我用的是工业级的屏幕,结果如下:
因为加了其他的外设,不方便把整个屏幕露出来
有问题记得给我指出来呀