视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
单片机图像与网络传输
2025-10-03 15:09:54 责编:小OO
文档
1.引言

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

2. 硬件接口电路

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

     图1中的DB200是一个产品摄像模块,它由镜头、图像缓存、时序发生、总线接口等电路构成;其外接信号是一个16脚的插座(9 ~ 16脚分别对应数据线D7 ~ D0,其它为地址、电源和读写控制线)。

图1中,U1、U4和DB200的片选信号由C52的地址线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)脚接C52的A8-A12,将15、16(SA8、SA9)脚接高电平来确保基地址为300H,其余地址线则全部接地。由于RTL8019AS的使能(AEN)信号是由C52的A15=1及A14=0时提供,因此我们可得出以下地址关系:

C52:    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

可见,如果C52输出地址0X8000至0X9F00,均可选中RTL8019AS。由于RTL8019AS的SA9和SA8恒接高电平,当C52的地址信号由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位总线模式;脚接低电平,使用非AUI接口;31、32脚接高电平,屏蔽远程自举加载功能;33脚所需复位信号,由C52的P1.5提供;29、30脚对应接C52的读写脚。

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)

 A15=1,#define   reg00    XBYTE[0x8000]   //对应300H  A14=0,A13=A12=A11=A10=A9=A8=0 

………………..

#define   reg10    XBYTE[0x9000]    A15=1, A14=0,A13=0,A12=1,A11=A10=A9=A8=0//对应310H  

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帧图像后,通过数据总线传送给C52;C52则将图像数据按TCP/IP协议封装成以太网帧(图3),然后通过数据总线送给RTL8019AS;RTL8019AS则将以太网帧经RJ45接口送到10M以太网上。

从图3可以看到,每个以太网帧的最大长度为1518字节,最小为字节。其数据部分最大为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;ireg04=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协议栈。本文在此给出了一个可供借鉴的实例。下载本文

显示全文
专题