STM32实现MLX90614非接触测温串口显示(标准库与HAL库实现)

目录

模块选择

编程环境

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文库

吾芯电子工作室

相关推荐
Net_Walke2 小时前
【STM32】CLion STM32开发环境搭建
stm32·单片机
laocooon5238578865 小时前
运行当前位置,显示文件全名,检查是否扩展名多次重叠
stm32·单片机·嵌入式硬件
沉醉不知归路15 小时前
cursor导入keil工程详细步骤
stm32
D.....l6 小时前
STM32学习(MCU控制)(I2C 模拟)
stm32·单片机·学习
A9better7 小时前
嵌入式开发学习日志42——stm32之SPI工作方式
stm32·单片机·嵌入式硬件·学习
D.....l8 小时前
STM32学习(MCU控制)(SysTick and TIM)
stm32·单片机·学习
python百炼成钢12 小时前
10.串口
linux·stm32·单片机·嵌入式硬件
充哥单片机设计20 小时前
【STM32项目开源】基于STM32的智能水质检测系统
stm32·单片机·嵌入式硬件
wuk99820 小时前
基于STM32平台的ADS1292心电采集驱动程序
stm32·单片机·嵌入式硬件
gihigo199821 小时前
基于STM32F4系列MCU和CS5530 24位SDADC的称重传感器系统实现
stm32·单片机·嵌入式硬件