温度传感器
**MLX90614(gy906-BAA)**非接触红外温度传感器是一种高性能、高精度的温度测量产品,广泛应用于医疗、工业等领域;有四个引脚SMBus通过控制协议SDA、SCL数据读取引脚。工作电压为3.3V。 *
下载完整的工程
产品配图
stm32cubemax 配置
串口温度测试:
电路连接说明: SDA引脚连接STM32F103c8t6单片机PB7,SCL引脚连接PB6引脚。 VCC连接3.3V引脚,GND3.连接单片机.3V对应的GND引脚。 因为IIC采用软模拟实现的引脚功能,因此采用在线下载的标准库MLX90614.c与MLX90614.h文件
移植到stm32cubemax去生成的项目,节省大家的时间。
main.c 文件展示:
#include "main.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "mlx90614.h" #include "stdio.h" int main(void) {
/* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ printf("START"); mlx90614_init(); HAL_Delay(1000); /* USER CODE END 2 */ /* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(1000);
printf("%f",mlx90614_read_temp());
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
MLX90614.h 文件展示:
#ifndef __MLX90614_H
#define __MLX90614_H
//#include "sys.h"
#include "main.h"
//==============================================MLX90614硬件接口==================================================
#define MLX90614_IIC_CLK RCC_APB2Periph_GPIOB
#define MLX90614_IIC_PORT GPIOB
#define MLX90614_IIC_PIN_SCL GPIO_PIN_6
#define MLX90614_IIC_PIN_SDA GPIO_PIN_7
#define MLX90614_IIC_SCL PBout(6)
#define MLX90614_IIC_SDA PBout(7)
#define MLX90614_READ_SDA PBin(7) //输入SDA
//==============================================MLX90614函数接口==================================================
void mlx90614_init(void);
float mlx90614_read_temp(void);
void delay_usssss(int n);
//==============================================MLX90614寄存器==================================================
#define RAM 0x00
#define EEPROM 0x20
#define MODE 0x60
#define EXITMODE 0x61
#define READFLAG 0xf0
#define SLEEP 0xff
#define RD 0x01
#define WR 0x00
#define AMBITEMPADDR 0x03
#define IR1ADDR 0x04
#define IR2ADDR 0x05
#define ENVITEMPADDR 0x06
#define OBJ1TEMPADDR 0x07
#define OBJ2TEMPADDR 0x08
#define TOBJMAXADDR 0x00
#define TOBJMINADDR 0x01
#define PWMCTRLADDR 0x02
#define TARANGEADDR 0x03
#define KEADDR 0x04
#define CONFIGADDR 0x05
#define SMBUSADDR 0x0e
#define RES1ADDR 0x0f
#define RES2ADDR 0x19
#define ID1ADDR 0x1c
#define ID2ADDR 0x1d
#define ID3ADDR 0x1e
#define ID4ADDR 0x1f
#define ACK_SUCCESS 0x01
#define ACK_FAIL 0x00
#define N 5
#endif
/--------------------- MLX90614.c 文件展示:
/*================================================================================================ // 文件功能:MlX90614的驱动文件 // 文件说明: // 文件类型: //------------------------------------------------------------------------------------------------ // 硬件平台:STM32F103C8T6 -cubemax // 软件平台:KEIL5 MDK //------------------------------------------------------------------------------------------------ // 开发组织: // 开发作者:heyque // 官方商城: //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ // 更新时间:2021-05-12 //----------------------------------------------------------------------------------------------- // 待完善内容: ================================================================================================*/ #include "mlx90614.h" /*================================================================================================ // @函数名称: // @函数功能:SDA输出配置 // @函数说明: //------------------------------------------------------------------------------------------------ // @参数值: 无 // @返回值: 无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-07-11 heyque 新建 //==============================================================================================*/ /*================================================================================================ // @函数名称: // @函数功能:产生通讯开始信号 // @函数说明:MLX90614在SCK=1时,检测到SDA由1到0表示通信开始 //------------------------------------------------------------------------------------------------ // @参数值: 无 // @返回值: 无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void mlx90614_iic_start(void) { MLX90614_SDA_OUT(); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_SET); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); delay_weimiao(5); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_RESET); delay_weimiao(5); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); delay_weimiao(5); } /*================================================================================================ // @函数名称: // @函数功能:产生通讯停止信号 // @函数说明:MLX90614在SCK=1时,检测到SDA由0到1表示通信结束 //------------------------------------------------------------------------------------------------ // @参数值: 无 // @返回值: 无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void mlx90614_iic_stop(void) { MLX90614_SDA_OUT(); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_RESET); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); delay_weimiao(5); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); delay_weimiao(5); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_SET); delay_weimiao(5); } /*================================================================================================ // @函数名称: // @函数功能:产生ACK应答 // @函数说明: //------------------------------------------------------------------------------------------------ // @参数值: 无 // @返回值: 无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void mlx90614_iic_ack(void) { HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); MLX90614_SDA_OUT(); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_RESET); delay_weimiao(2); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); delay_weimiao(5); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); } /*================================================================================================ // @函数名称: // @函数功能:产生NACK非应答 // @函数说明: //------------------------------------------------------------------------------------------------ // @参数值: 无 // @返回值: 无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void mlx90614_iic_no_ack(void) { HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); MLX90614_SDA_OUT(); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_SET); delay_weimiao(2); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); delay_weimiao(5); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); } /*================================================================================================ // @函数名称: // @函数功能:等待应答信号到来 // @函数说明: //------------------------------------------------------------------------------------------------ // @参数值: 无 // @返回值: 1,接收应答失败 0,接收应答成功 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ uint8_t mlx90614_iic_wait_ack(void) { uint8_t tempTime=0; MLX90614_SDA_IN(); //SDA设置为输入 HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_SET); delay_weimiao(1); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); delay_weimiao(1); while(HAL_GPIO_ReadPin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA)==1) { tempTime++; if(tempTime>250) { mlx90614_iic_stop(); return 1; } } HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET);//时钟输出0 return 0; } /*================================================================================================ // @函数名称: // @函数功能:从RAM/EEPROM中读取一个字节数据 // @函数说明:从MLX90614中的指定地址读取一个字节数据,高位在前,低位在后 //------------------------------------------------------------------------------------------------ // @参数值: ack_nack:主机应答信号 // @返回值: dat: 读取的数据 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ uint8_t mlx90614_iic_read_byte(uint8_t ack) { uint8_t i,receive=0; MLX90614_SDA_IN();//SDA设置为输入 for(i=0;i<8;i++ ) { HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); delay_weimiao(2); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); receive<<=1; if(HAL_GPIO_ReadPin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA)==1)receive++; delay_weimiao(1); } if (!ack) mlx90614_iic_no_ack();//发送nACK else mlx90614_iic_ack(); //发送ACK return receive; } /*================================================================================================ // @函数名称: // @函数功能:向EEPROM写一个字节数据 // @函数说明:在写完一个字节后检测MLX6014是否发送了应答信号 //------------------------------------------------------------------------------------------------ // @参数值: dat:需要发送的字节 // @返回值: s_ack:应答信号状态 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ uint8_t mlx90614_iic_write_byte(uint8_t dat) { uint8_t t; uint8_t s_ack=0; MLX90614_SDA_OUT(); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET);//拉低时钟开始数据传输 for(t=0;t<8;t++) { if((dat&0x80)>0) //0x80 1000 0000 HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_SET); else HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_RESET); dat<<=1; delay_weimiao(2); //对TEA5767这三个延时都是必须的 HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); delay_weimiao(2); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); delay_weimiao(2); } if(mlx90614_iic_wait_ack()) //高电平表示正确接收数据 (高?低??这个应该是低电平) { s_ack = ACK_FAIL; } else { s_ack = ACK_SUCCESS; } return s_ack; } /*================================================================================================ // @函数名称: // @函数功能:mlx90614初始化 // @函数说明: //------------------------------------------------------------------------------------------------ // @参数值: 无 // @返回值: 无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void mlx90614_init(void) { GPIO_InitTypeDef GPIO_InitStruct = { 0}; __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin : PB7 */ GPIO_InitStruct.Pin = MLX90614_IIC_PIN_SCL|MLX90614_IIC_PIN_SCL; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA|MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); HAL_GPIO_Init(MLX90614_IIC_PORT, &GPIO_InitStruct); } /*================================================================================================ // @函数名称: // @函数功能:计算PEC包裹校验码,根据接收的字节计算PEC码 // @函数说明:计算传入数据的PEC码 //------------------------------------------------------------------------------------------------ // @参数值: pec[]:传入的数据 // n:传入数据个数 // @返回值: pec[0]:计算得到的PEC值 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ static uint8_t pec_cal(uint8_t pec[],uint16_t n) { unsigned char crc[6]; unsigned char Bitposition=47; unsigned char shift; unsigned char i; unsigned char j; unsigned char temp; do{ crc[5]=0; //载入 CRC数值 0x000000000107 crc[4]=0; crc[3]=0; crc[2]=0; crc[1]=0x01; crc[0]=0x07; Bitposition=47; //设置Bitposition的最大值为47 shift=0; //在传送的字节中找出第一个“1” i=5; //设置最高标志位 (包裹字节标志) j=0; //字节位标志,从最低位开始 while((pec[i]&(0x80>>j))==0 && (i>0)) { Bitposition--; if(j<7) { j++; } else { j=0x00; i--; } }//while语句结束,并找出Bitposition中为“1”的最高位位置 shift=Bitposition-8; //得到CRC数值将要左移/右移的数值“shift” //对CRC数据左移“shift”位 while(shift) { for(i=5;i<0xFF;i--) { if((crc[i-1]&0x80) && (i>0)) //核对字节的最高位的下一位是否为"1" { //是 - 当前字节 + 1 temp=1; //否 - 当前字节 + 0 } //实现字节之间移动“1” else { temp=0; } crc[i]<<=1; crc[i]+=temp; } shift--; } //pec和crc之间进行异或计算 for(i=0;i<=5;i++) { pec[i]^=crc[i]; } }while(Bitposition>8); return pec[0]; //返回计算所得的crc数值 } /*================================================================================================ // @函数名称: // @函数功能:将MLX90614的工作模式从PWM模式切换到SMBus模式 // @函数说明:从PWM模式切换到SMBus的方法是将SCL保持至少1.44ms以上的低电平, // 如果PWM没有使能就不需要发送请求命令。 //------------------------------------------------------------------------------------------------ // @参数值:无 // @返回值:无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void pwm_to_smbus(void) { HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); delay_weimiao(1500); //大于1.44ms HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); } /*================================================================================================ // @函数名称: // @函数功能:退出睡眠模式 // @函数说明:保持SCK高电平后,SDA持续至少33ms低电平, // 在退出睡眠模式后需要间隔250ms(典型值)才输出数据。 //------------------------------------------------------------------------------------------------ // @参数值:无 // @返回值:无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void eixt_sleep(void) { HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_SET); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_SET); delay_weimiao(5); HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_RESET); HAL_Delay(35); //大于33ms退出睡眠模式 HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SDA, GPIO_PIN_SET); HAL_Delay(260); //大于250ms开始输出数据 } /*================================================================================================ // @函数名称: // @函数功能:清除EEPROM指定单元的数据 // @函数说明:在向EEPROM中写入数据之前必须先清除内存单元中的数据,也就是全部写入0 //------------------------------------------------------------------------------------------------ // @参数值: saddr:从机地址 // cmd:发送命令 // @返回值: 无 //------------------------------------------------------------------------------------------------ // @修改日志:2021-05-12 heyque 新建 //==============================================================================================*/ void mlx90614_clear_eeprom(uint8_t saddr,uint8_t cmd) { uint8_t retry = 10; //失败重复次数 uint8_t s_ack = 0; HAL_GPIO_WritePin(MLX90614_IIC_PORT, MLX90614_IIC_PIN_SCL, GPIO_PIN_RESET); while(retry--) { mlx90614_iic_start(); //发送起始位 s_ack = mlx90614_iic_write_byte((saddr<<1)|WR); //发送从机地址和Wr位 if(s_ack == ACK_SUCCESS) { s_ack = 0; s_ack = mlx90614_iic_write_byte(EEPROM|cmd); //发送命令,8位 EPROM表示对RAM操作,cmd表示操作EEPROM的地址$MLX90614.C if(s_ack == ACK_SUCCESS) { s_ack = 0; s_ack = mlx90614_iic_write_byte(0x00); //发送低字节 if(s_ack == ACK_SUCCESS) { s_ack = 0; s_ack = mlx90614_iic_write_byte(0x00); //发送高字节 if(s_ack == ACK_SUCCESS) { s_ack = 0; s_ack = mlx90614_iic_write_byte(0x6f); //发送PEC字节 if(s_ack == ACK_SUCCESS) { mlx90614_iic_stop(); //发送停止位 break; //退出循环 } else goto stop_ce; } else goto stop_ce; } else goto stop_ce; } else goto stop_ce; } else goto stop_ce; stop_ce: mlx90614_iic_stop(); //发送停止位,
芯片接收失败 标签: 体温枪用到的传感器传感器pec09