找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3855|回复: 0
收起左侧

监控数码相机的制作,含单片机源码,原理图和介绍文档

[复制链接]
ID:276009 发表于 2018-1-16 10:53 | 显示全部楼层 |阅读模式
  本文介绍一个监控用的数码相机的软硬件工作原理和实现方法。整个装置以51单片机为核心,采用CMOS图像传感器芯片OV7640进行图像的采集,由OV528芯片进行图像压缩,然后经SL811HS USB主机芯片将图像保存到U盘中。这是我多年前制作的小装置,经过了实际使用的测试。

1   引言
    在面对低端用户的应用中,设计一种体积小、使用安装容易,价格低廉,并能满足应用要求的简易视频监控装置,无疑会有较好的应用前景。基于性价比考虑,本装置以51单片机为控制中心,用CMOS图像芯片为传感器,以U盘作为存储介质来制作一个能自动拍摄的简易数码相机。它采用静态图像单帧间隔采集保存的方式,可以满足普通家庭安全监控的要求。

2    硬件设计
接口电路图.JPG
    图像处理芯片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     软件设计
主程序流程图.JPG
程序开始时,先进行初始化操作,然后就进入图像采集和存储的循环。对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秒左右。可以满足一般安防监控的要求。
采集图像的关键函数源码及注解如下:
  1. void Get_Picture(void)
  2. {   unsigned charxdata   *Ptr1;
  3.     byte idata bI;  byte idata bM;
  4.     byte idatabBuffer[6],bBuffer1[5];  word idatawK,wPackNo;
  5.     unsigned longwwI;

  6.     wwI = 0x01ffff;         wRec_Num = 0;
  7.     bBuffer[0] =0xAA;  bBuffer[1] = 0x04;  bBuffer[2] = 0x05; //get picture:
  8.     bBuffer[3] =0x00;  bBuffer[4] = 0x00;  bBuffer[5] = 0x00;
  9.     Send_Command(bBuffer,6);    //发送“获取图像”命令
  10.     WDT_CONTR = 0x00;       //0x3f  //feed watchdog //喂狗
  11.     MCU_LED1=1;MCU_LED2=1;MCU_LED3=1;MCU_LED4=1;   //运行状态指示-4个LED灭

  12.     while(wRec_Num<12) MCU_LED1=0;MCU_LED1=1;  //waitc328's ack+image size=12B
  13.     wRec_Num = 0;
  14.     if (RxBuf[1] ==0x0E && RxBuf[2] == 0x04 && RxBuf[7] == 0x0A)  //c328's ack
  15.     {   bBuffer1[3] = RxBuf[9];     bBuffer1[4] = RxBuf[10];    //=jpeg length
  16.         wPackNo =((word)bBuffer1[4] << 8) + (word)bBuffer1[3];
  17.         wPackNo /=512;  
  18.         bBuffer[0] =0xAA;  bBuffer[1] = 0x0E;  bBuffer[2] = 0x00;
  19.         bBuffer[3] =0x00;  bBuffer[4] = 0x00;  //bBuffer[4]=0th packetID=0
  20.         bBuffer[5] =0x00;
  21.         Send_Command(bBuffer,6);    //发送应答命令+ask for packetID=0
  22.         WDT_CONTR= 0x00;       //0x3f  //feed watchdog //喂狗
  23. //-------------------start of loop to receive wPackNo ofpackets----------
  24.         for (bI =0;bI < wPackNo;bI ++ )    //loop toreceive wPackNo of packets
  25.         {   
  26.             while(wRec_Num < 7) MCU_LED2=0;    MCU_LED2=1;  //wait for data size
  27.             WDT_CONTR= 0x00;   //0x3f  //feed watchdog //喂狗
  28.             wK =((word)RxBuf[3] << 8) + (word)RxBuf[2];//datasize=packetsize-6=512
  29.             while(wRec_Num<=wK) MCU_LED3=0;MCU_LED3=1; //waitimage receive finish
  30.             EA =0;  //DISABLE_INTERRUPTS;   
  31.             Ptr1=RxBuf+4;   //omitted the first 4B(ID+datasize)
  32.             WriteImg(Ptr1,wK);//omittedthe first 4B and last 2B(only write 512B)
  33.             EA =1;  //ENABLE_INTERRUPTS;

  34.             for (bM= 0;bM < 50 ;bM ++ )    // wait forc328 to receive MCU's ack
  35.             { }     //ifcode down by 12 Tcyc,bM<30 isnot enough;50 is ok

  36.             wRec_Num= 0;   wK = 0;                 
  37.             bBuffer[0]= 0xAA;  bBuffer[1] = 0x0E;
  38.             bBuffer[2]= 0x00;  bBuffer[3] = 0x00;
  39.             bBuffer[4]= bI + 1;        //bBuffer[4]=bI+1thpacketID
  40.             bBuffer[5]= 0x00;
  41.             Send_Command(bBuffer,6);    //发送应答命令+next packet ID
  42.             WDT_CONTR = 0x00;       //0x3f  //feedwatchdog //喂狗
  43.         }
  44. //----------------------//end of loop to receive wPackNoof packets-------------

  45.         while(wRec_Num < 7) MCU_LED4=0;    MCU_LED4=1;
  46.         WDT_CONTR= 0x00;   //0x3f  //feed watchdog //喂狗
  47.         wK =((word)RxBuf[3] << 8) + (word)RxBuf[2];    //lastpacket size
  48.         while(wRec_Num<=wK)MCU_LED1=0; MCU_LED1=1;     //waitlast package data
  49.             EA =0;  //DISABLE_INTERRUPTS;   
  50.             Ptr1=RxBuf;
  51.             WriteImg(Ptr1,wK); //omitted the first 4B and last 2B
  52.             EA =1;  //ENABLE_INTERRUPTS;   
  53.         MCU_LED1=0;     MCU_LED2=1;MCU_LED3=1;MCU_LED4=1;   //运行状态指示
  54.         bBuffer[0] =0xAA;  bBuffer[1] = 0x0E;      bBuffer[2] = 0x00;
  55.         bBuffer[3] =0x00;  bBuffer[4] = 0xF0;      bBuffer[5] = 0xF0;
  56.         Send_Command(bBuffer,6);        //发送last应答命令to c328
  57.         WDT_CONTR= 0x00;   //0x3f  //feed watchdog //喂狗
  58.     }   //end of "if (RxBuf[1] ==0x0E............"
  59.     WDT_CONTR = 0x00;       //0x3f  //feed watchdog //喂狗
  60. }
复制代码
我给出的附录源码为4个主要的C文件:Main.c,SL811.C,Fat32.c,serial.c。主程序在Main.c中,SL811.C和Fat32.c有U盘相关函数,serial.c里有图像驱动函数。均是经无错误编译并成功完成图像采集和存盘的源程序。硬件结构和接口图及软件流程图的介绍请看附件的“监控数码相机的制作.DOC”。 其他程序和头文件如果有人感兴趣,过后可以继续补充提供。
0.png

全部资料51hei下载地址:
camera-code -主要源码 DOC.zip (116.66 KB, 下载次数: 25)

评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表