GD32F470 GY-906 MLX90614ESF BAA BCC DCI IR红外测温传感器模块温度采集模块移植

2.12 MLX90614红外无接触测温传感器
MLX90614 系列模块是一组通用的红外测温模块。在出厂前该模块已进行校验及线性化,具有非接触、体积小、精度高,成本低等优点。被测目标温度和环境温度能通过单通道输出,并有两种输出接口,适合于汽车空调、室内暖气、家用电器、手持设备以及医疗设备应用等。测温方式可分为接触式和非接触式,接触式测温只能测量被测物体与测温传感器达到热平衡后的温度,所以响应时间长,且极易受环境温度的影响;而红外测温是根据被测物体的红外辐射能量来确定物体的温度,不与被测物体接触,具有影响动被测物体温度分布场,温度分辨率高、响应速度快、测温范围广、不受测温上限的限制、稳定性好等特点,所以我们选择mlx90614来作为红外测温模块。
  单片机与mlx90614红外测温模块之间通信的方式是“类IIC”通信,意思就是通信方式跟IIC通信方式很像但又不是IIC,它有另外一个名字叫做SMBus。SMBus (System Management Bus)是 1995 年由 intel 公司提出的一种高效同步串行总线,SMBus 只有两根信号线:双向数据线和时钟信号线,容许 CPU 与各种外围接口器件以串行方式进行通信、交换信息,即可以提高传输速度也可以减小器件的资源占用,另外即使在没有SMBus 接口的单片机上也可利用软件进行模拟。

2.12.1 模块来源
采购链接:GY-906 MLX90614ESF BAA BCC DCI IR红外测温传感器模块温度采集
资料下载链接:https://pan.baidu.com/s/1AsEBvVCiNAvTKqTeGSA60w
提取码:g06n

2.12.2 规格参数
工作电压:4.5~5.5V
工作电流:1.3~2.5mA
工作电流:1.3~2.5mA

2.12.3 移植过程
我们的目标是在梁山派GD32F470上能够测量物体温度和环境温度的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
2.12.3.1 查看资料
MLX90614中有两个存储器,分别为EEPROM和RAM。

  • MLX90614中共有32个字长为16位的EEPROM存储单元,其地址为000H—01FH。EEPROM中所有的寄存器都是可以通过SMBus进行读取,但只有部分寄存器是可以进行改写的(地址为0x00, 0x01, 0x02, 0x03, 0x04, 0x05*,0x0E, 0x0F, 0x19)。可改写部分如下图所示。因在出厂前模块已进行校验及线性化,所以我们直接使用默认参数,不需要修改。
名称 功能说明 地址
Tomax 测量物体温度上限设定 00H
Tomin 测量物体温度下限设定 01H
PWMCTRL 测量物体温度下限设定 02H
Ta range PWM控制 03H
Emissivity correction conefficient 环境温度范围设定 04H
Config Register1 发射率校准系数:0.1-1 05H
SMBus address(LSByte only) 配置寄存器 0EH

在这里插入图片描述

  • MLX90614中总共有32个17位的RAM存储单元,用户不能通过RAM来写入数据,只能读取RAM中的部分存储单元读取16位存储数据。其采集的环境温度数据保存在地址06H存储单元中,采集的被测物体温度数据存储在07H存储单元中。因此运用存储在RAM地址中的数据,通过公式的计算,可以得到环境温度Ta及被测物体温度数据To。
    在这里插入图片描述
    时序说明
    需要注意的是数据的低8位在前面,高8位在后。

在这里插入图片描述
器件地址(Slave Address)在数据手册中有说明,默认器件地址为0X5A;

在这里插入图片描述
命令(Command)是根据要控制的是RAM还是eeprom来决定一个字节中的BIT7BIT5。剩余的BIT4BIT0由要操控的地址决定。

在这里插入图片描述
例如,我要读取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都适用。
2.12.3.2 引脚选择

测温传感器 立创·梁山派
VIN 5V
GND GND
SCL PB9
SDA PB8

在这里插入图片描述

2.12.3.3 移植至工程
移植步骤中的导入.c和.h文件与上一节相同,只是将.c和.h文件更改为bsp_mlx90614.c与bsp_mlx90614.h。见2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件bsp_mlx90614.c中,编写如下代码。

/********************************************************************************
  * 文 件 名: bsp_mlx90614.c
  * 版 本 号: 初版
  * 修改作者: LC
  * 修改日期: 2023年04月19日
  * 功能介绍:          
  ******************************************************************************
  * 注意事项:
*********************************************************************************/

#include "bsp_mlx90614.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "systick.h"


/******************************************************************
 * 函 数 名 称:MLX90614_GPIO_Init
 * 函 数 说 明:MLX90614的引脚初始化
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:MLX90614是5V,而且立创·梁山派开发板的引脚输出是3.3V,
 *             故设置引脚模式时,必须设置为开漏模式
******************************************************************/
void MLX90614_GPIO_Init(void)
{
  /* 使能时钟 */
    rcu_periph_clock_enable(RCU_SCL);
        rcu_periph_clock_enable(RCU_SDA);
    
        /* 配置SCL为输出模式 */
        gpio_mode_set(PORT_SCL,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_SCL);
        /* 配置为推挽输出 50MHZ */
        gpio_output_options_set(PORT_SCL,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,GPIO_SCL);
        
        /* 配置SDA为输出模式 */
        gpio_mode_set(PORT_SDA,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_SDA);
        /* 配置为推挽输出 50MHZ */
        gpio_output_options_set(PORT_SDA,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,GPIO_SDA);
}


/******************************************************************
 * 函 数 名 称: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 );
                __nop();
                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读取环境温度 
*************************************************************/
#define CRC_VERIFY_ENABLE 1
float MLX90614_Read(unsigned char SlaveAddr, unsigned char RegAddr)
{
        int i = 0;
        unsigned char buff[3]={0};        //保存温度高低位与校验码
        unsigned char arr[6]={0};        //校验数据使用
        uint16_t temp = 0;                        //高低位整合数据保存
        float T=0.0;                                //换算出的实际温度
        
        IIC_Start();
        Send_Byte((SlaveAddr<<1)|0);//写命令
        I2C_WaitAck();                 //等待响应

    
        Send_Byte(RegAddr);//写入要操作的寄存器地址
        I2C_WaitAck();
   
    do{
        delay_1ms(1);
        IIC_Start();        //重新开始IIC
        Send_Byte((SlaveAddr<<1)|1);        //读命令
    }while( I2C_WaitAck() );

        buff[0] = Read_Byte();                        //保存温度数据的低8位
        IIC_Send_Ack(0);                                //主机发送应答
        buff[1] = Read_Byte();                        //保存温度数据的高8位
        IIC_Send_Ack(0);                                //主机发送应答
        buff[2] = Read_Byte();                        //保存校验码
        IIC_Send_Ack(1);                                //主机发送应答
        IIC_Stop();        //停止时序                                                        
                  
        
//使用校验
#if CRC_VERIFY_ENABLE
    arr[0] = (SlaveAddr<<1);    //器件地址+写     
    arr[1] = RegAddr;           //命令
    arr[2] = (SlaveAddr<<1)+1;  //器件地址+读
    arr[3] = buff[0];           //数据低8位
    arr[4] = buff[1];           //数据高8位
    
    if( PEC_Calculation(arr, 5) == buff[2] )//如果校验正确
    {
        temp = (short)(buff[1]<<8) | buff[0];//整合高低位
        T = (temp * 0.02) - 273.15 ;         //带入公式换算出实际温度
    }
    else
    {
        printf("ERROR CODE 4\r\n");
    }
#endif   
        
//不使用校验
#if !CRC_VERIFY_ENABLE
    temp = (uint16_t)(buff[1]<<8) | buff[0];
    T = (temp*0.02)-273.15 ;
#endif
        
        return T;
}                                                                                  


在文件bsp_mlx90614.h中,编写如下代码。

#ifndef _BSP_MLX90614_H_
#define _BSP_MLX90614_H_

#include "gd32f4xx.h"

//端口移植
#define RCU_SDA RCU_GPIOB
#define PORT_SDA GPIOB
#define GPIO_SDA GPIO_PIN_8

#define RCU_SCL RCU_GPIOB
#define PORT_SCL GPIOB
#define GPIO_SCL GPIO_PIN_9

//设置SDA输出模式
#define SDA_OUT()        gpio_mode_set(PORT_SDA,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_SDA)
//设置SDA输入模式
#define SDA_IN()        gpio_mode_set(PORT_SDA,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP,GPIO_SDA)
//获取SDA引脚的电平变化
#define SDA_GET()        gpio_input_bit_get(PORT_SDA,GPIO_SDA)
//SDA与SCL输出
#define SDA(x)          gpio_bit_write(PORT_SDA,GPIO_SDA, (x?SET:RESET))
#define SCL(x)          gpio_bit_write(PORT_SCL,GPIO_SCL, (x?SET:RESET))


void MLX90614_GPIO_Init(void);
float MLX90614_Read(unsigned char SlaveAddr, unsigned char RegAddr);
#endif

2.12.4 移植验证
在自己工程中的main主函数中,编写如下。

/********************************************************************************
  * 文 件 名: main.c
  * 版 本 号: 初版
  * 修改作者: LC
  * 修改日期: 2022年04月19日
  * 功能介绍:          
  ******************************************************************************
  * 注意事项:
*********************************************************************************/

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "sys.h"
#include "bsp_usart.h"
#include "bsp_mlx90614.h"

/************************************************
函数名称 : main
功    能 : 主函数
参    数 : 无
返 回 值 : 无
作    者 : LC
*************************************************/
int main(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 优先级分组
    systick_config();                                                  // 滴答定时器初始化
    sart_gpio_config(9600U);                                          // 串口0初始化
    MLX90614_GPIO_Init();
    printf("start\r\n");
    while(1) 
        {
            printf("temperature = %.2f\r\n", MLX90614_Read(0X5A, 0X07) );
            delay_1ms(1000);  
    }
}

移植现象:测量手心温度为36℃左右。

在这里插入图片描述
移植成功示例,见文件2.12.4-1 。

文件2.12.4-1

最近更新

  1. TCP协议是安全的吗?

    2024-04-03 14:18:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-03 14:18:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-03 14:18:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-03 14:18:05       18 阅读

热门阅读

  1. Vulkan Material 设计学习

    2024-04-03 14:18:05       14 阅读
  2. 自然语言处理(NLP):揭秘AI领域的“语言大师

    2024-04-03 14:18:05       15 阅读
  3. 如何搭建一个免费的源代码托管工具?

    2024-04-03 14:18:05       12 阅读
  4. python - 实现一个通用的插件类

    2024-04-03 14:18:05       12 阅读
  5. Matlab未装工具箱

    2024-04-03 14:18:05       16 阅读
  6. excel wps中编码格式转换

    2024-04-03 14:18:05       16 阅读
  7. Unity自定义框架开发

    2024-04-03 14:18:05       13 阅读
  8. 信创工程师招聘需求分析

    2024-04-03 14:18:05       14 阅读
  9. qgroundcontrol 遥控器校准-问题解决

    2024-04-03 14:18:05       13 阅读