一、硬件连接原理图
实物图:
?
二、OV2640驱动代码
1、SCCB_Init函数
//初始化SCCB接口
void SCCB_Init(void)
{
GPIO_InitTypeDef GPIO_InitABC;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);//使能GPIO时钟
GPIO_InitABC.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;//PD6,7
GPIO_InitABC.GPIO_Mode=GPIO_Mode_OUT;//PD6,7推挽输出
GPIO_InitABC.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIO_InitABC.GPIO_Speed=GPIO_Speed_50MHz;//50MHz
GPIO_InitABC.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOD,&GPIO_InitABC);//初始化
GPIO_SetBits(GPIOD,GPIO_Pin_6|GPIO_Pin_7);
SCCB_SDA_OUT();
}
2、OV2640_Init函数
u8 OV2640_Init(void)
{
u16 i=0;
u16 reg;
GPIO_InitTypeDef GPIO_InitABC;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);
GPIO_InitABC.GPIO_Pinn=GPIO_Pin_9|GPIO_Pin_15;//PG9,15推挽输出
GPIO_InitABC.GPIO_Mode=GPIO_Mode_OUT;//推挽输出
GPIO_InitABC.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIo-InitABC.GPIO_Speed=GPIO_Speed_50MHz;//50MHz
GPIO_InitABC.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOG,&GPIO_InitABC);//初始化
OV2640_PWDN=0;//POWER ON
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);//软复位OV2640
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;
}
//
for(i=0;i<sizeof(ov2640_uxga_init_reg_tbl)/2;i++)
{
SCCB_WR_Reg(ov2640_uxga_init_reg_tbl[i][0],ov2640_uxga_init_reg_tbl[i][1]);
}
return 0x00;//ok
}
3、OV2640_IPEG_Moed函数
//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]);
}
}
4、OV2640_RGB565_Mode函数
//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、OV2640_ImageWin_Set函数
/*设置图像开窗大小
由:OV2640_ImageSize_Set确定传感器输出分辨率大小
该函数则在这个范围上面进行开窗,用于OV2640_OutSize_Set的输出
注意:本函数的宽度和高度必须大于等于OV2640_OutSize_Set1函数的宽度和高度
OV2640_OutSize_Set设置的宽度和高度,根据本函数设置的宽度和高度,由DSP自动计算缩放比例,输出给外部设备。
width,height:宽度(对应:horizontal)和高度(对应:vertical)width和height都必须是四的倍数
返回值:0 设置成功 其它设置失败*/
u8 OV2640_ImageWin_Set(u16 offx,u16 offy,u16width,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/0FFX,0FFY的高位
SCCB_WR_Reg(0X57,(hsize>>2)&0X80);//设置H_SIZE/V_SIZE/0FFX,0FFY的高位
SCCB_WR_Reg(0XE0,0X00);
return 0;
}
三、DCMI驱动代码
1、My_DCMI_Init函数(完成DCMI的初始化、中断的配置、IO口的配置)
2、DCMI_DMA_Init函数
该函数用来配置DMA,包含四个参数: DMA_Memory0BaseAddr、DMA_BufferSize、DMA_MemoryDataSize、DMA_MemoryInc
DMA_Memory0BaseAddr:存储器地址,存储摄像头数据的内存地址(也可以是外设地址)
DMA_BufferSize:存储器长度
DMA_MemoryDataSize:存储器位宽
DMA_MemoryInc:存储器增长方式(用SRAM则地址自增,用LCD则不用增加)
3、单纯初始化函数是无法启用DCMI的,需要再加一个开始函数(DCMI_Start),有开启就会有关闭,后面呢还有一个关闭函数(DCMI_STOP)
//DCMI启动传输
void DCMI_Start(void)
{
LCD_SetCursor(0,0);
LCD_WriteRAM_Prepare();//开始写入GRAM
DMA_Cmd(DMA2_Stream1,ENABLE);//开启DMA2,Stream1
DCMI_CaptureCmd(ENABLE);//DCMI捕获使能
}
//DCMI关闭传输
void DCMI_Stop(void)
{
DCMI_CaptureCmd(DISABLE);//DCMI捕获使能关闭
while(DCMI->CR&0X01);//等待传输结束
DMA_Cmd(DMA2_Stream1,DISABLE);//关闭DMA2,Stream1
}
4、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++;
}
}
5、jpeg_data_process函数
//处理JPEG数据
//当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF,开始下一帧采集
void jpeg_data_process(void)
{
if(ov2640_mode)//只有在JPEG格式下才需要处理
{
if(jpeg_data_ok==0)//JPEG数据还未采集完
{
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;//标记数据未采集
}
}
}
|