单片机
返回首页

单片机图像采集与网络传输

2012-03-08 来源:微计算机信息

1.引言
    随着网络技术的发展和网络应用的普及,如何充分利用网络资源来实现低成本、高可靠的远程视频监控,已成为一个技术热点。本文介绍一个用单片机与图像采集模块接口,嵌入TCP/IP协议栈,制作“网络摄像头”的方法。本网络摄像头在一个组播式视频图像监控系统中,只作为组播源向以太网发送视频图像数据;其它监控计算机则作为组播成员接收数据。整个视频图像发送和监控系统在局域网中使用时,监控接收端的PC机只要加入了组播组,不必知道网络摄像头的IP地址和 MAC地址,也不需要两者的IP地址是在同一网段,均可接收到网络摄像头发出的图像数据,使用起来相当方便。

2. 硬件接口电路
    网络摄像头的硬件接口电路如图1所示。该电路采用的单片机是89C52芯片,另扩展32K的外部存储器,供网络和图像数据处理用。


    图1中的DB200是一个产品摄像模块,它由微型摄像镜头、图像缓存、时序发生、总线接口等电路构成;其外接信号是一个16脚的插座(9 ~ 16脚分别对应数据线D7 ~ D0,其它为地址、电源和读写控制线)。
    图1中,U1、U4和DB200的片选信号由89C52的地址线A14、A15和74HC00的3个与非门提供:A15=0时选通U4;A15=1及A14=0时选通U1;A15=1及A14=1时选通DB200。DB200的第8脚接A13用来选择其内部寄存器。
    RTL8019AS有3种工作方式:(1)跳线方式。(2)即插即用方式。(3)免跳线方式。RTL8019AS使用哪种工作方式由第65脚(JP)决定。为减少连线,我们采用跳线方式(把65脚接高电平)。这样网卡的传输介质、I/O基地址和中断号就由74、77、78、79、80、81、82、 84、85等引脚状态决定。
    RTL8019AS的81、82、84、85(BD0-BD3)脚接低电平,对应32个I/O寄存器地址范围为300H - 31FH;78-80(BD4-BD6)脚接低电平,对应中断号为INT0(IRQ2/9);74(BA14)、77(BD7)脚接低电平,为自动检测传输介质方式。
    RTL8019AS有20根地址(SA0-SA19)线,将其5、7、8、9、10(SA0-SA4)脚接89C52的A8-A12,将15、 16(SA8、SA9)脚接高电平来确保基地址为300H,其余地址线则全部接地。由于RTL8019AS的使能(AEN)信号是由89C52的 A15=1及A14=0时提供,因此我们可得出以下地址关系:
89C52:   A15 A14 A13 A12 A11 A10 A9  A8   A7………A0
8019:                 SA4 SA3 SA2 SA1 SA0   …………
2进制数:   1  0   0    0   0   0   0   0   0000 0000    16进制数: 0X8000
2进制数:   1  0   0    1   1   1   1   1   0000 0000    16进制数: 0X9F00
可见,如果89C52输出地址0X8000至0X9F00,均可选中RTL8019AS。由于RTL8019AS的SA9和SA8恒接高电平,当89C52 的地址信号由0X8000至0X9F00变动时,会有:SA9 SA8 SA7 SA6 SA5 SA4 SA3 SA2 SA1 SA0 =11 0000 0000 至 11 0001 1111,即对应选择RTL8019AS的I/O寄存器地址300H至31FH。
RTL8019AS的96脚(IOCS16B)接低电平,使其工作在8位总线模式;64脚接低电平,使用非AUI接口;31、32脚接高电平,屏蔽远程自举加载功能;33脚所需复位信号,由89C52的P1.5提供;29、30脚对应接89C52的读写脚。

3. 软件模块设计
    嵌入式系统一般采用简化的TCP/IP协议栈。常用的有IP、ARP、UDP、ICMP、TCP以及HTTP等协议。为了尝试实现一个最简易的嵌入式TCP/IP协议,我们选用UDP通讯方式。
    UDP的通讯方式有3种:点对点、广播和组播。考虑到点对点通讯需要ARP协议来取得目标节点的物理地址,我们不用点对点通讯。至于广播通讯和组播通讯,两者都不需要ARP协议。但广播方式有如下缺陷:(1)广播数据报不能跨过路由器传播;(2)广播时本地子网的所有主机都会接收到广播并作出响应,既增加了非接收者的开销,保密性也不好。我们采用的组播方式不存在这些问题,较适合作为网络视频监控的信息传输。

3.1 主程序工作流程


    网络摄像头的图像采集、打包、发送的软件流程如图2所示,对应的主程序源码见例程1。为了便于接收端正确判断每帧图像的开始,主程序在发送1帧图像数据前,先用Send_lwm( ) 函数发送特征字为“lwm”的4字节长的数据包(该函数从略),然后再发送图像数据。
void main(void)   //(例程1--循环采集和发送图像数据的主程序):
{  init_8019( );    // RTLS8019AS初始化。
     while(1)     // 循环采集和发送图像:
  {  img_capture( );  //  采集1帧图像。
    Send_lwm( );  // 发送图像开始的特征字“lwm”
    Send_img( );  // 发送1帧图像数据。
  }
}
3.2  以太网控制芯片的初始化
RTL8019AS 芯片有32个寄存器地址,映射到4个页面,每页有16个寄存器。本系统只用0页的14个(00-01H,04-0BH,0D-0EH,0F-10H)寄存器。程序先定义reg00-reg10, 然后用初始化函数init_8019( )对RTL8019AS各寄存器进行配置:
#define  XBYTE ((unsigned char volatile xdata *) 0)
#define  reg00   XBYTE[0x8000]  //对应300H  A15=1, A14=0,A13=A12=A11=A10=A9=A8=0
………………..
#define  reg10   XBYTE[0x9000]  //对应310H  A15=1, A14=0,A13=0,A12=1,A11=A10=A9=A8=0
sbit   RST8019  = P1 ^ 5;      // RST8019AS的硬件复位端。
void  init_8019(void)           // (例程2--RTL8019AS的初始化):
{  UINT C1; for(C1=0;C1<1000;C1++);  // 软件延时,确保芯片进入稳定状态
RST8019=1;   for(C1=0;C1<1000;C1++);  // 硬件复位、延时以确保芯片完全复位
RST8019=0;   for(C1=0;C1<1000;C1++);  // 硬件复位、延时以确保芯片完全复位
reg00=0x21;       // 选择第0页寄存器,并使芯片停止收发和DMA操作reg0e=0xC8;       // DCR: 采用普通、8位DMA方式
reg07=0xFF; reg0f=0x00;    // 清除和屏蔽所有中断(本系统未采用中断)  
reg0d=0xE0;       // TCR:采用普通发送模式、允许CRC产生和校验
}
    为了节省资源,上述对RTLS8019AS的初始化中,凡是与发送无关的寄存器都没有设置。发送时所要用的组播地址、物理地址和IP地址,则在打包时再封装到各协议层数据包的头部。

3.3  图像数据的采集


    负责图像采集的DB200摄像模块内部有数据、状态、采集控制和地址控制4个寄存器,表1是它们的寻址方式。对各寄存器的操作规则如下:
    (1)写操作-对采集控制寄存器(CAP_CTRLr)D0位写1,可启动采集过程;对地址控制寄存器(CAP_INCr)D0位写一次1,其图像缓存的地址就加1。
    (2)读操作-如果状态寄存器(CAP_STAUSr)的D0=1,表示可以开始图像采集过程;D1=1表示已完成1帧图像采集,可以读取数据寄存器(CAP_DATAr)的图像数据。
    DB200工作的地址范围是:1100 0000 0000 0000 ~ 1110 0000 0000 0000 = 0C00H ~ 0E00H。据此,我们可写出如下图像采集函数(例程3):
#define CAP_CONTROLr XBYTE[0X0C000]     //A15=1=A14, A13=0
#define CAP_STATUSr XBYTE[0X0C000]
void img_capture( )            // (例程3--图像采集):
{ while(!(CAP_STATUSr & 0x01));     // 检查DB200是否准备就绪?
 CAP_CONTROLr=0xff;        // 启动采集1帧图像过程。
 while(!(CAP_CONTROLr & 0x02));     // 是否采集完1帧图像?是就结束。
}
 img_capture( )函数只完成了1帧图像数据的采集,采集好的数据存在DB200的数据缓冲区内,留待Send_img( )函数读取和发送。Send_img( )是以读1行图像数据就发送1行的方式工作。其源码如下:
#define CAP_INCr  XBYTE[0X0E000]     //A15=1=A14,A13=1
#define CAP_DATAr  XBYTE[0X0E000] 
extern  UCHAR xdata  outbuf[1520]; 
void Send_img( )           // (例程4--图像数据的读取和发送):
{ UINT data Colon, Line ;
  for(Line=0;Line<288;Line++)        // 288行
  { for(Colon=0;Colon<385;Colon++)       // 385 列
   { databuf[Colon]=CAP_DATAr;     // 从 db200读1个像点到databuf。
    CAP_INCr=0xff;        // db200图像数据缓存地址加1。
   }
   udp_send(databuf, UDP_PORT, 386);        // 封装并发送1行图像数据。
  } 
}
3.4  图像数据的封装


    DB200采集完1帧图像后,通过数据总线传送给89C52;89C52则将图像数据按TCP/IP协议封装成以太网帧(图3),然后通过数据总线送给RTL8019AS;RTL8019AS则将以太网帧经RJ45接口送到10M以太网上。
从图3可以看到,每个以太网帧的最大长度为1518字节,最小为64字节。其数据部分最大为1500字节,最小为46字节。每个UDP数据传输前,必须加上 8字节的UDP头来构成UDP数据报;再加上20字节的IP头来构成IP数据报;最后加上14字节的帧头来构成以太网帧。这就是所谓的数据包封装。为了避免分段操作的麻烦,UDP数据报的最大长度应为1500 - 28=1472字节。在实际应用中,我们采用每行图像数据(385字节)封装一个包的方式传输数据。
void Data_send( UINT src_port, UINT datalen)    // (例程5--UDP数据报封装):
{ UDP_HEADER xdata * udp;    
 udp = (UDP_HEADER xdata *)(outbuf + 34); // 34=14(以太网帧头长)+ 20(IP报头长)  udp->dest_port = 2001;      // 目的端口号
 udp->source_port = 20011;     // 源端口号
 udp->length = 8 + datalen;     // UDP包总长= UDP头长度+数据长度
udp->checksum = 0;       // 不校验UDP数据报
 ip_pack(outbuf, dest_ipaddr, udp->length); // 封装IP包
}

void ip_pack(UCHAR xdata * outbuf, ULONG dest_ipaddr,  UINT datalen)//(例程6-封装IP包)
{   IP_HEADER xdata * ip;    static UINT ip_ident;  // datalen为UDP数据报总长度
   ip = (IP_HEADER xdata *)(outbuf + 14);    // 14字节为以太网帧头长度。
   ip->ver_len = 0x45;    ip->type_of_service = 0;  // 版本号和服务类型。
   ip->total_length = 20 + datalen;        // 数据报总长=IP头长度+数据长度
ip->identifier = ip_ident++;        // IP数据报序列号。
   ip->fragment_info = 0;                // IP数据报不分段。
   ip->time_to_live = 32;                // 生存时间。
   ip->protocol_id = UDP_TYPE;          // 协议类型为UDP=17。
   ip->header_cksum = 0;          // 校验和清0。
 ip->dest_ipaddr = 0xEA050607L;    // 0xEA050607L=234.5.6.7 为目标组播地址
 ip->source_ipaddr = 0xD224446FL;     // 0xD224446FL=210.36.68.111为本地IP地址
   ip->header_cksum = ~cksum(outbuf + 14, 20);  // 计算20字节的IP数据报头校验和
 eth_send(outbuf,  34 + datalen);     // 封装以太网帧并发送。
}
在上述例程5和例程6中,UDP的校验和是可选的,IP头的校验和是必需的。例程5将UDP检验和置为0,例程6则用cksum( )函数来计算IP头校验和。本地IP地址可取任意有效值。

3.5  以太网帧的封装和发送
    从图3可知,以太网帧封装就是要将目的MAC地址、源MAC地址和所要传输的数据类型放到待发送的IP数据报前(成为以太网帧头)。因为我们要进行的是组播发送,所以目的MAC地址也必须是组播的MAC地址;而本地的源MAC地址我们就用01:02:03:04:05:06。
    上面说到,“IP组播地址”范围是224.0.0.0到239.255.255.255。而以太网帧用到的“MAC组播地址”范围是 01:00:5E:00:00:00-01:00:5E:7F:FF:FF 。MAC组播地址的构成方法是:前3个字节固定用01:00:5E,后3个字节则用IP组播地址的后3个字节。所以我们用234.5.6.7作IP组播地址时,对应的MAC组播地址就是 01:00:5E:05:06:07。
    在下面的程序中,RTL8019AS用查询方式进行发送操作。
UCHAR code dest_hwaddr[6] = { 0x01, 0x00, 0x5E, 0x05, 0x06, 0x07}; // 目标MAC组播地址
UCHAR code my_hwaddr[6] =  { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; // 源MAC地址
void eth_send(UCHAR xdata * outbuf,  UINT Data_len)  // (例程7--以太网帧封装和发送):
{ UINT i , send_len;  ETH_HEADER xdata * eth;   eth = (ETH_HEADER xdata *)outbuf;
 for(i=0;i<6;i++)          
 { eth->dest_hwaddr[i]= dest_hwaddr[i];     // 装入目的MAC地址。
  eth->source_hwaddr[i]= my_hwaddr[i];     // 装入源MAC地址。
 }
 eth->frame_type = IP_PACKET;       // 数据类型为IP数据报
// send_len为实际要发送的以太网帧长度,它不能小于60字节:
 send_len = (Data_len>=60) ? Data_len : 60 ;
 reg00=0x22;         // 选择0页寄存器,启动芯片。
 while( reg00 & 0x04 );      // 原来的数据发送完没有?完了往下执行
 reg08=0x00;  reg09=0x40;     // 设置发送缓冲区开始地址为4000H。
//设置(RBCR0-1)远端DMA传送数据包长度(高、低字节):
 reg0a=(unsigned char)(Data_len); reg0b=(unsigned char)(Data_len>>8); 
 reg00=0x16;      // 设置远端DMA写,启动远端DMA传送数据到发送缓冲区
 for(i=0;i reg04=0x40;           // 设置发送缓冲区开始地址高字节
//设置(TBCR0-1)发送字节计数器的计数长度(高、低字节):   
 reg05=(unsigned char)(send_len); reg06=(unsigned char)(send_len>>8);   
 reg00=0x26;         // 启动本地DMA操作,向网络发送图像数据。
}
上述程序先设置好远端DMA开始地址(RSAR)和远端DMA数据字节数(RBCR),并设置远端DMA写( reg00=0x16),就可以把图像数据写入RTL8019AS的数据缓冲区。给出发送缓冲区首地址和数据包长度后,启动发送命令 (reg00=0x26), RTL8019AS就会按以太网协议将图像数据发送到网络上。

4. 结束语
    TCP/IP协议较复杂,嵌入式系统自身的资源又很有限,动辄几十K的TCP/IP协议栈,使很多入门者望而却步。其实要在嵌入式系统实现TCP/IP协议,只不过就是编制各个符合TCP/IP协议规则的软件模块罢了。根据自己系统的具体情况编制专门的功能模块,也可以实现相当简化的TCP/IP协议栈。本文在此给出了一个可供借鉴的实例。

参考文献:
[1] 吴礼发, 网络程序设计教程[M],北京:希望电子出版社,2002.1
[2]  RTL8019AS SPECIFICATION[EB/OL],REALTEKSEMI-CONDUCTOR CO., LTD ,  2000.8.20
[3] 单片机与TCP/IP网络[EB/OL], HTTP:// WWW.LAOGU.COM

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 永不缺相启动运行的电动机控制电路

  • MT3608构成3.7V转12V的升压电路图

  • 比较常见的功率整流器和滤波电路

  • 一个简单的红外耳机电路

  • 基于CA3193的热电偶放大器电路

  • 基于TDA1554的立体声放大器电路

    相关电子头条文章