#include "sys.h" #include "ov5640.h" #include "ov5640cfg.h" #include "ov5640af.h" #include "timer.h" #include "delay.h" #include "usart.h" #include "sccb.h" #include "pcf8574.h" #include "ltdc.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //OV5640 驱动代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2016/1/6 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2014-2024 //All rights reserved ////////////////////////////////////////////////////////////////////////////////// //OV5640写寄存器 //返回值:0,成功;1,失败. u8 OV5640_WR_Reg(u16 reg,u8 data) { u8 res=0; SCCB_Start(); //启动SCCB传输 if(SCCB_WR_Byte(OV5640_ADDR))res=1; //写器件ID if(SCCB_WR_Byte(reg>>8))res=1; //写寄存器高8位地址 if(SCCB_WR_Byte(reg))res=1; //写寄存器低8位地址 if(SCCB_WR_Byte(data))res=1; //写数据 SCCB_Stop(); return res; } //OV5640读寄存器 //返回值:读到的寄存器值 u8 OV5640_RD_Reg(u16 reg) { u8 val=0; SCCB_Start(); //启动SCCB传输 SCCB_WR_Byte(OV5640_ADDR); //写器件ID SCCB_WR_Byte(reg>>8); //写寄存器高8位地址 SCCB_WR_Byte(reg); //写寄存器低8位地址 SCCB_Stop(); //设置寄存器地址后,才是读 SCCB_Start(); SCCB_WR_Byte(OV5640_ADDR|0X01);//发送读命令 val=SCCB_RD_Byte(); //读取数据 SCCB_No_Ack(); SCCB_Stop(); return val; } //设置摄像头模块PWDN脚的状态 //sta:0,PWDN=0,上电. // 1,PWDN=1,掉电 void OV5640_PWDN_Set(u8 sta) { PCF8574_WriteBit(DCMI_PWDN_IO,sta); } //初始化OV5640 //配置完以后,默认输出是1600*1200尺寸的图片!! //返回值:0,成功 // 其他,错误代码 u8 OV5640_Init(void) { u16 i=0; u16 reg; //设置IO GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOG_CLK_ENABLE(); //开启GPIOA时钟 GPIO_Initure.Pin=GPIO_PIN_12; //PG12 GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //高速 HAL_GPIO_Init(GPIOG,&GPIO_Initure); //初始化 PCF8574_Init(); //初始化PCF8574 OV5640_RST(0); //必须先拉低OV5640的RST脚,再上电 delay_ms(20); OV5640_PWDN_Set(0); //POWER ON delay_ms(5); OV5640_RST(1); //结束复位 delay_ms(20); SCCB_Init(); //初始化SCCB 的IO口 delay_ms(5); reg=OV5640_RD_Reg(OV5640_CHIPIDH); //读取ID 高八位 reg<<=8; reg|=OV5640_RD_Reg(OV5640_CHIPIDL); //读取ID 低八位 if(reg!=OV5640_ID) { printf("ID:%d\r\n",reg); return 1; } OV5640_WR_Reg(0x3103,0X11); //system clock from pad, bit[1] OV5640_WR_Reg(0X3008,0X82); //软复位 delay_ms(10); //初始化 OV5640,采用SXGA分辨率(1600*1200) for(i=0;i>8); //设置实际输出宽度高字节 OV5640_WR_Reg(0x3809,width&0xff);//设置实际输出宽度低字节 OV5640_WR_Reg(0x380a,height>>8);//设置实际输出高度高字节 OV5640_WR_Reg(0x380b,height&0xff);//设置实际输出高度低字节 //以下设置决定输出尺寸在ISP上面的取图范围 //范围:xsize-2*offx,ysize-2*offy OV5640_WR_Reg(0x3810,offx>>8); //设置X offset高字节 OV5640_WR_Reg(0x3811,offx&0xff);//设置X offset低字节 OV5640_WR_Reg(0x3812,offy>>8); //设置Y offset高字节 OV5640_WR_Reg(0x3813,offy&0xff);//设置Y offset低字节 OV5640_WR_Reg(0X3212,0X13); //结束组3 OV5640_WR_Reg(0X3212,0Xa3); //启用组3设置 return 0; } //设置图像开窗大小(ISP大小),非必要,一般无需调用此函数 //在整个传感器上面开窗(最大2592*1944),用于OV5640_OutSize_Set的输出 //注意:本函数的宽度和高度,必须大于等于OV5640_OutSize_Set函数的宽度和高度 // OV5640_OutSize_Set设置的宽度和高度,根据本函数设置的宽度和高度,由DSP // 自动计算缩放比例,输出给外部设备. //width,height:宽度(对应:horizontal)和高度(对应:vertical) //返回值:0,设置成功 // 其他,设置失败 u8 OV5640_ImageWin_Set(u16 offx,u16 offy,u16 width,u16 height) { u16 xst,yst,xend,yend; xst=offx; yst=offy; xend=offx+width-1; yend=offy+height-1; OV5640_WR_Reg(0X3212,0X03); //开始组3 OV5640_WR_Reg(0X3800,xst>>8); OV5640_WR_Reg(0X3801,xst&0XFF); OV5640_WR_Reg(0X3802,yst>>8); OV5640_WR_Reg(0X3803,yst&0XFF); OV5640_WR_Reg(0X3804,xend>>8); OV5640_WR_Reg(0X3805,xend&0XFF); OV5640_WR_Reg(0X3806,yend>>8); OV5640_WR_Reg(0X3807,yend&0XFF); OV5640_WR_Reg(0X3212,0X13); //结束组3 OV5640_WR_Reg(0X3212,0Xa3); //启用组3设置 return 0; } //初始化自动对焦 //返回值:0,成功;1,失败. u8 OV5640_Focus_Init(void) { u16 i; u16 addr=0x8000; u8 state=0x8F; OV5640_WR_Reg(0x3000, 0x20); //reset MCU for(i=0;i1000)return 1; }while(state!=0x70); return 0; } //执行一次自动对焦 //返回值:0,成功;1,失败. u8 OV5640_Focus_Single(void) { u8 temp; u16 retry=0; OV5640_WR_Reg(0x3022,0x03); //触发一次自动对焦 while(1) { retry++; temp=OV5640_RD_Reg(0x3029); //检查对焦完成状态 if(temp==0x10)break; // focus completed delay_ms(5); if(retry>1000)return 1; } return 0; } //持续自动对焦,当失焦后,会自动继续对焦 //返回值:0,成功;其他,失败. u8 OV5640_Focus_Constant(void) { u8 temp=0; u16 retry=0; OV5640_WR_Reg(0x3023,0x01); OV5640_WR_Reg(0x3022,0x08);//发送IDLE指令 do { temp=OV5640_RD_Reg(0x3023); retry++; if(retry>1000)return 2; delay_ms(5); } while(temp!=0x00); OV5640_WR_Reg(0x3023,0x01); OV5640_WR_Reg(0x3022,0x04);//发送持续对焦指令 retry=0; do { temp=OV5640_RD_Reg(0x3023); retry++; if(retry>1000)return 2; delay_ms(5); }while(temp!=0x00);//0,对焦完成;1:正在对焦 return 0; }