这周组长接了个毕设的活交给我们做,模块大体上是用了OV7725+超声波+蜂鸣器报警+按键+LCD+LED。
一、简介
实现的功能是三个按键实现LCD视频的显示以及超声波距离的显示,设定一个报警距离,这个可根据按键二和按键三改变报警距离。若所测距离大于报警距离,则蜂鸣器不报警,且LED为绿灯,若所测距离小于报警距离,则蜂鸣器报警且LED显示红灯。
流程图如下:
在这个项目中我主要负责摄像头模块,摄像头的配置和显示。先对摄像头进行一下介绍:
1、这次项目用的是OV7725,该摄像头主要由镜头、图像传感器、板载电路、FIFO 缓存及下方的信号引脚组成。
以下为该摄像头的实体图和引脚图:
2、该摄像头与LCD的通讯:外部控制器对 OV7725 寄存器的配置参数是通过 SCCB 总线传输过去的,SCCB 总线跟 I2C 十分类似,所以在 STM32 驱动中可以直接使用片上 I2C 外设与它通讯。SCCB 的起始信号、停止信号及数据有效性与 I2C 完全一样,在 SCCB 协议中定义的读写操作与 I2C 也是一样的,这里就不多说了,学过32的人肯定都了解。
3、像素数据输出:
OV7725输出图像时则使用 VGA 或QVGA 时序。
VGA 在输出图像分辨率为 480*640
QVGA 是 Quarter VGA,其输出分辨率为 240*320
OV7725 传感器输出图像时,一帧帧地输出,在帧内的数据一般从左到右,从上到下,一个像素一个像素地输出(也可通过寄存器修改方向)。在输出图像时,共有8种模式,我一般习惯于从左到右,从上到下,即模式6。
3、FIFO读写时序
秉火的 OV7725 摄像头在图像传感器之外还添加了一个型号为 AL422B 的 FIFO,用于缓冲数据。AL422B 的本质是
一种 RAM 存储器,它的容量大小为 393216 字节,支持同时写入和读出数据。
4、摄像头驱动
摄像头采集数据的过程如下:
(1) 利用 SIO_C、SIO_D 引脚通过 SCCB 协议向 OV7725 的寄存器写入初始化配置;
(2) 初始化完成后,OV7725 传感器会使用 VGA 时序输出图像数据,它的 VSYNC 会
首先输出帧有效信号(低电平跳变),当外部的控制器(如 STM32)检测到该信号
时,把 WEN 引脚设置为高电平,并且使用 WRST 引脚复位 FIFO 的写指针到 0 地
址;
(3) 随着 OV7725 继续按 VGA 时序输出图像数据,它在传输每行有效数据时, HREF
引脚都会持续输出高电平,由于 WEN 和 HREF 同时为高电平输入至与非门,使得
其连接到 FIFO WE 引脚的输出为低电平,允许向 FIFO 写入数据,所以在这期间,
OV7725 通过它的 PCLK 和 D[0:7]信号线把图像数据存储到 FIFO 中,由于前面复
位了写指针,所以图像数据是从 FIFO 的 0 地址开始记录的;
(4) 各行图像数据持续传输至 FIFO,受 HREF 控制的 WE 引脚确保了写入到 FIFO 中
的都是有效的图像数据,OV7725 输出完一帧数据时,VSYNC 会再次输出帧有效
信号,表示一帧图像已输出完成;
(5) 控制器检测到上述 VSYNC 信号后,可知 FIFO 中已存储好一帧图像数据,这时控
制 WEN 引脚为低电平,使得 FIFO 禁止写入,防止 OV7725 持续输出的下一帧数
据覆盖当前 FIFO 数据;
(6) 控制器使用RRST复位读指针到FIFO的0地址,然后通过FIFO的RCLK和DO[0:7]
引脚,从 0 地址开始把 FIFO 缓存的整帧图像数据读取出来。在这期间,OV7725
是持续输出它采集到的图像数据的,但由于禁止写入 FIFO,这些数据被丢弃了;
(7) 控制器使用 WRST 复位写指针到 FIFO 的 0 地址,然后等待新的 VSYNC 有效信号
到来,检测到后把 WEN 引脚设置为高电平,恢复 OV7725 向 FIFO 的写入权限,
OV7725 输出的新一帧图像数据会被写入到 FIFO 的 0 地址中,重复上述过程。
摄像头的例程一般很容易找到,我主要说一下调试摄像头时遇到的问题。
1、因为之前就没有接触过摄像头,刚开始时LCD屏上显示的视频和图片都很模糊,以为是自己的代码写错了,分辨率设的太低,但是VGA和QVGA都试了,结果都是一样的。最后才发现这个摄像头可以调焦,被自己傻哭。
2、因为这个项目的按键一是LCD模式转换,一开始设置的是只显示距离,然后按键转成显示视频,但转成视频模式后就再也转不过来了,一直显示的是视频。经过查阅资料后才知道要先关闭视频后才能转换,于是在按键一的模式二标志位(change)加了关闭摄像头(也就是让摄像头不采集也不显示)代码:
if(change==0)
{
ImagDisp(cam_mode.lcd_sx,cam_mode.lcd_sy,cam_mode.cam_width,cam_mode.cam_height); //采集并显示
}
else if(change==1)
break;
于是模式的转换就解决了,但是又出现一个问题,视频转换后LCD有几行显示黑屏,于是想到在每次转换前清屏,但结果是清屏速率太快,LCD一直闪。最后的解决办法是在显示距离的函数内部一开始加上对每行的清屏,虽然办法比较笨,但实现的结果还不错。如果有大佬有比较好的解决方法,期待你们给我这个菜鸟讲讲。