MAX31865模块温度测量
文章目录
0 前言
本文主要介绍MAX31865 测温注意事项,并写出读取温度的示例代码,模块详细参数可以查阅相关手册,
1 注意事项
1.1 参考电阻
电阻温度检测器(RTD)是一种阻值随温度变化的电阻。铂是最常见、精度最高的测温金属丝材料。铂RTD称为PT-RTD,镍、铜和其它金属亦可用来制造RTD。RTD具有较宽的测温范围,最高达+800°C,具有较高精度和较好的可重复性,线性度适中。
为测量RTD阻值,接入参考电阻(RREF),该电阻与RTD串联,偏置电压作用在RREF上端,3线制典型应用电路如下图所示,
参考电阻的电流同样流过RTD。参考电阻两端的电压为ADC基准电压。RTD电压连接至ADC差分输入(RTDIN+和RTDIN-)。所以ADC产生的数字输出等于RTD电阻与参考电阻的比值。对于铂电阻RTD,选择阻值等于RTD 0°C阻值的4倍的参考电阻最为合适。因此,针对PT100选用400Ω参考电阻;针对PT1000则选用4kΩ参考电阻。
1.2 SPI时序图
读取寄存器数据,先写入要读的地址,再读取数据,时序图如下,
写数据到寄存器,先写入要写的地址,再写入数据, 如下图所示,
时钟极性和相位
1.3 寄存器
MAX3186主要有8个寄存器,如下表所示,
0x00:配置寄存器,需要配置2/3/4线,故障检测周期等
0x01-0x02:RTD电阻寄存器,由两个8位的寄存器组成,包含15位有效数据,RTD LBS 的bit0为故障位,表示检测到任意RTD故障,应用软件中需要做故障判断处理
0x03-0x06:故障上限和故障下限寄存器用于选择RTD故障检测的触发门限。
0x07:故障状态寄存器锁存所有检测到的故障位;向配置寄存器中的故障状态清除位写1时,将全部故障状态位清零。
2 将RTD数据寄存器值转换为温度
首先,利用下面公式确定RTD的阻值,
ADC编码 = RTD数据寄存器(01h – 02h)中的15位ADC转换结果,RREF = 基准电阻的阻值
如果RTD的阻值已知、电阻特性定义良好,则可通过计算或查找表确定温度值。
2.1 线性化温度数据
对于-100°C至+100°C温度范围,简单利用RTD数据可以很好地实现温度逼近,如下所示:
温度(°C) ≈ (ADC编码/32) – 256
从该式可以得出:0°C时,误差为0°C; -100°C时,误差为-1.75°C; +100°C时,误差为-1.4°C (假 设采用IEC751RTD,RREF等于0°C RTD电阻的四倍)。
PT100实际测量发现,50°环境中,计算值和实际值相差1.8°左右,这样无法直接用到项目中,那就看看第2种转换方式
2.2 RTD温度计算(PT100)
查阅了网上大量资料,都是用线性化处理的方式,最后在Github项目中,发现采用下面公式转化温度和实际测量值保持一致
更多详细说明请参考芯片手册《AN-709 APPLICATION NOTE》
3 示例代码
下图是某个项目中的MAX31865的设计图,这里参考电阻为402欧/1%,采用3线制接入PT100,主控芯片是STM32F107
温度采集的示例代码
// 定义结构体,用于读取整个模块数据
struct rtd_max31865
{
uint8_t config_reg;
uint16_t rtd_reg;
uint16_t hft_reg;
uint16_t lft_reg;
uint8_t status_reg;
};
void spi_delay( uint32_t delay )
{
while( delay--);
}
void send_byte( uint8_t data )
{
uint8_t i;
uint32_t delay = 0xff;
for (i = 0; i < 8; i++)
{
SPI3_SCLK_L();
spi_delay(delay);
if( data & 0x80 )
{
SPI3_MOSI_H();
}
else
{
SPI3_MOSI_L();
}
spi_delay(delay);
SPI3_SCLK_H();
spi_delay(delay);
data <<= 1;
}
}
uint8_t read_byte( void )
{
uint8_t i;
uint8_t read = 0;
uint32_t delay = 0xff;
for (i = 0; i < 8; i++)
{
SPI3_SCLK_L();
spi_delay(delay);
read = read << 1;
if ( SPI3_READ_BIT() )
{
read += 1;
}
else
{
read += 0;
}
SPI3_SCLK_H();
spi_delay(delay);
}
return read;
}
void max31865_config( uint8_t addr, uint8_t data )
{
send_byte( addr );
send_byte( data );
}
void max31865_read( struct rtd_max31865* max31865 )
{
uint8_t i, read_data[8];
send_byte( 0 );
for ( i = 0; i < 8; i++ )
{
read_data[i] = read_byte();
}
max31865->config_reg = read_data[0];
max31865->rtd_reg = ((read_data[1] << 8) | read_data[2]) >> 1;
max31865->hft_reg = ((read_data[3] << 8) | read_data[4]) >> 1;
max31865->lft_reg = (read_data[5] << 8) | read_data[6];
max31865->status_reg = read_data[7];
}
float max31865_read_temp( struct rtd_max31865* max31865 )
{
uint8_t i;
uint32_t adc_val = 0;
float rtd;
unsigned int data;
float Rt;
float Rt0 = 100; //PT100
float Z1,Z2,Z3,Z4,temp;
float a = 3.9083e-3;
float b = -5.775e-7;
float rpoly;
for ( i = 0; i < 10; i++ )
{
max31865_read(max31865);
adc_val += max31865->rtd_reg;
HAL_Delay(2);
}
Rt = (double)( adc_val * 402) / (32768 * 10);
Z1 = -a;
Z2 = a*a-4*b;
Z3 = 4*b/Rt0;
Z4 = 2*b;
temp = Z2+Z3*Rt;
temp = (sqrt(temp)+Z1)/Z4;
// 温度大于0
if(temp>=0)
{
return temp;
}
// 温度小于0
rpoly = Rt;
temp = -242.02;
temp += 2.2228 * rpoly;
rpoly *= Rt; // square
temp += 2.5859e-3 * rpoly;
rpoly *= Rt; // ^3
temp -= 4.8260e-6 * rpoly;
rpoly *= Rt; // ^4
temp -= 2.8183e-8 * rpoly;
rpoly *= Rt; // ^5
temp += 1.5243e-10 * rpoly;
return temp;
}
void max31865_init( void )
{
max31865_config( 0x80, 0xD0);
}
作者:九斗嵌入式