我是靠谱客的博主 安静高山,最近开发中收集的这篇文章主要介绍【单片机开发】OV2640在没有DCMI接口的情况下的STM32驱动(一)背景介绍(二)接线(三)软件实现,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
文章目录
- (一)背景介绍
- (二)接线
- (三)软件实现
(一)背景介绍
在之前刚学STM32的时候完成了一个ov7670的驱动
ov7670驱动
已经快要两年过去了,最近抽了一点时间又将之前搞得ov2640的驱动完善了一下
看一下效果吧。
(二)接线
GND | SCL | SDA | D0 | D2 | D4 | D6 | PCLK | PWDN |
---|---|---|---|---|---|---|---|---|
GND | PC1 | PC0 | PA0 | PA2 | PA4 | PA6 | PB10 | PC3 |
3.3 | VSYNC | HREF | RST | D1 | D3 | D5 | D7 | NC |
---|---|---|---|---|---|---|---|---|
3.3 | PC13 | PB11 | PC2 | PA1 | PA3 | PA5 | PA7 | 随便 |
(三)软件实现
main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "KEY.h"
#include "adc.h"
#include "malloc.h"
#include "Camera.h"
#include "LCD.h"
//PWDN 掉电模式高电平有效
//HREF 行同步信号
//VSYNC 帧同步信号
//PCLK像素同步信号 OV2640自带晶振,直接设置为输入
//GND SCL SDA D0 D2 D4 D6 PCLK PWDN
//GND PC1 PC0 PA0 PA2 PA4 PA6 PB10 PC3
//3.3 VSYNC HREF RST D1 D3 D5 D7 NC
//3.3 PC13 PB11 PC2 PA1 PA3 PA5 PA7
#define JPEG_TEST
#ifdef JPEG_TEST
//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
};
u8* jpeg_buf;
#define jpeg_buf_size 40*1024 //定义JPEG数据缓存jpeg_buf的大小(*4字节)
volatile u32 jpeg_data_len=0; //buf中的JPEG有效数据长度
/* 串口1发送数组 */
void JPEG_DMA_SendArray()
{
uint16_t sendLen =jpeg_buf_size; // 防止越界
while (DMA_GetCurrDataCounter(DMA1_Channel4)); // 检查DMA发送通道内是否还有数据
// DMA发送数据-要先关 设置发送长度 开启DMA
DMA_Cmd(DMA1_Channel4, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel4, sendLen); // 重新写入要传输的数据数量
DMA_Cmd(DMA1_Channel4, ENABLE); // 启动DMA发送
}
//JPEG测试
//JPEG数据,通过串口1发送给电脑.
void jpeg_test(void)
{
u32 i;
u8 *p;
u8 key;
u8 effect=0,expose=0;
u8 size=3; //默认是QVGA 320*240尺寸
u8 msgbuf[15]; //消息缓存区
mem_init();
jpeg_buf=mymalloc(jpeg_buf_size);//32K左右
while(!jpeg_buf) {
printf("MALLOC DATAn");
delay_ms(200);
}
LCD_Clear(WHITE);
OV2640_JPEG_Mode(); //JPEG模式
OV2640_OutSize_Set(jpeg_img_size_tbl[size][0],jpeg_img_size_tbl[size][1]);//设置输出尺寸
while(1)
{
key=KEY_Scan(0);
if(key==KEY0_PRES){
effect++;
effect%=7;
OV2640_Special_Effects(effect);
}
if(key==WKUP_PRES){
expose++;
expose%=5;
OV2640_Auto_Exposure(expose);
}
while(OV2640_VSYNC==0);//等待帧信号
while(OV2640_VSYNC==1){
while(OV2640_HREF)
{
while(OV2640_PCLK==0);
jpeg_buf[jpeg_data_len++]=OV2640_DATA;
if(jpeg_data_len>jpeg_buf_size){
JPEG_DMA_SendArray();
jpeg_data_len=0;
}
while(OV2640_PCLK==1);
}
}
}
}
#endif
#ifdef RGB_TEST
u8* ov2640_framebuf;
void rgb565_test(void)
{
u8 key;
u8 effect=0,expose=0;
int i=0,j=0;
u16 pixcnt=0; //像素统计
u32 pix=0;
u16 linepix=0;
u16 linecnt=0; //行数统计
mem_init();
ov2640_framebuf=mymalloc(128*128*2);//32K左右
while(!ov2640_framebuf) {
printf("MALLOC DATAn");
delay_ms(200);
}
OV2640_RGB565_Mode();
OV2640_OutSize_Set(128,128);
while(1)
{
key=KEY_Scan(0);
if(key==KEY0_PRES){
effect++;
effect%=7;
OV2640_Special_Effects(effect);
}
if(key==WKUP_PRES){
expose++;
expose%=5;
OV2640_Auto_Exposure(expose);
}
pix=0;
while(OV2640_VSYNC) //等待帧信号
{
}
pixcnt=0; //像素计数器清零
linecnt=0; //行统计清零
while(linecnt<128)
{
while(OV2640_HREF)
{
while(OV2640_PCLK==0);
ov2640_framebuf[256*linecnt+linepix]=OV2640_DATA;
pix++;
linepix++;
while(OV2640_PCLK==1);
while(OV2640_PCLK==0);
ov2640_framebuf[256*linecnt+linepix]=OV2640_DATA;
pix++;
linepix++;
while(OV2640_PCLK==1);
}
if(pix!=pixcnt)
{
pixcnt=pix;
linepix=0;
linecnt++;
}
}
for(i=0;i<128;i++)
for(j=0;j<128;j++)
{
LCD_DrawPoint_Color(j,i,(u16)(ov2640_framebuf[2*128*i+1+2*j]<<8|ov2640_framebuf[2*128*i+2*j]));
}
}
}
#endif
int main(void)
{
delay_init(); //延时函数初始化
uart1_init(115200);
LCD_Init();
KEY_Init();
while(OV2640_Init()) //初始化OV2640
{
printf("Camera ERRORn");
delay_ms(200);
}
ov2640_speed_ctrl();
#ifdef RGB_TEST
rgb565_test();
#else
jpeg_test();
#endif
}
SCCB.c
#include "sys.h"
#include "SCCB.h"
#include "delay.h"
//初始化SCCB接口
//CHECK OK
void SCCB_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能PC
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_0); // 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输输出
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_1); // 输出高
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;
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)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;
}
Camera.c
#include "sys.h"
#include "Camera.h"
#include "Camera_Config.h"
#include "delay.h"
#include "usart.h"
#include "sccb.h"
//OV2640速度控制
//根据LCD分辨率的不同,设置不同的参数
void ov2640_speed_ctrl(void)
{
u8 clkdiv,pclkdiv; //时钟分频系数和PCLK分频系数
clkdiv=15;
pclkdiv=4;
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XD3,pclkdiv); //设置PCLK分频
SCCB_WR_Reg(0XFF,0X01);
SCCB_WR_Reg(0X11,clkdiv); //设置CLK分频
}
void JTAG_Set(u8 mode)
{
u32 temp;
temp=mode;
temp<<=25;
RCC->APB2ENR|=1<<0; //开启辅助时钟
AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
AFIO->MAPR|=temp; //设置jtag模式
}
#define SWD_ENABLE 0X01
//初始化OV2640
//配置完以后,默认输出是1600*1200尺寸的图片!!
//返回值:0,成功
// 其他,错误代码
u8 OV2640_Init(void)
{
u16 i=0;
u16 reg;
GPIO_InitTypeDef GPIO_InitStructure;
//设置IO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE); //使能相关端口时钟
//PCLK
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PC15 输入 上拉
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_10);
//OV2640_PWDN
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PC3 输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_3);
//DATA
GPIO_InitStructure.GPIO_Pin = 0xff; //PA0~7 输入 上拉
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//OV2640_VSYNC
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//PC13输入
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
//OV2640_RST
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PC2输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_2);
//OV2640_HREF
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PB1输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_11);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
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 低八位
printf("MID:%xrn",reg);
if(reg!=OV2640_MID)
{
printf("MID:%xrn",reg);
return 1;
}
reg=SCCB_RD_Reg(OV2640_SENSOR_PIDH); //读取厂家ID 高八位
reg<<=8;
reg|=SCCB_RD_Reg(OV2640_SENSOR_PIDL); //读取厂家ID 低八位
printf("HID:%xrn",reg);
if(reg!=OV2640_PID)
{
printf("HID:%xrn",reg);
//return 2;
}
//初始化 OV2640,采用SXGA分辨率(1600*1200)
for(i=0;i<sizeof(ov2640_svga_init_reg_tbl)/2;i++)
{
SCCB_WR_Reg(ov2640_svga_init_reg_tbl[i][0],ov2640_svga_init_reg_tbl[i][1]);
}
return 0x00; //ok
}
//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,0X00);//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;
}
设计到的东西有点多,其他文件我就发在这了
OV2640驱动
最后
以上就是安静高山为你收集整理的【单片机开发】OV2640在没有DCMI接口的情况下的STM32驱动(一)背景介绍(二)接线(三)软件实现的全部内容,希望文章能够帮你解决【单片机开发】OV2640在没有DCMI接口的情况下的STM32驱动(一)背景介绍(二)接线(三)软件实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复