MLX90614 系列模块是一组通用的红外测温模块。在出厂前该模块已进行校验及线性化,具有非接触、体积小、精度高,成本低等优点。被测目标温度和环境温度能通过单通道输出,并有两种输出接口,适合于汽车空调、室内暖气、家用电器、手持设备以及医疗设备应用等。测温方式可分为接触式和非接触式,接触式测温只能测量被测物体与测温传感器达到热平衡后的温度,所以响应时间长,且极易受环境温度的影响;而红外测温是根据被测物体的红外辐射能量来确定物体的温度,不与被测物体接触,具有影响动被测物体温度分布场,温度分辨率高、响应速度快、测温范围广、不受测温上限的限制、稳定性好等特点,所以我们选择mlx90614来作为红外测温模块。
单片机与mlx90614红外测温模块之间通信的方式是“类IIC”通信,意思就是通信方式跟IIC通信方式很像但又不是IIC,它有另外一个名字叫做SMBus。SMBus (System Management Bus)是 1995 年由 intel 公司提出的一种高效同步串行总线,SMBus 只有两根信号线:双向数据线和时钟信号线,容许 CPU 与各种外围接口器件以串行方式进行通信、交换信息,即可以提高传输速度也可以减小器件的资源占用,另外即使在没有SMBus 接口的单片机上也可利用软件进行模拟。
1、模块来源
模块实物展示:
资料下载链接:
https://pan.baidu.com/s/1AsEBvVCiNAvTKqTeGSA60w
提取码:g06n
2、规格参数
工作电压:4.5~5.5V
工作电流:1.3~2.5mA
以上信息见厂家资料文件
3、移植过程
我们的目标是将例程移植至CW32F030C8T6开发板上【能够测量物体温度和环境温度的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
3.1查看资料
MLX90614中有两个存储器,分别为EEPROM和RAM。
MLX90614中共有32个字长为16位的EEPROM存储单元,其地址为000H—01FH。EEPROM中所有的寄存器都是可以通过SMBus进行读取,但只有部分寄存器是可以进行改写的(地址为0x00, 0x01, 0x02, 0x03, 0x04, 0x05*,0x0E, 0x0F, 0x19)。可改写部分如下图所示。因在出厂前模块已进行校验及线性化,所以我们直接使用默认参数,不需要修改。
MLX90614中总共有32个17位的RAM存储单元,用户不能通过RAM来写入数据,只能读取RAM中的部分存储单元读取16位存储数据。其采集的环境温度数据保存在地址06H存储单元中,采集的被测物体温度数据存储在07H存储单元中。因此运用存储在RAM地址中的数据,通过公式的计算,可以得到环境温度Ta及被测物体温度数据To。
需要注意的是数据的低8位在前面,高8位在后。
器件地址(Slave Address)在数据手册中有说明,默认器件地址为0X5A;
命令(Command)是根据要控制的是RAM还是eeprom来决定一个字节中的BIT7~BIT5。剩余的BIT4~BIT0由要操控的地址决定。
例如,我要读取RAM的Ta温度数据,则命令组成见下表。其中RAM地址为000x_xxxx,Ta温度数据地址为0x06=0000_0110,只取低5位则为xxx0_0110。
PEC是一个多项式为X8+X2+X1+1的CRC-8校验数据。
在数据手册中举了两个例子。其中0xB4为器件地址左移一位后的值。
得到温度的原始数据后,根据数据手册的说明进行换算即可得到温度。
以上是手册中举了一个例子,如果读取到的温度数据是0X3AF7,其10进制为15095,将10进制数 除以50或者乘以0.02得到301.9,再减去273.15即可得到实际温度。
温度 = 温度原始数据 * 0.02 - 273.15
该温度换算公式对To和Ta都适用。
3.2引脚选择
模块接线图
3.3移植至工程
工程模板参考入门手册的工程模板
移植步骤中的导入.c和.h文件与【CW32模块使用】DHT11温湿度传感器相同,只是将.c和.h文件更改为bsp_mlx90614.c与bsp_mlx90614.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件bsp_mlx90614.c中,编写如下代码。
/* * Change Logs: * Date Author Notes * 2024-06-20 LCKFB-ALP first version */ #include "bsp_mlx90614.h" #include "stdio.h" /****************************************************************** * 函 数 名 称:MLX90614_GPIO_Init * 函 数 说 明:MLX90614的引脚初始化 * 函 数 形 参:无 * 函 数 返 回:无 * 作 者:LC * 备 注:MLX90614是5V,而且开发板开发板的引脚输出是3.3V, * 故设置引脚模式时,必须设置为开漏模式 ******************************************************************/ void MLX90614_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化结构体 RCC_MLX90614_ENABLE(); // 使能GPIO时钟 GPIO_InitStruct.Pins = GPIO_SCL|GPIO_SDA; // GPIO引脚 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 输出速度高 GPIO_Init(PORT_MLX90614, &GPIO_InitStruct); // 初始化 } /****************************************************************** * 函 数 名 称:IIC_Start * 函 数 说 明:IIC起始时序 * 函 数 形 参:无 * 函 数 返 回:无 * 作 者:LC * 备 注:无 ******************************************************************/ void IIC_Start(void) { SDA_OUT(); SDA(1); delay_us(5); SCL(1); delay_us(5); SDA(0); delay_us(5); SCL(0); delay_us(5); } /****************************************************************** * 函 数 名 称:IIC_Stop * 函 数 说 明:IIC停止信号 * 函 数 形 参:无 * 函 数 返 回:无 * 作 者:LC * 备 注:无 ******************************************************************/ void IIC_Stop(void) { SDA_OUT(); SCL(0); SDA(0); SCL(1); delay_us(5); SDA(1); delay_us(5); } /****************************************************************** * 函 数 名 称:IIC_Send_Ack * 函 数 说 明:主机发送应答或者非应答信号 * 函 数 形 参:0发送应答 1发送非应答 * 函 数 返 回:无 * 作 者:LC * 备 注:无 ******************************************************************/ void IIC_Send_Ack(unsigned char ack) { SDA_OUT(); SCL(0); SDA(0); delay_us(5); if(!ack) SDA(0); else SDA(1); SCL(1); delay_us(5); SCL(0); SDA(1); } /****************************************************************** * 函 数 名 称:I2C_WaitAck * 函 数 说 明:等待从机应答 * 函 数 形 参:无 * 函 数 返 回:0有应答 1超时无应答 * 作 者:LC * 备 注:无 ******************************************************************/ unsigned char I2C_WaitAck(void) { char ack = 0; unsigned char ack_flag = 10; SCL(0); SDA(1); SDA_IN(); delay_us(5); SCL(1); delay_us(5); while( (SDA_GET()==1) && ( ack_flag ) ) { ack_flag--; delay_us(5); } if( ack_flag <= 0 ) { IIC_Stop(); return 1; } else { SCL(0); SDA_OUT(); } return ack; } /****************************************************************** * 函 数 名 称:Send_Byte * 函 数 说 明:写入一个字节 * 函 数 形 参:dat要写人的数据 * 函 数 返 回:无 * 作 者:LC * 备 注:无 ******************************************************************/ void Send_Byte(uint8_t dat) { int i = 0; SDA_OUT(); SCL(0);//拉低时钟开始数据传输 for( i = 0; i < 8; i++ ) { SDA( (dat & 0x80) > > 7 ); delay_us(1); SCL(1); delay_us(5); SCL(0); delay_us(5); dat< <=1; } } /****************************************************************** * 函 数 名 称:Read_Byte * 函 数 说 明:IIC读时序 * 函 数 形 参:无 * 函 数 返 回:读到的数据 * 作 者:LC * 备 注:无 ******************************************************************/ unsigned char Read_Byte(void) { unsigned char i,receive=0; SDA_IN();//SDA设置为输入 for(i=0;i< 8;i++ ) { SCL(0); delay_us(5); SCL(1); delay_us(5); receive< <=1; if( SDA_GET() ) { receive|=1; } delay_us(5); } SCL(0); return receive; } ///****************************************************************** // * 函 数 名 称:PEC_Calculation // * 函 数 说 明:PEC校验 // * 函 数 形 参:pec要校验的数据地址 len校验的长度 // * 函 数 返 回:校验后的值 // * 作 者:LC // * 备 注:无 //******************************************************************/ //static unsigned char PEC_Calculation(unsigned char *dat , unsigned char len) //{ // unsigned char i; // unsigned char crc=0; // while( len-- ) // { // crc ^= *dat++; // for( i=0 ; i< 8 ; i++ ) // { // if( crc&0x80 ) // { // crc = (crc< <1)^0x07; // } // else // { // crc = (crc< <1); // } // } // } // return crc; //} /************************************************************ * 函数名称:MLX90615_Read * 函数说明:读取MLX90615的温度 * 型 参:SlaveAddr = 器件地址 RegAddr = 要操作的寄存器地址 * 返 回 值:温度值 * 备 注: SlaveAddr = 0X5A默认器件地址 * RegAddr = 0X07读取被测量物体温度 * RegAddr = 0X06读取环境温度 *************************************************************/ float MLX90614_Read(unsigned char SlaveAddr, unsigned char RegAddr) { IIC_Start(); Send_Byte((SlaveAddr < < 1) | 0); // 写命令 if(I2C_WaitAck()) { IIC_Stop(); return 0.0; } Send_Byte(RegAddr); // 寄存器地址 if(I2C_WaitAck()) { IIC_Stop(); return 0.0; } // delay_ms(1); IIC_Start(); Send_Byte((SlaveAddr < < 1) | 1); // 读命令 if(I2C_WaitAck()) { IIC_Stop(); return 0.0; } uint8_t lowByte = Read_Byte(); // 低8位 IIC_Send_Ack(0); uint8_t highByte = Read_Byte(); // 高8位 IIC_Send_Ack(1); IIC_Stop(); uint16_t tempRaw = (highByte < < 8) | lowByte; float temperature = (tempRaw * 0.02) - 273.15; return temperature; }
在文件bsp_mlx90614.h中,编写如下代码。
/* * Change Logs: * Date Author Notes * 2024-06-20 LCKFB-ALP first version */ #ifndef _BSP_MLX90614_H_ #define _BSP_MLX90614_H_ #include "board.h" //端口移植 #define RCC_MLX90614_ENABLE() __RCC_GPIOA_CLK_ENABLE() #define PORT_MLX90614 CW_GPIOA #define GPIO_SDA GPIO_PIN_1 #define GPIO_SCL GPIO_PIN_0 //设置SDA输出模式 #define SDA_OUT() { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pins = GPIO_SDA; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_Init(PORT_MLX90614, &GPIO_InitStruct); } //设置SDA输入模式 #define SDA_IN() { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pins = GPIO_SDA; GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_Init(PORT_MLX90614, &GPIO_InitStruct); } //获取SDA引脚的电平变化 #define SDA_GET() GPIO_ReadPin(PORT_MLX90614, GPIO_SDA) //SDA与SCL输出 #define SDA(x) GPIO_WritePin(PORT_MLX90614, GPIO_SDA, (x?GPIO_Pin_SET:GPIO_Pin_RESET) ) #define SCL(x) GPIO_WritePin(PORT_MLX90614, GPIO_SCL, (x?GPIO_Pin_SET:GPIO_Pin_RESET) ) void MLX90614_GPIO_Init(void); float MLX90614_Read(unsigned char SlaveAddr, unsigned char RegAddr); void IIC_Stop(void); #endif
4、移植验证
在自己工程中的main主函数中,编写如下。
/* * Change Logs: * Date Author Notes * 2024-06-20 LCKFB-ALP first version */ #include "board.h" #include "stdio.h" #include "bsp_uart.h" #include "bsp_mlx90614.h" int32_t main(void) { board_init(); // 开发板初始化 uart1_init(115200); // 串口1波特率115200 MLX90614_GPIO_Init(); printf("Startrn"); while(1) { float t = MLX90614_Read(0X5A, 0X07); if( t != 0) { printf("temperature = %.2frn", t); } delay_ms(1000); } }
移植现象:测量手心温度为36℃左右。
模块移植成功案例代码:
链接:https://pan.baidu.com/s/1Ts1A7Eqng7yCa2YabmI6_A?pwd=LCKF
提取码:LCKF
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !