NTC熱敏電阻溫度採集與adc轉換

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

其中最主要的是
溫度變化,引起了熱敏電阻的變化,然後導致的電壓的變化,從而導致了adc的值發生改變,所以核心變成了,怎樣根據adc值得到溫度值

1.電路理論

在這裏插入圖片描述
不要問我圖爲啥是這個樣子,這是硬件工程師畫的板子
其中R_ntc指的是熱敏電阻,R1是個平衡電阻,電容不知道幹啥子用的,覺得是起個保護作用,但是電容並不影響理解,v_out就是ADC的輸出
每次熱敏電阻檢測到溫度變化的時候,輸出電壓都會隨之改變,通常使用分壓器
由於是串聯電路,電流相等,分壓,因此可得到公式

Vout/Rntc=VCC/(Rntc+R1) V_{out} /R_{ntc} = V_{CC}/(R_{ntc}+R_{1})

由此可以得到:
VCC/Vout=(Rntc+R1)/Rntc V_{CC}/V_{out} = (R_{ntc} + R_{1})/R_{ntc}

在數學上成立下式:
Dmax/Dout=(Rntc+R1)/RntcD_{max}/D_{out} = (R_{ntc} + R_{1})/R_{ntc}

其中Dmax指的是最大的ADC值也就是在3.3V的時候ADC等於4096,Dout也就是實際電壓輸出的ADC值。

所以我們要得到的就變成了電阻與溫度之間的對應關係

2. NTC熱敏電阻阻值與溫度之間的轉換

有一個這樣子的公式
Rt=Re(B(1/T11/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的對應關係就是
Dmax/Dout=(Rntc+R1)/RntcD_{max}/D_{out} = (R_{ntc} + R_{1})/R_{ntc}

所以就得到了ADC值對應的溫度。ADC值得到的方式也是通過excel表計算得到
在這裏插入圖片描述
關係曲線如下:
在這裏插入圖片描述
有大佬能指點指點我也行呀,我一直不確定這個變化趨勢是不是對的

3.NTC熱敏電阻溫度採集與adc轉換

這裏是重點部分了
首先是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函數不想貼上來了,因爲我用的是工業級的屏幕,結果如下:
在這裏插入圖片描述
因爲加了其他的外設,不方便把整個屏幕露出來

有問題記得給我指出來呀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章