作者:Signx
概述
当前的人脸识别摄像头,价格昂贵,拟改造成stm32单片机版本的,节省成本
功能:
1.连接摄像头OV2640,用fish指令开启摄像头
2.将摄像头数据传到电脑显示图片
3.将摄像头数据传到spi显示屏显示(未完成)
4.用人脸识别算法识别人脸开锁(未完成)
5.可登录到tencent Cloud云平台,实现上云
开发环境:
硬件:Art-pi+OV2640
RT-Thread版本:4.0.2
开发工具及版本:rt-stuidio V2.0.0
RT-Thread使用情况概述:
硬件框架:art-pi官方开发板+OV2640(dma+DCMI)
软件框架说明:
见思维导图
软件模块说明:
见思维导图
该系统的思维脑图如下:
演示效果:
视频:
实物图如下:
实现的效果如图:
连接电路如图所示:
实现功能:
1.连接摄像头OV2640,用fish指令开启摄像头
2.将摄像头数据传到电脑显示图片
3.将摄像头数据传到spi显示屏显示(未完成)
4.用人脸识别算法识别人脸开锁(未完成)
5.可登录到tencent Cloud云平台,实现上云主要碰到的技术难点:
1.art-pi组建库里有ov2640的软件包,本以为直接能用的,结果发现有很多缺失
首先是io口的确实,没有定义到足够的io口,所以代码里又加上了io口的定义以及初始化:
io口定义代码:
typedef enum
{
BMP_QQVGA = 0x00, /* BMP Image QQVGA 160x120 Size */
BMP_QVGA = 0x01, /* BMP Image VGA 800*480 Size */
JPEG_160x120 = 0x02, /* JPEG Image 160x120 Size */
JPEG_176x144 = 0x03, /* JPEG Image 176x144 Size */
JPEG_320x240 = 0x04, /* JPEG Image 320x240 Size */
JPEG_352x288 = 0x05 /* JPEG Image 352x288 Size */
}ImageFormat_TypeDef;
/*摄像头接口 */
//IIC SCCB
//#define CAMERA_I2C I2C1
//#define CAMERA_I2C_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
//
//#define CAMERA_I2C_SCL_PIN GPIO_PIN_8
//#define CAMERA_I2C_SCL_GPIO_PORT GPIOB
//#define CAMERA_I2C_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
//#define CAMERA_I2C_SCL_AF GPIO_AF4_I2C1
//
//#define CAMERA_I2C_SDA_PIN GPIO_PIN_9
//#define CAMERA_I2C_SDA_GPIO_PORT GPIOB
//#define CAMERA_I2C_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
//#define CAMERA_I2C_SDA_AF GPIO_AF4_I2C1
//VSYNC
#define DCMI_VSYNC_GPIO_PORT GPIOI
#define DCMI_VSYNC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define DCMI_VSYNC_GPIO_PIN GPIO_PIN_5
#define DCMI_VSYNC_AF GPIO_AF13_DCMI
// HSYNC
#define DCMI_HSYNC_GPIO_PORT GPIOH
#define DCMI_HSYNC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
#define DCMI_HSYNC_GPIO_PIN GPIO_PIN_8
#define DCMI_HSYNC_AF GPIO_AF13_DCMI
//PIXCLK
#define DCMI_PIXCLK_GPIO_PORT GPIOA
#define DCMI_PIXCLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define DCMI_PIXCLK_GPIO_PIN GPIO_PIN_6
#define DCMI_PIXCLK_AF GPIO_AF13_DCMI
//PWDN
#define DCMI_PWDN_GPIO_PORT GPIOH
#define DCMI_PWDN_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
#define DCMI_PWDN_GPIO_PIN GPIO_PIN_3
//RST
//#define DCMI_RST_GPIO_PORT GPIOH
//#define DCMI_RST_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
//#define DCMI_RST_GPIO_PIN GPIO_PIN_8
//数据信号线
#define DCMI_D0_GPIO_PORT GPIOC
#define DCMI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D0_GPIO_PIN GPIO_PIN_6
#define DCMI_D0_AF GPIO_AF13_DCMI
#define DCMI_D1_GPIO_PORT GPIOC
#define DCMI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DCMI_D1_GPIO_PIN GPIO_PIN_7
#define DCMI_D1_AF GPIO_AF13_DCMI
#define DCMI_D2_GPIO_PORT GPIOG
#define DCMI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
#define DCMI_D2_GPIO_PIN GPIO_PIN_10
#define DCMI_D2_AF GPIO_AF13_DCMI
#define DCMI_D3_GPIO_PORT GPIOG
#define DCMI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
#define DCMI_D3_GPIO_PIN GPIO_PIN_11
#define DCMI_D3_AF GPIO_AF13_DCMI
#define DCMI_D4_GPIO_PORT GPIOH
#define DCMI_D4_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
#define DCMI_D4_GPIO_PIN GPIO_PIN_14
#define DCMI_D4_AF GPIO_AF13_DCMI
#define DCMI_D5_GPIO_PORT GPIOI
#define DCMI_D5_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define DCMI_D5_GPIO_PIN GPIO_PIN_4
#define DCMI_D5_AF GPIO_AF13_DCMI
#define DCMI_D6_GPIO_PORT GPIOB
#define DCMI_D6_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define DCMI_D6_GPIO_PIN GPIO_PIN_8
#define DCMI_D6_AF GPIO_AF13_DCMI
#define DCMI_D7_GPIO_PORT GPIOI
#define DCMI_D7_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define DCMI_D7_GPIO_PIN GPIO_PIN_7
#define DCMI_D7_AF GPIO_AF13_DCMI
io口初始化代码:
void OV2640_HW_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/***DCMI引脚配置***/
/* 使能DCMI时钟 */
DCMI_PWDN_GPIO_CLK_ENABLE();
DCMI_VSYNC_GPIO_CLK_ENABLE();
DCMI_HSYNC_GPIO_CLK_ENABLE();
DCMI_PIXCLK_GPIO_CLK_ENABLE();
DCMI_D0_GPIO_CLK_ENABLE();
DCMI_D1_GPIO_CLK_ENABLE();
DCMI_D2_GPIO_CLK_ENABLE();
DCMI_D3_GPIO_CLK_ENABLE();
DCMI_D4_GPIO_CLK_ENABLE();
DCMI_D5_GPIO_CLK_ENABLE();
DCMI_D6_GPIO_CLK_ENABLE();
DCMI_D7_GPIO_CLK_ENABLE();
/*控制/同步信号线*/
GPIO_InitStructure.Pin = DCMI_VSYNC_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Pull = GPIO_PULLUP ;
GPIO_InitStructure.Alternate = DCMI_VSYNC_AF;
HAL_GPIO_Init(DCMI_VSYNC_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_HSYNC_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_VSYNC_AF;
HAL_GPIO_Init(DCMI_HSYNC_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_PIXCLK_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_PIXCLK_AF;
HAL_GPIO_Init(DCMI_PIXCLK_GPIO_PORT, &GPIO_InitStructure);
/*数据信号*/
GPIO_InitStructure.Pin = DCMI_D0_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D0_AF;
HAL_GPIO_Init(DCMI_D0_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D1_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D1_AF;
HAL_GPIO_Init(DCMI_D1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D2_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D2_AF;
HAL_GPIO_Init(DCMI_D2_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D3_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D3_AF;
HAL_GPIO_Init(DCMI_D3_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D4_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D4_AF;
HAL_GPIO_Init(DCMI_D4_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D5_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D5_AF;
HAL_GPIO_Init(DCMI_D5_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D6_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D6_AF;
HAL_GPIO_Init(DCMI_D6_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_D7_GPIO_PIN;
GPIO_InitStructure.Alternate = DCMI_D7_AF;
HAL_GPIO_Init(DCMI_D7_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = DCMI_PWDN_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(DCMI_PWDN_GPIO_PORT, &GPIO_InitStructure);
/*PWDN引脚,高电平关闭电源,低电平供电*/
HAL_GPIO_WritePin(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN,GPIO_PIN_RESET);
}
2.官方源代码里没有打开dcmi使能,导致编译的时候会报错,根据报错的情况把对应的使能开开就行;
3.官方代码导入之后并没有开启dcmi的中断,又要打开中断:
static rt_err_t rt_hw_dcmi_init(DCMI_HandleTypeDef *device)
{
RT_ASSERT(device != RT_NULL);
__HAL_RCC_DCMI_CLK_ENABLE();//signx
device->Instance = DCMI;
device->Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
device->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
device->Init.VSPolarity = DCMI_VSPOLARITY_LOW;
device->Init.HSPolarity = DCMI_HSPOLARITY_LOW;
device->Init.CaptureRate = DCMI_CR_ALL_FRAME;
device->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
device->Init.JPEGMode = DCMI_JPEG_ENABLE;
device->Init.ByteSelectMode = DCMI_BSM_ALL;
device->Init.ByteSelectStart = DCMI_OEBS_ODD;
device->Init.LineSelectMode = DCMI_LSM_ALL;
device->Init.LineSelectStart = DCMI_OELS_ODD;
if (HAL_DCMI_Init(device) != HAL_OK)
{
LOG_E("dcmi init error!");
return RT_ERROR;
}
DCMI->IER = 0x0;
__HAL_DCMI_ENABLE_IT(device, DCMI_IT_FRAME);
__HAL_DCMI_ENABLE(device);
HAL_NVIC_SetPriority(DCMI_IRQn, 0x00, 0x05);
HAL_NVIC_EnableIRQ(DCMI_IRQn);;
return RT_EOK;
}
4.官方的代码没有打开dma的中断,又把dma的中断打开:
static void rt_hw_dcmi_dma_init(void)
{
__HAL_RCC_DMA2_CLK_ENABLE();
hdma_dcmi.Instance = DMA2_Stream1;
hdma_dcmi.Init.Request = DMA_REQUEST_DCMI;
hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dcmi.Init.Mode = DMA_CIRCULAR;
hdma_dcmi.Init.Priority = DMA_PRIORITY_HIGH;
hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_dcmi.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_dcmi.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_dcmi.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_Init(&hdma_dcmi);
__HAL_LINKDMA(&rt_dcmi.DCMI_Handle, DMA_Handle, hdma_dcmi);
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x00, 0x00);
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);;
}
然后就把摄像头驱动起来了,这过程用去了3个周末的时间,吐槽一下官方库,没做好就没必要放出来嘛,放出来个有问题的,找问题比从头写更费劲
比赛感悟:
1.学习到了如何用单片机控制OV2640乃至其他的摄像头,学习到了DMA和HDCI的操作,这其中涉及到HDCI的引脚定义,需要查找手册书
2.Rt-thread真的是一款非常好用的实时系统,不光是功能强大,而且接口简洁明了,类linux的明明风格更是让开发者上手简单,先进的面向对象设计思想让我的代码公里也见长进
3.感谢RT和电路城提供这么好的机会,能让我有机会亲自操作ART-PI,当然STM32H750和开发板的强大性能还拥有很大的开发潜力,
4.由于时间关系(年底事情多,好多项目等着结项),原定的实现人脸识别开锁的功能做不了了,但是这么好的art-pi不能浪费了,所以接下来还会继续开发,直到完成所有的功能为止.学会了rtthread官方包的导入