单片机程序从A/D模块读到数值,根据其与真实温度之间的关系,将其转换为真实温度。
NTC测温电路原理图
NTC电阻Rt的阻值与温度的关系为:
NTC的电阻阻值与温度的关系
以12位的A/D为例,转换得到的数值AD与电阻Rt的关系为:
A/D值与电阻的关系
大多数工程师根据这两个公式自然而然推导出了温度与A/D值之间的关系式。
温度求解公式
得到这个公式以后,工程师很高兴,高中所学的数学知识总算是没有还给老师。
高兴之余,就埋头敲了以下的C语言,所幸C语言的math库支持浮点数运算,还能做倒数和对数运算。
#define B 3950.0 //温度系数#define TN 298.15 //额定温度(绝对温度加常温:273.15+25) #define RN 10 // 额定阻值(绝对温度时的电阻值10k) #define BaseVol 3.30 //ADC基准电压 float Get_Tempture(U16 adc) { float RV,RT,Tmp; RV=BaseVol/4096.0*(float)adc;//ADC为10位ADC,求出NTC电压:RV=ADCValu/1024*BaseVoltag RT=RV*10/(BaseVol-RV);//求出当前温度阻值 (BaseVoltage-RV)/R16=RV/RT; Tmp=1/(1/TN+(log(RT/RN)/B))-273.15; //RT = RN exp*B(1/T-1/TN) return Tmp; }
复制代码然后,产品就出货了。
到了客户手上,时不时出现了按键响应慢、通信出现误码等问题。
大部分单片机没有硬件浮点运算器,做浮点数运算时会花费大量的时间。
而对数运算也多转换为幂级数展开进行运算,涉及到大量的乘法运算。
即使cortex-M3系列处理器有单指令周期的乘法器,上述运行可以也要几毫秒时间。
对于没有硬件乘法器的单片机,比如PIC16系列的单片机,以及几毛钱一片的OTP的单片机,做上述运算估计得耗费几十秒时间。
大部分程序员编写代码时没有时间片以及分时处理的概念,一个耗时操作闭着眼晴就执行到底。
到最后主程序忙不过来了,就把需要即时处理的代码一股脑放在中断程序里面处理。
最后,整个软件时间性差,时不时会出现丢数据,无响应等情况。
编写软件一定要结合平台考虑时间复杂度和空间复杂度,
必须要根据产品的功能合理安排时间和空间,以便做到最佳性能。
对于A/D值到温度的转换,最快速的方法是通过查表加分段线性插值处理。
我们可以把 0度-100度对应的AD值存到一个100*16bit的const 表。
将得到的A/D数值从这个表中找到对应的区域。
在这个区域进行线性插值,得到相应的数值。代码如下:
#define AD_TEMP_RANGE_NUM 101#define AD_TEMP_VALUE_MAX 3739 #define AD_TEMP_VALUE_MIN 1241 #define AD_TEMP_TEMP_MAX 1000 #define AD_TEMP_TEMP_MIN 0 ///10K B= 3980 const U16 adrange[AD_TEMP_RANGE_NUM] = { 3740, 3723, 3705, 3687, 3668, 3648, 3628, 3607, 3585, 3563, 3541, 3517, 3493, 3469, 3444, 3418, 3392, 3365, 3338, 3310, 3282, 3253, 3224, 3194, 3164, 3134, 3103, 3072, 3040, 3009, 2976, 2944, 2912, 2879, 2846, 2813, 2780, 2746, 2713, 2680, 2647, 2613, 2580, 2547, 2514, 2481, 2448, 2416, 2384, 2352, 2320, 2288, 2257, 2226, 2195, 2165, 2135, 2106, 2077, 2048, 2020, 1992, 1964, 1937, 1910, 1884, 1858, 1833, 1808, 1784, 1760, 1737, 1714, 1691, 1669, 1647, 1626, 1605, 1585, 1565, 1546, 1527, 1508, 1490, 1472, 1455, 1438, 1422, 1406, 1390, 1374, 1360, 1345, 1331, 1317, 1303, 1290, 1277, 1265, 1252, 1240 }; U16 temp; advalue = AD_GET_VAL(0); if(advalue >= AD_TEMP_VALUE_MAX) { temp = AD_TEMP_TEMP_MIN; } else if(advalue < AD_TEMP_VALUE_MIN) { temp = AD_TEMP_TEMP_MAX; } else { for(j = 0; j< (AD_TEMP_RANGE_NUM - 1); j++) { if((advalue[i] < adrange[j]) && (advalue[i] >= adrange[j + 1])) { uchDiff = adrange[j] - adrange[j + 1]; uchData = adrange[j] - advalue[i]; uiData = uchData * 10; uiData = uiData + (uchDiff >> 1); uchData = uiData / uchDiff; uiData = j * 10; temp= uiData + uchData; break; } } }
复制代码该程序可以进一步优化,改为二分法查找。
来源:物联网全栈开发