1.JX90614红外测温传感器

之前想要做一期红外测温的实验,但是发现可参考的资料多是主流的MLX90614,JX90614的资料非常稀少,决定自己写驱动根据数据手册复现。该传感器使用IIC协议进行通信,通过读取数据寄存器当中的值即可获得当前的温度值(具体参考数据手册)

首先是他的电路连接,非常简单,我们采用软件IIC进行通信(任意选择两个GPIO配置为开漏输出模式即可),这里需要注意的是,该模块没有包含上拉电阻,需要在SDA、SCK与VCC之前都接上4.7K的电阻。

2.手把手复现

首先完成软件IIC接口的编写,这里使用PB11作为SDA,PB10作为SCK。

MI2C.h

#ifndef _MI2C_H
#define _MI2C_H

#include "stm32f10x.h"                  // Device header
#define GPIO_SDA_PORT  GPIOB
#define GPIO_SDA_PIN   GPIO_Pin_11
#define GPIO_SCK_PORT  GPIOB
#define GPIO_SCK_PIN   GPIO_Pin_10


void MI2C_Init(void);
void MI2C_W_SDA(uint8_t BitV);
void MI2C_W_SCK(uint8_t BitV);
uint8_t MI2C_R_SDA(void);
void App_I2C_Start(void);
void App_I2C_Stop(void);
void App_I2C_WriteByte(uint8_t Data);
uint8_t App_I2C_ReadByte(void);
void App_I2C_SendAck(uint8_t BitAck);
uint8_t App_I2C_ReceiveAck(void);

#endif

MI2C.c

#include "stm32f10x.h"                  // Device header
#include "MI2C.h"
#include "Delay.h"
//IO初始化
void MI2C_Init(void)
{
		/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB10和PB11引脚初始化为开漏输出
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

//写数据线
void MI2C_W_SDA(uint8_t BitV)
{
		GPIO_WriteBit(GPIO_SDA_PORT,GPIO_SDA_PIN,(BitAction)BitV);
	  Delay_us(2);
}
//写时钟线
void MI2C_W_SCK(uint8_t BitV)
{
	  GPIO_WriteBit(GPIO_SCK_PORT,GPIO_SCK_PIN,(BitAction)BitV);
	  Delay_us(2);
}

//读数据线
uint8_t MI2C_R_SDA(void)
{
		uint8_t Data;
	  Data = GPIO_ReadInputDataBit(GPIO_SDA_PORT,GPIO_SDA_PIN);
	  Delay_us(2);
	  return Data;
}
//起始位
void App_I2C_Start(void)
{
	  MI2C_W_SDA(1);
		MI2C_W_SCK(1);
	  MI2C_W_SDA(0);
		MI2C_W_SCK(0);
}
//停止位
void App_I2C_Stop(void)
{
	
	  MI2C_W_SDA(0);
		MI2C_W_SCK(1);
		MI2C_W_SDA(1);
}

//写1Byte数据
void App_I2C_WriteByte(uint8_t Data)
{
	 for(int i=0;i<8;i++)
	 {
			MI2C_W_SDA((0x80>>i)&Data);
		  MI2C_W_SCK(1);
		  MI2C_W_SCK(0);
	 }
}

//read 1Byte Data
uint8_t App_I2C_ReadByte(void)
{
		uint8_t Byte = 0x00;
	  MI2C_W_SDA(1);
	  for(int i=0;i<8;i++)
		{
			 MI2C_W_SCK(1);
			 if(MI2C_R_SDA()==1)
			 {
					Byte = Byte|(0x80>>i);
			 }
			 MI2C_W_SCK(0);
		}
		return Byte;
}

//发送应答
void App_I2C_SendAck(uint8_t BitAck)
{
		MI2C_W_SDA(BitAck);
	  MI2C_W_SCK(1);
	  MI2C_W_SCK(0);
}

//接收应答
uint8_t App_I2C_ReceiveAck(void)
{
	  uint8_t Data=0;
		MI2C_W_SDA(1);//主机释放总线
	  MI2C_W_SCK(1);
		Data = MI2C_R_SDA();
	  MI2C_W_SCK(0);
	  return Data;
}

然后我们通过查数据手册知道JX90164的设备地址为0x7F,设备的初始化和运行过程如下图

另外,从寄存器的描述章节可以找到数据存储的方式

可以看到温度数据是一个24bit的数据,我们需要分别接收MSB,CSB、LSB的8bit数据,然后合成一个24bit数据,就如下面的JX90164_Get_T_Data函数所写的内容一样。

JX90164.h

#ifndef _JX90614_H
#define _JX90614_H
#include "stm32f10x.h"                  // Device header
#include "MI2C.h"
#include "Serial.h"

void JX90164_WriteReg(uint8_t Address,uint8_t data);
uint8_t JX90164_ReadReg(uint8_t Address);
void JX90164_Init(void);
void JX90164_Get_T_Data(int32_t* Temp);

#endif 

JX90164_REG.h

#ifndef __JX90164_REG_H
#define __JX90164_REG_H


#define Soft_Reset 0x00
#define Data_ready 0x02
#define DATA1_MSB  0x10
#define DATA1_CSB  0x11
#define DATA1_LSB  0x12
#define CMD        0x30
#endif

JX90164.c

#include "stm32f10x.h"                  // Device header
#include "MI2C.h"
#include "Serial.h"
#include "JX90614.h"
#include "JX90614_reg.h"
#include "math.h"
#define JX90164_ADDRESS 0x7F


void JX90164_WriteReg(uint8_t Address,uint8_t data)
{
		App_I2C_Start();
	  App_I2C_WriteByte(JX90164_ADDRESS<<1);
	  App_I2C_ReceiveAck();
	  App_I2C_WriteByte(Address);
	  App_I2C_ReceiveAck();
	  App_I2C_WriteByte(data);
	  App_I2C_ReceiveAck();
	  App_I2C_Stop();
}

uint8_t JX90164_ReadReg(uint8_t Address)
{
	  uint8_t data;
		App_I2C_Start();
	  App_I2C_WriteByte(JX90164_ADDRESS<<1);
	  App_I2C_ReceiveAck();
	  App_I2C_WriteByte(Address);
	  App_I2C_ReceiveAck();
	
	
	  App_I2C_Start();
	  App_I2C_WriteByte(JX90164_ADDRESS<<1 | (0x01));
	  App_I2C_ReceiveAck();
	  data = App_I2C_ReadByte();
		App_I2C_SendAck(1);
	  App_I2C_Stop();
		
	  return data;
}

void JX90164_Init(void)
{
	  MI2C_Init();
		JX90164_WriteReg(CMD,0x00);
	  JX90164_WriteReg(CMD,0x08);
	  //JX90164_WriteReg(CMD,0x00);
}


void JX90164_Get_T_Data(int32_t* Temp)
{
		uint8_t DataH,DataC,DataL;
	  uint8_t Flag = 0x00;
	  Flag = JX90164_ReadReg(Data_ready);
	  DataH = JX90164_ReadReg(DATA1_MSB);
	  DataC = JX90164_ReadReg(DATA1_CSB);
	  DataL = JX90164_ReadReg(DATA1_LSB);
	  *Temp = (DataH<<16)|(DataC<<8)|(DataL);
}

最后需要对取得的数据在除以2的14次方就可以得到室温数据。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "mpu6050.h"
#include "MI2C.h"
#include "Serial.h"
#include "JX90614.h"
#include "math.h"
int32_t Temp;
int32_t realT;
uint8_t data_sda;
uint8_t data_sck;
int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Serial_Init();
	//MI2C_Init();
	JX90164_Init();
	
	while (1)
	{
		data_sda = MI2C_R_SDA();
//		data_sck = GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_10);
		OLED_ShowString(2,1,"tempTEST");
			JX90164_Get_T_Data(&Temp);
		 realT = Temp/(pow(2,14));
		Serial_Printf("temp: %d\r\n", realT);
		USART_Cmd(USART1,DISABLE);
		  OLED_ShowSignedNum(3, 1, realT, 5);
		USART_Cmd(USART1,ENABLE);
	}
}

实验结果如图

完整工程可以访问链接:https://download.csdn.net/download/qq_44465154/90576239?spm=1001.2101.3001.9500

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐