作者:Signx
概述
當(dāng)前的人臉識(shí)別攝像頭,價(jià)格昂貴,擬改造成stm32單片機(jī)版本的,節(jié)省成本
功能:
1.連接攝像頭OV2640,用fish指令開啟攝像頭
2.將攝像頭數(shù)據(jù)傳到電腦顯示圖片
3.將攝像頭數(shù)據(jù)傳到spi顯示屏顯示(未完成)
4.用人臉識(shí)別算法識(shí)別人臉開鎖(未完成)
5.可登錄到tencent Cloud云平臺(tái),實(shí)現(xiàn)上云
開發(fā)環(huán)境:
硬件:Art-pi+OV2640
RT-Thread版本:4.0.2
開發(fā)工具及版本:rt-stuidio V2.0.0
RT-Thread使用情況概述:
硬件框架:art-pi官方開發(fā)板+OV2640(dma+DCMI)
軟件框架說明:
見思維導(dǎo)圖
軟件模塊說明:
見思維導(dǎo)圖
該系統(tǒng)的思維腦圖如下:
演示效果:
視頻:
實(shí)物圖如下:
實(shí)現(xiàn)的效果如圖:
連接電路如圖所示:
實(shí)現(xiàn)功能:
1.連接攝像頭OV2640,用fish指令開啟攝像頭
2.將攝像頭數(shù)據(jù)傳到電腦顯示圖片
3.將攝像頭數(shù)據(jù)傳到spi顯示屏顯示(未完成)
4.用人臉識(shí)別算法識(shí)別人臉開鎖(未完成)
5.可登錄到tencent Cloud云平臺(tái),實(shí)現(xiàn)上云主要碰到的技術(shù)難點(diǎn):
1.art-pi組建庫(kù)里有ov2640的軟件包,本以為直接能用的,結(jié)果發(fā)現(xiàn)有很多缺失
首先是io口的確實(shí),沒有定義到足夠的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
//數(shù)據(jù)信號(hào)線
#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時(shí)鐘 */
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();
/*控制/同步信號(hào)線*/
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);
/*數(shù)據(jù)信號(hào)*/
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引腳,高電平關(guān)閉電源,低電平供電*/
HAL_GPIO_WritePin(DCMI_PWDN_GPIO_PORT,DCMI_PWDN_GPIO_PIN,GPIO_PIN_RESET);
}
2.官方源代碼里沒有打開dcmi使能,導(dǎo)致編譯的時(shí)候會(huì)報(bào)錯(cuò),根據(jù)報(bào)錯(cuò)的情況把對(duì)應(yīng)的使能開開就行;
3.官方代碼導(dǎo)入之后并沒有開啟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);;
}
然后就把攝像頭驅(qū)動(dòng)起來了,這過程用去了3個(gè)周末的時(shí)間,吐槽一下官方庫(kù),沒做好就沒必要放出來嘛,放出來個(gè)有問題的,找問題比從頭寫更費(fèi)勁
比賽感悟:
1.學(xué)習(xí)到了如何用單片機(jī)控制OV2640乃至其他的攝像頭,學(xué)習(xí)到了DMA和HDCI的操作,這其中涉及到HDCI的引腳定義,需要查找手冊(cè)書
2.Rt-thread真的是一款非常好用的實(shí)時(shí)系統(tǒng),不光是功能強(qiáng)大,而且接口簡(jiǎn)潔明了,類linux的明明風(fēng)格更是讓開發(fā)者上手簡(jiǎn)單,先進(jìn)的面向?qū)ο笤O(shè)計(jì)思想讓我的代碼公里也見長(zhǎng)進(jìn)
3.感謝RT和電路城提供這么好的機(jī)會(huì),能讓我有機(jī)會(huì)親自操作ART-PI,當(dāng)然STM32H750和開發(fā)板的強(qiáng)大性能還擁有很大的開發(fā)潛力,
4.由于時(shí)間關(guān)系(年底事情多,好多項(xiàng)目等著結(jié)項(xiàng)),原定的實(shí)現(xiàn)人臉識(shí)別開鎖的功能做不了了,但是這么好的art-pi不能浪費(fèi)了,所以接下來還會(huì)繼續(xù)開發(fā),直到完成所有的功能為止.學(xué)會(huì)了rtthread官方包的導(dǎo)入