MLX90632是一个小型SMD SFN封装中的非接触式红外温度传感器,可实现高精度非接触式温度测量,。该装置在出厂时使用存储在EEPROM存储器中的校准常数进行校准。环境温度和目标温度可根据这些校准常数和测量数据进行计算。
MLX90632在工厂进行校准,环境温度范围为-20至85摄氏度,目标温度范围为-20至200摄氏度。测量值是传感器视野内所有物体的平均温度。当传感器处于热平衡和恒温条件下(传感器组件之间无温差),应用程序设计者必须了解这些精度是有保证的,并且是可以实现的。
温度计的准确度可能会受到封装内温度差异的影响,原因包括(除其他外):传感器后面的热电子元件、传感器后面或旁边的加热器/冷却器,或靠近传感器的热/冷物体,不仅加热温度计中的传感元件,还加热温度计封装。
MLX90632的一个主要优点是通过内部测量算法,将传感器组件周围这些温差的测量效果降至最低。同样,局部热变化(如空气中的湍流)不会在热电堆的输出信号中产生热噪声。但是,有些极端情况会影响传感器。
MLX90632的典型电源电压为3.3V,与芯片的通信是由I 2 C在快速模式下完成的。通过I 2 C,外部微控制器可以访问以下块:用于测量数据的RAM存储器用于存储微调值、校准常数和设备/测量设置的EEPROM寄存器,以根据该数据控制传感器,外部微控制器可以计算目标温度,如果需要,还可以计算传感器温度。
传感器中集成了一个光学滤光片(长波通),可切断可见光和近红外辐射通量,以提供环境光抗扰度。该滤光片的波长通带为2~14μm。
其特性主要有:
型号 | MLX90632-BCB-000 | MLX90632-DCB-000 | MLX90632-DCB-100 |
---|---|---|---|
准确性 | 标准精度 | 医用级精度 | 医用级精度 |
I2C电压等级 | 3V3 | 1V8 | 1V8 |
电源电压范围 | 3-5V DC(模块带低压差稳压) |
---|---|
能耗 | 9.2µA(典型值)12µA(最大值) |
温度工作范围 | -20°C - 85°C |
输出信号 | I2C数字接口 |
PS: 传感器型号描述:
/*******************************************************************************
* 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, ®_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, ®_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) **********************************/
/*******************************************************************************
* 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) **********************************/
/*******************************************************************************
* 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");
}
STM32F1 使用标准库函数读取MLX90632非接触式温度传感器的完整工程可点击此处下载(有积分或者是会员的小伙伴可以支持一下!)
PS:鉴于积分实在有点糟心,所以我把工程上传到 Gitee|Github 上了,没有积分的小伙伴可以直接去下载
如果觉得文章对您有帮助,请关注、点赞,谢谢!