目录
模块选择
编程环境
MLX90614基本原理
通信协议(SMBus通信,类IIC通信)
代码实现
STM32与模块之间接线表
1.标准库实现温度采集
2.HAL库实现温度采集
模块选择
·STM32F103C8T6
·MLX90614 非接触式红外测温传感器
编程环境
·KEIL5(μVision V5.30.0.0) 其它版本影响并不大
·STM32CubeMX,版本不限
·串口助手
MLX90614基本原理
引脚说明
编号 | 名称 | 功能 |
1 | VCC | 电源正,3-5V |
2 | GND | 电源地 |
3 | SCL | 串行时钟输入 |
4 | SDA | 串行地址和数据输入/输出 |
MLX90614是一种红外温度计,用于非接触式温度测量。红外测温是根据被测物体的红外辐射能量来确定物体的温度,不与被测物体接触,具有不影响被测物体温度分布场,温度分辨率高、响应速度快、测温范围广、不受测温上限的限制、稳定性好等特点。适合于汽车空调、室内暖气、家用电器、手持设备以及医疗设备应用等。
MLX90614的出厂校准温度范围很广:环境温度为-40°C——125°C,目标温度为-70°C——380°C。测量值是传感器视场中所有物体的平均温度。在室温下,MLX90614的标准精确度为±0.5°C。
MLX90614由MLX81101红外热电堆传感器和包括含有稳压电路、低噪声放大器、A/D转换器、DSP单元、脉宽调制电路及逻辑控制电路的MLX90302信号处理芯片构成。
其工作原理为:红外热电堆传感器输出的温度信号经过内部低噪声、低失调的运算放大器(OPA)放大后经过A/D转换器(ADC)转换为17位数字信号通过可编程FIR及IIR低通数字滤波器(即DSP)处理后输出,输出结果存储在其内部RAM存储单元中。
MLX90614 是由内部状态机控制物体温度和环境温度的测量和计算,进行温度后处理,并将结果通过 PWM 或是 SMBus 模式输出。 ASSP 支持两个 IR 传感器。 (MLX90614xAx 只有一个 IR 传感器) IR 传感器的输出通过增益可编程的低噪声低失 调电压放大器放大,经过 Sigma Delta 调制器转换为单一比特流并反馈给 DSP 做后续的处理。信号通过可编程的 (用 EEPROM 实现) FIR 和 IIR 低通滤波器以进一步减低输入信号的带宽从而达到所需的噪声特性和刷新率。IIR 滤波器的输出为测量结果并存于内部 RAM 中,其中三个单元可被用到:一个是片内温度传感器(片上 PTAT 或 PTC),其余两个为 IR 传感器。 基于以上测量结果,计算出对应的环境温度 Ta 和物体温度 To,两个温度分辨率都为 0.01 ˚C。Ta 和 To 可通过两种方式读取:通过两线接口读取 RAM 单元,(0.02°C 分辨率,固定范围) 或者通过 PWM 数字模式输出。 (10 位分辨率, 范围可配置) 测量周期的最后一步为:测量所得 Ta 和 To 被重新调节为 PWM 所需的输出分辨率,并且该数据存在 PWM 状态 机的寄存器中,状态机可以产生固定频率和一定占空比来表示测量的数据。
通信协议(SMBus通信,类IIC通信)
单片机与MLX90614红外测温模块之间通信的方式是“类IIC”通信,意思就是通信方式跟IIC通信方式很像但又不是IIC,它有另外一个名字叫做SMBus。SMBus (System Management Bus)是 1995 年由 intel 公司提出的一种高效同步串行总线,SMBus 只有两根信号线:双向数据线和时钟信号线,容许 CPU 与各种外围接口器件以串行方式进行通信、交换信息,既可以提高传输速度也可以减小器件的资源占用,另外即使在没有SMBus 接口的单片机上也可利用软件进行模拟。
代码实现
STM32与模块之间接线表
MLX90614 | STM32F103C8T6 |
VCC | VCC |
GND | GND |
SCL | PB8 |
SDA | PB9 |
- | PA9(USART1_ TX) |
- | PA10(USART1_RX) |
1.标准库实现温度采集
主函数:
int main(void)
{
float Temperature=10;
char temStr[100] = "";
int i = 0; // 循环变量
delay_init(); // 延时函数初始化配置
uart_init(115200);
USART_SendData(USART1, 'A');
Mlx96014_Configuration();
/* Infinite loop */
while (1)
{
Temperature=SMBus_ReadTemp();
sprintf(temStr,"The Temperature is:%.2f\r\n",Temperature);
for(i=0;i<strlen(temStr);i++)
{
USART_SendData(USART1, temStr[i]);
delay_ms(1);
}
delay_ms(500);
}
}
mlx90614.c
/*******************************************************************************
* 文件名 : mlx90614.c
* 作 者 :
* 版 本 :
* 日 期 : 2015-08-07
* 描 述 : mlx90614函数
*******************************************************************************/
#include "stm32f10x.h"
#include "mlx90614.h"
/*******************************************************************************
* Function Name : Mlx90614_Configuration
* Description : Mlx90614_Configuration
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Mlx96014_Configuration(void)
{
GPIO_InitTypeDef GPIO; //声明一个结构体变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
// 温度传感器引脚配置
GPIO.GPIO_Pin = GPIO_Pin_9;//非接触温度传感器SDA 连接PB9
GPIO.GPIO_Speed = GPIO_Speed_50MHz;//管脚频率为50MHZ
GPIO.GPIO_Mode = GPIO_Mode_Out_OD;//输出模式为
GPIO_Init(GPIOB,&GPIO);//初始化GPIOB寄存器
GPIO.GPIO_Pin = GPIO_Pin_8;//非接触温度传感器SCL 连接PB8
GPIO.GPIO_Speed = GPIO_Speed_50MHz;//管脚频率为50MHZ
GPIO.GPIO_Mode = GPIO_Mode_Out_OD;//输出模式为
GPIO_Init(GPIOB,&GPIO);//初始化GPIOB寄存器
SDA_H;
SCL_H; //因为SMBus是下降沿触发
}
/*******************************************************************************
* Function Name : SMBus_StartBit
* Description : Generate START condition on SMBus
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SMBus_StartBit(void)
{
SDA_H; // Set SDA line
SMBus_Delay(1); // Wait a few microseconds
SCL_H; // Set SCK line
SMBus_Delay(5); // Generate bus free time between Stop
SDA_L; // Clear SDA line
SMBus_Delay(10); // Hold time after (Repeated) Start
// Condition. After this period, the first clock is generated.
//(Thd:sta=4.0us min)
SCL_L; // Clear SCK line
SMBus_Delay(2); // Wait a few microseconds
}
/*******************************************************************************
* Function Name : SMBus_StopBit
* Description : Generate STOP condition on SMBus
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SMBus_StopBit(void)
{
SCL_L; // Clear SCK line
SMBus_Delay(5); // Wait a few microseconds
SDA_L; // Clear SDA line
SMBus_Delay(5); // Wait a few microseconds
SCL_H; // Set SCK line
SMBus_Delay(10); // Stop condition setup time(Tsu:sto=4.0us min)
SDA_H; // Set SDA line
}
/*******************************************************************************
* Function Name : SMBus_SendByte
* Description : Send a byte on SMBus
* Input : Tx_buffer
* Output : None
* Return : None
*******************************************************************************/
u8 SMBus_SendByte(u8 Tx_buffer)
{
u8 Bit_counter;
u8 Ack_bit;
u8 bit_out;
for(Bit_counter=8; Bit_counter; Bit_counter--)
{
if (Tx_buffer&0x80)
{
bit_out=1; // If the current bit of Tx_buffer is 1 set bit_out
}
else
{
bit_out=0; // else clear bit_out
}
SMBus_SendBit(bit_out); // Send the current bit on SDA
Tx_buffer<<=1; // Get next bit for checking
}
Ack_bit=SMBus_ReceiveBit(); // Get acknowledgment bit
return Ack_bit;
}
/*******************************************************************************
* Function Name : SMBus_SendBit
* Description : Send a bit on SMBus
* Input : bit_out
* Output : None
* Return : None
*******************************************************************************/
void SMBus_SendBit(u8 bit_out)
{
if(bit_out==0)
{
SDA_L;
}
else
{
SDA_H;
}
SMBus_Delay(2); // Tsu:dat = 250ns minimum
SCL_H; // Set SCK line
SMBus_Delay(10); // High Level of Clock Pulse
SCL_L; // Clear SCK line
SMBus_Delay(10); // Low Level of Clock Pulse
// SMBUS_SDA_H(); // Master release SDA line ,
return;
}
/*******************************************************************************
* Function Name : SMBus_ReceiveBit
* Description : Receive a bit on SMBus
* Input : None
* Output : None
* Return : Ack_bit
*******************************************************************************/
u8 SMBus_ReceiveBit(void)
{
u8 Ack_bit;
SDA_H; //引脚靠外部电阻上拉,当作输入
SCL_H; // Set SCL line
SMBus_Delay(2); // High Level of Clock Pulse
if (SMBUS_SDA_PIN)
{
Ack_bit=1;
}
else
{
Ack_bit=0;
}
SCL_L; // Clear SCL line
SMBus_Delay(4); // Low Level of Clock Pulse
return Ack_bit;
}
/*******************************************************************************
* Function Name : SMBus_ReceiveByte
* Description : Receive a byte on SMBus
* Input : ack_nack
* Output : None
* Return : RX_buffer
*******************************************************************************/
u8 SMBus_ReceiveByte(u8 ack_nack)
{
u8 RX_buffer;
u8 Bit_Counter;
for(Bit_Counter=8; Bit_Counter; Bit_Counter--)
{
if(SMBus_ReceiveBit()) // Get a bit from the SDA line
{
RX_buffer <<= 1; // If the bit is HIGH save 1 in RX_buffer
RX_buffer |=0x01;
}
else
{
RX_buffer <<= 1; // If the bit is LOW save 0 in RX_buffer
RX_buffer &=0xfe;
}
}
SMBus_SendBit(ack_nack); // Sends acknowledgment bit
return RX_buffer;
}
/*******************************************************************************
* Function Name : SMBus_Delay
* Description : 延时 一次循环约1us
* Input : time
* Output : None
* Return : None
*******************************************************************************/
void SMBus_Delay(u16 time)
{
u16 i, j;
for (i=0; i<4; i++)
{
for (j=0; j<time; j++);
}
}
/*******************************************************************************
* Function Name : SMBus_ReadMemory
* Description : READ DATA FROM RAM/EEPROM
* Input : slaveAddress, command
* Output : None
* Return : Data
*******************************************************************************/
u16 SMBus_ReadMemory(u8 slaveAddress, u8 command)
{
u16 data; // Data storage (DataH:DataL)
u8 Pec; // PEC byte storage
u8 DataL=0; // Low data byte storage
u8 DataH=0; // High data byte storage
u8 arr[6]; // Buffer for the sent bytes
u8 PecReg; // Calculated PEC byte storage
u8 ErrorCounter; // Defines the number of the attempts for communication with MLX90614
ErrorCounter=0x00; // Initialising of ErrorCounter
slaveAddress <<= 1; //2-7位表示从机地址
do
{
repeat:
SMBus_StopBit(); //If slave send NACK stop comunication
--ErrorCounter; //Pre-decrement ErrorCounter
if(!ErrorCounter) //ErrorCounter=0?
{
break; //Yes,go out from do-while{}
}
SMBus_StartBit(); //Start condition
if(SMBus_SendByte(slaveAddress))//Send SlaveAddress 最低位Wr=0表示接下来写命令
{
goto repeat; //Repeat comunication again
}
if(SMBus_SendByte(command)) //Send command
{
goto repeat; //Repeat comunication again
}
SMBus_StartBit(); //Repeated Start condition
if(SMBus_SendByte(slaveAddress+1)) //Send SlaveAddress 最低位Rd=1表示接下来读数据
{
goto repeat; //Repeat comunication again
}
DataL = SMBus_ReceiveByte(ACK); //Read low data,master must send ACK
DataH = SMBus_ReceiveByte(ACK); //Read high data,master must send ACK
Pec = SMBus_ReceiveByte(NACK); //Read PEC byte, master must send NACK
SMBus_StopBit(); //Stop condition
arr[5] = slaveAddress;
arr[4] = command;
arr[3] = slaveAddress+1; //Load array arr
arr[2] = DataL;
arr[1] = DataH;
arr[0] = 0;
PecReg=PEC_Calculation(arr); //Calculate CRC
}
while(PecReg != Pec); //If received and calculated CRC are equal go out from do-while{}
data = (DataH<<8) | DataL; //data=DataH:DataL
return data;
}
/*******************************************************************************
* Function Name : PEC_calculation
* Description : Calculates the PEC of received bytes
* Input : pec[]
* Output : None
* Return : pec[0]-this byte contains calculated crc value
*******************************************************************************/
u8 PEC_Calculation(u8 pec[])
{
u8 crc[6];
u8 BitPosition=47;
u8 shift;
u8 i;
u8 j;
u8 temp;
do
{
/*Load pattern value 0x000000000107*/
crc[5]=0;
crc[4]=0;
crc[3]=0;
crc[2]=0;
crc[1]=0x01;
crc[0]=0x07;
/*Set maximum bit position at 47 ( six bytes byte5...byte0,MSbit=47)*/
BitPosition=47;
/*Set shift position at 0*/
shift=0;
/*Find first "1" in the transmited message beginning from the MSByte byte5*/
i=5;
j=0;
while((pec[i]&(0x80>>j))==0 && i>0)
{
BitPosition--;
if(j<7)
{
j++;
}
else
{
j=0x00;
i--;
}
}/*End of while */
/*Get shift value for pattern value*/
shift=BitPosition-8;
/*Shift pattern value */
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;
}/*End of for*/
shift--;
}/*End of while*/
/*Exclusive OR between pec and crc*/
for(i=0; i<=5; i++)
{
pec[i] ^=crc[i];
}/*End of for*/
}
while(BitPosition>8); /*End of do-while*/
return pec[0];
}
/*******************************************************************************
* Function Name : SMBus_ReadTemp
* Description : Calculate and return the temperature
* Input : None
* Output : None
* Return : SMBus_ReadMemory(0x00, 0x07)*0.02-273.15
*******************************************************************************/
float SMBus_ReadTemp(void)
{
return SMBus_ReadMemory(SA, RAM_ACCESS|RAM_Ta)*0.02-273.15;
}
/*********************************END OF FILE*********************************/
注意:
float SMBus_ReadTemp(void)
{
return SMBus_ReadMemory(SA, RAM_ACCESS|RAM_Ta)*0.02-273.15;
}
测的是环境温度,如果需要测量物体表面温度。
#define RAM_TOBJ1 0x07 //To1 address in the eeprom 表面温度
#define RAM_Ta 0x06 //Ta address in the eeprom 环境温度
实现效果:
2.HAL库实现温度采集
因为代码封装的较好,移植性较好,和标准库代码基本相似,只需要修改部分核心代码。
修改片段:
#define SMBUS_SCK_H() HAL_GPIO_WritePin(GPIOB, SMBus_SCL_Pin, GPIO_PIN_SET)
#define SMBUS_SCK_L() HAL_GPIO_WritePin(GPIOB, SMBus_SCL_Pin, GPIO_PIN_RESET)
#define SMBUS_SDA_H() HAL_GPIO_WritePin(GPIOB, SMBus_SDA_Pin, GPIO_PIN_SET)
#define SMBUS_SDA_L() HAL_GPIO_WritePin(GPIOB, SMBus_SDA_Pin, GPIO_PIN_RESET)
#define SMBUS_SDA_PIN() HAL_GPIO_ReadPin(GPIOB,SMBus_SDA_Pin)
基本就可以实现数据采集了。
注意:
float SMBus_ReadTemp(void)
{
return (SMBus_ReadMemory(SA, RAM_ACCESS|RAM_TaA)*0.02-273.15);
}
例子中测试的是物体温度,物体表面温度修改:
#define RAM_TOBJ1 0x07 // 物体表面温度
#define RAM_TaA 0x06 // 环境温度
这里需要需要注意的地方,CubeMX生成的代码需要修改一下,不然不能实现采集功能。
推挽输出
GPIO_MODE_OUTPUT_PP
修改成 开漏输出模式
GPIO_MODE_OUTPUT_OD
实现效果:
源码下载链接:
STM32实现MLX90614非接触测温串口显示(标准库与HAL库实现)资源-CSDN文库
吾芯电子工作室