本次实验使用的测温模块型号GY-906-DCC模块,测距为10cm左右。
一、简介
MLX90614 是一款红外非接触温度计。TO-39 金属封装里同时集成了红外感应热电堆探测器芯片和信处理专用集成芯片。
由于集成了低噪声放大器、17 位模数转换器和强大的数字信号处理单元,使得高精度和高分辨度的温计得以实现。温度计具备出厂校准化,有数字 PWM 和 SMBus(系统管理总线)输出模式。
作为标准,配置为 10 位的 PWM 输出格式用于连续传送温度范围为-20…120 ˚C 的物体温度,其分辨率为 0.14 ˚C。POR 默认模式是 SMBus 输出格式。
图1.典型应用电路图
(一)引脚定义和描述
图2.顶视图
引脚名 |
功能 |
VSS |
地。 金属罐也连接到该引脚上。 |
SCL/Vz |
两线通信协议的串行时钟信号。该引脚上的 5.7V 齐纳二极管用于连接外部双极晶体管 以实现对器件高电源电压 8 …16V 的应用。 |
PWM/SDA |
数字信号输入 / 输出。正常模式下该引脚以脉宽调制方式输出测量的物体温度。 SMBus 兼容模式下自动配置为开漏 NMOS。 |
VDD |
外部电源电压。 |
(二)MLX90614 存储器
EEPROM
EEPROM 里只有限定数目的地址是允许客户改写的。整个 EEPROM 可通过 SMBus 接口读和写。
图3.EEPROM
MLX90614 的 EEPROM 有 32 个 16 位存储单元,其中存储单元 Tomax,Tomin,Ta 分别是用户物体温度上下限和环境温度范围,PWMCTRL 是 PWM 配置寄存器。
MLX90614 可通过 PWM 或是 SMBus 兼容接口读取,由 EEPROM 配置选择 PWM 输出模式。 (出厂默认为SMBus) PWM 输出有两种可编程的格式,单个和双重数据传送,提供单线读取两个温度的功能。(双重可以选择物体或是物体和环境温度) PWM 周期通过片上振荡器驱动并可编程。
RAM
RAM 中不能写入数据,只能进行读取,并且只有有限数目是客户感兴趣的。
图4.RAM
MLX90614 的RAM有 32 个 17 位存储单元,其中TA,TOBJ1,TOBJ2是环境温度和物体温度,在SMBus方式下,可以从这几个存储单元读出环境和被测物体的温度。
命令 Command
图5.命令码
xxxxx 代表要读取/写入的内存地址的 低5 位。
(三)两线协议
SMBus 接口为两线协议,允许主控器件 (MD) 和一个或是一个以上的从动器件 (SD) 通信。系统在给定的时刻只有一个主控器件。MLX90614 只作为从动器件使用。
使用模拟IIC实现SMBus通信。
图6.IIC通信协议
起始信号和停止信号
图7.起始信号和停止信号
起始信号:在 SCL 线是高电平时 SDA 线从高电平向低电平切换。
停止信号:SCL 是高电平时 SDA 线由低电平向高电平切换。
起始和停止条件一般由主机产生 总线在起始条件后被认为处于忙的状态 在停止条件的某段时间后总线被认为再次处于空闲状态。如果产生重复起始 Sr 条件而不产生停止条件 总线会一直处于忙的状态。
//起始信号
void MLX906_START_Sign(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SDA_H;
MLX906_SCL_H;
Delay_us(2);
MLX906_SDA_L;
Delay_us(2);
MLX906_SCL_L;//钳住总线,准备开始数据传输
Delay_us(1);
}
//停止信号
void MLX906_STOP_Sign(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SCL_L;
MLX906_SDA_L;
Delay_us(2);
MLX906_SCL_H;
MLX906_SDA_H;
Delay_us(1);
}
应答信号和非应答信号
图8.应答信号
SCL在高电平期间SDA始终处于低电平,需要在传输完毕一个字节后发送。
//主机应答(ACK信号)
void MLX906_Ack(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SDA_L;
MLX906_SCL_L;
Delay_us(2);
MLX906_SCL_H;
Delay_us(2);
MLX906_SCL_L;
}
图9.非应答信号
SCL在高电平期间SDA始终处于高电平,需要在传输完毕一个字节后发送。
//不产生ACK应答信号
void MLX906_Nack(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SCL_L;
MLX906_SDA_H;
Delay_us(2);
MLX906_SCL_H;
Delay_us(2);
MLX906_SCL_L;
Delay_us(2);
}
响应
图10.IIC总线的响应
数据传输必须带响应。相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间,发送器释放SDA线(高)。
在响应的时钟脉冲期间 ,接收器必须将SDA 线拉低 ,使它在这个时钟脉冲的高电平期间保持稳定的低电平。
uint8_t MLX906_Wait_Ack(void)
{
MLX906_SDA_IN();//输入模式
uint8_t utime=0;
MLX906_SDA_H;
Delay_us(1);
MLX906_SCL_H;
Delay_us(1);
while(MLX906_READ_SDA())
{
utime++;
if(utime>=255)
{
MLX906_STOP_Sign();
return 1;//非应答信号
}
}
MLX906_SCL_L;
return 0;//应答信号
}
数据传输
在数据传输过程中,数据线SDA需在时钟线SCL为高电平时保持稳定,在低电平期间可修改或读取数据线电平状态。
发送到 SDA 线上的每个字节必须为8位 ,每次传输可以发送的字节数量不受限制 ,每个字节后必须跟一个响应位。
发送数据:
//发送一个字节数据
uint8_t MLX906_SendByte(uint8_t byte1)
{
uint8_t i,byte;
byte=byte1;
MLX906_SDA_OUT();//输出模式
for(i=0;i<8;i++)//高位先发
{
if(byte&0x80)
{
MLX906_SDA_H;
}
else
{
MLX906_SDA_L;
}
MLX906_SCL_H;
Delay_us(2);
MLX906_SCL_L;
Delay_us(2);
byte<<=1;
}
MLX906_SDA_H;//释放总线
return MLX906_Wait_Ack();//等待响应
}
读数据:
//读取一个字节
uint8_t MLX906_ReadByte(void)
{
uint8_t byte=0;
uint8_t i;
MLX906_SDA_IN();//输入模式
for(i=0;i<8;i++)
{
MLX906_SCL_H;//SCL高电平时读取数据
if(MLX906_READ_SDA())
{
byte|= 1<<(7-i);
}
MLX906_SCL_L;//下降沿时从机修改数据
Delay_us(2);
}
MLX906_Nack();
return byte;
}
二、总线协议
图11.SMBus 数据包组成
在 SD 接收到每个 8 位数据后,会回复 ACK/NACK 信息。当 MD 初始化通信,将首先发送受控地址,只有能识别该地址的 SD 会确认,其它的会保持沉默。如果 SD 未确认其中的任意字节,MD 应停止通信并重新发送信息。NACK 也会在 PEC 接收后出现,这意味着在接收的信息有错误并且 MD 应重新发送信息。
PEC 的计算结果是基于 除 START,REPEATED START,STOP,ACK, 和 NACK 位外的所有位。 PEC 是 CRC-8 的多项式 aX8+X2+X1+1。每个字节的最高有效位首先传送。
(一)读数据
图12.SMBus读数据格式
(二)软件流程
多个MLX90614可以用于一个系统中,通过地址不同区分器件,器件默认的地址为5AH,因此在多 MLX90614 系统中,需要给每个 MLX90614 分配一个不同的地址,在只有一个MLX90614 的系统中,MLX90614 识别地址 00h,即在单个 MLX90614 系统中,可以使用该地址访问它。
图13.读数据流程图
从MLX90614 种读出的数据是 16 位的,由高 8 位(DataH)和低 8 位(DataL)两部分组成,其中RAM地址 07H单元存储的是TOBJ1数据,数据范围从 0x27AD到 0x7FFF,表示的温度范围是-70.01℃到+382.19℃。
//读内存
uint16_t MLX906_ReadMemory(void)
{
uint8_t Pec,PecReg,ErrorCounter;
uint8_t TempL=0;
uint8_t TempH=0;
uint8_t arr[6];
ErrorCounter=0;
do
{
ErrorCounter++;
if(ErrorCounter==10)
{
return 0;
}
MLX906_START_Sign();//起始信号
if(MLX906_SendByte(0x00))//发送MLX90614地址
continue;
if(MLX906_SendByte(0x07))//发送读MLX90614 RAM地址
continue;
MLX906_START_Sign();//重新启动
if(MLX906_SendByte(0x01))//发送数据采集命令
continue;
TempL=MLX906_ReadByte();//读取地位数据
TempH=MLX906_ReadByte();//读取高位数据
Pec=MLX906_ReadByte();//读取校验位
MLX906_STOP_Sign();//停止信号
arr[5]= 0x00;
arr[4]= 0x07;
arr[3]= 0x01;
arr[2]= TempL;
arr[1]= TempH;
arr[0]= 0;
PecReg=CRC_Calculation(arr);//计算CRC校验
}while(PecReg!=Pec);
return (uint16_t)((TempH<<8)|TempL);
}
(三)环境温度和物体温度的计算
环境温度Ta
物体温度To
//读温度
float MLX906_Read_Temp(void)
{
return (float )MLX906_ReadMemory()*0.02-273.15;
}
三、实验结果
手腕温度测量(未校准),可能有所误差。
图14.手腕温度测量
mian函数中轮询打印。
图15.UART读取温度数据
四、附件
mlx906.h
#ifndef _MLX906_H_
#define _MLX906_H_
#include "stm32f10x.h"
#include "systick.h"
/*
引脚连接:
SCL 时钟线 - PB10
SDA 数据线 - PB11
*/
#define MLX906_SCL_H GPIO_WriteBit(GPIOB,GPIO_Pin_10,Bit_SET)
#define MLX906_SCL_L GPIO_WriteBit(GPIOB,GPIO_Pin_10,Bit_RESET)
#define MLX906_SDA_H GPIO_WriteBit(GPIOB,GPIO_Pin_11,Bit_SET)
#define MLX906_SDA_L GPIO_WriteBit(GPIOB,GPIO_Pin_11,Bit_RESET)
#define MLX906_READ_SDA() GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)
//配置SDA数据线的输入输出模式
#define MLX906_SDA_OUT() ?????//输出模式 自己配置哦
#define MLX906_SDA_IN() ?????//输入模式
//此处为笔者小设计中才用到的,不用管
#define MLX906_STATE_READ 1
#define MLX906_STATE_UNREAD 0
#define ANOMALY_TEMP 37 //体温异常
extern float MLX906_Temp;
extern uint8_t MLX906_Temp_State;
void MLX906_Init(void);
float MLX906_Read_Temp(void);
#endif
mlx906.c
#include "mlx906.h"
//MLX初始化函数
void MLX906_Init(void)
{
//初始化引脚
GPIO_InitTypeDef mlx906_gpio_init;
mlx906_gpio_init.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
mlx906_gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
mlx906_gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&mlx906_gpio_init);
MLX906_SCL_H;//拉高引脚电平
MLX906_SDA_H;
}
/* IIC 时序 */
//起始信号
void MLX906_START_Sign(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SDA_H;
MLX906_SCL_H;
Delay_us(2);
MLX906_SDA_L;
Delay_us(2);
MLX906_SCL_L;//钳住总线,准备开始数据传输
Delay_us(1);
}
//停止信号
void MLX906_STOP_Sign(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SCL_L;
MLX906_SDA_L;
Delay_us(2);
MLX906_SCL_H;
MLX906_SDA_H;
Delay_us(1);
}
uint8_t MLX906_Wait_Ack(void)
{
MLX906_SDA_IN();//输入模式
uint8_t utime=0;
MLX906_SDA_H;
Delay_us(1);
MLX906_SCL_H;
Delay_us(1);
while(MLX906_READ_SDA())
{
utime++;
if(utime>=255)
{
MLX906_STOP_Sign();
return 1;//非应答信号
}
}
MLX906_SCL_L;
return 0;//应答信号
}
//主机应答(ACK信号)
void MLX906_Ack(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SDA_L;
MLX906_SCL_L;
Delay_us(2);
MLX906_SCL_H;
Delay_us(2);
MLX906_SCL_L;
}
//不产生ACK应答信号
void MLX906_Nack(void)
{
MLX906_SDA_OUT();//输出模式
MLX906_SCL_L;
MLX906_SDA_H;
Delay_us(2);
MLX906_SCL_H;
Delay_us(2);
MLX906_SCL_L;
Delay_us(2);
}
//读取一个字节
uint8_t MLX906_ReadByte(void)
{
uint8_t byte=0;
uint8_t i;
MLX906_SDA_IN();//输入模式
for(i=0;i<8;i++)
{
MLX906_SCL_H;//SCL高电平时读取数据
if(MLX906_READ_SDA())
{
byte|= 1<<(7-i);
}
MLX906_SCL_L;//下降沿时从机修改数据
Delay_us(2);
}
MLX906_Nack();
return byte;
}
//发送一个字节数据
uint8_t MLX906_SendByte(uint8_t byte1)
{
uint8_t i,byte;
byte=byte1;
MLX906_SDA_OUT();//输出模式
for(i=0;i<8;i++)//高位先发
{
if(byte&0x80)
{
MLX906_SDA_H;
}
else
{
MLX906_SDA_L;
}
MLX906_SCL_H;
Delay_us(2);
MLX906_SCL_L;
Delay_us(2);
byte<<=1;
}
MLX906_SDA_H;//释放总线
return MLX906_Wait_Ack();//等待响应
}
//crc校验
uint8_t CRC_Calculation(uint8_t pec[])
{
uint8_t crc[6];//存放多项式
uint8_t BitPosition = 47;
uint8_t shift;
uint8_t i,j,temp;
do
{
crc[5]=0;
crc[4]=0;
crc[3]=0;
crc[2]=0;
crc[1]=0x01;
crc[0]=0x07;
BitPosition = 47;
shift = 0;
i=5;
j=0;
while((pec[i]&(0x80>>j))==0 && i>0)
{
BitPosition--;
if(j<7)
{
j++;
}
else
{
j= 0x00;
i--;
}
}
shift= BitPosition-8;
while(shift)
{
for(i=5;i<0xFF;i--)
{
if((crc[i-1]&0x80)&&(i>0))
{
temp=1;
}
else
{
temp=0;
}
crc[i]<<=1;
crc[i]+=temp;
}
shift--;
}
for(i=0;i<=5;i++)
{
pec[i]^=crc[i];
}
}while(BitPosition>8);
return pec[0];
}
//读内存
uint16_t MLX906_ReadMemory(void)
{
uint8_t Pec,PecReg,ErrorCounter;
uint8_t TempL=0;
uint8_t TempH=0;
uint8_t arr[6];
ErrorCounter=0;
do
{
ErrorCounter++;
if(ErrorCounter==10)
{
return 0;
}
MLX906_START_Sign();//起始信号
if(MLX906_SendByte(0x00))//发送MLX90614地址
continue;
if(MLX906_SendByte(0x07))//发送读MLX90614 RAM地址
continue;
MLX906_START_Sign();//重新启动
if(MLX906_SendByte(0x01))//发送数据采集命令
continue;
TempL=MLX906_ReadByte();//读取地位数据
TempH=MLX906_ReadByte();//读取高位数据
Pec=MLX906_ReadByte();//读取校验位
MLX906_STOP_Sign();//停止信号
arr[5]= 0x00;
arr[4]= 0x07;
arr[3]= 0x01;
arr[2]= TempL;
arr[1]= TempH;
arr[0]= 0;
PecReg=CRC_Calculation(arr);//计算CRC校验
}while(PecReg!=Pec);
return (uint16_t)((TempH<<8)|TempL);
}
//读温度
float MLX906_Read_Temp(void)
{
return (float )MLX906_ReadMemory()*0.02-273.15;
}
注:GPIO时钟已在main.c文件中做了相关配置。
SDA数据线的输入输出模式配置 由 读者自行配置。
望有助于各位理解,如有侵权,请联系删除。文章来源:https://www.toymoban.com/news/detail-860509.html
2023/1/7文章来源地址https://www.toymoban.com/news/detail-860509.html
到了这里,关于【STM32篇】驱动MXL90614红外测温模块的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!