Arduino 系列- NTC 温度传感器 + JXChart 实现温度采集测量仪

内容简介

专业的温度采集测量仪价格不菲,主要特点是精度高,配套完整的上位机绘制成温度曲线,方便观察。原理上来说,是通过一个温度传感器(NTC,即热敏电阻)来测量,经过MCU的AD采集经过处理后,传输到上位机并显示出来。
既然知道原理,为何不自己动手做一个简单的测温仪器呢?

开发环境

Arduino UNO+电阻(10kΩ)+NTC(10kΩ@25℃,B=3950)。
NTC与R1串联,并由5V供电。通过采集NTC与R1之间的压差来实现温度测量。本用AD通道 2 来进行测量。

Arduino范例代码如下

int sensorPin = A2; 
void setup() { 
  pinMode(sensorPin, INPUT); // 设置传感器引脚为输入模式
  Serial.begin(9600);// 初始化串口通信
} 
void loop() { 
  int value = analogRead(sensorPin);// 读取传感器数值 
  //发送的格式是{CH1,value}
  Serial.print ("{AD,");//头码+通道
  Serial.print (value, DEC);//以 10 进制格式发送数值
  Serial.print ("}");//结束码
  delay(1000); // 延迟1000毫秒
} 

此时可以看到,上传到上位机的是AD值,并不是实际的温度值。所以需要将AD值转换成对应的温度。

JXChart(查看使用方法) 采集如下图
在这里插入图片描述

2024/06/07 08:52:21.168(接收)ascii:{AD,540}
2024/06/07 08:52:22.168(接收)ascii:{AD,540}
2024/06/07 08:52:23.169(接收)ascii:{AD,540}
2024/06/07 08:52:24.169(接收)ascii:{AD,539}
2024/06/07 08:52:25.169(接收)ascii:{AD,539}
2024/06/07 08:52:26.169(接收)ascii:{AD,539}
2024/06/07 08:52:27.170(接收)ascii:{AD,539}
2024/06/07 08:52:28.170(接收)ascii:{AD,539}
2024/06/07 08:52:29.170(接收)ascii:{AD,538}
2024/06/07 08:52:30.170(接收)ascii:{AD,538}
2024/06/07 08:52:31.170(接收)ascii:{AD,538}

公式法

T1 = 1 / ( ln( Rt/R ) / B + 1/T2 )
(1) T1和T2指的是K度,即开尔文温度。
(2) Rt 是热敏电阻在T1温度下的阻值。
(3) R是热敏电阻在T2常温下的标称阻值。10K的热敏电阻25℃的值为10K(即R=10K)
具体可以参照这篇文章 热敏电阻NTC103、PT100温度计算公式

#define NTC_B 3950 // B值
#define NTC_T25 298.15  //25摄氏度的开尔文温度
#define NTC_R25 10000 //10 kΩ
          
float fGet_NTC_Temp(float Rntc)
{
	float temp;
  	temp = 1/(((log(Rntc/NTC_R25) / NTC_B) + 1/298.15))-273.15;
	return temp ;
}

问题又来了,Rntc是电阻值,而MCU采集到的是电压值,所以需要再次进行转换。首先确认一下,Arduino UNO的AD是10 bit,所以测量到的

AD = 1024R1/(Rntc+R1)
因此 Rntc = (1024
R1/AD) - R1

fGet_NTC_Temp 函数要改成

//---------公式法----------------------------
#define NTC_B 3950 // B值
#define NTC_T25 298.15  //25摄氏度的开尔文温度
#define NTC_R25 10000 //10 kΩ 25℃时的NTC电阻值
#define NTC_R1 10000 //10 kΩ 分压电阻R1

#define NTC_MAX 1017 // 最大温度AD值
#define NTC_MIN 8 // 最小温度AD值
float fGet_NTC_Temp(float AD_Rntc)
{
  float temp;
  float Rntc;
  if(AD_Rntc<=NTC_MIN)
  AD_Rntc=NTC_MIN;//对最低温进行限制,维持在-55℃以上
  else if(AD_Rntc>=NTC_MAX)
  AD_Rntc=NTC_MAX;//对最高温进行限制,维持在204℃以以下
  
  Rntc= NTC_R1*(1024/AD_Rntc) - NTC_R1 ;
  temp = 1/(((log(Rntc/NTC_R25) / NTC_B) + 1/298.15))-273.15;
  return temp ;
}

JXChart(查看使用方法) 采集如下图。
当前室温约26℃,手捏上去后,温度会缓慢上升
在这里插入图片描述

2024/06/07 08:56:41.864(接收)ascii:{formula,26.6804809570}
2024/06/07 08:56:42.866(接收)ascii:{formula,26.8586425781}
2024/06/07 08:56:43.868(接收)ascii:{formula,27.0371093750}
2024/06/07 08:56:44.869(接收)ascii:{formula,27.3052673339}
2024/06/07 08:56:45.871(接收)ascii:{formula,27.4844360351}
2024/06/07 08:56:46.873(接收)ascii:{formula,27.7537231445}
2024/06/07 08:56:47.875(接收)ascii:{formula,27.8436279296}
2024/06/07 08:56:48.876(接收)ascii:{formula,28.1138000488}
2024/06/07 08:56:49.878(接收)ascii:{formula,28.2943115234}
2024/06/07 08:56:50.879(接收)ascii:{formula,28.4751281738}
2024/06/07 08:56:51.881(接收)ascii:{formula,28.5656738281}
2024/06/07 08:56:52.883(接收)ascii:{formula,28.7469787597}
2024/06/07 08:56:53.884(接收)ascii:{formula,28.9286499023}
2024/06/07 08:56:54.886(接收)ascii:{formula,29.0195922851}
2024/06/07 08:56:55.888(接收)ascii:{formula,29.2017822265}
2024/06/07 08:56:56.889(接收)ascii:{formula,29.3842773437}
2024/06/07 08:56:57.891(接收)ascii:{formula,29.3842773437}
2024/06/07 08:56:58.893(接收)ascii:{formula,29.5671691894}
2024/06/07 08:56:59.894(接收)ascii:{formula,29.6587524414}

公式法的缺点是,计算量太大,不适合与低运算能力的MCU。因此,可以采用查表法

查表法

参考文章NTC 温度采样 二分查表及公式法

int sensorPin = A2; 
void setup() { 
  pinMode(sensorPin, INPUT); // 设置传感器引脚为输入模式
  Serial.begin(9600);// 初始化串口通信
} 
void loop() { 
  int value = analogRead(sensorPin);// 读取传感器数值 
  //发送的格式是{CH1,value}
  Serial.print ("{table,");//头码+通道
  Serial.print (tsp_BinaryTableSearch(value), DEC);//以 10 进制格式发送数值
  Serial.print ("}");//结束码
  delay(1000); // 延迟1000毫秒
} 
//---------查表法----------------------------
#define NTC_ADC_MAX 260
#define TSP_SHORT_CIRCUIT_THRESHOLD   1024U     /*!<NTC short-circuit */
#define TSP_OPEN_CIRCUIT_THRESHOLD    8U   /*!<NTC open-circuit */

#define TSP_MAX_T 204.0F // 最大温度值
#define TSP_MIN_T -55.0F // 最小温度值

const uint16_t NTC_adc_table[NTC_ADC_MAX] = {
8  ,9  ,9  ,10 ,11 ,12 ,13 ,14 ,15 ,16,  //-55~-46℃
17  ,19 ,20 ,22 ,23 ,25 ,27 ,29 ,31 ,33,  //-45~-36℃
35  ,38 ,40 ,43 ,46 ,49 ,52 ,55 ,59 ,62,  //-35~-26℃
66  ,70 ,75 ,79 ,84 ,89 ,94 ,99 ,105  ,110, //-25~-16℃
116 ,123  ,129  ,136  ,143  ,150  ,157  ,165  ,173  ,181, //-15~-6℃
190 ,198  ,207  ,216  ,225  ,235  ,244  ,254  ,264  ,275, //-5~4℃
285 ,296  ,306  ,317  ,328  ,339  ,351  ,362  ,373  ,385, //5~14℃
396 ,408  ,420  ,431  ,443  ,454  ,466  ,478  ,489  ,501, //15~24℃
512 ,523  ,535  ,546  ,557  ,568  ,579  ,589  ,600  ,610, //25~34℃
620 ,630  ,640  ,650  ,660  ,669  ,678  ,688  ,696  ,705, //35~44℃
714 ,722  ,730  ,738  ,746  ,754  ,761  ,768  ,775  ,782, //45~54℃
789 ,796  ,802  ,808  ,814  ,820  ,826  ,831  ,837  ,842, //55~64℃
847 ,852  ,857  ,862  ,866  ,871  ,875  ,879  ,883  ,887, //65~74℃
891 ,895  ,898  ,902  ,905  ,909  ,912  ,915  ,918  ,921, //75~84℃
924 ,926  ,929  ,932  ,934  ,937  ,939  ,941  ,943  ,946, //85~94℃
948 ,950  ,952  ,954  ,955  ,957  ,959  ,961  ,962  ,964, //95~104℃
965 ,967  ,968  ,970  ,971  ,973  ,974  ,975  ,976  ,978, //105~114℃
979 ,980  ,981  ,982  ,983  ,984  ,985  ,986  ,987  ,988, //115~124℃
989 ,989  ,990  ,991  ,992  ,993  ,993  ,994  ,995  ,995, //125~134℃
996 ,997  ,997  ,998  ,998  ,999  ,1000 ,1000 ,1001 ,1001,  //135~144℃
1002  ,1002 ,1003 ,1003 ,1004 ,1004 ,1004 ,1005 ,1005 ,1006,  //145~154℃
1006  ,1006 ,1007 ,1007 ,1007 ,1008 ,1008 ,1008 ,1009 ,1009,  //155~164℃
1009  ,1010 ,1010 ,1010 ,1010 ,1011 ,1011 ,1011 ,1012 ,1012,  //165~174℃
1012  ,1012 ,1012 ,1013 ,1013 ,1013 ,1013 ,1014 ,1014 ,1014,  //175~184℃
1014  ,1014 ,1014 ,1015 ,1015 ,1015 ,1015 ,1015 ,1015 ,1016,  //185~194℃
1016  ,1016 ,1016 ,1016 ,1016 ,1016 ,1017 ,1017 ,1017 ,1017,  //195~204℃
};
float tsp_BinaryTableSearch( float adc_val )
{
  int start = 0U, end = 0U, mid = 0U;
  end = ( sizeof( NTC_adc_table )/ sizeof( NTC_adc_table[0] ) ) - 1U;
  if( adc_val > TSP_SHORT_CIRCUIT_THRESHOLD )
  {
    return 204.0F;
  }
  else if( adc_val < TSP_OPEN_CIRCUIT_THRESHOLD )
  {
    return -55.0F;
  }
  else if( adc_val < NTC_adc_table[0] )
  {
    return -55.0F;
  }
  else if( adc_val > NTC_adc_table[end - 1U] )
  {
    return 204.0F;
  }
  else
  {
  }

  while ( start <= end )
  {
    mid = (start + end) >> 1; 
    if( adc_val ==  NTC_adc_table[mid] )
    {
      break;
    }
    if( ( adc_val > NTC_adc_table[mid] ) && ( adc_val < NTC_adc_table[mid+1U] ) )
    {
      break;
    }

    if( adc_val > NTC_adc_table[mid] )
    {
      start = mid + 1U; 
    }
    else if( adc_val < NTC_adc_table[mid] )
    {
      end = mid - 1U;
    }
    else
    {
    }
  }
  return (mid-55) +  (float)(adc_val-NTC_adc_table[mid] )/(float)(NTC_adc_table[mid+1]-NTC_adc_table[mid]);
}

JXChart(查看使用方法) 采集如下图
在这里插入图片描述

最后在对比一下“公式法”和“查表法”的温度曲线,从图中可以看到,两条曲线基本吻合。
在这里插入图片描述

2024/06/07 09:18:10.785(接收)ascii:{formula,31.0439453125}
2024/06/07 09:18:10.836(接收)ascii:{00table,31.0000000000}
2024/06/07 09:18:11.838(接收)ascii:{formula,31.3237304687}
2024/06/07 09:18:11.889(接收)ascii:{00table,31.2999992370}
2024/06/07 09:18:12.891(接收)ascii:{formula,31.5108032226}
2024/06/07 09:18:12.943(接收)ascii:{00table,31.5000000000}
2024/06/07 09:18:13.944(接收)ascii:{formula,31.7922363281}
2024/06/07 09:18:13.996(接收)ascii:{00table,31.7999992370}
2024/06/07 09:18:14.997(接收)ascii:{formula,31.9804077148}
2024/06/07 09:18:15.049(接收)ascii:{00table,32.0000000000}
2024/06/07 09:18:16.050(接收)ascii:{formula,32.1690673828}
2024/06/07 09:18:16.102(接收)ascii:{00table,32.1818199157}
2024/06/07 09:18:17.104(接收)ascii:{formula,32.2635498046}
2024/06/07 09:18:17.155(接收)ascii:{00table,32.2727279663}
2024/06/07 09:18:18.157(接收)ascii:{formula,32.3581542968}
2024/06/07 09:18:18.209(接收)ascii:{00table,32.3636360168}
2024/06/07 09:18:19.210(接收)ascii:{formula,32.4528808593}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

libertyman

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值