STM32F4驱动OV2640摄像头

一、概念

1.OV2640 摄像头

        OV2640 是 OV(OmniVision)公司生产的一颗 1/4 寸的 CMOS UXGA(1632*1232)图像传感器。该传感器体积小、工作电压低,提供单片 UXGA 摄像头和影像处理器的所有功能。通过 SCCB 总线控制(IIC总线),可以输出整帧、子采样、缩放和取窗口等方式的各种分辨率 8/10位影像数据。该产品 UXGA 图像最高达到 15 帧/秒(SVGA 可达 30 帧,CIF 可达 60 帧)。用户可以完全控制图像质量、数据格式和传输方式。所有图像处理功能过程包括伽玛曲线、白平衡、对比度、色度等都可以通过 SCCB 接口编程。OmmiVision 图像传感器应用独有的传感器技术,通过减少或消除光学或电子缺陷如固定图案噪声、拖尾、浮散等,提高图像质量,得到清晰的稳定的彩色图像。

1.1OV2640 的特点:

  • 高灵敏度、低电压适合嵌入式应用
  • 标准的 SCCB 接口,兼容 IIC 接口
  • 支持 RawRGB、RGB(RGB565/RGB555)、GRB422、YUV(422/420)和 YCbCr(422)输出格式
  • 支持 UXGA、SXGA、SVGA 以及按比例缩小到从 SXGA 到 40*30 的任何尺寸
  • 支持自动曝光控制、自动增益控制、自动白平衡、自动消除灯光条纹、自动黑电平校准等自动控制功能。同时支持色饱和度、色相、伽马、锐度等设置。
  • 支持闪光灯
  • 支持图像缩放、平移和窗口设置
  • 支持图像压缩,即可输出 JPEG 图像数据
  • 自带嵌入式微处理器

1.2 OV2640窗口

         ov2640在使用时,涉及到几个窗口,分别是传感器窗口、图像尺寸窗口、图像窗口和图像输出大小。这几个窗口与我们正常使用ov2640密切相关。

  1. 传感器窗口:该功能允许用户设置整个传感器区域(1632*1220)的感兴趣部分,也就是在传感器里面开窗,开窗范围从 2*2~1632*1220 都可以设置,不过要求这个窗口必须大于等于随后设置的图像尺寸
  2. 图像尺寸:图像尺寸也就是DSP输出图像的最大尺寸,该尺寸要小于等于前面我们传感器窗口设置所设定的窗口尺寸
  3. 图像窗口:图像窗口类似于传感器窗口,只是这个窗口是在我们前面设置的图像尺寸里面,再一次设置窗口大小,该窗口必须小于等于前面设置的图像尺寸
  4. 图像输出大小最终输出到外部的图像尺寸。该设置将图像窗口设置所决定的窗口大小,通过内部 DSP 处理,缩放成我们输出到外部的图像大小

 1.3 时序

        OV2640 的图像数据输出(通过 Y[9:0])就是在 PCLK,VSYNC 和 HREF/ HSYNC 的控制下进行的

  • PCLK,即像素时钟,一个 PCLK 时钟,输出一个像素(或半个像素)。
  • VSYNC,即帧同步信号。 
  • HREF /HSYNC,即行同步信号。 

行时序图

         从以上时序图可以看出,图像数据在 HREF 为高的时候输出,当 HREF 变高后,每一个 PCLK 时钟,输出一个8 位/10 位数据。我们采用8 位接口,所以每个PCLK 输出1 个字节,且在RGB/YUV输出格式下,每个 tp=2 个Tpclk,如果是 Raw 格式,则一个 tp=1 个 Tpclk。比如我们采用 UXGA时序,RGB565 格式输出,每 2 个字节组成一个像素的颜色(高低字节顺序可通过 0XDA 寄存器设置),这样每行输出总共有 1600*2 个 PCLK 周期,输出 1600*2 个字节。 

帧时序图

        上图清楚的表示了OV2640 在UXGA 模式下的数据输出。我们按照这个时序去读取OV2640
的数据,就可以得到图像数据。 

1.4 图像数据格式

        使用OV2640时,我们一般用两种输出方式:RGB565 和 JPEG。当输出 RGB565 格式数据的时候,时序完全就是上面两幅图介绍的关系。而当输出数据是 JPEG 数据的时候,同样也是这种方式输出(所以数据读取方法一模一样),不过 PCLK数目大大减少了,且不连续,输出的数据是压缩后的 JPEG 数据,输出的 JPEG 数据以:0XFF,0XD8 开头,以 0XFF,0XD9 结尾,且在 0XFF,0XD8 之前,或者 0XFF,0XD9 之后,会有不定数量的其他数据存在(一般是 0 ),这些数据我们直接忽略即可,将得到的0XFF,0XD8~0XFF,0XD9 之间的数据,保存为.jpg/.jpeg 文件,就可以直接在电脑上打开看到图像了。 

2.DCMI接口

        STM32F4 自带了一个数字摄像头(DCMI)接口该接口是一个同步并行接口,能够接收外部 8 位、10 位、12 位或 14 位 CMOS 摄像头模块发出的高速数据流。可支持不同的数据格式:YCbCr4:2:2/RGB565 逐行视频和压缩数据 (JPEG)

2.1 DCMI接口特点

  • 8 位、10 位、12 位或 14 位并行接口 
  • 内嵌码/外部行同步和帧同步 
  • 连续模式或快照模式 
  • 裁剪功能 
  • 支持以下数据格式: 

             1,8/10/12/14 位逐行视频:单色或原始拜尔(Bayer)格式 
             2,YCbCr 4:2:2 逐行视频 
             3,RGB 565 逐行视频 
             4,压缩数据:JPEG

2.2 DCMI接口信号

    DCMI 接口包括如下一些信号: 

  1. 数据输入(D[0:13]),用于接收摄像头的数据输出,接收OV2640我们只用了8位数据。
  2. 行同步输入信号(HSYNC),用于接收摄像头的HSYNC/HREF信号
  3. 垂直同步(场同步)输入(VSYNC),用于接摄像头的 VSYNC 信号。
  4. 像素时钟输入(PIXCLK),用于接摄像头的 PCLK 信号。 

        DCMI 接口是一个同步并行接口,可接收高速(可达 54 MB/s)数据流。该接口包含多达14 条数据线(D13-D0)和一条像素时钟线(PIXCLK)。像素时钟的极性可以编程,因此可以在像素时钟的上升沿或下降沿捕获数据

        DCMI 接收到的摄像头数据被放到一个 32 位数据寄存器(DCMI_DR)中,然后通过通用DMA 进行传输。图像缓冲区由 DMA 管理,而不是由摄像头接口管理。 

        从摄像头接收的数据可以按行/帧来组织原始 YUV/RGB/拜尔模式),也可以是一系列 
JPEG 图像。要使能 JPEG 图像接收,必须将 JPEG 位(DCMI_CR 寄存器的位 3)置 1。

        数据流可由可选的 HSYNC(水平同步)信号和 VSYNC(垂直同步)信号硬件同步,或
者通 过数据流中嵌入的同步码同步。 

DCMI 接口的框图

        DCMI 接口的数据与 PIXCLK(即 PCLK)保持同步并根据像素时钟的极性在像素时钟上升沿/下降沿发生变化。HSYNC(HREF)信号指示行的开始/结束,VSYNC 信号指示帧的开始/结束DCMI 信号波形如图 40.1.2.2 所示

        上图中,对应设置为:DCMI_PIXCLK 的捕获沿为下降沿,DCMI_HSYNC 和 DCMI_VSYNC的有效状态为 1注意,这里的有效状态实际上对应的是指示数据在并行接口上无效时,HSYNC/VSYNC 引脚上面的引脚电平

2.3 DCMI配置

        在OV2640实验中,我们用到的DCMI数据宽度位8位,通过设置DCMI_CR 中的EDM[1:0]=00 设置。此时DCMI_D0~D7 有效,DCMI_D8~D13 上的数据则忽略,这个时候,每次需要 4 个像素时钟来捕获一个 32 位数据。捕获的第一个数据存放在 32 位字的 LSB 位置,第四个数据存放在 32 位字的 MSB 位置 ,捕获数据字节在 32 位字中的排布如表 40.1.2.1 所示:

        DCMI 接口支持 DMA 传输,当 DCMI_CR 寄存器中的 CAPTURE 位置 1 时,激活 DMA接口。摄像头接口每次在其寄存器中收到一个完整的32 位数据块时,都将触发一个DMA 请求。

 DCMI_CR 寄存器各位描述 

  •  ENABLE,该位用于设置是否使能 DCMI,不过,在使能之前,必须将其他配置设置好。
  • FCRC[1:0],这两个位用于帧率控制,我们捕获所有帧,所以设置为 00 即可。
  • VSPOL,该位用于设置垂直同步极性,也就是 VSYNC 引脚上面,数据无效时的电平状态。
  • HSPOL,该位用于设置水平同步极性,也就是 HSYNC 引脚上面,数据无效时的电平状态。
  • PCKPOL,该位用于设置像素时钟极性,我们用上升沿捕获,所以设置为 1。
  • CM,该位用于设置捕获模式,我们用连续采集模式,所以设置为 0 即可。
  • CAPTURE,该位用于使能捕获,我们设置为 1该位使能后,将激活 DMA,DCMI 等待第一帧开始,然后生成 DMA 请求将收到的数据传输到目标存储器中。注意:该位必须在 DCMI
    的其他配置(包括 DMA)都设置好了之后,才设置!!

2.4 硬件同步

        硬件同步模式下将使用两个同步信号 (HSYNC/VSYNC)。根据摄像头模块/模式的不同,可能在水平/垂直同步期间内发送数据。由于系统会忽略 HSYNC/VSYNC 信号有效电平期间内接收的所有数据,HSYNC/VSYNC 信号相当于消隐信号。

        为了正确地将图像传输到 DMA/RAM 缓冲区,数据传输将与 VSYNC 信号同步。选择硬件同步模式并启用捕获(DCMI_CR 中的 CAPTURE 位置 1)时,数据传输将与 VSYNC 信号的 无效电平同步(开始下一帧时)。之后传输便可以连续执行,由 DMA 将连续帧传输到多个连续的缓冲区或一个具有循环特性的缓冲区。为了允许 DMA 管理连续帧,每一帧结束时都将激活VSIF(垂直同步中断标志,即帧中断),我们可以利用这个帧中断来判断是否有一帧数据采集完成,方便处理数据

        DCMI 接口的捕获模式支持:快照模式和连续采集模式。一般我们使用连续采集模式通过 DCMI_CR 中的 CM 位设置。另外,DCMI 接口还支持实现了 4 个字深度的 FIFO,配有一个简单的 FIFO 控制器,每次摄像头接口从 AHB 读取数据时读指针递增,每次摄像头接口向FIFO 写入数据时写指针递增。因为没有溢出保护,如果数据传输率超过 AHB 接口能够承受的速率,FIFO 中的数据就会被覆盖。如果同步信号出错,或者 FIFO 发生溢出,FIFO 将复位,DCMI 接口将等待新的数据帧开始。

二、程序编写:

以下程序对初始化函数进行展示:

//初始化OV2640
u8 OV2640_Init(void)
{
    u16 i=0;
	u16 reg;
	//初始化GPIO接口
    GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOG, ENABLE); 
	  
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOG, &GPIO_InitStructure);
	  
    //PWDN(PD3)
   	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	  
	OV2640_PWDN=0;
	delay_ms(10);
	OV2640_RST=0;
    delay_ms(10);
	OV2640_RST=1;	
    SCCB_Init();      
	SCCB_WR_Reg(OV2640_DSP_RA_DLMT, 0x01);	
   	SCCB_WR_Reg(OV2640_SENSOR_COM7, 0x80);	
    delay_ms(50); 
	reg=SCCB_RD_Reg(OV2640_SENSOR_MIDH);	
	reg<<=8;
	reg|=SCCB_RD_Reg(OV2640_SENSOR_MIDL);	
	  if(reg!=OV2640_MID)
	  {
	  	//printf("MID:%d\r\n",reg);
	  	return 1;
	  }
	  reg=SCCB_RD_Reg(OV2640_SENSOR_PIDH);	
	  reg<<=8;
	  reg|=SCCB_RD_Reg(OV2640_SENSOR_PIDL);	
	  if(reg!=OV2640_PID)
	  {
	  	//printf("HID:%d\r\n",reg);
	  	return 2;
	  }   
 	  //³õʼ»¯ OV2640,²ÉÓÃSXGA·Ö±æÂÊ(1600*1200)  
	  for(i=0;i<sizeof(ov2640_sxga_init_reg_tbl)/2;i++)
	  {
	    	SCCB_WR_Reg(ov2640_sxga_init_reg_tbl[i][0],ov2640_sxga_init_reg_tbl[i][1]);
   	} 
  	return 0x00; 	//ok
}

初始化DEMI接口:

//DCMI接口初始化
void My_DCMI_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOE, ENABLE); 
	RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI,ENABLE); 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ­
  GPIO_Init(GPIOA, &GPIO_InitStructure); 
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6; 
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11; 
  GPIO_Init(GPIOC, &GPIO_InitStructure); 	

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6; 
  GPIO_Init(GPIOE, &GPIO_InitStructure); 

	GPIO_PinAFConfig(GPIOA,GPIO_PinSource4,GPIO_AF_DCMI); //PA4,AF13  DCMI_HSYNC
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_DCMI); //PA6,AF13  DCMI_PCLK  
 	GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_DCMI); //PB7,AF13  DCMI_VSYNC 
 	GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_DCMI); //PC6,AF13  DCMI_D0  
 	GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_DCMI); //PC7,AF13  DCMI_D1 
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_DCMI); //PC8,AF13  DCMI_D2
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_DCMI); //PC9,AF13  DCMI_D3
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_DCMI);//PC11,AF13 DCMI_D4 
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_DCMI); //PB6,AF13  DCMI_D5 
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource5,GPIO_AF_DCMI); //PE5,AF13  DCMI_D6
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource6,GPIO_AF_DCMI); //PE6,AF13  DCMI_D7

	
	DCMI_DeInit(); 
 
 
  DCMI_InitStructure.DCMI_CaptureMode=DCMI_CaptureMode_Continuous; 
	DCMI_InitStructure.DCMI_CaptureRate=DCMI_CaptureRate_All_Frame; 
	DCMI_InitStructure.DCMI_ExtendedDataMode= DCMI_ExtendedDataMode_8b;   
	DCMI_InitStructure.DCMI_HSPolarity= DCMI_HSPolarity_Low; 
	DCMI_InitStructure.DCMI_PCKPolarity= DCMI_PCKPolarity_Rising; 
	DCMI_InitStructure.DCMI_SynchroMode= DCMI_SynchroMode_Hardware; 
	DCMI_InitStructure.DCMI_VSPolarity=DCMI_VSPolarity_Low; 
	DCMI_Init(&DCMI_InitStructure);

	DCMI_ITConfig(DCMI_IT_FRAME,ENABLE); 
	
	DCMI_Cmd(ENABLE);	 

  NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;		 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			 
	NVIC_Init(&NVIC_InitStructure);	 
}

实验结果: 

三、结束

        本文是对正点原子OV2640摄像头实验的学习,但是本文使用的开发板以及摄像头模块并不是整点原子的,因此GPIO接口可能对应不上。

整个实验的工程代码:https://download.csdn.net/download/sssxlxwbwz/72554042

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值