基于STM32+OV7670的图像采集系统(基础篇:ov7670介绍)
由于这部分内容过多,分开介绍,本文章主要是介绍ov7670模块。
一、简单认识
先来看一下外观:
OV7670,图像传感器,体积小,工作电压低,提供单片VGA摄像头和影像处理器的所有功能。通过SCCB总线控制,可以输入整帧、子采样、取窗口等方式的各种分辨率8位影像数据。
其他介绍比较繁琐,这里就不一一赘述了,我们只需要知道它是通过SCCB总线控制的就行了。
带FIFO与不带FIFO
目前市场上购买的ov7670模块分为两种,一种是不带FIFO芯片、一种是带FIFO芯片的。
FIFO是什么:(First Input First Output)先入先出的意思,它的本质是一种数据缓存器,只能顺序进行数据读和写。
FIFO的作用:就是OV7670输出数据过快,你所用的单片机跟不上,就需要这么一个数据缓存,让ov7670先把数据传入到FIFO,再让单片机去读写即可。
(有点枯燥,举个例子就很好理解了,想必大家都参加过英语四级考试,四级听力都经受过,是不是有种听天书的感觉,叭叭的讲的什么东西,上一句还没听懂呢,下一句已经开始。那个播音机 可以理解为这里的 ov7670作为数据的输出,坐在下面听的“你” 理解为 接受数据的单片机 作为数据输入端, 由于语速太快听不懂怎么办呢,,给你一个录音器,让你先录下来再去听,是不是有种开外挂的感觉,,,而FIFI就相当于录音器的作用将数据缓冲)
不带FIFO:就是单片机直接去接受ov7670传来的数据,但是这种方式对单片机的接收数据速率有很大的要求,需要使用性能好的单片机,价格嘛 自然会高不少。
带FIFO:相当于“带一个物理外挂”,这样处理起来就比较简单,ov7670采集到的数据自动传到FIFO中,我们只需读取FIFO中存储的数据即可。(对小白很相友善)
因此呢 博主强烈建议小白入手带FIFO的ov7670
二、ov7670是如何工作的
开篇我们也说了,ov7670是基于SCCB总线控制,可能不少人对该总线比较陌生,但是大家肯定都很熟悉IIC总线,而SCCB总线的控制方法基本上和IIC总线差不多,所以控制起来也比较简单。
先来看一下时序图:
字节格式:在SIO_C高电平期间数据保持,在SIO_C低电平时数据更新。和IIC一样
写一个字节:在SIO_C低电平区间改变SIO_D数据,在SIO_C高电平期间SIO_D保持
static u8 Sccb_Write_Byte(u8 dat)//写入一个字节的数据到SCCB
{
u8 i;
for(i=0;i<8;i++)
{
GPIO_WriteBit(SCCB_SID_PORT, SCCB_SID_PIN, (((dat<<i)&0x80))>>7); //数据线拉高或拉低
delay(DELAYTIME);
GPIO_WriteBit(SCCB_SIC_PORT, SCCB_SIC_PIN, Bit_SET); //时钟线拉高
delay(DELAYTIME);
GPIO_WriteBit(SCCB_SIC_PORT, SCCB_SIC_PIN, Bit_RESET); //时钟线拉低
delay(DELAYTIME);
}
GPIO_WriteBit(SCCB_SID_PORT, SCCB_SID_PIN, Bit_RESET); //复位数据线
return Get_Ack();
}
读一个字节:拉高SIO_C读SIO_D的状态。
static u8 Sccb_Read_Byte(void)//一个字节数据读取并且返回
{
u8 i,rbyte=0;
Sccb_Sid_Change_In();
for(i=0;i<8;i++)
{
GPIO_WriteBit(SCCB_SIC_PORT, SCCB_SIC_PIN, Bit_SET);
delay(DELAYTIME);
if(GPIO_ReadInputDataBit(SCCB_SID_PORT, SCCB_SID_PIN)) rbyte|=(0x80>>i);
delay(DELAYTIME);
GPIO_WriteBit(SCCB_SIC_PORT, SCCB_SIC_PIN, Bit_RESET);
delay(DELAYTIME);
}
Sccb_Sid_Change_Out();//输出
GPIO_WriteBit(SCCB_SID_PORT, SCCB_SID_PIN, Bit_RESET);
return rbyte;
}
连续写:
static u8 Write_Sensor_Reg(u8 regID, u8 regDat)//写OV7670寄存器
{
Start_Sccb(); //发送SCCB 总线开始传输命令
if(0 == Sccb_Write_Byte(0x42))//写地址
{
Stop_Sccb();//发送SCCB 总线停止传输命令
return(0);//错误返回
}
if(0 == Sccb_Write_Byte(regID))/寄存器ID
{
Stop_Sccb();//发送SCCB 总线停止传输命令
return(0); //错误返回
}
if(0 == Sccb_Write_Byte(regDat))//写数据到积存器
{
Stop_Sccb();//发送SCCB 总线停止传输命令
return(0);//错误返回
}
Stop_Sccb();//发送SCCB 总线停止传输命令
return(1);//成功返回
}
连续读:
static u8 Readd_Sensor_Reg(u8 regID, u8 *regDat)//读OV7670寄存器
{
//通过写操作设置寄存器地址
Start_Sccb();
if(0 == Sccb_Write_Byte(0x42))//写地址
{
Stop_Sccb();//发送SCCB 总线停止传输命令
return(0);//错误返回
}
if(0 == Sccb_Write_Byte(regID))//寄存器ID
{
Stop_Sccb();//发送SCCB 总线停止传输命令
return(0);//错误返回
}
Stop_Sccb();//发送SCCB 总线停止传输命令
//设置寄存器地址后,才是读
Start_Sccb();
if(0 == Sccb_Write_Byte(0x43))//读地址
{
Stop_Sccb();//发送SCCB 总线停止传输命令
return(0);//错误返回
}
*regDat = Sccb_Read_Byte();//返回读到的值
No_Ack();//发送NACK命令
Stop_Sccb();//发送SCCB 总线停止传输命令
return(1);//成功返回
}
摄像头初始化:
u8 Sensor_Init(void)//摄像头芯片初始化
{
u8 temp;
u8 i = 0;
temp = 0x80;
if(0 == Write_Sensor_Reg(0x12,temp)) //Reset SCCB总线
{
return 0 ;//错误返回
}
if(0 == Readd_Sensor_Reg(0x0b, &temp))//读ID
{
return 0 ;//错误返回
}
//正常的话 temp==0x73
if(temp == 0x73)//OV7670
{
for(i=0;i<OV7670_REG_NUM;i++)
{
if(0 == Write_Sensor_Reg(OV7670_reg[i][0],OV7670_reg[i][1]))
{
return 0;//错误返回
}
}
}
return 1; //ok
}
到此前期初始化工作已做完。转战到下一篇文章,讲解如何用ov7670识别车牌。
更多推荐
所有评论(0)