STM32F4外设配置速查【OV2640摄像头部分】

本文详细介绍了OV2640摄像头的SCCB时序、不同分辨率输出、窗口和尺寸设置,以及JPEG时序配置。涵盖了硬件配置、软件驱动和实际应用流程,适合进行图像采集和处理的项目开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

OV2640

OV2640是OmniVision公司生产的1/4英寸CMOS UXGA(1632_1232分辨率)图像传感器

特点:

  • 体积小、工作电压低、灵敏度高
  • 具有单片UXGA摄像头和影像处理器的所有功能
  • 通过SCCB总线控制
  • 可输出整帧、子采样、缩放、取窗口等方式各种分辨率的8/10位影像数据
  • 最高帧数15帧/秒(SVGA可达30帧,CIF可达60帧)
  • 用户定义图像质量、数据格式、传输方式等
  • 所有图像处理功能都可以通过SCCB接口(行摄像机控制总线协议,相当于一个简易的I2C协议)编程
  • 兼容I2C接口
  • 支持RawRGB、RGB、GRB422、YUV和YCbCr输出格式
  • 内置DSP,支持UXGA、SXGA、SVGA以及按比例缩小到从SXGA到40*30的任何尺寸,支持图像缩放
  • 支持自动曝光控制、自动增益控制、自动白平衡、自动消除灯光条纹、自动黑电平校准等自动控制功能和色饱和度、色相、伽马、锐度等设置,支持闪光灯
  • 支持图像压缩,可输出JPEG图像数据

SCCB时序

SCCB(Serial Camera Control Bus串行摄像头控制总线)总线是由OV(OmniVision)公司定义和发展的三线式串行总线。现在SCCB总线大多采用两线式接口总线,接口总线包括SIOC串行时钟输入线和SIOD串行双向数据线,分别相当于IIC协议的SCL信号线和SDA信号线。SCCB就是个简化版的IIC,可以直接使用IIC的软件驱动代码改编成SCCB的驱动

基本概念简介

UXGA1600*1200
SXGA1280*1024
XVGA1280*960
WXGA1280*800
XGA1024*768
SVGA800*600
VGA640*480
QQVGA160*120
CIF352*288
PCLK像素时钟:一个PCLK时钟,输出一个(Raw格式)或半个(RGB565格式)像素
VSYNC帧同步信号
HREF/HSYNC行同步信号

ov2640的图像数据输出通过Y[9:0]寄存器输出,这里只使用一**字节(8位)**数据,再PCLK、VSYNC、HREF/HSYNC控制下进行

对于Raw格式数据, 1 ∗ t p = 1 ∗ T P C L K 1*t_p=1*T_{PCLK} 1tp=1TPCLK

对于YUV/RGB格式数据, 1 ∗ t p = 2 ∗ T P C L K 1*t_p=2*T_{PCLK} 1tp=2TPCLK

行输出时序

HREF高电平期间的PCLK上升沿进行输出,每个PCLK上升沿从Y[9:0]输出一个**字节(8位)**数据

PCLK最大可达36MHz

例:以UXGA(1600*1200)时序,采用RGB565格式输出,每2字节组成一个像素的颜色,且低字节在前高字节在后。这样每行输出总共有1600*2个PCLK周期输出1600*2个字节

帧输出时序

输出开始时,VSYNC输出 4 ∗ t L I N E 4*t_{LINE} 4tLINE有效电平(可自行设置为高/低)脉冲

27193 ∗ t p 27193*t_p 27193tp后,HREF拉高,开始输出行数据,每行数据输出之间以 322 ∗ t p 322*t_p 322tp为间隔,直到完成所有行输出

最后会有 57697 ∗ t p 57697*t_p 57697tp间隔才能进行下一帧输出

JPEG时序

JPEG输出时,PCLK大大减少,HREF不连续,数据流以0xFF、0xD8开头,以0xFF、0xD9结束,将此间数据保存为.jpg文件即可在电脑打开查看

相关硬件配置

OV2640传感器窗口设置

传感器窗口设置允许用户设置整个传感器区域(1632*1220)的感兴趣部分,即在传感器里面开窗,开窗范围从2*2到1632*1220都可以设置,但要求这个窗口必须大于等于随后设置的图像尺寸

详细内容可查看数据手册

图像尺寸设置

DSP输出到LCD的图像最大尺寸,该尺寸要小于等于传感器窗口设置所设定的窗口尺寸

图像窗口设置

在设置的图像尺寸里面再次设置窗口大小,该窗口必须小于等于前面设置的图像尺寸,该窗口设置后的图像范围将用于输出到外部

图像输出大小设置(缩放设置)

控制最终输出到外部的图像尺寸

该设置仅会对图像进行缩放处理,如果设置的图像输出大小不等于图像窗口设置图像大小,那么图像就会被缩放处理,只有两者大小一样(图像输出大小=图像窗口设置大小)时,输出比例才是1:1

OV2640模块参数

  1. 支持RGB565/JPEG数据输出
  2. 支持最大UXGA分辨率输出
  3. 支持图像任意缩放
  4. 自带24M有源晶振、3.3V稳压电路、带滤光片的感光红外镜头
  5. 支持手动对焦(旋下盖上螺丝调节镜头即可)

引脚参数:

脚位名称说明
1GND接地
2VCC3.3接3.3V电源
3OV_SCLSCCB时钟线(I)
4OV_VSYNC帧同步信号(O)
5OV_SDASCCB数据线(I/O)
6OV_HREF行同步信号(O)
8OV_RESET复位信号,低电平有效(I)
15OV_PCLK像素时钟(O)
17OV_PWDN掉电模式使能,高电平有效(I)
18NC空脚
7、9、10、11、12、13、14、16OV_D0~D7数据线(O)

OV2640模块使用过程

初始化

  1. 初始化IO口
  2. 上电、复位
  3. 读取传感器ID
  4. 执行初始化序列

全部内容由OV2640公司提供源码

MCU读取模块图像数据

  1. 等待帧同步(等待VSYNC信号)
  2. 等待HRED为高电平
  3. 等待第一个PCLK上升沿
  4. 读取第一个像素的低字节
  5. 等待第二个PCLK上升沿
  6. 读取第一个像素的高字节
  7. 等待下一个PCLK上升沿
  8. 重复4-7步骤直到读完剩余像素
  9. 结束读取

DCMI接口

DCMI(Digital Camera Interface)是STM32F4xx自带的数字摄像头接口,属于同步并行接口

特性:

  • 能够接受外部8、10、12、14位并行接口最高54MB/s的高速数据流

  • 支持内嵌码/外部行同步/帧同步

  • 支持连续模式或快照模式

  • 支持裁剪功能

  • 可支持不同数据格式:单色或原始拜尔(Bayer)格式、YCbCr 4:2:2逐行视频、RGB565逐行视频、压缩数据(JPEG)格式

  • 接口通过FIFO和数据格式化器直接与AHB总线相连

该接口包含14条数据线(D13-D0)和1条像素时钟线(PIXCLK),且像素时钟的有效电平可由用户程序决定,能在像素时钟的上升沿或下降沿捕获数据

DCMI接口包含以下信号:

DCMI接口引脚别名对应OV2640接口引脚
数据流输入D[0:13]数据流输出D[0:7]
水平同步输入HREF/HSYNC行同步行同步信号HREF/HSYNC
垂直同步输入VSYNC帧同步/场同步帧同步信号VSYNC
像素时钟输入PIXCLK像素时钟像素时钟PCLK

时序

数据与PIXCLK同步,并根据像素时钟的极性在像素时钟上升沿/下降沿发生变化

HREF/HSYNC指示行的开始或结束,VSYNC指示帧的开始或结束

DCMI时序与上述OV2640时序基本一致,但DCMI的PIXCLK有效沿可自定义,且HSYNC、VSYNC有效状态对应指示数据在并行接口上无效时,HSYNC/VSYNC引脚上的引脚电平(人话:和OV2640的有效状态相反

数据存储

DCMI接收到的数据存储在DCMI_DR 32位寄存器内,接入OV2640模块时采用8位数据宽度,所以每4个像素时钟才捕获完32位数据,第一个字节存放在LSB位置,第四个字节存放在MSB位置遵守低字节在前,高字节在后

DCMI支持DMA传输,DCMI可被配置为每在其数据寄存器中收到一个完整的32位数据块时,发送一个DMA请求,由DMA将寄存器内的值搬运到目的地址(如LCD/SRAM)

注意:DCMI的DMA请求映射在DMA2 Channel1 Stream1上;如果使用DCMI->DMA->LCD的传输路径,因为LCD是16位宽(RGB565),但DCMI_DR是32位宽,所以一次DCMI引起的DMA请求将引发往LCD写2次数据

相关设置

DCMI支持连续模式和快照模式,连续模式=录像;快照模式=照相

DCMI支持内嵌码同步和硬件同步,一般采用硬件同步

硬件同步下使用HSYNC和VSYNC两个信号,系统会忽略两个信号有效电平期间接收的所有数据,即硬件同步模式下的HSYNC、VSYNC信号相当于消隐信号

初始化流程

  1. 配置相关引脚复用为DCMI
  2. 使能DCMI时钟
  3. 设置DCMI工作模式和PCLK、HSYNC、VSYNC等参数
  4. 设置DMA搬运DCMI数据
  5. 使能DCMI传输

实际配置方法与代码

硬件配置

OV2640模块-转接-DCMI接口 对应好即可

软件配置

  1. sccb协议驱动(与I2C协议类似)

sccb.h

#ifndef __SCCB_H
	#define __SCCB_H
	#include "sys.h"
	//IO方向设置
	#define SCCB_SDA_IN() {GPIOD->MODER&=~(3<<(7*2));GPIOD->MODER|=0<<7*2;} //PD7输入
	#define SCCB_SDA_OUT() {GPIOD->MODER&=~(3<<(7*2));GPIOD->MODER|=1<<7*2;} //PD7输出

	//IO操作函数
	#define SCCB_SCL PDout(6) //PD6配置为SCL(仅输出)
	#define SCCB_SDA PDout(7) //SDA输出
	#define SCCB_READ_SDA PDin(7) //SDA输出

	#define SCCB_ID 0X60 //OV2640的ID

	void SCCB_Init(void);//SCCB接口初始化
	void SCCB_Start(void);//起始信号
	void SCCB_Stop(void);//停止信号
	void SCCB_No_Ack(void);//NA信号
	u8 SCCB_WR_Byte(u8 dat);//写数据
	u8 SCCB_RD_Byte(void);//读数据
	u8 SCCB_WR_Reg(u8 reg,u8 data);//写寄存器
	u8 SCCB_RD_Reg(u8 reg);//读寄存器
#endif

sccb.c

#include "sccb.h"
#include "delay.h"

//初始化SCCB接口 
void SCCB_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);//使能GPIOD时钟
    
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;//PD6、PD7
	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(GPIOD,&GPIO_InitStructure);
 
	GPIO_SetBits(GPIOD,GPIO_Pin_6|GPIO_Pin_7);//初始为高电平
	SCCB_SDA_OUT();
}

//SCCB起始信号
//时钟为高时,数据线下降沿,为SCCB起始信号
//在激活状态下,SDA和SCL均为低电平
void SCCB_Start(void)
{
    SCCB_SDA=1;//数据线高电平	   
    SCCB_SCL=1;//时钟线高时数据线下降沿
    delay_us(50);
    SCCB_SDA=0;
    delay_us(50);
    SCCB_SCL=0;//数据线恢复低电平,单操作函数必要	  
}

//SCCB停止信号
//时钟为高时,数据线上升沿,为SCCB停止信号
//空闲状况下,SDA,SCL均为高电平
void SCCB_Stop(void)
{
    SCCB_SDA=0;
    delay_us(50);	 
    SCCB_SCL=1;//数据线高电平
    delay_us(50);
    SCCB_SDA=1;//时钟线高时数据线上升沿
    delay_us(50);
}

//NA信号
void SCCB_No_Ack(void)
{
	delay_us(50);
	SCCB_SDA=1;//SDA、SCL都为高电平
	SCCB_SCL=1;
	delay_us(50);
	SCCB_SCL=0;
	delay_us(50);
	SCCB_SDA=0;
	delay_us(50);
}

//SCCB写入一个字节
//返回值:0,成功;1,失败
u8 SCCB_WR_Byte(u8 dat)
{
	u8 j,res;	 
	for(j=0;j<8;j++)//循环8次发送数据
	{
		if(dat&0x80)
            SCCB_SDA=1;	
		else
            SCCB_SDA=0;
		dat<<=1;//发送数据
		delay_us(50);
		SCCB_SCL=1;
		delay_us(50);
		SCCB_SCL=0;		   
	}
	SCCB_SDA_IN();//设置SDA为输入 
	delay_us(50);
	SCCB_SCL=1;//接收第九位,判断是否发送成功
	delay_us(50);
	if(SCCB_READ_SDA)//读取到NA数据
        res=1;//SDA=1发送失败,返回1
	else
        res=0;//SDA=0发送成功,返回0
	SCCB_SCL=0;		 
	SCCB_SDA_OUT();//设置SDA为输出 
    
	return res;
}

//SCCB读取一个字节
//SCL上升沿,数据锁存
//返回值:读到的数据
u8 SCCB_RD_Byte(void)
{
	u8 temp=0,j;
	SCCB_SDA_IN();//设置SDA为输入  
	for(j=8;j>0;j--)//循环8次接收数据
	{
		delay_us(50);
		SCCB_SCL=1;
		temp=temp<<1;
		if(SCCB_READ_SDA)
            temp++;   
		delay_us(50);
		SCCB_SCL=0;
	}
	SCCB_SDA_OUT();//设置SDA为输出    
	
    return temp;
}

//写寄存器
//返回值:0,成功;1,失败.
u8 SCCB_WR_Reg(u8 reg,u8 data)
{
	u8 res=0;
	SCCB_Start();//启动SCCB传输
	if(SCCB_WR_Byte(SCCB_ID))
        res=1;//写器件ID	  
	delay_us(100);
  	if(SCCB_WR_Byte(reg))
        res=1;//写寄存器地址	  
	delay_us(100);
  	if(SCCB_WR_Byte(data))
       res=1;//写数据	 
  	SCCB_Stop();
  	return
        res;
}

//读寄存器
//返回值:读到的寄存器值
u8 SCCB_RD_Reg(u8 reg)
{
	u8 val=0;
	SCCB_Start();//启动SCCB传输
	SCCB_WR_Byte(SCCB_ID);//写器件ID
	delay_us(100);	 
  	SCCB_WR_Byte(reg);//写寄存器地址	  
	delay_us(100);	  
	SCCB_Stop();   
	delay_us(100);	   
	
    //设置寄存器地址后进行读操作
	SCCB_Start();
	SCCB_WR_Byte(SCCB_ID|0X01);//发送读命令	  
	delay_us(100);
  	val=SCCB_RD_Byte();//读取数据
  	SCCB_No_Ack();
  	SCCB_Stop();
  	return val;
}
  1. ov2640驱动

ov2640.h

#ifndef _OV2640_H
#define _OV2640_H
#include "sys.h"
#include "sccb.h"

#define OV2640_PWDN PGout(9) //POWER_DOWN控制信号 
#define OV2640_RST PGout(15) //复位控制信号 

/*片内信息核对*/
#define OV2640_MID 0X7FA2
#define OV2640_PID 0X2642
 
//当选择DSP地址(0XFF=0X00)时,OV2640的DSP寄存器地址映射表
#define OV2640_DSP_R_BYPASS     0x05
#define OV2640_DSP_Qs           0x44
#define OV2640_DSP_CTRL         0x50
#define OV2640_DSP_HSIZE1       0x51
#define OV2640_DSP_VSIZE1       0x52
#define OV2640_DSP_XOFFL        0x53
#define OV2640_DSP_YOFFL        0x54
#define OV2640_DSP_VHYX         0x55
#define OV2640_DSP_DPRP         0x56
#define OV2640_DSP_TEST         0x57
#define OV2640_DSP_ZMOW         0x5A
#define OV2640_DSP_ZMOH         0x5B
#define OV2640_DSP_ZMHH         0x5C
#define OV2640_DSP_BPADDR       0x7C
#define OV2640_DSP_BPDATA       0x7D
#define OV2640_DSP_CTRL2        0x86
#define OV2640_DSP_CTRL3        0x87
#define OV2640_DSP_SIZEL        0x8C
#define OV2640_DSP_HSIZE2       0xC0
#define OV2640_DSP_VSIZE2       0xC1
#define OV2640_DSP_CTRL0        0xC2
#define OV2640_DSP_CTRL1        0xC3
#define OV2640_DSP_R_DVP_SP     0xD3
#define OV2640_DSP_IMAGE_MODE   0xDA
#define OV2640_DSP_RESET        0xE0
#define OV2640_DSP_MS_SP        0xF0
#define OV2640_DSP_SS_ID        0x7F
#define OV2640_DSP_SS_CTRL      0xF8
#define OV2640_DSP_MC_BIST      0xF9
#define OV2640_DSP_MC_AL        0xFA
#define OV2640_DSP_MC_AH        0xFB
#define OV2640_DSP_MC_D         0xFC
#define OV2640_DSP_P_STATUS     0xFE
#define OV2640_DSP_RA_DLMT      0xFF 

//当选择传感器地址(0XFF=0X01)时,OV2640的DSP寄存器地址映射表
#define OV2640_SENSOR_GAIN       0x00
#define OV2640_SENSOR_COM1       0x03
#define OV2640_SENSOR_REG04      0x04
#define OV2640_SENSOR_REG08      0x08
#define OV2640_SENSOR_COM2       0x09
#define OV2640_SENSOR_PIDH       0x0A
#define OV2640_SENSOR_PIDL       0x0B
#define OV2640_SENSOR_COM3       0x0C
#define OV2640_SENSOR_COM4       0x0D
#define OV2640_SENSOR_AEC        0x10
#define OV2640_SENSOR_CLKRC      0x11
#define OV2640_SENSOR_COM7       0x12
#define OV2640_SENSOR_COM8       0x13
#define OV2640_SENSOR_COM9       0x14
#define OV2640_SENSOR_COM10      0x15
#define OV2640_SENSOR_HREFST     0x17
#define OV2640_SENSOR_HREFEND    0x18
#define OV2640_SENSOR_VSTART     0x19
#define OV2640_SENSOR_VEND       0x1A
#define OV2640_SENSOR_MIDH       0x1C
#define OV2640_SENSOR_MIDL       0x1D
#define OV2640_SENSOR_AEW        0x24
#define OV2640_SENSOR_AEB        0x25
#define OV2640_SENSOR_W          0x26
#define OV2640_SENSOR_REG2A      0x2A
#define OV2640_SENSOR_FRARL      0x2B
#define OV2640_SENSOR_ADDVSL     0x2D
#define OV2640_SENSOR_ADDVHS     0x2E
#define OV2640_SENSOR_YAVG       0x2F
#define OV2640_SENSOR_REG32      0x32
#define OV2640_SENSOR_ARCOM2     0x34
#define OV2640_SENSOR_REG45      0x45
#define OV2640_SENSOR_FLL        0x46
#define OV2640_SENSOR_FLH        0x47
#define OV2640_SENSOR_COM19      0x48
#define OV2640_SENSOR_ZOOMS      0x49
#define OV2640_SENSOR_COM22      0x4B
#define OV2640_SENSOR_COM25      0x4E
#define OV2640_SENSOR_BD50       0x4F
#define OV2640_SENSOR_BD60       0x50
#define OV2640_SENSOR_REG5D      0x5D
#define OV2640_SENSOR_REG5E      0x5E
#define OV2640_SENSOR_REG5F      0x5F
#define OV2640_SENSOR_REG60      0x60
#define OV2640_SENSOR_HISTO_LOW  0x61
#define OV2640_SENSOR_HISTO_HIGH 0x62

/*OV2640初始化函数*/
u8 OV2640_Init(void);
/*OV2640选项调节函数*/
void OV2640_JPEG_Mode(void);
void OV2640_RGB565_Mode(void);
void OV2640_Auto_Exposure(u8 level);
void OV2640_Light_Mode(u8 mode);
void OV2640_Color_Saturation(u8 sat);
void OV2640_Brightness(u8 bright);
void OV2640_Contrast(u8 contrast);
void OV2640_Special_Effects(u8 eft);
void OV2640_Color_Bar(u8 sw);
/*OV2640硬件软件"开窗"函数*/
void OV2640_Window_Set(u16 sx,u16 sy,u16 width,u16 height);
u8 OV2640_OutSize_Set(u16 width,u16 height);
u8 OV2640_ImageWin_Set(u16 offx,u16 offy,u16 width,u16 height);
u8 OV2640_ImageSize_Set(u16 width,u16 height);
#endif

ov2640.c

#include "ov2640.h"
#include "ov2640cfg.h"
#include "timer.h“
#include "sccb.h"
#include "delay.h"
#include "usart.h"

//初始化OV2640 
//默认输出1600*1200尺寸的图片
//返回值:0,成功
//    其他,错误代码
u8 OV2640_Init(void)
{ 
	u16 i=0;
	u16 reg;

    /*设置IO连接OV2640*/
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	//GPIOG9,15初始化设置
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_15;//PG9,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);

	OV2640_PWDN=0;//开始硬复位
	delay_ms(10);
	OV2640_RST=0;//复位OV2640
	delay_ms(10);
	OV2640_RST=1;//结束复位
    
	SCCB_Init();//初始化SCCB 的IO口	 
	SCCB_WR_Reg(OV2640_DSP_RA_DLMT,0x01);//操作sensor寄存器
	SCCB_WR_Reg(OV2640_SENSOR_COM7,0x80);//开始软复位
	delay_ms(50);
	reg=SCCB_RD_Reg(OV2640_SENSOR_MIDH);//读取厂家ID 高八位
	reg<<=8;//存入寄存器
	reg|=SCCB_RD_Reg(OV2640_SENSOR_MIDL);//读取厂家ID 低八位 并 存入寄存器
	if(reg!=OV2640_MID)
	{
		printf("MID:%d\r\n",reg);
		return 1;
	}
    
	reg=SCCB_RD_Reg(OV2640_SENSOR_PIDH);//读取厂家ID 高八位
	reg<<=8;
	reg|=SCCB_RD_Reg(OV2640_SENSOR_PIDL);//读取厂家ID 低八位
	if(reg!=OV2640_PID)
	{
		printf("HID:%d\r\n",reg);
		return 2;
	}
    
	/*采用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;
} 

/*参数选项函数*/
//OV2640切换为JPEG模式
void OV2640_JPEG_Mode(void) 
{
	u16 i=0;
	//设置:YUV422格式
	for(i=0;i<(sizeof(ov2640_yuv422_reg_tbl)/2);i++)
	{
		SCCB_WR_Reg(ov2640_yuv422_reg_tbl[i][0],ov2640_yuv422_reg_tbl[i][1]); 
	} 
	
	//设置:输出JPEG数据
	for(i=0;i<(sizeof(ov2640_jpeg_reg_tbl)/2);i++)
	{
		SCCB_WR_Reg(ov2640_jpeg_reg_tbl[i][0],ov2640_jpeg_reg_tbl[i][1]);  
	}  
}
//OV2640切换为RGB565模式
void OV2640_RGB565_Mode(void) 
{
	u16 i=0;
	//设置:RGB565输出
	for(i=0;i<(sizeof(ov2640_rgb565_reg_tbl)/2);i++)
	{
		SCCB_WR_Reg(ov2640_rgb565_reg_tbl[i][0],ov2640_rgb565_reg_tbl[i][1]); 
	} 
} 
//自动曝光设置参数表,支持5个等级
const static u8 OV2640_AUTOEXPOSURE_LEVEL[5][8]=
{
	{
		0xFF,0x01,
		0x24,0x20,
		0x25,0x18,
		0x26,0x60,
	},
	{
		0xFF,0x01,
		0x24,0x34,
		0x25,0x1c,
		0x26,0x00,
	},
	{
		0xFF,0x01,	
		0x24,0x3e,	
		0x25,0x38,
		0x26,0x81,
	},
	{
		0xFF,0x01,
		0x24,0x48,
		0x25,0x40,
		0x26,0x81,
	},
	{
		0xFF,0x01,	
		0x24,0x58,	
		0x25,0x50,	
		0x26,0x92,	
	},
}; 
//OV2640自动曝光等级设置
//level:0~4
void OV2640_Auto_Exposure(u8 level)
{  
	u8 i;
	u8* p=(u8*)OV2640_AUTOEXPOSURE_LEVEL[level];
	for(i=0;i<4;i++)
	{ 
		SCCB_WR_Reg(p[i*2],p[i*2+1]); 
	} 
} 
//白平衡设置
//0:自动
//1:太阳sunny
//2,阴天cloudy
//3,办公室office
//4,家里home
void OV2640_Light_Mode(u8 mode)
{
	u8 regccval=0X5E;//Sunny 
	u8 regcdval=0X41;
	u8 regceval=0X54;
	switch(mode)
	{ 
		case 0://auto 
			SCCB_WR_Reg(0XFF,0X00);	 
			SCCB_WR_Reg(0XC7,0X10);//AWB ON 
			return;  	
		case 2://cloudy
			regccval=0X65;
			regcdval=0X41;
			regceval=0X4F;
			break;	
		case 3://office
			regccval=0X52;
			regcdval=0X41;
			regceval=0X66;
			break;	
		case 4://home
			regccval=0X42;
			regcdval=0X3F;
			regceval=0X71;
			break;	
	}
	SCCB_WR_Reg(0XFF,0X00);	 
	SCCB_WR_Reg(0XC7,0X40);	//AWB OFF 
	SCCB_WR_Reg(0XCC,regccval); 
	SCCB_WR_Reg(0XCD,regcdval); 
	SCCB_WR_Reg(0XCE,regceval);  
}
//色度设置
//0:-2
//1:-1
//2,0
//3,+1
//4,+2
void OV2640_Color_Saturation(u8 sat)
{ 
	u8 reg7dval=((sat+2)<<4)|0X08;
	SCCB_WR_Reg(0XFF,0X00);		
	SCCB_WR_Reg(0X7C,0X00);		
	SCCB_WR_Reg(0X7D,0X02);				
	SCCB_WR_Reg(0X7C,0X03);			
	SCCB_WR_Reg(0X7D,reg7dval);			
	SCCB_WR_Reg(0X7D,reg7dval); 		
}
//亮度设置
//0:(0X00)-2
//1:(0X10)-1
//2,(0X20) 0
//3,(0X30)+1
//4,(0X40)+2
void OV2640_Brightness(u8 bright)
{
  SCCB_WR_Reg(0xff, 0x00);
  SCCB_WR_Reg(0x7c, 0x00);
  SCCB_WR_Reg(0x7d, 0x04);
  SCCB_WR_Reg(0x7c, 0x09);
  SCCB_WR_Reg(0x7d, bright<<4); 
  SCCB_WR_Reg(0x7d, 0x00); 
}
//对比度设置
//0:-2
//1:-1
//2,0
//3,+1
//4,+2
void OV2640_Contrast(u8 contrast)
{
	u8 reg7d0val=0X20;//默认为普通模式
	u8 reg7d1val=0X20;
  	switch(contrast)
	{
		case 0://-2
			reg7d0val=0X18;	 	 
			reg7d1val=0X34;	 	 
			break;	
		case 1://-1
			reg7d0val=0X1C;	 	 
			reg7d1val=0X2A;	 	 
			break;	
		case 3://1
			reg7d0val=0X24;	 	 
			reg7d1val=0X16;	 	 
			break;	
		case 4://2
			reg7d0val=0X28;	 	 
			reg7d1val=0X0C;	 	 
			break;	
	}
	SCCB_WR_Reg(0xff,0x00);
	SCCB_WR_Reg(0x7c,0x00);
	SCCB_WR_Reg(0x7d,0x04);
	SCCB_WR_Reg(0x7c,0x07);
	SCCB_WR_Reg(0x7d,0x20);
	SCCB_WR_Reg(0x7d,reg7d0val);
	SCCB_WR_Reg(0x7d,reg7d1val);
	SCCB_WR_Reg(0x7d,0x06);
}
//特效设置
//0:普通模式    
//1,负片
//2,黑白   
//3,偏红色
//4,偏绿色
//5,偏蓝色
//6,复古	    
void OV2640_Special_Effects(u8 eft)
{
	u8 reg7d0val=0X00;//默认为普通模式
	u8 reg7d1val=0X80;
	u8 reg7d2val=0X80; 
	switch(eft)
	{
		case 1://负片
			reg7d0val=0X40; 
			break;	
		case 2://黑白
			reg7d0val=0X18; 
			break;	 
		case 3://偏红色
			reg7d0val=0X18; 
			reg7d1val=0X40;
			reg7d2val=0XC0; 
			break;	
		case 4://偏绿色
			reg7d0val=0X18; 
			reg7d1val=0X40;
			reg7d2val=0X40; 
			break;	
		case 5://偏蓝色
			reg7d0val=0X18; 
			reg7d1val=0XA0;
			reg7d2val=0X40; 
			break;	
		case 6://复古
			reg7d0val=0X18; 
			reg7d1val=0X40;
			reg7d2val=0XA6; 
			break;	 
	}
	SCCB_WR_Reg(0xff,0x00);
	SCCB_WR_Reg(0x7c,0x00);
	SCCB_WR_Reg(0x7d,reg7d0val);
	SCCB_WR_Reg(0x7c,0x05);
	SCCB_WR_Reg(0x7d,reg7d1val);
	SCCB_WR_Reg(0x7d,reg7d2val); 
}
//彩条测试
//sw:0,关闭彩条
//   1,开启彩条(注意OV2640的彩条是叠加在图像上面的)
void OV2640_Color_Bar(u8 sw)
{
	u8 reg;
	SCCB_WR_Reg(0XFF,0X01);
	reg=SCCB_RD_Reg(0X12);
	reg&=~(1<<1);
	if(sw)reg|=1<<1; 
	SCCB_WR_Reg(0X12,reg);
}

/*硬件软件窗口配置*/

//设置图像输出窗口 
//sx,sy,起始地址
//width,height:宽度(对应:horizontal)和高度(对应:vertical)
void OV2640_Window_Set(u16 sx,u16 sy,u16 width,u16 height)
{
	u16 endx;
	u16 endy;
	u8 temp; 
	endx=sx+width/2;//V*2
 	endy=sy+height/2;
	
	SCCB_WR_Reg(0XFF,0X01);			
	temp=SCCB_RD_Reg(0X03);//读取Vref之前的值
	temp&=0XF0;
	temp|=((endy&0X03)<<2)|(sy&0X03);
	SCCB_WR_Reg(0X03,temp);//设置Vref的start和end的最低2位
	SCCB_WR_Reg(0X19,sy>>2);//设置Vref的start高8位
	SCCB_WR_Reg(0X1A,endy>>2);//设置Vref的end的高8位
	
	temp=SCCB_RD_Reg(0X32);//读取Href之前的值
	temp&=0XC0;
	temp|=((endx&0X07)<<3)|(sx&0X07);
	SCCB_WR_Reg(0X32,temp);//设置Href的start和end的最低3位
	SCCB_WR_Reg(0X17,sx>>3);//设置Href的start高8位
	SCCB_WR_Reg(0X18,endx>>3);//设置Href的end的高8位
}
//设置图像输出大小
//OV2640输出图像的大小(分辨率),完全由改函数确定
//width,height:宽度(对应:horizontal)和高度(对应:vertical),width和height必须是4的倍数
//返回值:0,设置成功
//    其他,设置失败
u8 OV2640_OutSize_Set(u16 width,u16 height)
{
	u16 outh;
	u16 outw;
	u8 temp;
    
	if(width%4)
        return 1;
	if(height%4)
        return 2;
    
	outw=width/4;
	outh=height/4;
	SCCB_WR_Reg(0XFF,0X00);	
	SCCB_WR_Reg(0XE0,0X04);			
	SCCB_WR_Reg(0X5A,outw&0XFF);//设置OUTW的低八位
	SCCB_WR_Reg(0X5B,outh&0XFF);//设置OUTH的低八位
    
	temp=(outw>>8)&0X03;
	temp|=(outh>>6)&0X04;
	SCCB_WR_Reg(0X5C,temp);//设置OUTH/OUTW的高位 
	SCCB_WR_Reg(0XE0,0X00);
    
	return 0;
}
//设置图像开窗大小
//由:OV2640_ImageSize_Set确定传感器输出分辨率从大小.
//该函数则在这个范围上面进行开窗,用于OV2640_OutSize_Set的输出
//注意:本函数的宽度和高度,必须大于等于OV2640_OutSize_Set函数的宽度和高度
//     OV2640_OutSize_Set设置的宽度和高度,根据本函数设置的宽度和高度,由DSP
//     自动计算缩放比例,输出给外部设备.
//width,height:宽度(对应:horizontal)和高度(对应:vertical),width和height必须是4的倍数
//返回值:0,设置成功
//    其他,设置失败
u8 OV2640_ImageWin_Set(u16 offx,u16 offy,u16 width,u16 height)
{
	u16 hsize;
	u16 vsize;
	u8 temp;
    
	if(width%4)
        return 1;
	if(height%4)
        return 2;
    
	hsize=width/4;
	vsize=height/4;
	SCCB_WR_Reg(0XFF,0X00);	
	SCCB_WR_Reg(0XE0,0X04);					
	SCCB_WR_Reg(0X51,hsize&0XFF);//设置H_SIZE的低八位
	SCCB_WR_Reg(0X52,vsize&0XFF);//设置V_SIZE的低八位
	SCCB_WR_Reg(0X53,offx&0XFF);//设置offx的低八位
	SCCB_WR_Reg(0X54,offy&0XFF);//设置offy的低八位
    
	temp=(vsize>>1)&0X80;
	temp|=(offy>>4)&0X70;
	temp|=(hsize>>5)&0X08;
	temp|=(offx>>8)&0X07; 
    
	SCCB_WR_Reg(0X55,temp);//设置H_SIZE/V_SIZE/OFFX,OFFY的高位
	SCCB_WR_Reg(0X57,(hsize>>2)&0X80);//设置H_SIZE/V_SIZE/OFFX,OFFY的高位
	SCCB_WR_Reg(0XE0,0X00);	
    
	return 0;
} 
//该函数设置图像尺寸大小,也就是所选格式的输出分辨率
//UXGA:1600*1200,SVGA:800*600,CIF:352*288
//width,height:图像宽度和图像高度
//返回值:0,设置成功
//    其他,设置失败
u8 OV2640_ImageSize_Set(u16 width,u16 height)
{ 
	u8 temp;
    
	SCCB_WR_Reg(0XFF,0X00);			
	SCCB_WR_Reg(0XE0,0X04);			
	SCCB_WR_Reg(0XC0,(width)>>3&0XFF);//设置HSIZE的10:3位
	SCCB_WR_Reg(0XC1,(height)>>3&0XFF);//设置VSIZE的10:3位
    
	temp=(width&0X07)<<3;
	temp|=height&0X07;
	temp|=(width>>4)&0X80;
    
	SCCB_WR_Reg(0X8C,temp);	
	SCCB_WR_Reg(0XE0,0X00);
    
	return 0;
}

ov2640cfg.h

//OV2640 SXGA初始化寄存器序列表
//模式选择
//内容过长,略去,详见正点原子教程
  1. dcmi接口配置

dcmi.h

#ifndef _DCMI_H
	#define _DCMI_H
	#include "sys.h"

	void My_DCMI_Init(void);
	void DCMI_DMA_Init(u32 DMA_Memory0BaseAddr,u16 DMA_BufferSize,u32 DMA_MemoryDataSize,u32 DMA_MemoryInc);
	void DCMI_Start(void);
	void DCMI_Stop(void);

	void DCMI_Set_Window(u16 sx,u16 sy,u16 width,u16 height);
	void DCMI_CR_Set(u8 pclk,u8 hsync,u8 vsync);

#endif

dcmi.c

#include "dcmi.h"
#include "lcd.h"
#include "led.h"
#include "ov2640.h”

u8 ov_frame=0;//帧率
extern void jpeg_data_process(void);//JPEG数据处理函数

DCMI_InitTypeDef DCMI_InitStructure;//全局变量注意

//DCMI中断服务函数
void DCMI_IRQHandler(void)
{
	if(DCMI_GetITStatus(DCMI_IT_FRAME)==SET)//捕获到一帧图像
	{
		jpeg_data_process();//jpeg数据处理	
		DCMI_ClearITPendingBit(DCMI_IT_FRAME);//清除帧中断
		LED1=!LED1;//LED指示捕获到图像
		ov_frame++;
		LCD_SetCursor(0,0);//重置LCD
		LCD_WriteRAM_Prepare();//开始写入GRAM
	}
} 

//DCMI DMA配置
//DMA_Memory0BaseAddr:存储器地址——将要存储摄像头数据的内存地址(也可以是外设地址)
//DMA_BufferSize:存储器长度——0~65535
//DMA_MemoryDataSize:存储器位宽  
//DMA_MemoryInc:存储器增长方式
void DCMI_DMA_Init(u32 DMA_Memory0BaseAddr,u16 DMA_BufferSize,u32 DMA_MemoryDataSize,u32 DMA_MemoryInc)
{ 
	DMA_InitTypeDef  DMA_InitStructure;
	
  	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//使能DMA2时钟
	DMA_DeInit(DMA2_Stream1);//清空流
	while (DMA_GetCmdStatus(DMA2_Stream1)!=DISABLE);//等待DMA2Stream1可配置 
	
  	/*配置DMA2 Stream1 Channel1*/
  	DMA_InitStructure.DMA_Channel=DMA_Channel_1;//DMA2Stream1Channel1
  	DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&DCMI->DR;//外设地址:DCMI->DR
  	DMA_InitStructure.DMA_Memory0BaseAddr=DMA_Memory0BaseAddr;//DMA存储器0地址
  	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//外设到存储器模式
    
  	DMA_InitStructure.DMA_BufferSize=DMA_BufferSize;//数据传输量 
  	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设非增量模式
  	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc;//存储器增量模式
  	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;//外设数据长度:32位
  	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize;//存储器数据长度
    
  	DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//使用循环模式 
  	DMA_InitStructure.DMA_Priority=DMA_Priority_High;//高优先级
    
  	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Enable;//使能FIFO        
  	DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;//使用全FIFO 
  	
    DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;//外设突发单次传输
  	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//存储器突发单次传输
    //应用设置
  	DMA_Init(DMA2_Stream1,&DMA_InitStructure);
}

//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);//使能GPIOA B C E时钟
	RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI,ENABLE);//使能DCMI时钟
  	
    /*PA4、PA6、PB6、PB7、PC6、PC7、PC8、PC9、PC11、PE5、PE6设置为复用输出*/
  	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_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_6;//PA4、6复用输出
    //应用设置
  	GPIO_Init(GPIOA, &GPIO_InitStructure);
  	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7|GPIO_Pin_6;//PB6、7复用输出
    //应用设置
  	GPIO_Init(GPIOB, &GPIO_InitStructure);
  	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11;//PC6、7、8、9、11 复用输出
    //应用设置
  	GPIO_Init(GPIOC, &GPIO_InitStructure);
  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;//PE5、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;//8位数据格式  
	DCMI_InitStructure.DCMI_HSPolarity= DCMI_HSPolarity_Low;//HSYNC低电平有效
    DCMI_InitStructure.DCMI_VSPolarity=DCMI_VSPolarity_Low;//VSYNC低电平有效
	DCMI_InitStructure.DCMI_PCKPolarity= DCMI_PCKPolarity_Rising;//PCLK上升沿有效
	DCMI_InitStructure.DCMI_SynchroMode= DCMI_SynchroMode_Hardware;//硬件同步HSYNC,VSYNC
    //应用设置
	DCMI_Init(&DCMI_InitStructure);

	DCMI_ITConfig(DCMI_IT_FRAME,ENABLE);//使能帧中断 
	
	DCMI_Cmd(ENABLE);//使能DCMI
	//此时不能捕获,还要启动传输
    NVIC_InitStructure.NVIC_IRQChannel=DCMI_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//子优先级0
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//IRQ通道使能
    //应用设置
	NVIC_Init(&NVIC_InitStructure);
}

//DCMI,启动传输
void DCMI_Start(void)
{  
	LCD_SetCursor(0,0);//重置LCD
	LCD_WriteRAM_Prepare();//开始写入GRAM
	DMA_Cmd(DMA2_Stream1, ENABLE);//开启DMA2Stream1 
	DCMI_CaptureCmd(ENABLE);//使能DCMI捕获
}
//DCMI,关闭传输
void DCMI_Stop(void)
{ 
  	DCMI_CaptureCmd(DISABLE);//关闭DCMI捕获	
	while(DCMI->CR&0X01);//等待传输结束
	DMA_Cmd(DMA2_Stream1,DISABLE);//关闭DMA2Stream1
}
  1. main()配置

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "usmart.h"  
#include "usart2.h"  
#include "timer.h" 
#include "ov2640.h" 
#include "dcmi.h" 

u8 ov2640_mode=0;//工作模式:0,RGB565模式;1,JPEG模式

#define jpeg_buf_size 31*1024//定义JPEG数据缓存jpeg_buf的大小(*4字节)
__align(4) u32 jpeg_buf[jpeg_buf_size];//JPEG数据缓存buf
volatile u32 jpeg_data_len=0;//buf中的JPEG有效数据长度 
volatile u8 jpeg_data_ok=0;//JPEG数据采集完成标志 
						   //0,数据没有采集完;
						   //1,数据采集完了,但是还没处理;
						   //2,数据已经处理完成了,可以开始下一帧接收
//JPEG尺寸支持列表
const u16 jpeg_img_size_tbl[][2]=
{
	176,144,	//QCIF
	160,120,	//QQVGA
	352,288,	//CIF
	320,240,	//QVGA
	640,480,	//VGA
	800,600,	//SVGA
	1024,768,	//XGA
	1280,1024,	//SXGA
	1600,1200,	//UXGA
}; 
const u8*EFFECTS_TBL[7]={"Normal","Negative","B&W","Redish","Greenish","Bluish","Antique"};//7种特效 
const u8*JPEG_SIZE_TBL[9]={"QCIF","QQVGA","CIF","QVGA","VGA","SVGA","XGA","SXGA","UXGA"};//JPEG 9种尺寸 

//处理JPEG数据
//当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF.开始下一帧采集.
void jpeg_data_process(void)
{
	if(ov2640_mode)//只有在JPEG格式下,才需要做处理
	{
		if(jpeg_data_ok==0)//如果还未采集完数据
		{	
			DMA_Cmd(DMA2_Stream1, DISABLE);//停止当前传输 
			while(DMA_GetCmdStatus(DMA2_Stream1)!=DISABLE);//等待DMA2_Stream1可配置  
			jpeg_data_len=jpeg_buf_size-DMA_GetCurrDataCounter(DMA2_Stream1);//得到此次数据传输的长度
			jpeg_data_ok=1;//标记JPEG数据采集完成,等待其他函数处理
		}
        
		if(jpeg_data_ok==2)//如果jpeg数据已经被处理了
		{
			DMA2_Stream1->NDTR=jpeg_buf_size;	
			DMA_SetCurrDataCounter(DMA2_Stream1,jpeg_buf_size);//传输长度为jpeg_buf_size*4字节
			DMA_Cmd(DMA2_Stream1,ENABLE);//重新传输
			jpeg_data_ok=0;//标记数据未采集
		}
	}
}

//JPEG测试
//JPEG数据,通过串口1发送给电脑.
void jpeg_test(void)
{
	u32 i; 
	u8* p;
	u8 key;
	u8 effect=0,saturation=2,contrast=2;
	u8 size=3;//默认QVGA 320*240尺寸
	u8 msgbuf[15];//消息缓存区 
	LCD_Clear(WHITE);
	POINT_COLOR=RED; 
	LCD_ShowString(30,70,200,16,16,"OV2640 JPEG Mode");
	LCD_ShowString(30,100,200,16,16,"KEY0:Contrast");//对比度
	//LCD_ShowString(30,120,200,16,16,"KEY1:Saturation");//色彩饱和度
	//LCD_ShowString(30,140,200,16,16,"KEY2:Effects");//特效 
	LCD_ShowString(30,160,200,16,16,"KEY_UP:Size");//分辨率设置 
	sprintf((char*)msgbuf,"JPEG Size:%s",JPEG_SIZE_TBL[size]);
	LCD_ShowString(30,180,200,16,16,msgbuf);//显示当前JPEG分辨率
	
 	OV2640_JPEG_Mode();//JPEG模式
	My_DCMI_Init();//初始化DCMI
	DCMI_DMA_Init((u32)&jpeg_buf,jpeg_buf_size,DMA_MemoryDataSize_Word,DMA_MemoryInc_Enable);//初始化DMA
	OV2640_OutSize_Set(jpeg_img_size_tbl[size][0],jpeg_img_size_tbl[size][1]);//设置输出尺寸
	DCMI_Start();//启动传输
	
    while(1)
	{
		if(jpeg_data_ok==1)//若已经采集完一帧图像
		{  
			p=(u8*)jpeg_buf;
			LCD_ShowString(30,210,210,16,16,"Sending JPEG data...");//提示正在传输数据
			for(i=0;i<jpeg_data_len*4;i++)//dma传输1次等于4字节,要乘4
			{
				while((USART1->SR&0X40)==RESET);//循环发送直到发送完毕  		
				USART1->DR=p[i];
				key=KEY_Scan(0);
				if(key)
                    break;//若按键按下则需要处理,跳至下部分
			}
			if(key)//有按键按下,需要处理
			{  
				LCD_ShowString(30,210,210,16,16,"Quit Sending data");//提示退出数据传输
                
				switch(key)
				{				    
					case KEY0_PRES://对比度设置
						contrast++;
						if(contrast>4)contrast=0;
						OV2640_Contrast(contrast);
						sprintf((char*)msgbuf,"Contrast:%d",(signed char)contrast-2);
						break;
					case KEY1_PRES://饱和度Saturation
						//saturation++;
						//if(saturation>4)saturation=0;
						//OV2640_Color_Saturation(saturation);
						//sprintf((char*)msgbuf,"Saturation:%d",(signed char)saturation-2);
						break;
					case KEY2_PRES://特效设置				 
						//effect++;
						//if(effect>6)effect=0;
						//OV2640_Special_Effects(effect);//设置特效
						//sprintf((char*)msgbuf,"%s",EFFECTS_TBL[effect]);
						break;
					case WKUP_PRES://JPEG输出尺寸设置   
						size++;  
						if(size>8)size=0;   
						OV2640_OutSize_Set(jpeg_img_size_tbl[size][0],jpeg_img_size_tbl[size][1]);//设置输出尺寸  
						sprintf((char*)msgbuf,"JPEG Size:%s",JPEG_SIZE_TBL[size]);
						break;
				}
                
				LCD_Fill(30,180,239,190+16,WHITE);
				LCD_ShowString(30,180,210,16,16,msgbuf);//显示提示内容
				delay_ms(800); 				  
			}
            else 
                LCD_ShowString(30,210,210,16,16,"Send data complete!!");//提示传输结束设置 
			jpeg_data_ok=2;	//标记jpeg数据处理完毕,可以让DMA采集下一帧
		}		
	}    
} 

//RGB565测试
//RGB数据直接显示在LCD上面
void rgb565_test(void)
{ 
	u8 key;
	u8 effect=0,saturation=2,contrast=2;
	u8 scale=1;//默认是全尺寸缩放
	u8 msgbuf[15];//消息缓存区
    
	LCD_Clear(WHITE);
    POINT_COLOR=RED; 
	LCD_ShowString(30,70,200,16,16,"OV2640 RGB565 Mode");
	LCD_ShowString(30,100,200,16,16,"KEY0:Contrast");//对比度
	//LCD_ShowString(30,130,200,16,16,"KEY1:Saturation");//色彩饱和度
	//LCD_ShowString(30,150,200,16,16,"KEY2:Effects");//特效 
	LCD_ShowString(30,170,200,16,16,"KEY_UP:FullSize/Scale");//1:1尺寸(显示真实尺寸)/全尺寸缩放
	
	OV2640_RGB565_Mode();//RGB565模式
	My_DCMI_Init();//DCMI配置
	DCMI_DMA_Init((u32)&LCD->LCD_RAM,1,DMA_MemoryDataSize_HalfWord,DMA_MemoryInc_Disable);//DCMI DMA配置  
 	OV2640_OutSize_Set(lcddev.width,lcddev.height); 
	DCMI_Start();//启动传输
	while(1)
	{
		key=KEY_Scan(0); 
		if(key)
		{ 
			DCMI_Stop();//停止显示
			switch(key)
			{				    
				case KEY0_PRES://对比度设置
					contrast++;
					if(contrast>4)contrast=0;
					OV2640_Contrast(contrast);
					sprintf((char*)msgbuf,"Contrast:%d",(signed char)contrast-2);
					break;
				case KEY1_PRES:	//饱和度Saturation
					//saturation++;
					//if(saturation>4)saturation=0;
					//OV2640_Color_Saturation(saturation);
					//sprintf((char*)msgbuf,"Saturation:%d",(signed char)saturation-2);
					break;
				case KEY2_PRES://特效设置				 
					//effect++;
					//if(effect>6)effect=0;
					//OV2640_Special_Effects(effect);//设置特效
					//sprintf((char*)msgbuf,"%s",EFFECTS_TBL[effect]);
					break;
				case WKUP_PRES://1:1尺寸(显示真实尺寸)/缩放	    
					scale=!scale;  
					
                    if(scale==0)
					{
						OV2640_ImageWin_Set((1600-lcddev.width)/2,(1200-lcddev.height)/2,lcddev.width,lcddev.height);//1:1真实尺寸
						OV2640_OutSize_Set(lcddev.width,lcddev.height); 
						sprintf((char*)msgbuf,"Full Size 1:1");
					}
                    else
					{
						OV2640_ImageWin_Set(0,0,1600,1200);				//全尺寸缩放
						OV2640_OutSize_Set(lcddev.width,lcddev.height); 
						sprintf((char*)msgbuf,"Scale");
					}
					break;
			}
			LCD_ShowString(30,50,210,16,16,msgbuf);//显示提示内容
			delay_ms(800);
			DCMI_Start();//重新开始传输
		} 
		delay_ms(10);		
	}    
}

int main(void)
{ 
	u8 key;
	u8 t;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);//初始化延时函数
	uart_init(115200);//初始化串口波特率为115200
	usart2_init(42,115200);//初始化串口2波特率为115200
	LED_Init();//初始化LED 
 	LCD_Init();//LCD初始化  
 	KEY_Init();//按键初始化 
	TIM3_Int_Init(10000-1,8400-1);//10Khz计数,1秒钟中断一次
	
 	usmart_dev.init(84);//初始化USMART
 	POINT_COLOR=RED;//设置字体为红色 

	while(OV2640_Init())//初始化OV2640
	{
		LCD_ShowString(30,130,240,16,16,"OV2640 ERR");
		delay_ms(200);
	    LCD_Fill(30,130,239,170,WHITE);
		delay_ms(200);
	}
	LCD_ShowString(30,130,200,16,16,"OV2640 OK");
    
 	while(1)
	{	
		key=KEY_Scan(0);
		if(key==KEY0_PRES)//RGB565模式
		{
			ov2640_mode=0;   
			break;
		}
        else if(key==WKUP_PRES)//JPEG模式
		{
			ov2640_mode=1;
			break;
		}
        
		t++; 									  
		if(t==100)
            LCD_ShowString(30,150,230,16,16,"KEY0:RGB565  KEY_UP:JPEG");//闪烁显示提示信息
 		if(t==200)
		{	
			LCD_Fill(30,150,230,150+16,WHITE);
			t=0; 
		}
		delay_ms(5);
	}
	if(ov2640_mode)
        jpeg_test();
	else 
        rgb565_test(); 
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值