前言
网络上关于
ZigBee
和
MAX31865
的相关资料较少,对于如何在
CC2530
上实现对
PT100
温度数据的读取的资料更是几乎没有。因此本文对MAX31865芯片和模块的使用进行简要介绍,并提供使用源码,同时提供自制模块的相关原理图。
二、MAX31865芯片介绍
2.1简介:
该芯片主要用于测量PT100/PT1000热电阻的阻值,通过SPI对内置存放温度的ADC码进行读取,进而通过公式获得热电阻值并换算成温度值。内片内置15位ADC,满量程时精度0.5℃,可以满足绝大部分需求。
2.2:读写时序
如图2.1所示读时序,首先拉低CS使能脚,时钟SCLK由高变低,写入一个电平,通过SDI写入八位地址,由高到低,而后拉低时钟,往复8次。
写入地址后,通过拉低拉高SCKL,从SDO读取电平。
需要注意的是:
1.读写时必须满足最小上升/下降时间
2.写地址时SDO为高阻态
3.单片机对应的SDO需要设置为输入模式
图2.1 SPI读时序
写时序相对来说比较简单,不再赘述。
图2.2 SPI写时序
2.3:配置寄存器
 根据芯片手册我们可以看到,如图2.3所示配置寄存器的读地址为0x00,写地址为0x80。读配置寄存器可以验证写入的配置是否生效,同时可以通过读出地址与写入地址是否对应来判断模块是否正常工作。
D4是选择PT100的接线(2 4/3线制),其余各个位的功能及作用具体看芯片手册。
□ 不考虑功耗的情况下,四线制可以写入0xC2;
□ 考虑功耗,采用1-shot,则可以写入0x01;值得注意的时,在1-shot模式下,在读取阻值之前首先需要打开Vbias给RC网络充电,60Hz下需要52ms,50Hz下需要62.5ms;而后再对D5位写高,完成一次电阻转换。读取完温度数据后,重新关闭Vbias即可。
图2.3 MAX31865配置寄存器
2.4错误标志
如图2.3中的第4567寄存器,通过对其配置,可以设置温度报警门限上限和下限。
简单来说,比如一个PT100能测温范围是-200℃到500℃,用户想设置下限报警值为-180℃,上限报警值为480℃,那么当max31865转换RTD后,会将0x01和0x02寄存器结果与上限值和下限值比较,如果不在设置的范围,就会产生错误标志。错误标志存在0x07寄存器中。
2.5温度读取
如图2.4所示,D0是用于指示是否有图3.3中设定的错误出现。
○读取温度时,可以先读取0x07寄存器,看是不是等于0x00,即是说无错误标志。有错误标志时,0x07寄存器里面某个值就是1。
○而后依次读取0x01和0x02地址的数据,并移除掉D0标志位。
○由ADC码转换为热电阻阻值公式如下:
图2.4 MAX31865读取温度
四、代码
代码已经有足够的注释,因此不再详细介绍。
4.1 配置I/O寄存器
I/O口设置
//-----------------RTD端口定义----------------
#define RTD_CLK P0_4 //SCLK
#define RTD_SDO P0_5 //serial data output 即单片机输入 MOSI
#define RTD_SDI P0_6 //serial data input 即单片机输出 MISO
#define RTD_CS P0_7 //片选脚
I/O初始化和MAX31865配置寄存器配置
P0DIR是CC2530配置P0口输入输出寄存器。
P0INP是CC2530配置上拉/下拉寄存器。
其他芯片例如51、STM32可以进行类似配置,除SDO设置为输入外,其余可设置为推挽输出。
/************************************************
*函数名:RTD_Init(void)
*函数功能:Max18650寄存器配置,单片机I/O配置
*返回值:无
*注:为减小转换功耗,VIAS设为常闭,采用1-shot模式
*************************************************/
void RTD_Init(void)
{
P0DIR |= 0xDF;//SDO设置为输入 SKI CS SDI设置为输出
P0INP &= 0xDF;//上拉/下拉
P2INP |= 0x20;//下拉输入
//RTD_WR_REG(0x80,0xC2);//写配置寄存器 BIAS ON,自动,4线,60HZ 0xC2
RTD_WR_REG(0x80,0x01);//配置寄存器 BIAS OFF,1-shot,4线,50HZ 抑制工频噪声
//RTD_RD_Data(0x00);
}
4.2 SPI写寄存器
/************************************
*函数名:RTD_WR_REG(uint8 adr,uint8 cmd)
*函数功能:对RTD寄存器配置
*adr:寄存器写地址
*cmd:要写入的命令
*返回值:无
***********************************/
void RTD_WR_REG(uint8 adr,uint8 cmd)
{
uint8 i;
RTD_CS_Clr();//拉低片选,选中芯片
for(i=0;i<8;i++)//写寄存器地址
{
RTD_SCLK_Clr();
if(adr&0x80)
RTD_SDI_Set();//若地址数据最高位为高,则SDI拉高
else
RTD_SDI_Clr();//若地址数据最高位为低,则SDI拉低
RTD_SCLK_Set();
adr<<=1; //地址数据左移,次高位变为最高位
}
RTD_SCLK_Set();
//Delayms(1);
for(i=0;i<8;i++)//写寄存器数据
{
RTD_SCLK_Clr();
if(cmd&0x80)
RTD_SDI_Set();//数据最高位为高,则SDI拉高
else
RTD_SDI_Clr();//数据最高位为低,则SDI拉低
RTD_SCLK_Set();
cmd<<=1; //数据左移,次高位变为最高位
}
RTD_SCLK_Set();
RTD_CS_Set();
}
4.3 SPI读寄存器
/************************************
*函数名:RTD_RD_Data(uint8 adr)
*函数功能:从RTD寄存器中读数据
*adr:读取寄存器所在地址
*返回值:data 读取到的值
***********************************/
uint8 RTD_RD_Data(uint8 adr)
{
uint8 i;
uint8 data = 0x00;
if(adr==0x01||adr==0x02)//读取温度寄存器时
RTD_WR_REG(0x80,0xA1);//启动一次电阻测试转换
RTD_CS_Clr();//拉低片选,选中芯片
for(i=0;i<8;i++)
{
RTD_SCLK_Clr();
if(adr&0x80)
RTD_SDI_Set();//数据最高位为高,则SDI拉高
else
RTD_SDI_Clr();//数据最高位为低,则SDI拉低
RTD_SCLK_Set();
adr<<=1; //数据左移,次高位变为最高位
}
for(i=0;i<8;i++)
{
RTD_SCLK_Clr();
if(RTD_SDO)
data|= 0x01;//该位置1
// else
// data|= 0x00;//该位置0
if(i<7)
data<<=1; //数据左移,次高位变为最高位
RTD_SCLK_Set();
}
RTD_CS_Set();
return data;//返回读取到的数据
}
4.4 SPI读MSB ADC值
/*********************************************
*函数名:RTD_READ_MSB()
*函数功能:读取MSB寄存器ADC值
*返回值:Rt寄存器高八位
*********************************************/
uint8 RTD_READ_MSB(void)
{
unsigned char MSB = 0;
//uint8 i;
//float Rt;
//float Rt,temperature;
//float c,temp;
RTD_WR_REG(0x80,0x81);//打开VBAIS
Delayms(50);//滤波电容充电
//for(i=0;i<60;i++)
//MicroWait(1000);//滤波电容充电
while(MSB < 38) //温度大于-40摄氏度
MSB = RTD_RD_Data(0x01);
//data = data<<8;
//data|= RTD_LSB_Ave_Fliter(5);
//RTD_WR_REG(0x80,0x01);//配置寄存器 关闭VBIAS 减小功耗
//data>>=1; //去掉Fault位
//Rt = (float)data/32768.0*Rref;
// c = Rt/R0 - 1;
// temp = Sqrt(b*b - 4*a*c);
// temperature = (-b + temp)/(2*a);
//return Rt;
return MSB;
}
4.5 SPI读LSB ADC值 均值滤波
/*********************************************
*函数名:RTD_LSB_Ave_Fliter(uint8 num)
*函数功能:对LSB寄存器读到的数值进行均值滤波
*NUM:读取0x02寄存器次数,即对多少次采样取均值
*返回值:sum/num LSB寄存器均值
*********************************************/
uint8 RTD_LSB_Ave_Fliter(uint8 num)
{
//uint8 data[num];
uint8 i;
unsigned int sum = 0;
for(i=0;i
sum += RTD_RD_Data(0x02);
return(sum/num);
}
4.6 头文件相关定义
#define st(x) do { x } while (__LINE__ == -1)
#define RTD_CS_Clr() st(RTD_CS = 0;)
#define RTD_CS_Set() st(RTD_CS = 1;)
#define RTD_SDI_Clr() st(RTD_SDI = 0;)
#define RTD_SDI_Set() st(RTD_SDI = 1;)
#define RTD_SCLK_Clr() st(RTD_CLK = 0;)
#define RTD_SCLK_Set() st(RTD_CLK = 1;)
void Delayms(uint8 xms);//延时函数
uint8 RTD_LSB_Ave_Fliter(uint8 num);//滤波函数
//RTD控制用函数
void RTD_WR_REG(uint8 adr,uint8 cmd);
uint8 RTD_RD_Data(uint8 adr);
void RTD_Init(void);
uint8 RTD_READ_MSB(void);
4.7 主函数
/***************************
//主函数
***************************/
void main(void)
{
RTD_Init();
RTD_READ_MSB();
RTD_LSB_Ave_Fliter(5);
}
五、PCB
图4.1 MAX31865模块4线制电路图
图4.2 MAX31865模块3线制电路图
图4.3 MAX31865模块2线制电路图 根据芯片手册接线原理图(图4.1-4.3)可以绘制出如图4.4所示的原理图,BJ1 2 3 用于选择线制。
图4.4 MAX31865 3.3MCU电路图 需要注意的是,如图4.5所示,MAX31865模块为了能够实现5V电压输入和5V供电单片机的适配会在接单片机的引脚处上拉3.3V,并增加二极管,防止5V电平直接加在MAX31865上,损坏芯片。
图4.5 MAX31865 5VMCU电路图