参考:https://blog.csdn.net/kehyuanyu/article/details/103178926
硬件电路:
硬件上有两个热敏电阻,分别有ADC1和ADC3采集温度信息。其中ADC3是测量光机温度的,温度和阻值的对照表参考《村田热敏电阻NCP15WF104F03RC.pdf》;ADC1是DMD位置主板上,对照表参考《热敏电阻100k_3950_101203.xls》。
PhoneWindowManager.java里面有加接口去读adc值的。这里已调试ADC3获取光机温度为例:
ADC3读到的电压值如何转换为热敏电阻电压值、热敏电阻温度值?
根据上面电路,热敏电阻与R250串联,对3.3V(实测3.317V)进行分压,热敏电阻两端电压U=3.3*Rw/(R250+Rw)。当外接温度变化时,主芯片通过ADC3(SAR3口)采集变化电压值,反推出当前的温度。
SAR3引脚配置
E4 的pin 脚定义:
mst358\vendor\mstar\mboot\MBoot\sboot\inc\mainz\board\chip\MSD93AEGM8.h
SAR3 口定义:
mst358\vendor\mstar\mboot\MBoot\sboot\inc\mainz\board\BD_MST142B_10A_MAINZ.h
mboot 定义好sar3口之后,就可以使用下面接口来获取adc 值了。
//-------------------------------------------------------------------------------------------------
/// Set SAR as ADC channel.
/// @ingroup G_SAR_COMMON
/// @param u8Channel: sar ADC channel 0~7
/// @param bEnable: 1: configured as ADC, 0: configured as GPIO input
/// @return E_SAR_ADC_OK: Success
/// @return E_SAR_ADC_FAIL or other values: Failure
//-------------------------------------------------------------------------------------------------
SAR_AdcResult MDrv_SAR_Adc_Config(MS_U8 u8Channel,MS_BOOL bEnable);
//-------------------------------------------------------------------------------------------------
/// Get ADC value function for each SAR channel.
/// @ingroup G_SAR_COMMON
/// @param u8Channel: sar ADC channel 0~7
/// @return MS_U8: ADC value
//-------------------------------------------------------------------------------------------------
MS_U8 MDrv_SAR_Adc_GetValue(MS_U8 u8Channel);
mboot和kernel中可以直接使用MDrv_SAR_Adc_GetValue()来获取某一个通道的ADC值,注意只能返回8-bit的值。对于SAR 3 ,就是直接使用MDrv_SAR_Adc_GetValue(3)来获取ADC值。有了ADC 值下一步就需要建立和温度的函数关系。
热敏电阻的阻值
由于热敏电阻是可变电阻,我们需要在计算温度之前测量电阻,但是我们不能直接测量电阻,只能测量电压。利用分压器电路采集测量热敏电阻和已知电阻之间的电压,分压器的公式是:
就热敏电阻电路中的分压器而言,上述等式中的变量为:
这个等式可以重新排列和简化,以解决R2,即热敏电阻的电阻:
R2=(R1*Vout)/(Vin-Vout)
带入本项目的电路,其中R1=10K,Vin=3.3V,Vout由SAR 3 采集。即:
R2=(10K x Vout )/(3.3V- Vout)。
温度计算,Steinhart-Hart方程和B值法
参考:
https://baijiahao.baidu.com/s?id=1620021463882312794&wfr=spider&for=pc
https://wenku.baidu.com/view/e2f53c4c2f3f5727a5e9856a561252d380eb2092.html
https://blog.csdn.net/kezunhb/article/details/86631695
使用Steinhart-Hart方程或者B值计算方法将热敏电阻的电阻值转换为温度读数。
-
Steinhart-Hart方程计算法:
1/T = A + B•ln® + C•[ln®]
这里: T 为绝对温度K(开尔文温度),R 单位是欧姆 -
温度系数B值计算法:
R = R(25℃)•exp[B•(1/T - 1/298.15)]
这里: T 为绝对温度K(开尔文温度),R(25℃) 是热敏电阻在 25℃时的阻值 (单位为Ω) -
C语言实现的温度计算公式
Tsteinhart = 1/(A+Blog(Rth)+Cpow(log(Rth),3))-273.15;
Tbeta = 1/(1/(273.15+25)+1/Beta*log(Rth/R25))-273.15;
下面使用温度系数B值计算法。《村田热敏电阻NCP15WF104F03RC.pdf》中有:
也就是说25度时,R25=100K,Beta常数根据实际应用场景而选择,这里我们选择25度~85度,即Beta=4311,代入公式:
Tbeta = 1/(1/(273.15+25)+1/4311log(Rth/(100K)))-273.15
= 1/(1/298.15+1/4311log(Rth/(100K)))-273.15
注:
温度系数计算: NTC热敏电阻计算器V1.0
https://www.etdev.net/data/attachment/forum/201901/ntc_calculator/
NTC热敏电阻计算器使用方法:https://www.etdev.net/thread-104-1-1.html
用上面的工具,计算得到Beta=4200,这个值算出来的温度更加接近于《村田热敏电阻NCP15WF104F03RC.pdf》映射表的值。
ln、log、lg在数学公式中和c语言中的区别:
参考:http://www.cplusplus.com/reference/cmath/
数学中log是对数符号,右边写真数和底数(上面是真数,下面是底数)lg是以10为底数(例lg100=2)(lg为常用对数)ln是以e为底数(lne2=2)(ln为自然对数 e=2.718281828459045…)
c语言里面只有两个函数log和log10,其中函数 log(x) 表示是以e为底的自然对数,即 ln(x)函数。 log10(x) 以10为底的对数,即 lg(x)。以其它数为底的对数用换底公式来表示:loga(b)=ln(b)/ln(a),C语言表示成log(b)/log(a)。
C代码实现(示例)
//电压换算成温度
int temp_data(void)
{
float temp=0;
float Rth=0;
float R25=100000;
float T25=273.15+25;
float Beta=4200;
float Ka=273.15;
float vol=(float)((Get_Adc_Average())*(3.3/255));
Rth=(10000*vol)/(3.3-vol); //10000kΩ is R249 value
temp=1/(1/T25+log(Rth/R25)/Beta)-Ka+0.5; //+0.5是误差矫正
return temp;
}
Java代码中的实现(示例)
private short mOldAdcValueDMD=0;
private short mDMDTemperatureValue=0;
private short getDMDTemperature(short adcValue){
if(adcValue == mOldAdcValueDMD
|| adcValue == (mOldAdcValueDMD - 1)
|| adcValue == (mOldAdcValueDMD + 1)){
return mDMDTemperatureValue;
}
short DMDtemp = 0;
float Rth=0;
float R25=100000;
float T25=(float)273.15+25;
float Beta=3950;
float Ka=(float)273.15;
float vol=(float)(adcValue*(3.3/255));
Rth=(float)((10000*vol)/(3.3-vol)); //10000kΩ is R249 value
DMDtemp=(short)(1/(1/T25+MathUtils.log(Rth/R25)/Beta)-Ka+0.5); //+0.5是误差矫正
mDMDTemperatureValue=(short)DMDtemp;
mOldAdcValueDMD = adcValue;
return mDMDTemperatureValue;
}
然后,按照上面的方法集成了软件,但发现硬件上如论怎么测量,光机温度SAR3检测电压一直为3.3V,而SAR1检测电压是有变化的。让硬件分析,回复说光机内部不是使用热敏电阻(硬件需要修改:去掉上拉电阻R250、贴R800为0Ω),而是使用了S-5813A/5814A系列温度传感器IC,规格书参考《S5813A_5814A_E.pdf》。。这款芯片的内部原理可能是将热敏电阻的电压转换为线性输出的电压值了:
Ta = -30°C: 2.582 V典型值
Ta = +30°C: 1.940 V典型值
Ta = +100°C: 1.145 V典型值
Y=ax+b
2.582=a*(-30)+b
1.940=a*(30)+b
1.145=a*(100)+b
第1、2计算得到:
A=-0.0107
B=2.261
第2、3计算得到:
a=-0.011356
b=2.2806
第1、3计算得到:
A=-0.011054
B=2.2504
因为S-5813A转换出来的电压值也不是完全线性的,为降低误差,这里分两个区间来计算温度:
第一个区间是-30°~30°,Vol=-0.0107Ta+2.261,则Ta=(2.261-Vol)/0.0107
第二个区间是30°~100°,Vol=-0.011356Ta+2.2806,则Ta=(2.2806-Vol)/0.011356
Java代码中的实现(示例)
private short mOldAdcValueRay=0;
private short mRayTemperatureValue=0;
private short getRayTemperature(short adcValue){
if(adcValue == mOldAdcValueRay){
return mRayTemperatureValue;
}
float vol=(float)(adcValue*(3.3/255));
if(vol > 2.6)
return mRayTemperatureValue;
else if(vol < 1.150)
return mRayTemperatureValue;
float Raytemp = 0;
if(vol < 1.940){ //30°~100°
Raytemp = (float)((2.2806-vol)/0.011356);
}else{ //-30°~30°
Raytemp = (float)((2.261-vol)/0.0107);
}
Log.d(TAG, "getRayTemperature() adcValue="+adcValue+" vol="+vol+" Raytemp="+Raytemp);
mRayTemperatureValue = (short)Raytemp;
mOldAdcValueRay = adcValue;
return mRayTemperatureValue;
}
测试:
光机内部温度(SAR3):
用万用表测得S-5813A输出电压也是1.74V,而因光机是密封的、不能拆开,需要用I2C读取光机温度值,来判断误差多大。
光机外部温度(热敏电阻检测),即DMD温度(SAR1):
最后用温度测量仪矫对测试结果。
其他
上面是使用公式将ADC值转温度值,有另外一种方法是制作两个表值,表一是ADC值,表二是从通过I2C读取光机温度值,两个表可定制出光机温度曲线图,然后将两个表数据集成到代码。这种做法相对来说获取的温度值更加准确,缺点是代码移植性较差、在采集光机温度值时可能烧坏光机。