stm32f103可以驱动摄像头吗?_stm32f103c8t6手册

2022-11-09 14:31:43 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

最近,由于想要做摄像头巡线小车,所以就花了两个星期的时间写了一个OV7725的摄像头驱动。

主要器材:鹰眼OV7725摄像头、stm32f103vet6、LCD液晶屏(ILI9341)

在这里我不讲解OV7725的工作原理(传输时序、寄存器配置),但是关键还是在OV7725上,详细讲解网上有很多,也可以参考下这篇博客https://www.cnblogs.com/raymon-tec/category/767436.html,看完之后再来看我写的。我主要讲下鹰眼。代码和我找到的所有相关资料都可以来下载https://download.csdn.net/download/qq_40499719/10699817。

因为看到野火的教程中有OV7725的讲解,所以就准备用现成的代码来做,在实验室找了很久却只发现了鹰眼OV7725的摄像头。在了解了野火OV7725和鹰眼OV7725之后才意识到,野火提供的代码不能直接驱动鹰眼,因为两者有很大的差别。

野火提供的OV7725能传输多种格式的图片(如RGB565、RGB555等),并且自带FIFO,把FIFO作为拍摄图片的缓存区以提高传输速率;鹰眼OV7725自带硬件二值化电路,因此OV7725采集到的像素数据会被硬件二值化电路自动转化成二值像素数据后传输,速度可能要比带FIFO的更快。

刚开始在网上搜了很多资料,逛了很多论坛,大部分都是说stm32f1系列的板子不能直接驱动鹰眼。 原因主要有几点:

  1. OV7725时钟频率太高,也就是说传输速度太快,最高可达150帧每秒,而stm32f1系列的板子的时钟太慢,跟不上OV7725的传输速度,这样就会导致数据阻塞。
  2. 摄像头一帧数据太大,比stm32的内存都还要大。而我用的是stm32f103ve,其内存只有64kb,还不够装一帧的图片。

所以只能靠自己边看手册边敲代码……下面是我的总结。

(一)弄懂鹰眼OV7725外部接口

外部引脚图

鹰眼共有20根排针其中5根没有实际作用。其他排针接口的作用如下。

  • PCLK:数据传输时钟信号,即每传输一次有效数据(8个像素),PCLK引脚的电平跳变一次
  • HREF:行中断信号,即每传输完一行数据(一行多少像素这要看自己怎么配置,我是一行320个像素),HREF引脚的电平跳变一次
  • VSYNC:场中断信号线,即每次传输完一帧数据(我配置的是320×240),VSYNC引脚的电平跳变一次
  • Y0-Y7:数据线,每次的像素数据会通过这8根引脚来传输,Y7传输的是第一个像素数据、Y0是最后一个
  • SIO_C与SIO_D:SCCB线,用来配置OV7725的寄存器寄存器,传输方式与I2C完全一样

(二)理解鹰眼OV7725数据传输

鹰眼自带二值化电路,它会将采集到的图像自动二值化处理,因此其像素输出和普通的OV7725不同。鹰眼在每个PCLK时钟信号会同通过Y0-Y7引脚时输出8个像素数据,也就是每次输出一个字节(8位),每个引脚输出1(高电平)表示黑色、输出0(低电平)表示白色。要特别注意的是,一次数据的高位是前面的像素,低位是后面的像素,即Y7传输的是第一个像素数据、Y0是最后一个。

鹰眼的数据传输是先从一帧图片的第一行第一个像素开始往后传输的,每次传输8个像素并且PCLK信号跳变一次。当传输到第一行的最后一个像素后,HREF跳变一次,鹰眼会再从下一行的第一个像素开始往后传输……以此类推直到最后一个像素传输完成,VSYNC会跳变一次。(如下图)

像素传输顺序

鹰眼自带有源晶振,因此当鹰眼与stm32传输像素数据时会产生时钟信号,stm32在特定的时钟信号处采集的数据才是有效数据。那么在什么信号处采集数据才有效呢?这可以参考OV7725手册中的数据传输的时序图。

在这我直接写上采集时序:当VSYNC低电平时数据有效,因此当检测到VSYNC下降沿时可以开始检测PCLK,此时PCLK高电平有效,因此在检测到PCLK上升沿时就可以采集Y0-Y7的像素数据了。

理解了鹰眼的数据传输后就解决了前面提到的一个问题:stm32装不下一帧的图片。普通的OV7725传输的数据2个字节表示一个像素,如果使用320×240的分辨率,那么一帧图片就要320x240x2/1024=150kb>64kb,如果用鹰眼那么一帧图片只需要320×240/8/1024=9.375kb<64kb,这样使用鹰眼就可以直接将数据存在stm内存中了。(关于传输速率的问题其实在配置OV7725寄存器的时候是可以调节的)

(三)在stm32中具体的实施

首先给大家展示一下我的连线方式

鹰眼与stm32连线方式

关于SCCB、OV7725和LCD液晶屏的配置我就不讲了,我只讲stm32对鹰眼的数据采集和处理。

要采集数据首先得申请一个变量来存放数据,因为每个PCLK时钟会传输一个字节的数据,所以可以申请一个8位的数组,这个数组至少得存放一帧的图片吧,根据鹰眼的数据传输可知这个8位数组大小为320×240/8=9600。要注意的是这个数组最好是一个静态的,也就是说最好不要在函数中申请,因为stm32的堆空间有限,可能装不下这个数组。(如果一定要增大堆空间可以更改startup_stm32f10x_hd.s文件中的Heap_Size)

采集鹰眼数据时有多种方法。我使用的是stm32中断采集,并且只用到了PCLK中断和VSYNC中断。在配置stm32与PCLK和VSYNC连接的引脚时就要开启对应的EXIT中断,VSYNC中断优先级高于PCLK中断,采集PCLK的引脚使用上升沿中断、采集VSYNC的引脚使用下降沿中断。(两个中断服务函数如下)

代码语言:javascript复制
/* PCLK中断 服务程序 */
void OV7725_PCLK_EXTI_INT_FUNCTION(void)
{
	if ( EXTI_GetITStatus(OV7725_PCLK_EXTI_LINE) != RESET ) //检查EXTI_Line线路上的中断请求是否发送到了NVIC,如果确认中断就执行
	{
		*(Pixel_Pointer  ) = ((OV7725_DATA_GPIO_PORT->IDR) & 0xff00)>>8; //取PAB高八位的有效数据,存入数组
	}
	EXTI_ClearITPendingBit(OV7725_PCLK_EXTI_LINE);		    	//清除EXTI_Line线路挂起标志位
}

/* VSYNC中断 服务程序 */
void OV7725_VSYNC_EXTI_INT_FUNCTION(void)
{
	if ( EXTI_GetITStatus(OV7725_VSYNC_EXTI_LINE) != RESET ) 	//检查EXTI_Line线路上的中断请求是否发送到了NVIC 
	{
		if( Ov7725_vsync == 0 ) //新的一帧开始
		{
			Pixel_Pointer = Pixel_Original;					//像素数据指针复位
			PCLK_EXIT_DISABLE(ENABLE);							//点PCLK断使能,即允许向像素数组中写入数据	
			Ov7725_vsync = 1;
		}
		else if( Ov7725_vsync == 1 ) //新的一帧结束
		{
			PCLK_EXIT_DISABLE(DISABLE);							//点中断失能,即禁止向像素数组中写入数据
			Ov7725_vsync = 2;
		}        
		EXTI_ClearITPendingBit(OV7725_VSYNC_EXTI_LINE);		    //清除EXTI_Line0线路挂起标志位
	}    
}

中断服务函数表示的是:当程序进入到VSYNC中断服务函数中开启PCLK中断,在PCLK中断中就可以采集数据并处理存放到数组中,当再次进入VSYNC中断函数时表明一帧图像传输完成,这时就停止PCLK中断,在主函数中就将数组中的数据传输到LCD液晶屏上,这样就完成了一次循环。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/190361.html原文链接:https://javaforall.cn

0 人点赞