文章目录
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的驱动
基本概念简介
UXGA | 1600*1200 |
---|---|
SXGA | 1280*1024 |
XVGA | 1280*960 |
WXGA | 1280*800 |
XGA | 1024*768 |
SVGA | 800*600 |
VGA | 640*480 |
QQVGA | 160*120 |
CIF | 352*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} 1∗tp=1∗TPCLK
对于YUV/RGB格式数据, 1 ∗ t p = 2 ∗ T P C L K 1*t_p=2*T_{PCLK} 1∗tp=2∗TPCLK
行输出时序
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} 4∗tLINE有效电平(可自行设置为高/低)脉冲
27193 ∗ t p 27193*t_p 27193∗tp后,HREF拉高,开始输出行数据,每行数据输出之间以 322 ∗ t p 322*t_p 322∗tp为间隔,直到完成所有行输出
最后会有 57697 ∗ t p 57697*t_p 57697∗tp间隔才能进行下一帧输出
JPEG时序
JPEG输出时,PCLK大大减少,HREF不连续,数据流以0xFF、0xD8开头,以0xFF、0xD9结束,将此间数据保存为.jpg文件即可在电脑打开查看
相关硬件配置
OV2640传感器窗口设置
传感器窗口设置允许用户设置整个传感器区域(1632*1220)的感兴趣部分,即在传感器里面开窗,开窗范围从2*2到1632*1220都可以设置,但要求这个窗口必须大于等于随后设置的图像尺寸
详细内容可查看数据手册
图像尺寸设置
即DSP输出到LCD的图像最大尺寸,该尺寸要小于等于传感器窗口设置所设定的窗口尺寸
图像窗口设置
在设置的图像尺寸里面再次设置窗口大小,该窗口必须小于等于前面设置的图像尺寸,该窗口设置后的图像范围将用于输出到外部
图像输出大小设置(缩放设置)
控制最终输出到外部的图像尺寸
该设置仅会对图像进行缩放处理,如果设置的图像输出大小不等于图像窗口设置图像大小,那么图像就会被缩放处理,只有两者大小一样(图像输出大小=图像窗口设置大小)时,输出比例才是1:1
OV2640模块参数
- 支持RGB565/JPEG数据输出
- 支持最大UXGA分辨率输出
- 支持图像任意缩放
- 自带24M有源晶振、3.3V稳压电路、带滤光片的感光红外镜头
- 支持手动对焦(旋下盖上螺丝调节镜头即可)
引脚参数:
脚位 | 名称 | 说明 |
---|---|---|
1 | GND | 接地 |
2 | VCC3.3 | 接3.3V电源 |
3 | OV_SCL | SCCB时钟线(I) |
4 | OV_VSYNC | 帧同步信号(O) |
5 | OV_SDA | SCCB数据线(I/O) |
6 | OV_HREF | 行同步信号(O) |
8 | OV_RESET | 复位信号,低电平有效(I) |
15 | OV_PCLK | 像素时钟(O) |
17 | OV_PWDN | 掉电模式使能,高电平有效(I) |
18 | NC | 空脚 |
7、9、10、11、12、13、14、16 | OV_D0~D7 | 数据线(O) |
OV2640模块使用过程
初始化
- 初始化IO口
- 上电、复位
- 读取传感器ID
- 执行初始化序列
全部内容由OV2640公司提供源码
MCU读取模块图像数据
- 等待帧同步(等待VSYNC信号)
- 等待HRED为高电平
- 等待第一个PCLK上升沿
- 读取第一个像素的低字节
- 等待第二个PCLK上升沿
- 读取第一个像素的高字节
- 等待下一个PCLK上升沿
- 重复4-7步骤直到读完剩余像素
- 结束读取
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信号相当于消隐信号
初始化流程
- 配置相关引脚复用为DCMI
- 使能DCMI时钟
- 设置DCMI工作模式和PCLK、HSYNC、VSYNC等参数
- 设置DMA搬运DCMI数据
- 使能DCMI传输
实际配置方法与代码
硬件配置
OV2640模块-转接-DCMI接口 对应好即可
软件配置
- 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;
}
- 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初始化寄存器序列表
//模式选择
//内容过长,略去,详见正点原子教程
- 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
}
- 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();
}