本帖最后由 王建峰 于 2018-5-6 17:23 编辑
最近做比赛,需要用到摄像头。手上有探索者开发板,与带FIFO摄像头OV7670各一块,探索版没有OV7670摄像头的接口与程序,自能自己写IO口驱动。另外有坛友使用杜邦线连接,但我试过发现杜邦线太长造成的干扰比较大,太短的会然连线显得乱糟糟的。于是我打算利用OV2640的驱动接口,作为0V7670的驱动接口,反正两个接口都很像,只要改改程序对应的引脚配置就可以了。虽然功能还没实现,但总算把摄像头驱动起来了,先留个记录,备忘。
硬件资源:探索版F4开发板|带FIFO摄像头OV7670|杜邦线两根、
1.功能
串口打印输出识别黑线的偏移值与帧率,由于手上没有配套的液晶屏,不能进行显示处理。
2.软件修改
1.将DCMI端口对应的引脚配置成摄像头上的接口相对应,
首先是对摄像头进行读写控制的引脚
[mw_shl_code=c,true]#define OV7670_WRST PBout(7) //写指针复位
#define OV7670_RCK PAout(6) //读数据时钟
#define OV7670_RRST PAout(4) //读指针复位
#define OV7670_CS PGout(15) //片选信号(OE)
#define OV7670_WREN PGout(9) //写入FIFO使能
#define OV7670_VSYNC PAin(8) //同步信号检测IO[/mw_shl_code]
然后通过8个IO口对摄像头进行读数据操作 D0~D7
[mw_shl_code=c,true]#define OV7670_DATA (u8)( (PEin(6)*128)+(PEin(5)*64)+(PBin(6)*32)+(PCin(11)*16)+(PCin(9)*8)+(PCin(8)*4)+(PCin(7)*2)+PCin(6)*1)[/mw_shl_code]
DCMI中的8个数据IO口不是一组IO,我这里又是直接使用IO口读,所以就通过以上的方式读取一个字节数据。
摄像头 寄存器通过 SCCB 时序访问并设置 ,由于SCCB和IIC时序一样,对SCCB的初始化就是对IIC的初始化!,这里就配置了IIC ,也就是PB8和PB9两个引脚,要分别接到DCMI的PD6和PD7两个口。
引脚配置:
[mw_shl_code=c,true] GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE); //使能相关端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4| GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO ///仿照这个做改动
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //带上拉电阻的输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //带上拉电阻的输入模式
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //带上拉电阻的输入模式
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_7 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //带上拉电阻的输入模式
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_11 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_7 | GPIO_Pin_6);[/mw_shl_code]
2.使用外部中断让读数据操作与摄像头输出同步
将PA6配置成外部中断,具体中断中处理:
[mw_shl_code=c,true]u8 ov_sta;
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line8)==SET)
{
if(ov_sta<2)
{
if(ov_sta==0)
{
OV7670_WRST=0; //复位写指针
OV7670_WRST=1;
OV7670_WREN=1; //允许写入FIFO
}else OV7670_WREN=0; //禁止写入FIFO
ov_sta++;
}
}
EXTI_ClearITPendingBit(EXTI_Line8); //清除LINE15上的中断标志位
}
[/mw_shl_code]
当摄像头采集一帧图像时,控制允许写入FIFO。然后控制禁止写入FIFO,直到单片机从FIFO中读取完这一帧数据,也就是ov_sta=0,才能允许下一帧图像被写入FIFO。。
3.使用定时器计算帧率
配置定时器3为1s触发一次,也就是1s刷新一次帧率。
[mw_shl_code=applescript,true]void TIM3_IRQHandler(void) //TIM3中断
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
{
// printf("frame:%dfps
",ov_frame); //通过串口显示
ov_frame=0;
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位
}[/mw_shl_code]
每完成一帧图像的采集,ov_frame这个变量+1
4.采集一帧60*80的像素点阵,并存放在一个二维数组
[mw_shl_code=c,true]
void camera_refresh(void)
{
u16 color;
if(ov_sta==2)
{
OV7670_CS=0;
OV7670_RRST=0; //开始复位读指针
OV7670_RCK=0;
OV7670_RCK=1;
OV7670_RCK=0;
OV7670_RRST=1; //复位读指针结束
OV7670_RCK=1;
for(col=0;col<240;col++)
{
if((col%4)==0)h++; //隔点采样,,,每4个距离采样一次
for(row=0;row<320;row++)
{
OV7670_RCK=0;
color=OV7670_DATA; //读数据
OV7670_RCK=1;
// color<<=8;
OV7670_RCK=0;
// color|=OV7670_DATA; //读数据
OV7670_RCK=1;
if(((col%4)==0)&&((row%4)==0))
{
v++;
Pic_Buff[v-1][h-1]=(u8)color; //将采集的坐标点的颜 {MOD}信息存到二维数组中 (以便二值化处理)
}
// color<<=8; //数据格式转换----转换为RGB格式
// color_r = color&0xf800;
// color_b = color>>11;
// color >>=5;
// color_g =color&0x07e0;
// color= color_r + color_g + color_b;
// GPIOB->CRL=0X33333333;
// LCD->LCD_RAM=color;
}
v = 0;
}
h=0;
OV7670_CS=1;
OV7670_RCK=0;
OV7670_RCK=1;
EXTI->
R=1<<15; //清除LINE8上的中断标志位
ov_sta=0; //开始下一次采集
ov_frame++;
// LCD_Scan_Dir(DFT_SCAN_DIR); //恢复默认扫描方向
}
} [/mw_shl_code]
3.硬件连接
硬件连接很简单直接把摄像头插在DCMI接口座上,同时把引脚连接 PD6 - PB8 , PD7 - PB9。
DCMI接口与单片机GPIO对应关系
基于探索者,以上就把摄像头驱动的部分配置好了,想具体实现功能的话,直接把写好了的函数移植过来就可以了!!!
程序附上、、、
OV7670定位黑带 .zip
(5.45 MB, 下载次数: 341)
2018-5-4 22:47 上传
点击文件名下载附件
一周热门 更多>