本文介绍一个监控用的数码相机的软硬件工作原理和实现方法。整个装置以51单片机为核心,采用CMOS图像传感器芯片OV7640进行图像的采集,由OV528芯片进行图像压缩,然后经SL811HS USB主机芯片将图像保存到U盘中。这是我多年前制作的小装置,经过了实际使用的测试。
1 引言 在面对低端用户的应用中,设计一种体积小、使用安装容易,价格低廉,并能满足应用要求的简易视频监控装置,无疑会有较好的应用前景。基于性价比考虑,本装置以51单片机为控制中心,用CMOS图像芯片为传感器,以U盘作为存储介质来制作一个能自动拍摄的简易数码相机。它采用静态图像单帧间隔采集保存的方式,可以满足普通家庭安全监控的要求。
2 硬件设计 图像处理芯片OV7640和OV528均是美国OmniVision公司的产品。OV7640是CMOS彩色图像传感器,负责图像的采集。它内置640×480分辨率的象素阵列,并支持外部水平、垂直同步输入格式、数字视频输出、增益控制、自动白平衡等。OV528则是一款高性能的DSP。本装置采用的OV528有两个功能:一是将单片机发出的图像设置和读写控制命令传给OV7640,二是将OV7640采集到的图像数据压缩成JPEG格式后,再传输给单片机。最后,由单片机将JPEG图像文件经SL811HS的USB主机接口写到外接U盘中。 USB主机接口采用Cypress公司的SL811HS的USB芯片。它兼容USB1.1规范,支持usb主机或usb设备功能。 由于USB接口芯片SL811HS的M/S脚接低电平时,工作于主机方式;当M/S脚接高电平时,工作于设备方式。为了能让它充当外接U盘设备的主机接口,所以将M/S脚接地。而SL811HS的地址和数据信号是分时复用的,所以只要将的AD0-AD7与单片机的数据总线连接即可。至于地址信号和数据信号的区分,则由充当地址控制线的A0决定。在读写SL811HS,先让A0=0,向数据总线发送要读写的地址;然后让A0=1,再向数据总线发送要读写的数据。连接INT0的中断信号可使SL811HS有事件发生时(当有USB设备接入时,可触发该中断),单片机可通过读取SL811HS 的状态寄存器来判断事件类型,并做出相应处理。 STC89LE51RD+是51系列兼容的单片机,它有64K的FLASH可用于装载运行程序。由于它只有1K的RAM,不能满足工作要求,所以另外扩展了32K的RAM(图中未画出)。由单片机的A15提供片外RAM和SL811HS的片选信号(A15=0选片外RAM,A15=1选SL811HS)。单片机通过串口向OV528发送图像采集命令和接收图像数据,通过并口和SL811HS将图像数据写到U盘。 3 软件设计 程序开始时,先进行初始化操作,然后就进入图像采集和存储的循环。对SL811HS芯片的初始化操作主要包括内部寄存器复位和USB总线复位。对图像芯片初始化是通过ov528实现:它设置图像尺寸为320*240的JPEG格式,每个数据包大小为518字节(内含512字节图像数据,这是允许的包数据最大字节数)。 在主程序的循环体中,单片机不断检测USB设备状态,如果发现设备(U盘)接入,则通过SL811HS进行U盘设备枚举。一旦枚举成功,就创建文件,进行图像采集和数据存盘,如此不停循环。当然每次创建的文件名应该不同(文件名采用字母加序号方式)。 因为实现U盘文件系统的程序设计已有很多文献介绍,在此不予讨论。 4 图像采集命令 图像采集是由单片机通过串口向OV528发送控制命令来实现的(命令格式由OV528手册提供)。单片机每次发送图像采集命令前,均要发送一系列同步(SYNC)信号,以便让单片机与OV528建立通讯连接(OV528有波特率检测和自适应功能)。工作正常时,命令和应答包都是6个字节。“同步信号”的格式为16进制“AA 0D 00 00 00 00”,“应答(ACK)”的格式为“AA 0E XX** 00 00”。“XX”表示根据不同命令取不同值,“**”表示可取任意值。 单片机收到OV528的应答和同步信号后,才开始图像采集。图像采集的工作流程如图5所示,其各步骤涉及的相关命令如下: (1)为了保证图像采集工作方式不变,单片机每次开始图像采集时,都先设置图像格式和每个数据包的大小。“设置图像格式”的命令字为“AA 01 00 07 ** 05”。其中07表示图像为JPEG格式,05表示图像尺寸为320*240,“**”表示该字节可取任意值。 (2)“设置数据包大小”的命令为“AA 06 08 06 02 00”,其中第3-4字节“0602”为数据包大小。因为是低字节在前,高字节在后,调整后为0206H,即518字节。 (3)“获取图像”命令的格式为“AA 04 05 00 00 00”。当单片机发出“获取图像”命令时, OV528会回应1个6字节的应答包和1个6字节的数据包。该6字节数据包的第4和第5字节为图像文件的长度。 (4)单片机根据图像文件长度参数来计算后面要接收多少个512字节的图像数据,才能接收完整个图像文件(注意,最后一个包的图像数据通常不够512字节)。 (5)单片机发出带有包序列号的“请求数据包”命令,并逐个接收数据包。“请求数据包”命令格式为“AA 0E 00 00 LL HH”, 后2个字节为包序列号,低字节在前,高字节在后。如“AA 0E 00 00 00 00”为“请求第0个数据包”, “AA 0E 00 00 01 00” 为“请求第1个数据包”,依此类推。 (6)单片机接收到的一个518字节的数据包结构依次为:2字节的包序列号,2字节数据长度,512字节的图像数据和2字节的校验码。所以单片机每接收一个数据包后,都应剔除开不属图像数据的这6个字节。当接收完所有的数据包后,就将图像文件存盘。由于对U盘的操作比较慢,最后应有短暂延时,待写U盘操作完成后,再进入下一次图像采集过程。 本系统采用320X240的JPEG图像格式时,每个文件大小为5-14KB,写一个文件到U盘约要3秒左右。可以满足一般安防监控的要求。 采集图像的关键函数源码及注解如下: - void Get_Picture(void)
- { unsigned charxdata *Ptr1;
- byte idata bI; byte idata bM;
- byte idatabBuffer[6],bBuffer1[5]; word idatawK,wPackNo;
- unsigned longwwI;
- wwI = 0x01ffff; wRec_Num = 0;
- bBuffer[0] =0xAA; bBuffer[1] = 0x04; bBuffer[2] = 0x05; //get picture:
- bBuffer[3] =0x00; bBuffer[4] = 0x00; bBuffer[5] = 0x00;
- Send_Command(bBuffer,6); //发送“获取图像”命令
- WDT_CONTR = 0x00; //0x3f //feed watchdog //喂狗
- MCU_LED1=1;MCU_LED2=1;MCU_LED3=1;MCU_LED4=1; //运行状态指示-4个LED灭
- while(wRec_Num<12) MCU_LED1=0;MCU_LED1=1; //waitc328's ack+image size=12B
- wRec_Num = 0;
- if (RxBuf[1] ==0x0E && RxBuf[2] == 0x04 && RxBuf[7] == 0x0A) //c328's ack
- { bBuffer1[3] = RxBuf[9]; bBuffer1[4] = RxBuf[10]; //=jpeg length
- wPackNo =((word)bBuffer1[4] << 8) + (word)bBuffer1[3];
- wPackNo /=512;
- bBuffer[0] =0xAA; bBuffer[1] = 0x0E; bBuffer[2] = 0x00;
- bBuffer[3] =0x00; bBuffer[4] = 0x00; //bBuffer[4]=0th packetID=0
- bBuffer[5] =0x00;
- Send_Command(bBuffer,6); //发送应答命令+ask for packetID=0
- WDT_CONTR= 0x00; //0x3f //feed watchdog //喂狗
- //-------------------start of loop to receive wPackNo ofpackets----------
- for (bI =0;bI < wPackNo;bI ++ ) //loop toreceive wPackNo of packets
- {
- while(wRec_Num < 7) MCU_LED2=0; MCU_LED2=1; //wait for data size
- WDT_CONTR= 0x00; //0x3f //feed watchdog //喂狗
- wK =((word)RxBuf[3] << 8) + (word)RxBuf[2];//datasize=packetsize-6=512
- while(wRec_Num<=wK) MCU_LED3=0;MCU_LED3=1; //waitimage receive finish
- EA =0; //DISABLE_INTERRUPTS;
- Ptr1=RxBuf+4; //omitted the first 4B(ID+datasize)
- WriteImg(Ptr1,wK);//omittedthe first 4B and last 2B(only write 512B)
- EA =1; //ENABLE_INTERRUPTS;
- for (bM= 0;bM < 50 ;bM ++ ) // wait forc328 to receive MCU's ack
- { } //ifcode down by 12 Tcyc,bM<30 isnot enough;50 is ok
- wRec_Num= 0; wK = 0;
- bBuffer[0]= 0xAA; bBuffer[1] = 0x0E;
- bBuffer[2]= 0x00; bBuffer[3] = 0x00;
- bBuffer[4]= bI + 1; //bBuffer[4]=bI+1thpacketID
- bBuffer[5]= 0x00;
- Send_Command(bBuffer,6); //发送应答命令+next packet ID
- WDT_CONTR = 0x00; //0x3f //feedwatchdog //喂狗
- }
- //----------------------//end of loop to receive wPackNoof packets-------------
- while(wRec_Num < 7) MCU_LED4=0; MCU_LED4=1;
- WDT_CONTR= 0x00; //0x3f //feed watchdog //喂狗
- wK =((word)RxBuf[3] << 8) + (word)RxBuf[2]; //lastpacket size
- while(wRec_Num<=wK)MCU_LED1=0; MCU_LED1=1; //waitlast package data
- EA =0; //DISABLE_INTERRUPTS;
- Ptr1=RxBuf;
- WriteImg(Ptr1,wK); //omitted the first 4B and last 2B
- EA =1; //ENABLE_INTERRUPTS;
- MCU_LED1=0; MCU_LED2=1;MCU_LED3=1;MCU_LED4=1; //运行状态指示
- bBuffer[0] =0xAA; bBuffer[1] = 0x0E; bBuffer[2] = 0x00;
- bBuffer[3] =0x00; bBuffer[4] = 0xF0; bBuffer[5] = 0xF0;
- Send_Command(bBuffer,6); //发送last应答命令to c328
- WDT_CONTR= 0x00; //0x3f //feed watchdog //喂狗
- } //end of "if (RxBuf[1] ==0x0E............"
- WDT_CONTR = 0x00; //0x3f //feed watchdog //喂狗
- }
复制代码 我给出的附录源码为4个主要的C文件:Main.c,SL811.C,Fat32.c,serial.c。主程序在Main.c中,SL811.C和Fat32.c有U盘相关函数,serial.c里有图像驱动函数。均是经无错误编译并成功完成图像采集和存盘的源程序。硬件结构和接口图及软件流程图的介绍请看附件的“监控数码相机的制作.DOC”。 其他程序和头文件如果有人感兴趣,过后可以继续补充提供。
全部资料51hei下载地址:
camera-code -主要源码 DOC.zip
(116.66 KB, 下载次数: 25)
|