STM32F4的DCMI接口驱动OV7670摄像头

2019-07-20 06:48发布

本帖最后由 王建峰 于 2018-5-6 17:23 编辑

     最近做比赛,需要用到摄像头。手上有探索者开发板,与带FIFO摄像头OV7670各一块,探索版没有OV7670摄像头的接口与程序,自能自己写IO口驱动。另外有坛友使用杜邦线连接,但我试过发现杜邦线太长造成的干扰比较大,太短的会然连线显得乱糟糟的。于是我打算利用OV2640的驱动接口,作为0V7670的驱动接口,反正两个接口都很像,只要改改程序对应的引脚配置就可以了。虽然功能还没实现,但总算把摄像头驱动起来了,先留个记录,备忘。
硬件资源:探索版F4开发板|带FIFO摄像头OV7670|杜邦线两根、

1.功能
      串口打印输出识别黑线的偏移值与帧率,由于手上没有配套的液晶屏,不能进行显示处理。 QQ截图20180504160612.png

2.软件修改
1.将DCMI端口对应的引脚配置成摄像头上的接口相对应,
     首先是对摄像头进行读写控制的引脚
[mw_shl_code=c,true]#define OV7670_WRST                PBout(7)                //写指针复位
#define OV7670_RCK                PAout(6)                //读数据时钟
#define OV7670_RRST                PAout(4)                  //读指针复位
#define OV7670_CS                PGout(15)                  //片选信号(OE)
#define OV7670_WREN                PGout(9)                //写入FIFO使能
#define OV7670_VSYNC          PAin(8)                //同步信号检测IO[/mw_shl_code]

     然后通过8个IO口对摄像头进行读数据操作 D0~D7
[mw_shl_code=c,true]#define OV7670_DATA                (u8)( (PEin(6)*128)+(PEin(5)*64)+(PBin(6)*32)+(PCin(11)*16)+(PCin(9)*8)+(PCin(8)*4)+(PCin(7)*2)+PCin(6)*1)[/mw_shl_code]
     DCMI中的8个数据IO口不是一组IO,我这里又是直接使用IO口读,所以就通过以上的方式读取一个字节数据。

     摄像头 寄存器通过 SCCB 时序访问并设置 ,由于SCCB和IIC时序一样,对SCCB的初始化就是对IIC的初始化!,这里就配置了IIC ,也就是PB8和PB9两个引脚,要分别接到DCMI的PD6和PD7两个口。

引脚配置:
[mw_shl_code=c,true]         GPIO_InitTypeDef  GPIO_InitStructure;
         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);         //使能相关端口时钟


        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4| GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO                                                        ///仿照这个做改动
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO        
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_15;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化GPIO        
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;                                //带上拉电阻的输入模式
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_SetBits(GPIOA,GPIO_Pin_8);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;                                //带上拉电阻的输入模式
        GPIO_Init(GPIOE, &GPIO_InitStructure);
        GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5);
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;                                //带上拉电阻的输入模式
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        GPIO_SetBits(GPIOB,GPIO_Pin_6);
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_7 | GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;                                //带上拉电阻的输入模式
        GPIO_Init(GPIOC, &GPIO_InitStructure);
        GPIO_SetBits(GPIOC,GPIO_Pin_11 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_7 | GPIO_Pin_6);[/mw_shl_code]

2.使用外部中断让读数据操作与摄像头输出同步
将PA6配置成外部中断,具体中断中处理:
[mw_shl_code=c,true]u8 ov_sta;
void EXTI9_5_IRQHandler(void)
{                        

        if(EXTI_GetITStatus(EXTI_Line8)==SET)
        {     
                if(ov_sta<2)
                {
                        if(ov_sta==0)
                        {
                                OV7670_WRST=0;                 //复位写指针                                   
                                OV7670_WRST=1;        
                                OV7670_WREN=1;                //允许写入FIFO
                        }else OV7670_WREN=0;        //禁止写入FIFO         
                        ov_sta++;
                }
        }
        EXTI_ClearITPendingBit(EXTI_Line8);    //清除LINE15上的中断标志位  
}
[/mw_shl_code]
当摄像头采集一帧图像时,控制允许写入FIFO。然后控制禁止写入FIFO,直到单片机从FIFO中读取完这一帧数据,也就是ov_sta=0,才能允许下一帧图像被写入FIFO。。
3.使用定时器计算帧率
配置定时器3为1s触发一次,也就是1s刷新一次帧率。
[mw_shl_code=applescript,true]void TIM3_IRQHandler(void)   //TIM3中断
{               
        if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
        {
        //                        printf("frame:%dfps ",ov_frame);                                        //通过串口显示
                                        ov_frame=0;        
        }
        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}[/mw_shl_code]
每完成一帧图像的采集,ov_frame这个变量+1

4.采集一帧60*80的像素点阵,并存放在一个二维数组
[mw_shl_code=c,true]
void camera_refresh(void)
{
         u16 color;        
        

        if(ov_sta==2)
        {
                 OV7670_CS=0;         
                 OV7670_RRST=0;                                //开始复位读指针
                OV7670_RCK=0;
                OV7670_RCK=1;
                OV7670_RCK=0;
                OV7670_RRST=1;                                //复位读指针结束
                OV7670_RCK=1;
               
                for(col=0;col<240;col++)
                {
                        if((col%4)==0)h++;                        //隔点采样,,,每4个距离采样一次
                        for(row=0;row<320;row++)
                        {  
                                OV7670_RCK=0;
                                color=OV7670_DATA;                //读数据
                                OV7670_RCK=1;         
                //                        color<<=8;                                          
                                OV7670_RCK=0;
                //                        color|=OV7670_DATA;                //读数据                                
                                OV7670_RCK=1;
                                
                                if(((col%4)==0)&&((row%4)==0))
                                {                                                
                                                v++;
                                                Pic_Buff[v-1][h-1]=(u8)color;                                //将采集的坐标点的颜 {MOD}信息存到二维数组中 (以便二值化处理)
                                                        
                                }
                                
        //                                color<<=8;                                                        //数据格式转换----转换为RGB格式
        //                                color_r = color&0xf800;
        //                                color_b = color>>11;
        //                                color >>=5;
        //                                color_g =color&0x07e0;                 
        //                                color= color_r + color_g + color_b;        
        //                                GPIOB->CRL=0X33333333;                                                         
        //                                LCD->LCD_RAM=color;
                        }
                        v = 0;
                }
                h=0;         
                OV7670_CS=1;                                                         
                OV7670_RCK=0;
                OV7670_RCK=1;
                EXTI->R=1<<15;                     //清除LINE8上的中断标志位
                ov_sta=0;                                        //开始下一次采集
                ov_frame++;
        //                LCD_Scan_Dir(DFT_SCAN_DIR);        //恢复默认扫描方向         
        }
}        [/mw_shl_code]

3.硬件连接
硬件连接很简单直接把摄像头插在DCMI接口座上,同时把引脚连接 PD6 - PB8 , PD7 - PB9。
QQ截图20180504164431.png
DCMI接口与单片机GPIO对应关系
QQ截图20180504160230.png





基于探索者,以上就把摄像头驱动的部分配置好了,想具体实现功能的话,直接把写好了的函数移植过来就可以了!!!
程序附上、、、
OV7670定位黑带 .zip (5.45 MB, 下载次数: 341) 2018-5-4 22:47 上传 点击文件名下载附件







友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。