Basé sur la reconnaissance faciale stm32 et la mesure de la température infrarouge

teneur

1. Fonction projet

2. Schéma de principe

3. Vidéo physique

4. Images réelles


Adresse de téléchargement des données : basée sur la reconnaissance faciale STM32 et la mesure de la température infrarouge

1. Fonction projet

Ce système se compose d'un circuit de système minimum de micro-ordinateur monopuce stm32f103c8t6 + circuit de reconnaissance faciale k210 + circuit de mesure de la température infrarouge du corps humain sans contact.Les
fonctions sont les suivantes :
1. Les informations sur le visage sont collectées par la caméra pour identification
. 2. Deux des boutons indépendants sont utilisés respectivement pour la saisie de visage et la reconnaissance de visage.

3. Appuyez sur le bouton d'entrée de visage pour effectuer l'entrée de visage.
4. Appuyez sur le bouton de reconnaissance faciale, il peut être reconnu en continu pendant 30 secondes.
5. Module de mesure de température infrarouge sans contact. Il peut mesurer la température du corps humain en temps réel et la distance de mesure effective est de 1 à 1,5 cm.S'il est attaché au module, les données seront trop volumineuses.
6. L'écran oled affiche les données mesurées par le module de mesure de température infrarouge MLX90614 en temps réel.

7. L'heure est affichée en temps réel et l'heure peut être ajustée en appuyant sur le bouton

2. Schéma de principe

3. Vidéo physique

Basé sur la reconnaissance faciale stm32 et la mesure de la température infrarouge

4. Images réelles

 

5. Procédure

#include "mlx90614.h"

/**
* @功能 I2C通信状态改变后的延时
* @说明 无
* @参数 无
* @返回值 无
*/
void I2C_Delay(void)
{
delay_us(5);
}
/****************************************************************
*初始化MLX_IIC用的端口
****************************************************************/
void MLX_I2C_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);;//使能 GPIOB 时钟
	
	//GPIOB6,B7初始化设置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;//推挽模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
	MLX_IIC_SCL=1;
	MLX_IIC_SDA=1;	
	
}
/*******************************************************************************
* 函 数 名         : SDA_OUT
* 函数功能		   : SDA输出配置	   
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void MLX_SDA_OUT(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//GPIOB9初始化设置
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;//推挽模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
	GPIO_SetBits(GPIOB,GPIO_Pin_7);	//上拉
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
}

/*******************************************************************************
* 函 数 名         : SDA_IN
* 函数功能		   : SDA输入配置	   
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void MLX_SDA_IN(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	//GPIOB9初始化设置
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//输入模式
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
}


/**
* @功能 产生通讯开始信号
* @说明 MLX90614在SCK=1时,检测到SDA由1到0表示通信开始
* @参数 无
* @返回值 无
*/
void I2C_Start(void)
{
MLX_SDA_OUT();
MLX_IIC_SDA=1;
MLX_IIC_SCL=1;
I2C_Delay();
MLX_IIC_SDA=0;
I2C_Delay();
MLX_IIC_SCL=0;
I2C_Delay();
}
/**
* @功能 产生通讯停止信号
* @说明 MLX90614在SCK=1时,检测到SDA由0到1表示通信结束
* @参数 无
* @返回值 无
*/
void I2C_Stop(void)
{
MLX_SDA_OUT();
MLX_IIC_SDA=0;
MLX_IIC_SCL=0;
I2C_Delay();
MLX_IIC_SCL=1;
I2C_Delay();
MLX_IIC_SDA=1;
I2C_Delay();
}

/*******************************************************************************
* 函 数 名         : IIC_Ack
* 函数功能		   : 产生ACK应答  
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void I2C_Ack(void)
{
	MLX_IIC_SCL=0;
	MLX_SDA_OUT();
	MLX_IIC_SDA=0;
	delay_us(2);
	MLX_IIC_SCL=1;
	delay_us(5);
	MLX_IIC_SCL=0;
}

/*******************************************************************************
* 函 数 名         : IIC_NAck
* 函数功能		   : 产生NACK非应答  
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/		    
void I2C_NAck(void)
{
	MLX_IIC_SCL=0;
	MLX_SDA_OUT();
	MLX_IIC_SDA=1;
	delay_us(2);
	MLX_IIC_SCL=1;
	delay_us(5);
	MLX_IIC_SCL=0;
}	

/*******************************************************************************
* 函 数 名         : IIC_Wait_Ack
* 函数功能		   : 等待应答信号到来   
* 输    入         : 无
* 输    出         : 1,接收应答失败
        			 0,接收应答成功
*******************************************************************************/
u8 I2C_Wait_Ack(void)
{
	u8 tempTime=0;
	
	MLX_SDA_IN();      //SDA设置为输入  
	MLX_IIC_SDA=1;
	delay_us(1);	   
	MLX_IIC_SCL=1;
	delay_us(1);	 
	while(MLX_READ_SDA)
	{
		tempTime++;
		if(tempTime>250)
		{
			I2C_Stop();
			return 1;
		}
	}
	MLX_IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 


/**
* @功能 将MLX90614的工作模式从PWM模式切换到SMBus模式
* @说明 从PWM模式切换到SMBus的方法是将SCL保持至少1.44ms以上的低电平
* 如果PWM没有使能就不需要发送请求命令
* @参数 无
* @返回值 无
*/
void PwmToSMBus(void)
{
MLX_IIC_SCL=0;
delay_us(1500); //大于1.44ms
MLX_IIC_SCL=1;
}
/**
* @功能 退出睡眠模式
* @说明 保持SCK高电平后,SDA持续至少33ms低电平,
* 在退出睡眠模式后需要间隔250ms(典型值)才输出数据。
* @参数 无
* @返回值 无
*/
void Eixt_Sleep(void)
{
MLX_IIC_SCL=1;
MLX_IIC_SDA=1;
I2C_Delay();
MLX_IIC_SDA=0;
delay_ms(35); //大于33ms退出睡眠模式
MLX_IIC_SDA=1;
delay_ms(260); //大于250ms开始输出数据
}
/**
* @功能 从RAM/EEPROM中读取一个字节数据
* @说明 从MLX90614中的指定地址读取一个字节数据,高位在前,低位在后
* @参数 ack_nack:主机应答信号
* @返回值 dat: 读取的数据
*/
uint8_t I2C_ReadByte(uint8_t ack)
{
   u8 i,receive=0;
	 MLX_SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
      MLX_IIC_SCL=0; 
      delay_us(2);
		  MLX_IIC_SCL=1;
      receive<<=1;
      if(MLX_READ_SDA)receive++;   
		  delay_us(1); 
    }					 
    if (!ack)
        I2C_NAck();//发送nACK
    else
        I2C_Ack(); //发送ACK   
    return receive;
}
/**
* @功能 向EEPROM写一个字节数据
* @说明 在写完一个字节后检测MLX6014是否发送了应答信号
* @参数 dat:需要发送的字节
* @返回值 s_ack:应答信号状态
*/
uint8_t I2C_WriteByte(uint8_t dat)
{
    u8 t;   
	  uint8_t s_ack=0;
	  MLX_SDA_OUT(); 	    
    MLX_IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
    if((dat&0x80)>0) //0x80  1000 0000
		MLX_IIC_SDA=1;
		else
		MLX_IIC_SDA=0;
        dat<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		MLX_IIC_SCL=1;
		delay_us(2); 
		MLX_IIC_SCL=0;	
		delay_us(2);
    }	 
if(I2C_Wait_Ack()) //高电平表示正确接收数据  (高?低??这个应该是低电平)
{
s_ack = ACK_FAIL;
}
else
{
s_ack = ACK_SUCCESS;
}
//delay_us(2*N);//修改的
//MLX_IIC_SCL=0;	
//delay_us(4*N);
return s_ack;
}
/**
* @功能 读MLX90614的RAM中内容
* @说明 主要读取三个,环境温度,物体温度1,物体温度2
* 器件从地址可以通过向EEPROM的SMBus地址0x0E中写入来进行设定。
* @参数 saddr:从机地址,7位地址,任何MLX90614都会对0x00地址作出反应
* cmd:存放温度的寄存器地址
* @返回值 Data:读取出来的数值
*using Read Word: SA(write) - Command - SA(read) - LSByte - MSByte - PEC
*/
uint16_t I2C_ReadRAM(uint8_t saddr,uint8_t cmd)
{
	uint16_t Data;
	uint8_t DataL; //接收数据低字节
	uint8_t DataH; //接收数据高字节
	uint8_t PEC;
	uint8_t retry = 10; //失败重复次数
	uint8_t s_ack = 0;
	uint8_t Pecreg; //计算的PEC值
	uint8_t buf[6]; //存储已接收数据的缓存
	MLX_IIC_SCL=0;	
	while(retry--)
	{
		I2C_Start(); //发送起始位
		s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位
		if(s_ack == ACK_SUCCESS)
		{
			s_ack = 0;
			s_ack = I2C_WriteByte(RAM|cmd);
			//发送命令,8位,RAM表示对RAM操作,cmd表示操作RAM的地址
			if(s_ack == ACK_SUCCESS)
			{
				s_ack = 0;
				I2C_Start(); //重新发送起始位
				s_ack = I2C_WriteByte((saddr<<1)+1); //发送从机地址和Rd位
				if(s_ack == ACK_SUCCESS)
				{
					s_ack = 0;
					DataL = I2C_ReadByte(1); //读数据低字节
					DataH = I2C_ReadByte(1); //读数据高字节
					PEC = I2C_ReadByte(1); //读数据PEC字节
					// DataL=RX_byte(0); //
					// DataH=RX_byte(0); //
					// PEC=RX_byte(1);
					I2C_Stop(); //发送停止位
					buf[5]=(saddr<<1);
					buf[4]=EEPROM|cmd;
					buf[3]=(saddr<<1)|RD;
					buf[2]=DataL;
					buf[1]=DataH;
					buf[0]=0;
					Pecreg=PEC_Cal(buf,6); //调用计算 PEC 的函数
					if(Pecreg == PEC)
					{
						break; //退出循环
					}
				}
				else goto stop_rr;
				}
				else goto stop_rr;
		}
		else goto stop_rr;
		stop_rr:
		I2C_Stop(); //发送停止位,芯片接收失败
	}
	PEC = PEC+1;
	Data = (DataH<<8) + DataL;
	return Data;
}
/**
* @功能 清除EEPROM指定单元的数据
* @说明 在向EEPROM中写入数据之前必须先清除内存单元中的数据,也就是全部写入0
* @参数 saddr:从机地址
cmd:发送命令
* @返回值 无
*/
void I2C_ClearEEPROM(uint8_t saddr,uint8_t cmd)
{
uint8_t retry = 10; //失败重复次数
uint8_t s_ack = 0;
MLX_IIC_SCL=0;	
while(retry--)
{
I2C_Start(); //发送起始位
s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(EEPROM|cmd);
//发送命令,8位 EPROM表示对RAM操作,cmd表示操作EEPROM的地址$MLX90614.C
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(0x00); //发送低字节
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(0x00); //发送高字节
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(0x6f); //发送PEC字节
if(s_ack == ACK_SUCCESS)
{
I2C_Stop(); //发送停止位
break; //退出循环
}
else goto stop_ce;
}
else goto stop_ce;
}
else goto stop_ce;
}
else goto stop_ce;
}
else goto stop_ce;
stop_ce:
I2C_Stop(); //发送停止位,芯片接收失败
}
delay_ms(5); //擦除完成至少等待5ms
}
/**
* @功能 读EEPROM指定单元的数据
* @说明 从指定从机读取指定EEPROM地址的数据
* @参数 saddr:从机地址
cmd:读取EEPROM地址
* @返回值 Data:读取数据
*/
uint16_t I2C_ReadEEPROM(uint8_t saddr,uint8_t cmd)
{
uint8_t retry = 10;
uint8_t s_ack;
uint16_t Data;
uint8_t DataL; //接收数据低字节
uint8_t DataH; //接收数据高字节
uint8_t PEC; //接收的PEC值
uint8_t Pecreg; //计算的PEC值
uint8_t buf[6]; //存储已接收数据的缓存
while(retry--)
{
I2C_Start(); //发送起始位
s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(EEPROM|cmd); //发送命令
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
I2C_Start(); //重新发送起始位
s_ack = I2C_WriteByte((saddr<<1)|RD); //发送从机地址和Rd位
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
DataL = I2C_ReadByte(1); //读数据低字节
DataH = I2C_ReadByte(1); //读数据高字节
PEC = I2C_ReadByte(1); //读数据PEC字节
I2C_Stop(); //发送停止位
buf[5]=(saddr<<1);
buf[4]=EEPROM|cmd;
buf[3]=(saddr<<1)|RD;
buf[2]=DataL;
buf[1]=DataH;
buf[0]=0;
Pecreg=PEC_Cal(buf,6); //调用计算 PEC 的函数
if(Pecreg == PEC)
{
break;
}
}
else goto stop_re;
}
else goto stop_re;
}
else goto stop_re;
stop_re:
I2C_Stop();
}
Data = (DataH<<8) + DataL;
return Data;
}
/**
* @功能 写EEPROM指定单元的数据
* @说明 在向EEPROM中写入数据之前必须先清除内存单元中的数据,也就是全部写入0
* @参数 saddr:要清除数据的内存单元
* @返回值 无
*/
void I2C_WriteEEPROM(uint8_t saddr,uint8_t cmd,uint8_t DataL,uint8_t DataH)
{
uint8_t retry = 10; //失败重复次数
uint8_t s_ack = 0;
uint8_t Pecreg; //存储计算所得PEC结果$MLX90614.C
uint8_t buf[6]; //存储将要发送字节的缓冲器
buf[5]=0;
buf[4]=saddr<<1;
buf[3]=cmd;
buf[2]=DataL;
buf[1]=DataH;
buf[0]=0;
Pecreg=PEC_Cal(buf,6);
MLX_IIC_SCL=0;	
while(retry--)
{
I2C_Start(); //发送起始位
s_ack = I2C_WriteByte((saddr<<1)|WR); //发送从机地址和Wr位
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(EEPROM|cmd); //发送命令
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(DataL); //发送低字节
if(s_ack == ACK_SUCCESS)
{
s_ack = 0;
s_ack = I2C_WriteByte(DataH); //发送高字节
if(s_ack == ACK_SUCCESS)
{
I2C_Stop(); //发送停止位
break; //退出循环
}
else goto stop_we;
}
else goto stop_we;
}
else goto stop_we;
}

else goto stop_we;
stop_we:
I2C_Stop();
}
delay_ms(5); //写入之后等待5ms
}
/**
* @功能 计算PEC包裹校验码,根据接收的字节计算PEC码
* @说明 计算传入数据的PEC码
* @参数 pec[]:传入的数据
n:传入数据个数
* @返回值 pec[0]:计算得到的PEC值
*/
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器件地址
* @说明 器件从地址可以通过向EEPROM的SMBus地址0x0E中写入来进行设定。
为了给从器件设定地址,必须先以0x00+Wr当作从地址开始,当主机
发送此命令,MLX90614总是会反馈并忽略掉内部芯片编码信息。
向EEPROM写入数据前需要清除原来的数据,就是向修改单元写入0x0000
擦除之后需要等待5ms才可以重新写入数据
修改地址时写入的地址高字节MLX90614会忽略
修改之后需要重新将MLX90614的电源断开重启。
* @参数 soaddr:从机旧地址
snaddr:从机新地址
* @返回值 无
*/
void I2C_SetSlaveAddr(uint8_t soaddr,uint8_t snaddr)
{
// uint8_t cmd = EEPROM|SMBUSADDR;
// uint8_t DataL = snaddr;
// uint8_t DataH = 0x00;
// EEPROM_WRITE(snaddr,cmd,0x00,0x00);
// EEPROM_WRITE(snaddr,cmd,DataL,DataH);
}

/*************************************************
*函数名   :  CALTEMP()
*功 能    : 把读回来的数据转换为摄氏度
*说 明    : 从RAM里面读出来的是一个比较大的数(可以用显示屏打印出来看看)
             需要使用下面的公式把温度转换出来://Temperature data is T=(Data)*0.02-273.15
*参 数    : TEMP为要转换的数据         
*修改时间 : 2019/3/15

***************************************************/
void CALTEMP(unsigned long int TEMP)
{
   unsigned long int T;
   unsigned int A, B;
   //unsigned int tempb;
   
   T=TEMP*2;
	 if(T>=27315) //温度:零上
   {
     T=T-27315;
     A=T/100;
     B=T-A*100;
    }
		else//温度:零下
    {
     T=27315-T;
     A=T/100;
     B=T-A*100;
     }  
}

Je suppose que tu aimes

Origine blog.csdn.net/qq_35654286/article/details/124233195
conseillé
Classement