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条评论
快来发表一下你的评论吧 !