STM32驱动K210人脸识别模块经验汇总

本次是基于HLK-KT210 AI人脸识别模块和STM32单片机进行设计的人脸识别项目。主要是人脸识别功能的分析和使用。

1 模块连接

本次使用了海凌科生产的DEMO板,但是由于板子的客观因素,TTL串口没有设计好,需要自行引线才行,故需了解好模块的引脚。串口TTL进行交叉通信,GND做共地处理。如图所示,芯片模组的2引脚是RXD,连接到USB-TTL调试器的TXD或者单片机的TXD,模组的3引脚是TXD,接USB-TTL调试器的RXD或者单片机的RXD,波特率设置为115200(出厂默认,后期可自行更改)进行调试。USB-C口可以直接调试和供电,故不再说明C口,因本设计是自己焊接的板子,所以C口用起来不合适。注意的是供电部分一定要接稳点电压,1A以上,保持电源稳定才行。
STM32驱动K210人脸识别模块经验汇总_第1张图片

STM32驱动K210人脸识别模块经验汇总_第2张图片

2 上位机调试

根据手册和官方给的串口调试软件扩展部分的指令,比较容易的进行测试。需要注意的是自己做指令进行验证的话需要CRC校验位,那么可以通过在线网址进行生成,模型和网址如下。
STM32驱动K210人脸识别模块经验汇总_第3张图片
STM32驱动K210人脸识别模块经验汇总_第4张图片

3 根据手册和调试过程画的人脸录入和识别的流程

STM32驱动K210人脸识别模块经验汇总_第5张图片
STM32驱动K210人脸识别模块经验汇总_第6张图片
STM32驱动K210人脸识别模块经验汇总_第7张图片

4 简单的STM32驱动验证

本次仅仅只是个开头,做了人脸信息录入和识别的功能,其它功能以后有时间再去设计驱动,入门以后其实就不复杂了,框架基本已成,后面有时间会更新。

/**
  * @说明     由燃烧电子于2022年3月24日做的初始版本V1.0
  * @TEL      Q2772272579
  * @readme   仅供参考
  */
#ifndef __HLK210_h
#define __HLK210_h

#include "stm32f10x.h"
#include <string.h>
#include <stdio.h>
#include "Def_config.h"
#include "delay.h"

//
#include "usart1.h" 
#define HLK210_SendByte  USART1_SendByte  


//模组返回的消息类型说明
#define HLK210_CTROK           0x00 // 操作成功
#define HLK210_CHECKEDFACE     0x01 // 检测到人脸
#define HLK210_LIVINGBODY      0x02 // 活体通过
#define HLK210_STRERROR        0x03 // 存储操作错误
#define HLK210_STRFULL         0x04 // 人脸库已满
#define HLK210_CHECKOUT        0x05 // 检测超时
#define HLK210_IDERROR         0x06 // 人脸编号ID不存在
#define HLK210_FORMERROR       0x07 // 参数或格式错误
#define HLK210_OTHERERROR      0x08 // 其他错误
#define HLK210_RAMERROR        0x09 // RAM中暂缓的模板不存在
#define HLK210_HAVEDFACE       0x0A // 此人脸已注册

typedef enum {NORMAL,INPUTFACEID,CHECKFACEID,DELETEFACEID}ENUM_HLK210;

#define HLK210_NORMALANSWERLEN   18  //命令发出应答长度
#define HLK210_FACEANSWERLEN     21  //人脸录入时反馈字节长度
#define HLK210_RECOANSWERLEN     22  //人类识别时反馈字节长度

#define HLK210_USART_REC_LEN 50
typedef struct SaveData 
{
	char HLK210_Buffer[HLK210_USART_REC_LEN];
	char CmdDataLen;		
	ENUM_JUDGE isGetData;		//是否获取到GPS数据
	ENUM_JUDGE isParseData;	//是否解析完成
	ENUM_JUDGE isUsefull;		//信息是否有效
	ENUM_HLK210 NowMode;
	char TimeCount;
} _HLK210_Data;
extern _HLK210_Data HLK210_Data;

void HLK210_ClearDate(void);
void HLK210_Receive_Byte(u8 res);
void HLK210_InputFaceID(void);
void HLK210_CheckFaceID(void);

#endif 

#include "HLK210.h"

#include "bsp_i2c_gpio.h"
#include "bsp_i2c_OLED.h"
#include "delay.h"
#include "usart3.h" 

unsigned char HLK210_FaceStorageCmd[18] ={0x5A, 0x2C, 0x00, 0x00, 0x00, 0x12, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xE5};//人脸录入指令
unsigned char HLK210_FaceCheckCmd[18] = {0x5A, 0x2C, 0x00, 0x00, 0x00, 0x12, 0x02, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0xA8};  //人脸识别指令
unsigned char HLK210_FaceDelete[18] = {0x5A, 0x2C, 0x00, 0x00, 0x00, 0x12, 0x0D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x1E};  //人脸清空指令
unsigned char HLK210_LightOn[18] = {0x5A, 0x2C, 0x00, 0x00, 0x00, 0x12, 0x12, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xAA, 0x15};  //开补光灯指令

unsigned char HLK210_RECEICV_BUFFER[HLK210_USART_REC_LEN];

_HLK210_Data HLK210_Data;
u8 HLK210_point=0;
void HLK210_Receive_Byte(u8 res) //将此函数放到串口中断函数里,res形参放串口接收值。
{
	HLK210_RECEICV_BUFFER[HLK210_point++] = res;
	if(HLK210_point>1 && (HLK210_RECEICV_BUFFER[HLK210_point-2]==0x5a && HLK210_RECEICV_BUFFER[HLK210_point-1]==0x2c))
	{
		HLK210_RECEICV_BUFFER[0]=HLK210_RECEICV_BUFFER[HLK210_point-2];
		HLK210_RECEICV_BUFFER[1]=HLK210_RECEICV_BUFFER[HLK210_point-1];
		HLK210_point=2;
	}
	if(HLK210_point>=HLK210_Data.CmdDataLen)
	{
		HLK210_Data.isGetData = TRUE;
		memset(HLK210_Data.HLK210_Buffer, 0, HLK210_USART_REC_LEN);      //清空
		memcpy(HLK210_Data.HLK210_Buffer,HLK210_RECEICV_BUFFER, HLK210_point); 	//保存数据
	}
	if(HLK210_point>HLK210_USART_REC_LEN)
	{
		HLK210_point=HLK210_USART_REC_LEN-1;
	}
}
void HLK210_ClearDate(void)
{
	memset(HLK210_RECEICV_BUFFER, 0, HLK210_USART_REC_LEN);      //清空
	HLK210_point=0;
	
	HLK210_Data.CmdDataLen = HLK210_NORMALANSWERLEN;
	memset(HLK210_Data.HLK210_Buffer, 0, HLK210_USART_REC_LEN);      //清空
	HLK210_Data.isGetData = FALSE;
	HLK210_Data.isParseData = FALSE;
	HLK210_Data.isUsefull =  FALSE;
	HLK210_Data.NowMode = NORMAL;
	HLK210_Data.TimeCount = 0;
}

void HLK210_Send_Cmd(u8 *cmd)
{
	u8 i=0;
	for(i=0;i<18;i++)
	{
		HLK210_SendByte(*cmd++);  // == *(cmd++) 取cmd所指单元的值,cmd指向下一单元,即cmd自加1
	}
}
void HLK210_InputFaceID(void)
{
	u8 i=0;
	HLK210_ClearDate();
	HLK210_Data.CmdDataLen = HLK210_NORMALANSWERLEN;
	HLK210_Data.NowMode = INPUTFACEID;
	
	HLK210_Send_Cmd(HLK210_LightOn);  //开补光灯
	while(HLK210_Data.isGetData == FALSE); //等待接收完应答数据
	HLK210_Data.isGetData = FALSE;
	for(i=0;i<HLK210_Data.CmdDataLen;i++)
	{
		USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
	}
	
	HLK210_Send_Cmd(HLK210_FaceStorageCmd);
	while(HLK210_Data.isGetData == FALSE); //等待接收完应答数据
	HLK210_Data.isGetData = FALSE;
	for(i=0;i<HLK210_Data.CmdDataLen;i++)
	{
		USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
	}
	HLK210_Data.CmdDataLen = HLK210_FACEANSWERLEN;
//	while(HLK210_Data.isGetData == FALSE); //等待接收完应答数据
//	HLK210_Data.isGetData = FALSE;
//	for(i=0;i
//	{
//		USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
//	}
}
void HLK210_CheckFaceID(void)
{
	u8 i=0;
	HLK210_ClearDate();
	HLK210_Data.CmdDataLen = HLK210_NORMALANSWERLEN;
	HLK210_Data.NowMode = CHECKFACEID;
	
	HLK210_Send_Cmd(HLK210_LightOn);  //开补光灯
	while(HLK210_Data.isGetData == FALSE); //等待接收完应答数据
	HLK210_Data.isGetData = FALSE;
	for(i=0;i<HLK210_Data.CmdDataLen;i++)
	{
		USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
	}
	
	HLK210_Send_Cmd(HLK210_FaceCheckCmd);
	while(HLK210_Data.isGetData == FALSE); //等待接收完应答数据
	HLK210_Data.isGetData = FALSE;
	for(i=0;i<HLK210_Data.CmdDataLen;i++)
	{
		USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
	}
	HLK210_Data.CmdDataLen = HLK210_RECOANSWERLEN;
}

调用人脸识别方法(本次没有识别ID号,只是做了有没有识别成功的功能,后面再更新别的,数组19位存的就是有没有成功标识,成功位0,否则为其他值,常见为0x02:检测到人脸但未识别)

void Proc_CVHK210(void)
{
	if(HLK210_Data.isGetData == TRUE && HLK210_Data.NowMode == CHECKFACEID)
	{
		HLK210_Data.isGetData = FALSE;
		HLK210_Data.TimeCount = 0;
//		for(i=0;i
//		{
//			USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
//		}
		if(HLK210_Data.HLK210_Buffer[6]==0x02 && HLK210_Data.HLK210_Buffer[7]==0x0D && HLK210_Data.HLK210_Buffer[19]==0X00) 
		{
			LCD_Show.personNum = 2;
		}
		if(HLK210_Data.HLK210_Buffer[6]==0x02 && HLK210_Data.HLK210_Buffer[7]==0x0D && HLK210_Data.HLK210_Buffer[19]!=0X00) 
		{
			LCD_Show.personNum = 1;
		}
		LCD_Display();
	}
}

调用超时检测方法,因没有人脸时需要更新屏幕显示为“无人”状态,故用定时器设定3秒时间,没有收到人脸数据时,设定为无人。

if(TIM4_FlagStatus.Flag_1000MS == TRUE)
{
	HLK210_Data.TimeCount  ++;
	if(HLK210_Data.isGetData == FALSE && HLK210_Data.TimeCount>2)
	{
		LCD_Show.personNum = 0;
		LCD_Display();
		HLK210_Data.TimeCount = 3;
	}
}

串口1设定为和K210模块通信串口,调试过程进行串口3输出串口1接收到的人脸识别模块数据,以验证接收设计程序是否有问题。

HLK210_InputFaceID();
if(HLK210_Data.isGetData == TRUE && HLK210_Data.NowMode == INPUTFACEID)
{
	HLK210_Data.isGetData = FALSE;
	for(i=0;i<HLK210_Data.CmdDataLen;i++)
	{
		USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
	}
	if(HLK210_Data.HLK210_Buffer[6]==0x03 && HLK210_Data.HLK210_Buffer[7]==0x0D && HLK210_Data.HLK210_Buffer[18]==0X00) //录入成功
	{
		HLK210_CheckFaceID();
	}
}
if(HLK210_Data.isGetData == TRUE && HLK210_Data.NowMode == CHECKFACEID)
{
	HLK210_Data.isGetData = FALSE;
	for(i=0;i<HLK210_Data.CmdDataLen;i++)
	{
		USART3_SendByte(HLK210_Data.HLK210_Buffer[i]);
	}
}

5 效果如下

你可能感兴趣的:(单片机嵌入式,c语言,stm32,单片机,嵌入式硬件,计算机视觉)