【本文发布于,未经许可不得转载,转载须注明出处】
1、MLX90614使用SMBus进行通讯,很多文章都没能说清楚I2C和SMBus的区别。反正在这里,这两者没什么区别,无需纠结。
2、貌似需要搭配透镜使用才能有更好的精度和更远的测量距离。
3、无地址选择引脚,内部也无唯一ID,要实现一条总线上挂接多个MLX90614,需要单独给每一个传感器的EEPROM写入不同的地址值之后才能挂到总线上.(暂无此需求,未研究)
#ifndef __MLX90614_H__
#define __MLX90614_H__#include "public.h"#define MLX90614_FIXED_BUS_ADDR 0x00 //不可修改的地址
#define MLX90614_EEPROM_BUS_ADDR 0x00 //可修改的地址,保存于eeprom的地址0eh处#define MLX90614_MASK_RAM_ACCESS 0x00 //访问 RAM 或上此值
#define MLX90614_MASK_EEPROM_ACCESS 0x20 //访问 eeprom 或上此值
#define MLX90614_MASK_READ_FLAG 0xf0 //访问 flag 或上此值
#define MLX90614_ENTER_SLEEP_MODE 0xff // #define MLX90614_EEPROM_ADDR___TO_MAX (MLX90614_MASK_EEPROM_ACCESS | 0x00)
#define MLX90614_EEPROM_ADDR___TO_MIN (MLX90614_MASK_EEPROM_ACCESS | 0x01)
#define MLX90614_EEPROM_ADDR___PWM_CTRL (MLX90614_MASK_EEPROM_ACCESS | 0x02)
#define MLX90614_EEPROM_ADDR___TA_RANGE (MLX90614_MASK_EEPROM_ACCESS | 0x03)
#define MLX90614_EEPROM_ADDR___EMISSIVITY (MLX90614_MASK_EEPROM_ACCESS | 0x04)
#define MLX90614_EEPROM_ADDR___CONFIG_REG1 (MLX90614_MASK_EEPROM_ACCESS | 0x05)
#define MLX90614_EEPROM_ADDR___SMBUS_ADDR (MLX90614_MASK_EEPROM_ACCESS | 0x0E)
#define MLX90614_EEPROM_ADDR___ID_NUMBER1 (MLX90614_MASK_EEPROM_ACCESS | 0x1C)
#define MLX90614_EEPROM_ADDR___ID_NUMBER2 (MLX90614_MASK_EEPROM_ACCESS | 0x1D)
#define MLX90614_EEPROM_ADDR___ID_NUMBER3 (MLX90614_MASK_EEPROM_ACCESS | 0x1E)
#define MLX90614_EEPROM_ADDR___ID_NUMBER4 (MLX90614_MASK_EEPROM_ACCESS | 0x1F)#define MLX90614_RAM_ADDR___RAW_DATA_IR_CH1 (MLX90614_MASK_RAM_ACCESS | 0x04)
#define MLX90614_RAM_ADDR___RAW_DATA_IR_CH2 (MLX90614_MASK_RAM_ACCESS | 0x05)
#define MLX90614_RAM_ADDR___TA (MLX90614_MASK_RAM_ACCESS | 0x06) //环境温度
#define MLX90614_RAM_ADDR___TOBJ1 (MLX90614_MASK_RAM_ACCESS | 0x07) //物体温度
#define MLX90614_RAM_ADDR___TOBJ2 (MLX90614_MASK_RAM_ACCESS | 0x08)#define MLX90614_SCL_PORT PORT1
#define MLX90614_SCL_PIN PIN5
#define MLX90614_SCL_PIN_MODE OPENDRAIN_OUTPUT#define MLX90614_SDA_PORT PORT1
#define MLX90614_SDA_PIN PIN4
#define MLX90614_SDA_PIN_MODE_IN() do {*((volatile uint8_t*)(&PORT->PM0+MLX90614_SDA_PORT)) |= (1 << MLX90614_SDA_PIN);} while (0)
#define MLX90614_SDA_PIN_MODE_OUT() do {*((volatile uint8_t*)(&PORT->PM0+MLX90614_SDA_PORT)) &= ~(1 << MLX90614_SDA_PIN);} while (0)
#define MLX90614_SDA_PIN_GET() PORT_GetBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN)typedef enum {MLX90164_WRITE = 0,MLX90164_READ
} mlx90164_cmdtype; #define MLX90164_NUM 1typedef struct {uint8_t Online[MLX90164_NUM]; //是否在线uint8_t Valid[MLX90164_NUM]; //温度值是否有效int32_t Temperature_Ta[MLX90164_NUM]; //环境温度 2位小数int32_t Temperature_To[MLX90164_NUM]; //物体温度 2位小数
} MLX90164_t; extern MLX90164_t MLX90164_data;void MLX90614_Init(void);
void MLX90614_Proc(void);#endif
/********************************************************************************* @copyright* @file .c* @author* @version* @date 2023/1* @brief 红外测温传感器******************************************************************************* @attention*******************************************************************************/#include "MLX90614.h"MLX90164_t MLX90164_data;
uint8_t calc[32];
uint8_t *calc_p = calc;#define DELAY_xUS 2 //uint8_t Calc_PEC_CRC8(uint8_t *dat, uint8_t len)
{uint8_t i;uint8_t crc = 0;while ( len-- ){crc ^= *dat++;for ( i = 0 ; i < 8 ; i++ ){if ( crc & 0x80 ){crc = (crc << 1) ^ 0x07;}else{crc = (crc << 1);}}}return crc;
}
/*** @brief 起始信号* @note SCL高电平期间,SDA跳变为低。需要保证start前sda和scl均为高* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_Start(void)
{MLX90614_SDA_PIN_MODE_OUT();PORT_SetBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//PORT_ClrBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);DELAY_US(DELAY_xUS);//PORT_ClrBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//
}
/*** @brief 结束信号* @note SCL高电平期间,SDA跳变为高* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_Stop(void)
{MLX90614_SDA_PIN_MODE_OUT();PORT_ClrBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//PORT_SetBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);
}
/*** @brief 主机发出应答* @note 发送完8bit后,第9bit发送前的SCL低电平期间,SDA拉低* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_ACK(void)
{MLX90614_SDA_PIN_MODE_OUT();PORT_ClrBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//PORT_ClrBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//
}
/*** @brief 主机发出非应答* @note 发送完8bit后,第9bit发送前的SCL低电平期间,SDA拉高* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_NACK(void)
{MLX90614_SDA_PIN_MODE_OUT();PORT_SetBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//PORT_ClrBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//
}
/*** @brief 等待从机应答* @note 每发送一个字节后,再产生一个scl低电平让从机把应答信号放到sda上* @param* @retval* @author PWH* @date 2022/7*/
uint8_t MLX90614_WaitACK(void)
{uint8_t ack;MLX90614_SDA_PIN_MODE_IN();PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);ack = MLX90614_SDA_PIN_GET() ? 0 : 1; //从机拉低sda应答DELAY_US(DELAY_xUS);//PORT_ClrBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//return ack;
}
/*** @brief* @note* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_SendByte(uint8_t _1byte)
{uint8_t i;MLX90614_SDA_PIN_MODE_OUT();for (i = 0; i < 8; i++){if (_1byte & 0x80)PORT_SetBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);elsePORT_ClrBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//_1byte <<= 1;PORT_ClrBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN); //时钟低电平期间才允许数据变化DELAY_US(DELAY_xUS);//}
}
/*** @brief* @note* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_ReadByte(uint8_t *_1byte)
{uint8_t i;*_1byte = 0;MLX90614_SDA_PIN_MODE_IN();for (i = 0; i < 8; i++){PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//*_1byte <<= 1;if (MLX90614_SDA_PIN_GET())*_1byte |= 0x01;PORT_ClrBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);DELAY_US(DELAY_xUS);//}
}
/*** @brief* @note* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_ReadWrite(uint8_t mlx_addr, mlx90164_cmdtype cmd, uint8_t reg_addr, uint8_t *bytes, uint8_t bytes_num)
{uint8_t i;calc_p = calc; //缓存一帧用作校验计算*calc_p++ = (mlx_addr <<= 1) & 0xfe; //器件地址MLX90614_Start();MLX90614_SendByte(mlx_addr & 0xfe); MLX90614_WaitACK();MLX90614_SendByte(reg_addr); //寄存器地址*calc_p++ = reg_addr;MLX90614_WaitACK();if (cmd == MLX90164_WRITE){for (i = 0; i < bytes_num; i++) //发送数据{*calc_p++ = *bytes;MLX90614_SendByte(*bytes++);MLX90614_WaitACK();}MLX90614_SendByte(Calc_PEC_CRC8(calc, calc_p - calc)); //发送校验}else{MLX90614_Start();MLX90614_SendByte(mlx_addr | 0x01); //器件地址 读*calc_p++ = mlx_addr | 0x01;MLX90614_WaitACK();for (i = 0; i < bytes_num; i++){MLX90614_ReadByte(bytes);if (i == bytes_num - 1) {MLX90614_NACK();}else {MLX90614_ACK();}*calc_p++ = *bytes++;}}MLX90614_Stop();
}/*** @brief 初始化* @note* @param* @retval* @author PWH* @date 2022/7*/
void MLX90614_Init(void)
{uint32_t delay;PORT_Init(MLX90614_SCL_PORT, MLX90614_SCL_PIN, MLX90614_SCL_PIN_MODE);PORT_ClrBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN); //拉低scl超过1.44ms,传感器将由pwm转为i2c工作模式UserTimer_Reset(&delay);while (UserTimer_Read(&delay) < 3);PORT_SetBit(MLX90614_SCL_PORT, MLX90614_SCL_PIN);PORT_Init(MLX90614_SDA_PORT, MLX90614_SDA_PIN, OPENDRAIN_OUTPUT);MLX90614_SDA_PIN_MODE_OUT();PORT_SetBit(MLX90614_SDA_PORT, MLX90614_SDA_PIN);memset(MLX90164_data.Online, 0, sizeof(MLX90164_data));
}#define MLX_TEST 0
/*** @brief* @note main while中调用* @param* @retval* @author PWH* @date 2023/2*/
void MLX90614_Proc(void)
{static uint32_t timer = 0;uint8_t temp[3];uint16_t temperature;#if (MLX_TEST == 1)uint8_t i;#endifif (UserTimer_Read(&timer) > TIMEOUT_1S) //1s{UserTimer_Reset(&timer);MLX90164_data.Online[0] = 0;MLX90164_data.Valid[0] = 0;MLX90614_ReadWrite(MLX90614_FIXED_BUS_ADDR, MLX90164_READ, MLX90614_RAM_ADDR___TA, temp, 3);#if (MLX_TEST == 1)for (i = 0; i < calc_p - calc; i++){printf("calc[%d] = %#xrn", i, calc[i]);}printf("temp0=%#x,temp1=%#x,temp2=%#xrn", temp[0], temp[1], temp[2]);#endifif (Calc_PEC_CRC8(calc, calc_p - calc - 1) == temp[2]){MLX90164_data.Temperature_Ta[0] = (int32_t)(*((uint16_t *)temp) * 2) - (int32_t)27315;#if (MLX_TEST == 1)printf("ta成功temp0=%#x,temp1=%#x,temp2=%#xrn", temp[0], temp[1], temp[2]);#endif
// MLX90164_data.Online[0] = 1;
// MLX90164_data.Valid[0] = 1;}#if (MLX_TEST == 1)else{printf("ta失败-%#xrn", Calc_PEC_CRC8(calc, calc_p - calc - 1));}#endifMLX90614_ReadWrite(MLX90614_FIXED_BUS_ADDR, MLX90164_READ, MLX90614_RAM_ADDR___TOBJ1, temp, 3);#if (MLX_TEST == 1)for (i = 0; i < calc_p - calc; i++){printf("calc[%d] = %#xrn", i, calc[i]);}printf("temp0=%#x,temp1=%#x,temp2=%#xrn", temp[0], temp[1], temp[2]);#endifif (Calc_PEC_CRC8(calc, calc_p - calc - 1) == temp[2]){//温度换算公式:寄存器值 * 0.02, 结果单位为开尔文MLX90164_data.Temperature_To[0] = (int32_t)(*((uint16_t *)temp) * 2) - (int32_t)27315;#if (MLX_TEST == 1)printf("to成功temp0=%#x,temp1=%#x,temp2=%#xrn", temp[0], temp[1], temp[2]);#endifMLX90164_data.Online[0] = 1;MLX90164_data.Valid[0] = 1;}#if (MLX_TEST == 1)else{printf("to失败-%#xrn", Calc_PEC_CRC8(calc, calc_p - calc - 1));}printf("环境温度%f℃,物体温度%f℃rnrn", (float)MLX90164_data.Temperature_Ta[0] / 100, (float)MLX90164_data.Temperature_To[0] / 100);#endif}
}
本文发布于:2024-02-04 11:31:11,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170706184255176.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |