采用如下的NTC测温电路进行温度测量。将电源电压经过固定电阻以及NTC电阻分压送入单片机进行A/D转换之后。
单片机程序从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;
  • }
  • }
  • }
  • 复制代码
    带个转换过程在72MHz的主频时,耗时大概在几个us。
    该程序可以进一步优化,改为二分法查找。



    来源:物联网全栈开发