• STM32F1读取MLX90632非接触式红外温度传感器


    MLX90632 简介

    MLX90632是一个小型SMD SFN封装中的非接触式红外温度传感器,可实现高精度非接触式温度测量,。该装置在出厂时使用存储在EEPROM存储器中的校准常数进行校准。环境温度和目标温度可根据这些校准常数和测量数据进行计算。
    MLX90632在工厂进行校准,环境温度范围为-20至85摄氏度,目标温度范围为-20至200摄氏度。测量值是传感器视野内所有物体的平均温度。当传感器处于热平衡和恒温条件下(传感器组件之间无温差),应用程序设计者必须了解这些精度是有保证的,并且是可以实现的。
    温度计的准确度可能会受到封装内温度差异的影响,原因包括(除其他外):传感器后面的热电子元件、传感器后面或旁边的加热器/冷却器,或靠近传感器的热/冷物体,不仅加热温度计中的传感元件,还加热温度计封装。
    MLX90632的一个主要优点是通过内部测量算法,将传感器组件周围这些温差的测量效果降至最低。同样,局部热变化(如空气中的湍流)不会在热电堆的输出信号中产生热噪声。但是,有些极端情况会影响传感器。
    MLX90632的典型电源电压为3.3V,与芯片的通信是由I 2 C在快速模式下完成的。通过I 2 C,外部微控制器可以访问以下块:用于测量数据的RAM存储器用于存储微调值、校准常数和设备/测量设置的EEPROM寄存器,以根据该数据控制传感器,外部微控制器可以计算目标温度,如果需要,还可以计算传感器温度。
    传感器中集成了一个光学滤光片(长波通),可切断可见光和近红外辐射通量,以提供环境光抗扰度。该滤光片的波长通带为2~14μm。
    其特性主要有:

    • 高温环境下精准稳定的工作
    • 采用 3mm x 3mm x 1mm DFN 封装,无需采用体积庞大的 TO 罐封装
    • 消费级:测量物体温度为 -20 °C 至 200 °C,精度±1 ℃;医疗级:测量物体温度为-20 °C 至 100 °C,人体温度测量精度高达±0.2 °C
    • 使用 I2C 数字接口进行出厂校准,50° 的视场角
    • 工作温度范围: -20 °C 至 85 °C

    MLX90632 不同型号的异同

    型号MLX90632-BCB-000MLX90632-DCB-000MLX90632-DCB-100
    准确性标准精度医用级精度医用级精度
    I2C电压等级3V31V81V8
    电源电压范围3-5V DC(模块带低压差稳压)
    能耗9.2µA(典型值)12µA(最大值)
    温度工作范围-20°C - 85°C
    输出信号I2C数字接口

    PS: 传感器型号描述:

    mlx90632型号描述

    使用STM32F1单片机驱动MLX90632

    • bsp_mlx90632.c 文件
    /*******************************************************************************
    *   Filename:       bsp_mlx90632.c
    *   Revised:        All copyrights reserved to Roger.
    *   Date:           2020-10-17
    *   Revision:       v1.0
    *   Writer:	        Roger-WY.
    *
    *   Description:    非接触式红外温度传感器模块驱动(数字式)
    *
    *
    *   Notes:          https://www.melexis.com/zh/product/MLX90632/MLX90632
    *   All copyrights reserved to Roger-WY
    *******************************************************************************/
    #include "bsp_mlx90632.h"
    #include 
    
    
    //----------------------------------------------------------------------------//
    #define MLX90632_I2C_SCL_RCC     RCC_APB2Periph_GPIOC
    #define MLX90632_I2C_SCL_PIN	 GPIO_Pin_4			/* 连接到SCL时钟线的GPIO */
    #define MLX90632_I2C_SCL_PORT    GPIOC
    
    #define MLX90632_I2C_SDA_RCC     RCC_APB2Periph_GPIOC
    #define MLX90632_I2C_SDA_PIN	 GPIO_Pin_5			/* 连接到SDA数据线的GPIO */
    #define MLX90632_I2C_SDA_PORT    GPIOC
    
    
    /* 定义读写SCL和SDA的宏 */
    #define MLX90632_I2C_SCL_1()     MLX90632_I2C_SCL_PORT->BSRR = MLX90632_I2C_SCL_PIN			/* SCL = 1 */
    #define MLX90632_I2C_SCL_0()     MLX90632_I2C_SCL_PORT->BRR  = MLX90632_I2C_SCL_PIN			/* SCL = 0 */
    
    #define MLX90632_I2C_SDA_1()     MLX90632_I2C_SDA_PORT->BSRR = MLX90632_I2C_SDA_PIN			/* SDA = 1 */
    #define MLX90632_I2C_SDA_0()     MLX90632_I2C_SDA_PORT->BRR  = MLX90632_I2C_SDA_PIN			/* SDA = 0 */
    
    #define MLX90632_I2C_SDA_READ()  ((MLX90632_I2C_SDA_PORT->IDR & MLX90632_I2C_SDA_PIN) != 0)	/* 读SDA口线状态 */
    #define MLX90632_I2C_SCL_READ()  ((MLX90632_I2C_SCL_PORT->IDR & MLX90632_I2C_SCL_PIN) != 0)	/* 读SCL口线状态 */
    
    #define MLX90632_DELAY_MS(a) bsp_DelayNms(a);
    
    //----------------------------------------------------------------------------//
    #define POW10 10000000000LL
    
    /* 灵敏度 */
    static double emissivity = 0.0;
    
    stMlx90632CalibraParTypeDef stMlxCalibraPar;
    //============================================================================//
    
    
    /*
    ********************************************************************************
    *	函 数 名: Mlx90632_i2c_Delay
    *	功能说明: I2C总线位延迟,最快400KHz
    *	形    参:  无
    *	返 回 值: 无
    ********************************************************************************
    */
    static void Mlx90632_i2c_Delay(void)
    {
        volatile uint8_t i;
    
        for(i = 0; i < 50; i++);
    }
    
    
    static void Mlx90632_i2c_Start(void)
    {
        /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
        MLX90632_I2C_SDA_1();
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SCL_1();
        Mlx90632_i2c_Delay();
    
        MLX90632_I2C_SDA_0();
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SCL_0();
    //	Mlx90632_i2c_Delay();
    }
    
    /*******************************************************************************
     * 名    称: i2c_Stop
     * 功    能: CPU发起I2C总线停止信号
     * 入口参数: 无
     * 出口参数: 无
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注: 停止时序
     *            SCL _____/ˉˉˉˉˉˉˉ
     *            SDA _________/ˉˉˉˉˉ
     *                       |   |
     *                       STOP
     *******************************************************************************/
    static void Mlx90632_i2c_Stop(void)
    {
        /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
    
        MLX90632_I2C_SCL_0();
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SDA_0();
        Mlx90632_i2c_Delay();
    
        MLX90632_I2C_SCL_1();
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SDA_1();
    //	Mlx90632_i2c_Delay();
    }
    
    /*******************************************************************************
     * 名    称: i2c_WaitAck
     * 功    能: CPU产生一个时钟,并读取器件的ACK应答信号
     * 入口参数: 无
     * 出口参数: 返回0表示正确应答,1表示无器件响应
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    static uint8_t Mlx90632_i2c_WaitAck(void)
    {
        uint8_t re;
        uint8_t TimeOutCnt = 20;  /* 超时计数器 */
    
        MLX90632_I2C_SDA_1();	/* CPU释放SDA总线 */
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SCL_1();	/* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
        Mlx90632_i2c_Delay();
    
        while(TimeOutCnt --)
        {
            if(MLX90632_I2C_SDA_READ())	  /* CPU读取SDA口线状态 */
            {
                re = 1;
            }
            else
            {
                re = 0;
            }
        }
        MLX90632_I2C_SCL_0();
        Mlx90632_i2c_Delay();
        return re;
    }
    
    /*******************************************************************************
     * 名    称: i2c_Ack
     * 功    能: CPU产生一个ACK信号
     * 入口参数: 无
     * 出口参数: 无
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    static void Mlx90632_i2c_Ack(void)
    {
        MLX90632_I2C_SDA_0();	/* CPU驱动SDA = 0 */
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SCL_1();	/* CPU产生1个时钟 */
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SCL_0();
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SDA_1();	/* CPU释放SDA总线 */
    }
    
    /*******************************************************************************
     * 名    称: i2c_NAck
     * 功    能: CPU产生1个NACK信号
     * 入口参数: 无
     * 出口参数: 无
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    static void Mlx90632_i2c_NAck(void)
    {
        MLX90632_I2C_SDA_1();	/* CPU驱动SDA = 1 */
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SCL_1();	/* CPU产生1个时钟 */
        Mlx90632_i2c_Delay();
        MLX90632_I2C_SCL_0();
        Mlx90632_i2c_Delay();
    }
    
    /*******************************************************************************
    * 名    称: bsp_InitI2C
    * 功    能: 配置I2C总线的GPIO,采用模拟IO的方式实现
    * 入口参数: 无
    * 出口参数: 无
    * 作  者: Roger-WY
    * 创建日期: 2018-06-29
    * 修    改:
    * 修改日期:
    * 备    注:
    *******************************************************************************/
    static void Mlx90632_InitI2C(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        RCC_APB2PeriphClockCmd(MLX90632_I2C_SCL_RCC | MLX90632_I2C_SDA_RCC, ENABLE);	/* 打开GPIO时钟 */
    
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_OD;	        /* 开漏输出模式 */
    
        GPIO_InitStructure.GPIO_Pin = MLX90632_I2C_SCL_PIN;
        GPIO_Init(MLX90632_I2C_SCL_PORT, &GPIO_InitStructure);
    
        GPIO_InitStructure.GPIO_Pin = MLX90632_I2C_SDA_PIN;
        GPIO_Init(MLX90632_I2C_SDA_PORT, &GPIO_InitStructure);
    
        /* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */
        Mlx90632_i2c_Stop();
    }
    
    /*******************************************************************************
     * 名    称: i2c_SendByte
     * 功    能: CPU向I2C总线设备发送8bit数据
     * 入口参数: _ucByte : 等待发送的字节
     * 出口参数: 无
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    static void Mlx90632_i2c_SendByte(uint8_t _ucByte)
    {
        uint8_t i;
    
        /* 先发送字节的高位bit7 */
        for(i = 0; i < 8; i++)
        {
            MLX90632_I2C_SCL_0();
            Mlx90632_i2c_Delay();
    
            if(_ucByte & 0x80)
            {
                MLX90632_I2C_SDA_1();
            }
            else
            {
                MLX90632_I2C_SDA_0();
            }
    
            _ucByte <<= 1;	/* 左移一个bit */
    
            Mlx90632_i2c_Delay();
    
            MLX90632_I2C_SCL_1();
            Mlx90632_i2c_Delay();
        }
        MLX90632_I2C_SCL_0();
        Mlx90632_i2c_Delay();
    
    }
    
    /*******************************************************************************
     * 名    称: Mlx90632_i2c_ReadByte
     * 功    能: CPU从I2C总线设备读取8bit数据
     * 入口参数: 无
     * 出口参数: 读到的数据
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    static uint8_t Mlx90632_i2c_ReadByte(void)
    {
        uint8_t i;
        uint8_t value;
    
        /* 读到第1个bit为数据的bit7 */
        value = 0;
        for(i = 0; i < 8; i++)
        {
            value <<= 1;
            MLX90632_I2C_SCL_0();
            Mlx90632_i2c_Delay();
            MLX90632_I2C_SCL_1();
            Mlx90632_i2c_Delay();
    
            if(MLX90632_I2C_SDA_READ())
            {
                value++;
            }
        }
        MLX90632_I2C_SCL_0();
        Mlx90632_i2c_Delay();
    
        return value;
    }
    
    
    //============================================================================//
    
    
    /*******************************************************************************
    * 名    称: bsp_Mlx90632Init
    * 功    能: Mlx90632传感器的初始化
    * 入口参数: 无
    * 出口参数: 无
    * 作  者: Roger-WY.
    * 创建日期: 2018-08-08
    * 修    改:
    * 修改日期:
    * 备    注:
    *******************************************************************************/
    int8_t bsp_Mlx90632Init(void)
    {
        int8_t ucError      = 0;
    
        Mlx90632_InitI2C();
    
        bsp_Mlx90632ReadCalibraParInit(&stMlxCalibraPar);
    
        ucError = bsp_Mlx90632ReadCalibraParFromEeprom(&stMlxCalibraPar);
        return (ucError);
    
    }
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632WriteReg
     * 功    能: 对寄存器写值
     * 入口参数: devAddr:设备地址 regAddr:寄存器地址 data:写入寄存器的值
     * 出口参数: 读到的数据
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int8_t bsp_Mlx90632WriteReg(uint8_t devAddr, uint16_t regAddr, uint16_t data)
    {
        uint8_t ucAck = 0;
        uint8_t sendBuffer[5] = {0}; //used to save the data to send
    
        sendBuffer[0] = devAddr << 1;
        sendBuffer[1] = (uint8_t)(regAddr >> 8);
        sendBuffer[2] = (uint8_t)regAddr;
        sendBuffer[3] = (uint8_t)(data >> 8);
        sendBuffer[4] = (uint8_t)data;
    
        Mlx90632_i2c_Start();
        for(uint8_t i = 0; i < 5; i ++)
        {
            Mlx90632_i2c_SendByte(sendBuffer[i]);
            ucAck = Mlx90632_i2c_WaitAck();
            if(ucAck)           /* 如果Mlx90632,没有应答 */
            {
                goto cmd_fail;	/* 器件无应答 */
            }
        }
        /* 发送I2C总线停止信号 */
        Mlx90632_i2c_Stop();
        return 0;	/* 执行成功 */
    
    cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
        /* 发送I2C总线停止信号 */
        Mlx90632_i2c_Stop();
        return -1;
    
    }
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadReg
     * 功    能: 从寄存器里读值
     * 入口参数: devAddr:设备地址 regAddr:寄存器地址 ppBuf:读取寄存器值的缓存区 nBytes:读取寄存器的字节数
     * 出口参数: 读到的数据
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int8_t bsp_Mlx90632ReadReg(uint8_t devAddr, uint16_t regAddr, uint8_t* ppBuf, uint8_t nBytes)
    {
        uint8_t ucAck = 0;
        uint8_t ValBuf[6] = {0};
        uint8_t prcRegVal = 0;
        uint8_t i = 0;
    
        ValBuf[0] = devAddr << 1;
        ValBuf[1] = (uint8_t)(regAddr >> 8);
        ValBuf[2] = (uint8_t)regAddr;
    
        ValBuf[3] = (devAddr << 1) | 0x01;
    
    
        Mlx90632_i2c_Start();
        for(i = 0; i < 3; i++)
        {
            Mlx90632_i2c_SendByte(ValBuf[i]);
            ucAck = Mlx90632_i2c_WaitAck();
            if(ucAck)           /* 如果没有应答 */
            {
                goto cmd_fail;	/* 器件无应答 */
            }
        }
    
        //------------------------------------------------------------------------//
        Mlx90632_i2c_Start();
        Mlx90632_i2c_SendByte(ValBuf[3]);
        ucAck = Mlx90632_i2c_WaitAck();
        if(ucAck)           /* 如果没有应答 */
        {
            goto cmd_fail;	/* 器件无应答 */
        }
    
        while(nBytes)
        {
            *ppBuf = Mlx90632_i2c_ReadByte();
            if(nBytes == 1)
                Mlx90632_i2c_NAck();
            else
                Mlx90632_i2c_Ack();
    
            nBytes--;
            ppBuf++;
        }
    
        /* 发送I2C总线停止信号 */
        Mlx90632_i2c_Stop();
        return 0;
    
    cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
        /* 发送I2C总线停止信号 */
        Mlx90632_i2c_Stop();
        return -1;
    }
    
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadWord
     * 功    能: 从寄存器里读一个字(16-bit)
     * 入口参数: regAddr:寄存器地址 value:读取寄存器值的缓存区
     * 出口参数: 0:读取成功 其他值,读取失败
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int8_t bsp_Mlx90632ReadWord(uint16_t regAddr, uint16_t* value)
    {
        int8_t ret = 0;
        uint8_t buf[2] = {0};
        ret = bsp_Mlx90632ReadReg(MLX90632_ADDR, regAddr, buf, 2);
        *value = buf[1] | (buf[0] << 8);
        return ret;
    }
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadDoubleWord
     * 功    能: 从寄存器里读双字(32-bit)
     * 入口参数: regAddr:寄存器地址 value:读取寄存器值的缓存区
     * 出口参数: 0:读取成功 其他值,读取失败
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int8_t bsp_Mlx90632ReadDoubleWord(uint16_t regAddr, uint32_t* value)
    {
        int8_t ret = 0;
        uint8_t buf[4] = {0};
        ret = bsp_Mlx90632ReadReg(MLX90632_ADDR, regAddr, buf, 4);
        *value = buf[2] << 24 | buf[3] << 16 | buf[0] << 8 | buf[1];
        return ret;
    }
    /*******************************************************************************
     * 名    称: bsp_Mlx90632WriteWord
     * 功    能: 往寄存器里写入一个字(16-bit)
     * 入口参数: regAddr:寄存器地址 value:读取寄存器值的缓存区
     * 出口参数: 0:读取成功 其他值,读取失败
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int8_t bsp_Mlx90632WriteWord(uint16_t regAddr, uint16_t data)
    {
        int8_t ret = 0;
        ret = bsp_Mlx90632WriteReg(MLX90632_ADDR, regAddr, data) ;
        return (ret);
    }
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadCalibraParInit
     * 功    能: 校准参数初始化,如果eeprom的校准参数读出来为空,就是使用此默认值
     * 入口参数: pPar:校准参数结构体指针
     * 出口参数: 无
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    void bsp_Mlx90632ReadCalibraParInit(stMlx90632CalibraParTypeDef* pPar)
    {
        pPar->PR = 0x00587f5b;
        pPar->PG = 0x04a10289;
        pPar->PT = 0xfff966f8;
        pPar->PO = 0x00001e0f;
        pPar->Ea = 4859535;
        pPar->Eb = 5686508;
        pPar->Fa = 53855361;
        pPar->Fb = 42874149;
        pPar->Ga = -14556410;
        pPar->Ha = 16384;
        pPar->Hb = 0;
        pPar->Gb = 9728;
        pPar->Ka = 10752;
    }
    
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadCalibraParFromEeprom
     * 功    能: 从传感器内部EEPROM中读取校准参数
     * 入口参数: pPar:校准参数结构体指针
     * 出口参数: 无
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int8_t bsp_Mlx90632ReadCalibraParFromEeprom(stMlx90632CalibraParTypeDef* pPar)
    {
        int8_t ret = 0;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_P_R, (uint32_t*)&pPar->PR);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_P_G, (uint32_t*)&pPar->PG);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_P_O, (uint32_t*)&pPar->PO);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_P_T, (uint32_t*)&pPar->PT);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_Ea, (uint32_t*)&pPar->Ea);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_Eb, (uint32_t*)&pPar->Eb);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_Fa, (uint32_t*)&pPar->Fa);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_Fb, (uint32_t*)&pPar->Fb);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadDoubleWord(MLX90632_EE_Ga, (uint32_t*)&pPar->Ga);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadWord(MLX90632_EE_Gb, (uint16_t*)&pPar->Gb);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadWord(MLX90632_EE_Ha, (uint16_t*)&pPar->Ha);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadWord(MLX90632_EE_Hb, (uint16_t*)&pPar->Hb);
        if(ret < 0)
            return ret;
        ret = bsp_Mlx90632ReadWord(MLX90632_EE_Ka, (uint16_t*)&pPar->Ka);
        if(ret < 0)
            return ret;
        return 0;
    }
    
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632StartMeasurement
     * 功    能: 触发传感器开始测量,但是只是触发测量周期,等待数据准备就绪,它不读取任何内容,只是触发并等待完成。
     * 入口参数: 无
     * 出口参数: 无
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注: 此处超时等待是阻塞的
     *******************************************************************************/
    int bsp_Mlx90632StartMeasurement(void)
    {
        int ret, tries = 100;
        uint16_t reg_status;
    
        ret = bsp_Mlx90632ReadWord(MLX90632_REG_STATUS, &reg_status);
        if(ret < 0)
            return ret;
    
        ret = bsp_Mlx90632WriteWord(MLX90632_REG_STATUS, reg_status & (~MLX90632_STAT_DATA_RDY));
        if(ret < 0)
            return ret;
    
        while(tries-- > 0)
        {
            ret = bsp_Mlx90632ReadWord(MLX90632_REG_STATUS, &reg_status);
            if(ret < 0)
                return ret;
            if(reg_status & MLX90632_STAT_DATA_RDY)
                break;
            /* minimum wait time to complete measurement
             * should be calculated according to refresh rate
             * atm 10ms - 11ms
             */
            //usleep(10000, 11000);
            MLX90632_DELAY_MS(10);  //提供延时函数,此处延时10ms左右
        }
    
        if(tries < 0)
        {
            // data not ready
            return -ETIMEDOUT;
        }
    
        return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
    }
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ChannelNewSelect
     * 功    能: 根据 bsp_Mlx90632StartMeasurement 的返回值,获取通道的顺序。
     * 入口参数: ret:bsp_Mlx90632StartMeasurement 的返回值  *channel_new:指向存储新通道值的内存位置的指针 *channel_new:指向存储旧通道值的内存位置的指针
     * 出口参数: 0:正常
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注: 如果返回值不是1/2 则不分配通道序列
     *******************************************************************************/
    int32_t bsp_Mlx90632ChannelNewSelect(int32_t ret, uint8_t* channel_new, uint8_t* channel_old)
    {
        switch(ret)
        {
        case 1:
            *channel_new = 1;
            *channel_old = 2;
            break;
    
        case 2:
            *channel_new = 2;
            *channel_old = 1;
            break;
    
        default:
            return -EINVAL;
        }
        return 0;
    }
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadTempAmbientRaw
     * 功    能: 读取环境原始旧值和新值
     * 入口参数: ambient_new_raw:原始环境温度新值  ambient_old_raw:原始环境温度旧值
     * 出口参数: 0:正常
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int32_t bsp_Mlx90632ReadTempAmbientRaw(int16_t* ambient_new_raw, int16_t* ambient_old_raw)
    {
        int32_t ret;
        uint16_t read_tmp;
    
        ret = bsp_Mlx90632ReadWord(MLX90632_RAM_3(1), &read_tmp);
        if(ret < 0)
            return ret;
        *ambient_new_raw = (int16_t)read_tmp;
    
        ret = bsp_Mlx90632ReadWord(MLX90632_RAM_3(2), &read_tmp);
        if(ret < 0)
            return ret;
        *ambient_old_raw = (int16_t)read_tmp;
    
        return ret;
    }
    
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadTempObjectRaw
     * 功    能: 读取对象原始温度新值和旧值
     * 入口参数: start_measurement_ret: 返回值 object_new_raw:物体原始温度新值  object_old_raw:物体原始温度旧值
     * 出口参数: 0:正常
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int32_t bsp_Mlx90632ReadTempObjectRaw(int32_t start_measurement_ret,
                                          int16_t* object_new_raw, int16_t* object_old_raw)
    {
        int32_t ret;
        uint16_t read_tmp;
        int16_t read;
        uint8_t channel, channel_old;
    
        ret = bsp_Mlx90632ChannelNewSelect(start_measurement_ret, &channel, &channel_old);
        if(ret != 0)
            return -EINVAL;
    
        ret = bsp_Mlx90632ReadWord(MLX90632_RAM_2(channel), &read_tmp);
        if(ret < 0)
            return ret;
    
        read = (int16_t)read_tmp;
    
        ret = bsp_Mlx90632ReadWord(MLX90632_RAM_1(channel), &read_tmp);
        if(ret < 0)
            return ret;
        *object_new_raw = (read + (int16_t)read_tmp) / 2;
    
        ret = bsp_Mlx90632ReadWord(MLX90632_RAM_2(channel_old), &read_tmp);
        if(ret < 0)
            return ret;
        read = (int16_t)read_tmp;
    
        ret = bsp_Mlx90632ReadWord(MLX90632_RAM_1(channel_old), &read_tmp);
        if(ret < 0)
            return ret;
        *object_old_raw = (read + (int16_t)read_tmp) / 2;
    
        return ret;
    }
    /*******************************************************************************
     * 名    称: bsp_Mlx90632ReadTempRaw
     * 功    能: 读取温度原始值
     * 入口参数: ambient_new_raw:环境原始温度新值  ambient_old_raw:环境原始温度旧值
    *             object_new_raw:物体原始温度新值  object_old_raw:物体原始温度旧值
     * 出口参数: 0:正常
     * 作  者: Roger-WY
     * 创建日期: 2022-05-04
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int32_t bsp_Mlx90632ReadTempRaw(int16_t* ambient_new_raw, int16_t* ambient_old_raw,
                                    int16_t* object_new_raw, int16_t* object_old_raw)
    {
        int32_t ret, start_measurement_ret;
    
        // trigger and wait for measurement to complete
        start_measurement_ret = bsp_Mlx90632StartMeasurement();
        if(start_measurement_ret < 0)
            return start_measurement_ret;
    
        /** Read new and old **ambient** values from sensor */
        ret = bsp_Mlx90632ReadTempAmbientRaw(ambient_new_raw, ambient_old_raw);
        if(ret < 0)
            return ret;
    
        /** Read new and old **object** values from sensor */
        ret = bsp_Mlx90632ReadTempObjectRaw(start_measurement_ret, object_new_raw, object_old_raw);
    
        return ret;
    }
    
    /* DSPv5 */
    double bsp_Mlx90632PreprocessTempAmbient(int16_t ambient_new_raw, int16_t ambient_old_raw, int16_t Gb)
    {
        double VR_Ta, kGb;
    
        kGb = ((double)Gb) / 1024.0;
    
        VR_Ta = ambient_old_raw + kGb * (ambient_new_raw / (MLX90632_REF_3));
        return ((ambient_new_raw / (MLX90632_REF_3)) / VR_Ta) * 524288.0;
    }
    
    double bsp_Mlx90632PreprocessTempObject(int16_t object_new_raw, int16_t object_old_raw,
                                            int16_t ambient_new_raw, int16_t ambient_old_raw,
                                            int16_t Ka)
    {
        double VR_IR, kKa;
    
        kKa = ((double)Ka) / 1024.0;
    
        VR_IR = ambient_old_raw + kKa * (ambient_new_raw / (MLX90632_REF_3));
        return ((((object_new_raw + object_old_raw) / 2) / (MLX90632_REF_12)) / VR_IR) * 524288.0;
    }
    
    double bsp_Mlx90632CalcTempAmbient(int16_t ambient_new_raw, int16_t ambient_old_raw, int32_t P_T,
                                       int32_t P_R, int32_t P_G, int32_t P_O, int16_t Gb)
    {
        double Asub, Bsub, Ablock, Bblock, Cblock, AMB;
    
        AMB = bsp_Mlx90632PreprocessTempAmbient(ambient_new_raw, ambient_old_raw, Gb);
    
        Asub = ((double)P_T) / (double)17592186044416.0;
        Bsub = (double)AMB - ((double)P_R / (double)256.0);
        Ablock = Asub * (Bsub * Bsub);
        Bblock = (Bsub / (double)P_G) * (double)1048576.0;
        Cblock = (double)P_O / (double)256.0;
    
        return Bblock + Ablock + Cblock;
    }
    
    
    /*******************************************************************************
    * 名    称: bsp_Mlx90632CalcTempObjectIteration
    * 功    能: 物体温度的迭代计算
    * 入口参数: prev_object_temp: 上次计算的物体温度值,如果没有,默认为25.0摄氏度
    *            object: 通过 bsp_Mlx90632PreprocessTempObject 函数获取的物体温度值
    *            剩余的参数都是校正值
    * 出口参数: 0:正常
    * 作  者: Roger-WY
    * 创建日期: 2022-05-04
    * 修    改:
    * 修改日期:
    * 备    注:
    *******************************************************************************/
    static double bsp_Mlx90632CalcTempObjectIteration(double prev_object_temp, int32_t object, double TAdut,
            int32_t Ga, int32_t Fa, int32_t Fb, int16_t Ha, int16_t Hb,
            double emissivity)
    {
        double calcedGa, calcedGb, calcedFa, TAdut4, first_sqrt;
        // temp variables
        double KsTAtmp, Alpha_corr;
        double Ha_customer, Hb_customer;
    
    
        Ha_customer = Ha / ((double)16384.0);
        Hb_customer = Hb / ((double)1024.0);
        calcedGa = ((double)Ga * (prev_object_temp - 25)) / ((double)68719476736.0);
        KsTAtmp = (double)Fb * (TAdut - 25);
        calcedGb = KsTAtmp / ((double)68719476736.0);
        Alpha_corr = (((double)(Fa * POW10)) * Ha_customer * (double)(1 + calcedGa + calcedGb)) /
                     ((double)70368744177664.0);
        calcedFa = object / (emissivity * (Alpha_corr / POW10));
        TAdut4 = (TAdut + 273.15) * (TAdut + 273.15) * (TAdut + 273.15) * (TAdut + 273.15);
    
        first_sqrt = sqrt(calcedFa + TAdut4);
    
        return sqrt(first_sqrt) - 273.15 - Hb_customer;
    }
    
    
    void bsp_Mlx90632SetEmissivity(double value)
    {
        emissivity = value;
    }
    
    double bsp_mlx90632GetEmissivity(void)
    {
        if(emissivity == 0.0)
        {
            return 1.0;
        }
        else
        {
            return emissivity;
        }
    }
    
    double bsp_Mlx90632CalcTempObject(int32_t object, int32_t ambient,
                                      int32_t Ea, int32_t Eb, int32_t Ga, int32_t Fa, int32_t Fb,
                                      int16_t Ha, int16_t Hb)
    {
        double kEa, kEb, TAdut;
        double temp = 25.0;
        double tmp_emi = bsp_mlx90632GetEmissivity();
        int8_t i;
    
        kEa = ((double)Ea) / ((double)65536.0);
        kEb = ((double)Eb) / ((double)256.0);
        TAdut = (((double)ambient) - kEb) / kEa + 25;
    
        //iterate through calculations
        for(i = 0; i < 5; ++i)
        {
            temp = bsp_Mlx90632CalcTempObjectIteration(temp, object, TAdut, Ga, Fa, Fb, Ha, Hb, tmp_emi);
        }
        return temp;
    }
    
    
    
    /***************************** (END OF FILE) **********************************/
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771
    • 772
    • 773
    • 774
    • 775
    • 776
    • 777
    • 778
    • 779
    • 780
    • 781
    • 782
    • 783
    • 784
    • 785
    • 786
    • 787
    • 788
    • 789
    • 790
    • 791
    • 792
    • 793
    • 794
    • 795
    • 796
    • 797
    • 798
    • 799
    • 800
    • 801
    • 802
    • 803
    • 804
    • 805
    • 806
    • 807
    • 808
    • 809
    • 810
    • 811
    • 812
    • 813
    • 814
    • 815
    • 816
    • 817
    • 818
    • 819
    • 820
    • 821
    • 822
    • 823
    • 824
    • 825
    • 826
    • 827
    • 828
    • 829
    • 830
    • 831
    • 832
    • 833
    • 834
    • 835
    • 836
    • 837
    • 838
    • 839
    • 840
    • 841
    • 842
    • 843
    • 844
    • 845
    • 846
    • 847
    • 848
    • 849
    • 850
    • 851
    • 852
    • 853
    • 854
    • 855
    • 856
    • 857
    • 858
    • 859
    • 860
    • 861
    • 862
    • 863
    • 864
    • 865
    • 866
    • 867
    • 868
    • 869
    • 870
    • 871
    • 872
    • 873
    • 874
    • 875
    • 876
    • 877
    • 878
    • 879
    • 880
    • 881
    • 882
    • 883
    • 884
    • 885
    • 886
    • 887
    • 888
    • bsp_mlx90632.h 文件
    /*******************************************************************************
    *   Filename:       bsp_mlx90632.h
    *   Revised:        All copyrights reserved to Roger.
    *   Date:           2022-05-02
    *   Revision:       v1.0
    *   Writer:	        Roger-WY.
    *
    *   Description:    非接触式红外温度传感器模块驱动(数字式)  头文件
    *******************************************************************************/
    #ifndef __BSP_MLX90632_H__
    #define __BSP_MLX90632_H__
    
    #include "stm32f10x.h"
    #include "bsp_timer.h"
    
    #define MLX90632_TEMP_READ_ERR_CODE -99
    /* Solve errno not defined values */
    #ifndef ETIMEDOUT
    #define ETIMEDOUT 110 /**< From linux errno.h */
    #endif
    #ifndef EINVAL
    #define EINVAL 22 /**< From linux errno.h */
    #endif
    #ifndef EPROTONOSUPPORT
    #define EPROTONOSUPPORT 93 /**< From linux errno.h */
    #endif
    
    typedef struct __mlx90632calibrationpar
    {
        int32_t PR;
        int32_t PG;
        int32_t PO;
        int32_t PT;
        int32_t Ea;
        int32_t Eb;
        int32_t Fa;
        int32_t Fb;
        int32_t Ga;
        int16_t Gb;
        int16_t Ha;
        int16_t Hb;
        int16_t Ka;
    }stMlx90632CalibraParTypeDef;
    
    /* MLX90632 内部寄存器地址定义 */
    /* Private defines -----------------------------------------------------------*/
    /* Definition of I2C address of MLX90632 */
    #define MLX90632_ADDR       0x3A
    #define MLX90632_ADDR_WR   (MLX90632_ADDR << 1)
    
    #define BITS_PER_LONG 32
    
    /* BIT, GENMASK and ARRAY_SIZE macros are imported from kernel */
    #ifndef BIT
    #define BIT(x) (1UL << (x))
    #endif
    #ifndef GENMASK
    #ifndef BITS_PER_LONG
    #warning "Using default BITS_PER_LONG value"
    #define BITS_PER_LONG 64 /**< Define how many bits per long your CPU has */
    #endif
    #define GENMASK(h, l) \
        (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
    #endif
    #ifndef ARRAY_SIZE
    #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) /**< Return number of elements in array */
    #endif
    
    /* Memory sections addresses */
    #define MLX90632_ADDR_RAM   0x4000 /**< Start address of ram */
    #define MLX90632_ADDR_EEPROM    0x2480 /**< Start address of user eeprom */
    
    /* EEPROM addresses - used at startup */
    #define MLX90632_EE_CTRL    0x24d4 /**< Control register initial value */
    #define MLX90632_EE_CONTROL MLX90632_EE_CTRL /**< More human readable for Control register */
    
    #define MLX90632_EE_I2C_ADDRESS 0x24d5 /**< I2C address register initial value */
    #define MLX90632_EE_VERSION 0x240b /**< EEPROM version reg - assumed 0x101 */
    
    #define MLX90632_EE_P_R     0x240c /**< Calibration constant ambient reference register 32bit */
    #define MLX90632_EE_P_G     0x240e /**< Calibration constant ambient gain register 32bit */
    #define MLX90632_EE_P_T     0x2410 /**< Calibration constant ambient tc2 register 32bit	*/
    #define MLX90632_EE_P_O     0x2412 /**< Calibration constant ambient offset register 32bit */
    #define MLX90632_EE_Aa      0x2414 /**< Aa calibration const register 32bit */
    #define MLX90632_EE_Ab      0x2416 /**< Ab calibration const register 32bit */
    #define MLX90632_EE_Ba      0x2418 /**< Ba calibration const register 32bit */
    #define MLX90632_EE_Bb      0x241a /**< Bb calibration const register 32bit */
    #define MLX90632_EE_Ca      0x241c /**< Ca calibration const register 32bit */
    #define MLX90632_EE_Cb      0x241e /**< Cb calibration const register 32bit */
    #define MLX90632_EE_Da      0x2420 /**< Da calibration const register 32bit */
    #define MLX90632_EE_Db      0x2422 /**< Db calibration const register 32bit */
    #define MLX90632_EE_Ea      0x2424 /**< Ea calibration constant register 32bit */
    #define MLX90632_EE_Eb      0x2426 /**< Eb calibration constant register 32bit */
    #define MLX90632_EE_Fa      0x2428 /**< Fa calibration constant register 32bit */
    #define MLX90632_EE_Fb      0x242a /**< Fb calibration constant register 32bit */
    #define MLX90632_EE_Ga      0x242c /**< Ga calibration constant register 32bit */
    
    #define MLX90632_EE_Gb      0x242e /**< Ambient Beta calibration constant 16bit */
    #define MLX90632_EE_Ka      0x242f /**< IR Beta calibration constant 16bit */
    
    #define MLX90632_EE_Ha      0x2481 /**< Ha customer calibration value register 16bit */
    #define MLX90632_EE_Hb      0x2482 /**< Hb customer calibration value register 16bit */
    
    /* Register addresses - volatile */
    #define MLX90632_REG_I2C_ADDR   0x3000 /**< Chip I2C address register */
    
    /* Control register address - volatile */
    #define MLX90632_REG_CTRL   0x3001 /**< Control Register address */
    #define MLX90632_CFG_SOC_SHIFT 3 /**< Start measurement in step mode */
    #define MLX90632_CFG_SOC_MASK BIT(MLX90632_CFG_SOC_SHIFT)
    #define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /**< PowerMode Mask */
    /* PowerModes statuses */
    #define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
    #define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /**< Pwrmode hold */
    #define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /**< Pwrmode sleep step*/
    #define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /**< Pwrmode step */
    #define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /**< Pwrmode continuous*/
    
    /* Device status register - volatile */
    #define MLX90632_REG_STATUS         0x3fff /**< Device status register */
    #define MLX90632_STAT_BUSY          BIT(10) /**< Device busy indicator */
    #define MLX90632_STAT_EE_BUSY       BIT(9) /**< Device EEPROM busy indicator */
    #define MLX90632_STAT_BRST          BIT(8) /**< Device brown out reset indicator */
    #define MLX90632_STAT_CYCLE_POS     GENMASK(6, 2) /**< Data position in measurement table */
    #define MLX90632_STAT_DATA_RDY      BIT(0) /**< Data ready indicator */
    
    /* RAM_MEAS address-es for each channel */
    #define MLX90632_RAM_1(meas_num)    (MLX90632_ADDR_RAM + 3 * meas_num)
    #define MLX90632_RAM_2(meas_num)    (MLX90632_ADDR_RAM + 3 * meas_num + 1)
    #define MLX90632_RAM_3(meas_num)    (MLX90632_ADDR_RAM + 3 * meas_num + 2)
    
    /* Timings (ms) */
    #define MLX90632_TIMING_EEPROM      100 /**< Time between EEPROM writes */
    
    /* Magic constants */
    #define MLX90632_EEPROM_VERSION     0x105 /**< EEPROM DSP version for constants */
    #define MLX90632_EEPROM_WRITE_KEY   0x554C /**< EEPROM write key 0x55 and 0x4c */
    #define MLX90632_RESET_CMD          0x0006 /**< Reset sensor (address or global) */
    #define MLX90632_MAX_MEAS_NUM       31 /**< Maximum number of measurements in list */
    #define MLX90632_EE_SEED            0x3f6d /**< Seed for the CRC calculations */
    #define MLX90632_REF_12             12.0 /**< ResCtrlRef value of Channel 1 or Channel 2 */
    #define MLX90632_REF_3              12.0 /**< ResCtrlRef value of Channel 3 */
    
    
    /* MLX90632 供外部调用函数 */
    int8_t bsp_Mlx90632Init(void);
    int8_t bsp_Mlx90632ReadCalibraParFromEeprom(stMlx90632CalibraParTypeDef *pPar);
    void bsp_Mlx90632ReadCalibraParInit(stMlx90632CalibraParTypeDef *pPar);
    int bsp_Mlx90632StartMeasurement(void);
    int32_t bsp_Mlx90632ChannelNewSelect(int32_t ret, uint8_t *channel_new, uint8_t *channel_old);
    int32_t bsp_Mlx90632ReadTempAmbientRaw(int16_t *ambient_new_raw, int16_t *ambient_old_raw);
    void bsp_Mlx90632SetEmissivity(double value);
    double bsp_Mlx90632CalcTempObject(int32_t object, int32_t ambient,
                                     int32_t Ea, int32_t Eb, int32_t Ga, int32_t Fa, int32_t Fb,
                                     int16_t Ha, int16_t Hb);
    double bsp_Mlx90632CalcTempAmbient(int16_t ambient_new_raw, int16_t ambient_old_raw, int32_t P_T,
                                      int32_t P_R, int32_t P_G, int32_t P_O, int16_t Gb);
    double bsp_Mlx90632PreprocessTempObject(int16_t object_new_raw, int16_t object_old_raw,
                                           int16_t ambient_new_raw, int16_t ambient_old_raw,
                                           int16_t Ka);
    double bsp_Mlx90632PreprocessTempAmbient(int16_t ambient_new_raw, int16_t ambient_old_raw, int16_t Gb);
    int32_t bsp_Mlx90632ReadTempRaw(int16_t *ambient_new_raw, int16_t *ambient_old_raw,
                                   int16_t *object_new_raw, int16_t *object_old_raw);
    
    extern stMlx90632CalibraParTypeDef stMlxCalibraPar;
    
    #endif
    /***************************** (END OF FILE) **********************************/
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • main 函数读取温度
    /*******************************************************************************
     *   Filename:       main.c
     *   Revised:        All copyrights reserved to Roger-WY.
     *   Revision:       v1.0
     *   Writer:	     Roger-WY.
     *
     *   Description:    主函数模块
     *
     *   Notes:
     *     				E-mail:261313062@qq.com
     *
     *******************************************************************************/
    
    
    /***************************头文件声明区***************************************/
    
    #include "includes.h"
    #include "app_var.h"
    
    #include "bsp_mlx90632.h"
    
    /********************************宏定义区**************************************/
    /* 定义例程名和例程发布日期 */
    #define EXAMPLE_NAME	"STM32F103XXX_MLX90632_Demo"
    #define EXAMPLE_DATE	"2022-05-02"
    #define DEMO_VER		"1.0.0"
    
    /***************************变量定义及声明区***********************************/
    
    double pre_ambient, pre_object, ambient, object;
    stMlx90632CalibraParTypeDef stmlxCalibraPar = {0};
    
    /***************************函数定义及声明区***********************************/
    void app_SeggerRttInit(void);
    static void app_ShowPowerOnInfo(void);
    
    
    /*============================================================================*/
    /*============================================================================*/
    /*============================================================================*/
    
    
    /*******************************************************************************
     * 名    称: main
     * 功    能: 主函数
     * 入口参数: 无
     * 出口参数: 无
     * 作  者: Roger-WY.
     * 创建日期: 2015-06-25
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    int main(void)
    {
    	int16_t ambient_new_raw;
    	int16_t ambient_old_raw;
    	int16_t object_new_raw;
    	int16_t object_old_raw;
        /***********************************************
        * 描述: 初始化硬件设备
        */
        bsp_Init(); /* 为了是main函数看起来更简洁些,将硬件初始化的代码封装到这个函数 */
    
        bsp_Mlx90632Init();
        
        /***********************************************
        * 描述:打印上电信息
        */
        app_SeggerRttInit();
    	app_ShowPowerOnInfo();
    
        /***********************************************
        * 描述: 创建软定时器
        */
        bsp_StartAutoTimer( 0,1000 );   /* 启动自动重载软定时器0 用于1S定时任务 */
        /***********************************************
        * 描述: 进入主程序循环体
        */
        while(1)
        {
            /***********************************************
            * 描述:用户可以在此函数内执行CPU休眠和喂狗等
            * 这个函数在bsp.c 中定义。
            */
            bsp_Idle();                                     /* 调用MODS_Poll() */
    
            /*   用户执行的任务    */
            /*   1S定时到    */
            if(bsp_CheckTimer(0)) {
                bsp_LedToggle(1);  /* 翻转LED1 */
                
                /* Get raw data from MLX90632 */
                bsp_Mlx90632ReadTempRaw(&ambient_new_raw, &ambient_old_raw, &object_new_raw, &object_old_raw);
                /* Pre-calculations for ambient and object temperature calculation */
                pre_ambient = bsp_Mlx90632PreprocessTempAmbient(ambient_new_raw, ambient_old_raw, stMlxCalibraPar.Gb);
                pre_object = bsp_Mlx90632PreprocessTempObject(object_new_raw, object_old_raw, ambient_new_raw, ambient_old_raw, stMlxCalibraPar.Ka);
                /* Set emissivity = 1 */
                bsp_Mlx90632SetEmissivity(1.0);
                /* Calculate ambient and object temperature */
                ambient = bsp_Mlx90632CalcTempAmbient(ambient_new_raw, ambient_old_raw, stMlxCalibraPar.PT, stMlxCalibraPar.PR, stMlxCalibraPar.PG, stMlxCalibraPar.PO, stMlxCalibraPar.Gb);
                object = bsp_Mlx90632CalcTempObject(pre_object, pre_ambient, stMlxCalibraPar.Ea, stMlxCalibraPar.Eb, stMlxCalibraPar.Ga, stMlxCalibraPar.Fa, stMlxCalibraPar.Fb, stMlxCalibraPar.Ha, stMlxCalibraPar.Hb);
                
    
                printf("MLX90632 Measure Object Temp:%f ℃,Ambient Temp:%f\n",object,ambient);
                
             }
        }
    }
    
    
    void app_SeggerRttInit(void)
    {
        /***********************************************
        * 描述: RTT使用配置
        */
        /* 配置通道0,上行配置*/
    	SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
    	/* 配置通道0,下行配置*/
    	SEGGER_RTT_ConfigDownBuffer(0, "RTTDOWN", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
    }
    /*******************************************************************************
     * 名    称: app_ShowPowerOnInfo
     * 功    能: 上电打印相关信息
     * 入口参数: 无
     * 出口参数: 无
     * 作  者: Roger-WY.
     * 创建日期: 2015-06-25
     * 修    改:
     * 修改日期:
     * 备    注:
     *******************************************************************************/
    static void app_ShowPowerOnInfo(void)
    {
    	/***********************************************
        * 描述: 通过RTT打印信息
        */
        SEGGER_RTT_SetTerminal(0);
        SEGGER_RTT_printf(0,"\n\r");
    	SEGGER_RTT_printf(0,"*************************************************************\n\r");
    	SEGGER_RTT_printf(0,"* 例程名称   : %s\r\n", EXAMPLE_NAME);	/* 打印例程名称 */
    	SEGGER_RTT_printf(0,"* 例程版本   : %s\r\n", DEMO_VER);		/* 打印例程版本 */
    	SEGGER_RTT_printf(0,"* 发布日期   : %s\r\n", EXAMPLE_DATE);	/* 打印例程日期 */
    
    	/* 打印ST固件库版本,这3个定义宏在stm32f10x.h文件中 */
    	SEGGER_RTT_printf(0,"* 固件库版本 : V%d.%d.%d (STM32F10x_StdPeriph_Driver)\r\n", __STM32F10X_STDPERIPH_VERSION_MAIN,
               __STM32F10X_STDPERIPH_VERSION_SUB1,__STM32F10X_STDPERIPH_VERSION_SUB2);
    	SEGGER_RTT_printf(0,"* \r\n");	/* 打印一行空格 */
    	SEGGER_RTT_printf(0,"* Email : wangyao@zhiyigroup.cn \r\n");
    	SEGGER_RTT_printf(0,"* 淘宝店: zhisheng.taobao.com\r\n");
    	SEGGER_RTT_printf(0,"* 技术支持QQ群  : 539041646 \r\n");
    	SEGGER_RTT_printf(0,"* Copyright www.zhiyigroup.cn 至一电子科技\r\n");
    	SEGGER_RTT_printf(0,"*************************************************************\n\r");
    
    	/***********************************************
        * 描述: 通过串口打印信息
        */
        printf("\n\r");
    	printf("*************************************************************\n");
    	printf("* 例程名称   : %s\r\n", EXAMPLE_NAME);	/* 打印例程名称 */
    	printf("* 例程版本   : %s\r\n", DEMO_VER);		/* 打印例程版本 */
    	printf("* 发布日期   : %s\r\n", EXAMPLE_DATE);	/* 打印例程日期 */
    	printf("* --------------------------\r\n");	/*  */
    	printf("* 接线方式       \r\n");	/* 接线方式 */
        printf("* VCC ---- 3.3VDC~5VDC      \r\n");	/* 接线方式 */
        printf("* GND ---- GND              \r\n");	/* 接线方式 */
        printf("* SCL ---- PC4              \r\n");	/* 接线方式 */
        printf("* SDA ---- PC5              \r\n");	/* 接线方式 */
    	printf("* 串口使用 UASRT1(PA9/PA10) \r\n");	/*  */
    	printf("* --------------------------\r\n");	/* 接线方式 */
        
    	/* 打印ST固件库版本,这3个定义宏在stm32f10x.h文件中 */
    	printf("* 固件库版本 : V%d.%d.%d (STM32F10x_StdPeriph_Driver)\r\n", __STM32F10X_STDPERIPH_VERSION_MAIN,
               __STM32F10X_STDPERIPH_VERSION_SUB1,__STM32F10X_STDPERIPH_VERSION_SUB2);
    	printf("* \r\n");	/* 打印一行空格 */
    	printf("* Email : wangyao@zhiyigroup.cn \r\n");
    	printf("* 淘宝店: zhisheng.taobao.com\r\n");
    	printf("* 技术支持QQ群  : 539041646 \r\n");
    	printf("* Copyright www.zhiyigroup.cn 至一电子科技\r\n");
    	printf("*************************************************************\n\r");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181

    完整的工程

    STM32F1 使用标准库函数读取MLX90632非接触式温度传感器的完整工程可点击此处下载(有积分或者是会员的小伙伴可以支持一下!)

    PS:鉴于积分实在有点糟心,所以我把工程上传到 Gitee|Github 上了,没有积分的小伙伴可以直接去下载

    结束语

    如果觉得文章对您有帮助,请关注、点赞,谢谢!

  • 相关阅读:
    世界杯来了,让 Towhee 带你多语言「以文搜球」!
    【杂叙】北京住房公积金提取
    根据 Application ID找到 Hive 的 SQL 语句
    阿里35+老测试员生涯回顾,自动化测试真的有这么吃香吗?
    Timeline 时间线自定义节点为Checkbox
    【PaperReading】情感人的互联网:通过视听信号实现跨文化的可持续情感计算
    Servlet 中的 RequestDispatcher
    Vscode启动uniapp项目报错
    php请求库guzzlehttp/guzzle:~6.0拦截请求异常,自定义处理异常案例
    啸叫检测的方法:基于DSP的实现
  • 原文地址:https://blog.csdn.net/u012121390/article/details/126067733