【STM32】天空星STM32F407-MLX90614红外无接触测温传感器移植成功案例

文章结尾有移植好的工程文件可以直接下载

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

12.1 模块来源

采购链接:

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

资料下载链接:

GY906传感器资料.zip

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

12.3 移植过程
我们的目标是在天空星STM32F407上能够测量物体温度和环境温度的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
12.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来决定一个字节中的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都适用。
    12.3.2 引脚选择
    在这里插入图片描述
    12.3.3 移植至工程
    在文件bsp_mlx90614.c中,编写如下代码。
/*
 * 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
 * 开发板官网:www.lckfb.com
 * 技术支持常驻论坛,任何技术问题欢迎随时交流学习
 * 立创论坛:https://oshwhub.com/forum
 * 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
 * 不靠卖板赚钱,以培养中国工程师为己任
 * 

 Change Logs:
 * Date           Author       Notes
 * 2024-03-18     LCKFB-LP    first version
 */

#include "bsp_mlx90614.h"
#include "stdio.h"
#include "board.h"


/******************************************************************
 * 函 数 名 称:MLX90614_GPIO_Init
 * 函 数 说 明:MLX90614的引脚初始化
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:MLX90614是5V,而且立创·天空星开发板的引脚输出是3.3V,
 *             故设置引脚模式时,必须设置为开漏模式
******************************************************************/
void MLX90614_GPIO_Init(void)
{
        RCC_AHB1PeriphClockCmd(RCC_MLX90614, ENABLE); // 使能GPIO时钟
        
        GPIO_InitTypeDef  GPIO_InitStructure;

        GPIO_InitStructure.GPIO_Pin = GPIO_SDA|GPIO_SCL;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_Init(PORT_MLX90614, &GPIO_InitStructure);
        
}


/******************************************************************
 * 函 数 名 称: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)
{
        re:
    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;
    }

    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中,编写如下代码。

/*
 * 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
 * 开发板官网:www.lckfb.com
 * 技术支持常驻论坛,任何技术问题欢迎随时交流学习
 * 立创论坛:https://oshwhub.com/forum
 * 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
 * 不靠卖板赚钱,以培养中国工程师为己任
 * 

 Change Logs:
 * Date           Author       Notes
 * 2024-03-18     LCKFB-LP    first version
 */
#ifndef _BSP_MLX90614_H_
#define _BSP_MLX90614_H_

#include "stm32f4xx.h"

//端口移植
#define RCC_MLX90614         RCC_AHB1Periph_GPIOB
#define PORT_MLX90614         GPIOB


#define GPIO_SDA                 GPIO_Pin_8
#define GPIO_SCL                 GPIO_Pin_9

//设置SDA输出模式
#define SDA_OUT()   {        \
                        GPIO_InitTypeDef  GPIO_InitStructure; \
                        GPIO_InitStructure.GPIO_Pin = GPIO_SDA; \
                        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; \
                        GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; \
                        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; \
                        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; \
                        GPIO_Init(PORT_MLX90614, &GPIO_InitStructure); \
                     }
//设置SDA输入模式
#define SDA_IN()    {        \
                        GPIO_InitTypeDef  GPIO_InitStructure; \
                        GPIO_InitStructure.GPIO_Pin = GPIO_SDA; \
                        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; \
                        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; \
                        GPIO_Init(PORT_MLX90614, &GPIO_InitStructure); \
                    }
//获取SDA引脚的电平变化
#define SDA_GET()       GPIO_ReadInputDataBit(PORT_MLX90614, GPIO_SDA)
//SDA与SCL输出
#define SDA(x)          GPIO_WriteBit(PORT_MLX90614, GPIO_SDA, (x?Bit_SET:Bit_RESET) )
#define SCL(x)          GPIO_WriteBit(PORT_MLX90614, GPIO_SCL, (x?Bit_SET:Bit_RESET) )



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

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

/*
 * 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
 * 开发板官网:www.lckfb.com
 * 技术支持常驻论坛,任何技术问题欢迎随时交流学习
 * 立创论坛:https://oshwhub.com/forum
 * 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
 * 不靠卖板赚钱,以培养中国工程师为己任
 * 

 Change Logs:
 * Date           Author       Notes
 * 2024-03-18     LCKFB-LP    first version
 */
#include "board.h"
#include "bsp_uart.h"
#include <stdio.h>
#include "bsp_mlx90614.h"

int main(void)
{
    
    board_init();
    
    uart1_init(115200U);

    MLX90614_GPIO_Init();
    printf("Start\r\n");
    while(1) 
    {
        float t = MLX90614_Read(0X5A, 0X07);
        if( t != 0)
        {
            printf("temperature = %.2f\r\n", t);
        }
        delay_ms(1000);  
    }
        

}

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

在这里插入图片描述
模块移植成功案例代码:

天空星STM32F407-MLX90614红外无接触测温传感器移植成功案例.zip

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值