嵌入式以太网串口服务器.docx

上传人:b****8 文档编号:11446202 上传时间:2023-03-01 格式:DOCX 页数:17 大小:421.57KB
下载 相关 举报
嵌入式以太网串口服务器.docx_第1页
第1页 / 共17页
嵌入式以太网串口服务器.docx_第2页
第2页 / 共17页
嵌入式以太网串口服务器.docx_第3页
第3页 / 共17页
嵌入式以太网串口服务器.docx_第4页
第4页 / 共17页
嵌入式以太网串口服务器.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

嵌入式以太网串口服务器.docx

《嵌入式以太网串口服务器.docx》由会员分享,可在线阅读,更多相关《嵌入式以太网串口服务器.docx(17页珍藏版)》请在冰豆网上搜索。

嵌入式以太网串口服务器.docx

嵌入式以太网串口服务器

嵌入式以太网串口服务器

摘要:

本文提出了一种以高性能微处理器Cortex-M3芯片STM32F103C8T6和以太网控制芯片ENC28J60为核心的转换系统,实现串口(RS232)和网口(RJ45)的数据通过以太网互发,提高了传输数据的抗干扰性,节省了更新换代的成本,达到了远程控制、远程通信的目的。

1、引言

随着Internet快速发展与普及,将一些设备联入网络已经成为越来越多人的共识。

利用基于TCP/IP的串口数据流传输的实现来控制管理的设备硬件,无需投资大量的人力、物力来进行管理、更换或者升级,而串口服务器是为RS-232/485/422到TCP/IP 之间完成数据转换的通讯接口转换器。

2、嵌入式以太网串口服务器的硬件设计

本系统主要有三大模块组成,分别是由微处理器芯片STM32F103C8T6构成的MCU模块,由网络控制芯片ENC28J60与含RJ45和网络变压器的HR91105A构成的网口模块,由串口控制芯片MAX-232与RS232接口构成的串口模块。

设备发送过来的信息通过串口模块之后,送入MCU进行处理,然后通过网络模块发送至以太网进行显示。

如图一所示为服务器的系统设计框图。

图1系统设计框图

2.1、MCU模块

本系统设计引用了嵌入式应用方面性价比高的Cortex—M3STM32F103C8T6作为处理器,Cortex—M3类型的STM32F103C8T6处理器采用表面贴片的48管脚LQFP封装,最高工作频率为72MHZ,工作温度为-40℃~+85℃。

其具有提供丰富的外围接口,包括(CAN、I2C、SPI、UART、USB等)低功耗、门数少、中断延迟小、调试容易,支持TCP/IP协议栈中的IP/ICMP/TCP/UDP/DHCP等协议,动态获取IP,,支持标准socket编程等优点。

2.2、串口模块

几乎所有的微控制器、PC都提供串行接口,使用电子工业协会(EIA)推荐的RS-232-C标准。

由于RS-232-C标准所定义的高、低电平信号与STM32F103系统的LVTTL电路所定义的高、低电平信号完全不同,所以,两者间要进行通信必须经过信号电平的转换。

目前我们用USB-232电平转换芯片PL2303HX,实现USB转串口的功能。

本系统采用PH2303HX芯片和USB接口设计了一个实现USB转串口接口模块。

PL2303单独使用12MHZ晶振,这是USB必须使用的频率,其采用模块化电路,RXD接单片机TXD,TXD接单片机的RXD。

其连接电路如图2所示:

图2USB转串口电路模块

2.3、网口模块

ENC28J60是带有行业标准串行外设接口(SerialPeripheralInterface,SPI)的独立以太网控制器。

它可以作为任何配备有SPI的控制器的以太网接口。

ENC28J60符合IEEE802.3的全部规范,采用一系列包过滤机制以对传入数据包进行限制。

还提供了一个内部的DMA模块,以实现快速数据吞吐和硬件支持的IP校验和计算。

与主控制器的通信通过两个中断引脚和SPI实现,数据传输速率高达10mb/s。

两个专用的引脚用于连接LED,进行网络活动状态指示。

ENC28J60总共只有28引脚,提供QFN/TF。

ENC28J60典型应用电路如图3所示:

图3ENC28J60典型应用电路

以太网串口服务器网络模块采用ENC28J60作为主芯片,单芯片即可实现以太网接入,利用该模块,基本上只要是个单片机,就可以实现以太网的连接,网络模块原理图如图4所示:

图4网络模块原理图

3、嵌入式以太网串口服务器的软件初始化

3.1、uip简介

uIP由瑞典计算机科学学院(网络嵌入式系统小组)的AdamDunkels开发。

其源代码由C语言编写,并完全公开。

uIP协议栈去掉了完整的TCP/IP中不常用的功能,简化了通讯流程,但保留了网络通信必须使用的协议,设计重点放在了IP/TCP/ICMP/UDP/ARP这些网络层和传输层协议上,保证了其代码的通用性和结构的稳定性。

由于uIP协议栈专门为嵌入式系统而设计,因此还具有如下优越功能:

1)代码非常少,其协议栈代码不到6K,很方便阅读和移植。

2)占用的内存数非常少,RAM占用仅几百字节。

3)其硬件处理层、协议栈层和应用层共用一个全局缓存区,不存在数据的拷贝,且发送和接收都是依靠这个缓存区,极大的节省空间和时间。

4)支持多个主动连接和被动连接并发。

5)其源代码中提供一套实例程序:

web服务器,web客户端,电子邮件发送程序(SMTP客户端),Telnet服务器,DNS主机名解析程序等。

通用性强,移植起来基本不用修改就可以通过。

6)对数据的处理采用轮循机制,不需要操作系统的支持。

由于uIP对资源的需求少和移植容易,大部分的8位微控制器都使用过uIP协议栈,而且很多的著名的嵌入式产品和项目(如卫星,Cisco路由器,无线传感器网络)中都在使用uIP协议栈。

uIP相当于一个代码库,通过一系列的函数实现与底层硬件和高层应用程序的通讯,对于整个系统来说它内部的协议组是透明的,从而增加了协议的通用性。

uIP协议栈与系统底层和高层应用之间的关系如图5所示:

图5uip在系统中的位置

从上图可以看出,uIP协议栈主要提供2个函数供系统底层调用:

uip_input和uip_periodic。

另外和应用程序联系主要是通过UIP_APPCALL函数。

当网卡驱动收到一个输入包时,将放入全局缓冲区uip_buf中,包的大小由全局变量uip_len约束。

同时将调用uip_input()函数,这个函数将会根据包首部的协议处理这个包和需要时调用应用程序。

当uip_input()返回时,一个输出包同样放在全局缓冲区uip_buf里,大小赋给uip_len。

如果uip_len是0,则说明没有包要发送。

否则调用底层系统的发包函数将包发送到网络上。

uIP周期计时是用于驱动所有的uIP内部时钟事件。

当周期计时激发,每一个TCP连接都会调用uIP函数uip_periodic()。

类似于uip_input()函数。

uip_periodic()函数返回时,输出的IP包要放到uip_buf中,供底层系统查询uip_len的大小发送。

由于使用TCP/IP的应用场景很多,因此应用程序作为单独的模块由用户实现。

uIP协议栈提供一系列接口函数供用户程序调用,其中大部分函数是作为C的宏命令实现的,主要是为了速度、代码大小、效率和堆栈的使用。

用户需要将应用层入口程序作为接口提供给uIP协议栈,并将这个函数定义为宏UIP_APPCALL()。

这样,uIP在接受到底层传来的数据包后,在需要送到上层应用程序处理的地方,调用UIP_APPCALL()。

在不用修改协议栈的情况下可以适配不同的应用程序。

3.2、程序设计

本系统要实现TCP/IP通信,还要实现和串口交换数据,因此我们采用轮询的方式,第一次调用轮询函数的时候创建两个定时器,当收到包的时候(uip_len>0),先区分是IP包还是ARP包,针对不同的包做不同的处理,对我们来说,主要是通过uip_input处理IP包,实现数据处理。

当没有收到包的时候(uip_len=0),通过定时器处理各个TCP/UDP连接以及ARP表处理。

其轮询处理函数为:

//uip事件处理函数

//必须将该函数插入用户主循环,循环调用.

voiduip_polling(void)

{

u8i;

staticstructtimerperiodic_timer,arp_timer;

staticu8timer_ok=0;

if(timer_ok==0)//仅初始化一次

{

timer_ok=1;

timer_set(&periodic_timer,CLOCK_SECOND/2);//创建1个0.5秒的定时器

timer_set(&arp_timer,CLOCK_SECOND*10);//创建1个10秒的定时器

}

uip_len=tapdev_read();//读取一个IP包,数据长度.uip_len在uip.c中定义

if(uip_len>0)//有数据

{

//处理IP数据包(只有校验通过的IP包才会被接收)

if(BUF->type==htons(UIP_ETHTYPE_IP))//是否是IP包?

{

uip_arp_ipin();//去除以太网头结构,更新ARP表

uip_input();//IP包处理

//当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0

//需要发送的数据在uip_buf,长度是uip_len(这是2个全局变量)

if(uip_len>0)//需要回应数据

{

uip_arp_out();//加以太网头结构,主动连接时可能要构造ARP请求

tapdev_send();//发送数据到以太网

}

}

elseif(BUF->type==htons(UIP_ETHTYPE_ARP))//处理arp报文,是否是ARP请求包?

{

uip_arp_arpin();

//当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0

//需要发送的数据在uip_buf,长度是uip_len(这是2个全局变量)

if(uip_len>0)tapdev_send();//需要发送数据,则通过tapdev_send发送

}

}elseif(timer_expired(&periodic_timer))//0.5秒定时器超时

{

timer_reset(&periodic_timer);//复位0.5秒定时器

//轮流处理每个TCP连接,UIP_CONNS缺省是40个

for(i=0;i

{

uip_periodic(i);//处理TCP通信事件

//当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0

//需要发送的数据在uip_buf,长度是uip_len(这是2个全局变量)

if(uip_len>0)

{

uip_arp_out();//加以太网头结构,主动连接时可能要构造ARP请求

tapdev_send();//发送数据到以太网

}

}

#ifUIP_UDP//UIP_UDP

//轮流处理每个UDP连接,UIP_UDP_CONNS缺省是10个

for(i=0;i

{

uip_udp_periodic(i);//处理UDP通信事件

//当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0

//需要发送的数据在uip_buf,长度是uip_len(这是2个全局变量)

if(uip_len>0)

{

uip_arp_out();//加以太网头结构,主动连接时可能要构造ARP请求

tapdev_send();//发送数据到以太网

}

}

#endif

//每隔10秒调用1次ARP定时器函数用于定期ARP处理,ARP表10秒更新一次,旧的条目会被抛弃

if(timer_expired(&arp_timer))

{

timer_reset(&arp_timer);

uip_arp_timer();

}

}

}

TCP应用接口函数:

//TCP应用接口函数(UIP_APPCALL)

//完成TCP服务(包括server和client)和HTTP服务

voidtcp_demo_appcall(void)

{

switch(uip_conn->lport)//本地监听端口80和1200

{

caseHTONS(80):

httpd_appcall();

break;

caseHTONS(1200):

tcp_server_demo_appcall();

break;

default:

break;

}

switch(uip_conn->rport)//远程连接1400端口

{

caseHTONS(1400):

tcp_client_demo_appcall();

break;

default:

break;

}

}

除此之外,我们需要对串口进行初始化,并建立相应的串口程序文件,便于其它函数的调用,实现串口上数据的交换。

串口函数初始化:

voiduart_init(u32bound){

//GPIO端口设置

GPIO_InitTypeDefGPIO_InitStructure;

USART_InitTypeDefUSART_InitStructure;

NVIC_InitTypeDefNVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);//使能USART1,GPIOA时钟以及复用功能时钟

//USART1_TXPA.9

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//PA.9

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出

GPIO_Init(GPIOA,&GPIO_InitStructure);

//USART1_RXPA.10

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入

GPIO_Init(GPIOA,&GPIO_InitStructure);

//Usart1NVIC配置

NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3

NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;//子优先级3

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//IRQ通道使能

NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器

//USART初始化设置

USART_InitStructure.USART_BaudRate=bound;//一般设置为9600;

USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长为8位数据格式

USART_InitStructure.USART_StopBits=USART_StopBits_1;//一个停止位

USART_InitStructure.USART_Parity=USART_Parity_No;//无奇偶校验位

USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件数据流控制

USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//收发模式

USART_Init(USART1,&USART_InitStructure);//初始化串口

USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启中断

USART_Cmd(USART1,ENABLE);//使能串口

}

主函数的实现是对整个嵌入式以太网串口服务器的统筹管理,实现系统的有序整合和运行。

其主函数为:

intmain(void)

{

delay_init();//延时函数初始化

NVIC_Configuration();//NVIC中断分组2:

2位抢占优先级,2位响应优先级

uart_init(9600);//串口初始化为9600

RTC_Init();//初始化RTC

while(tapdev_init())//初始化ENC28J60如果初始化失败,就会死在这里

{

delay_ms(200);

};

uip_init();//uIP初始化

uip_ipaddr(ipaddr,192,168,1,105);//设置本地设置IP地址uip_sethostaddr(ipaddr);

uip_ipaddr(ipaddr,192,168,1,1);//网关IP地址(其实就是你路由器的IP地址)

uip_setdraddr(ipaddr);

uip_ipaddr(ipaddr,255,255,255,0);//设置网络掩码

uip_setnetmask(ipaddr);

uip_listen(HTONS(80));//监听80端口,用于WebServer

uip_listen(HTONS(1200));//监听1200端口,用于TCPServer

tcp_client_connect();//尝试连接到TCPServer端,用于TCPClient

udp_server_connect();//尝试连接到UDPClient端,用于UDPServer端口1600udp_client_connect();//尝试连接到UDPServer端,用于UDPClient端口1500

while

(1)

{

uip_polling();//处理uip事件,必须插入到用户程序的循环体中

if(uip_test_mode==0){//TCP测试

if(tcp_server_tsta!

=tcp_server_sta)//TCPServer状态改变

{if(tcp_server_sta&(1<<6))//收到新数据

{

printf("TCPServerRX:

%s\r\n",tcp_server_databuf);//打印

tcp_server_sta&=~(1<<6);//标记数据已经被处理

}

tcp_server_tsta=tcp_server_sta;

}

if(tcp_client_tsta!

=tcp_client_sta)//TCPClient状态改变

{

if(tcp_client_sta&(1<<6))//收到新数据

{

printf("TCPClientRX:

%s\r\n",tcp_client_databuf);//打印

tcp_client_sta&=~(1<<6);//标记数据已经被处理

}

tcp_client_tsta=tcp_client_sta;

}

}else{//UDP测试

if(udp_server_sta&(1<<6))//收到新数据

{

printf("TCPServerRX:

%s\r\n",udp_server_databuf);//打印数据

udp_server_sta&=~(1<<6);//标记数据已经被处理

}

if(udp_client_sta&(1<<6))//收到新数据

{

printf("UDPClientRX:

%s\r\n",udp_client_databuf);//打印数据

udp_client_sta&=~(1<<6);//标记数据已经被处理

}

}

if(FLAG1){//TCP/UDP模式切换

if(uip_test_mode==0){

tcp_server_tsta=0XFF;

tcp_client_tsta=0XFF;

}

uip_test_mode=!

uip_test_mode;

}

if(FLAG2)//TCPServer请求发送数据

{

if(uip_test_mode==0){

if(tcp_server_sta&(1<<7))//连接还存在

{

sprintf((char*)tcp_server_databuf,"%d\r\n",tcnt);

tcp_server_sta|=1<<5;//标记有数据需要发送

}

}else{

sprintf((char*)udp_server_databuf,"%d\r\n",tcnt);

udp_server_sta|=1<<5;//标记有数据需要发送

tcnt++;

}

}

if(FLAG3)//TCPClient请求发送数据

{

if(uip_test_mode==0){

if(tcp_client_sta&(1<<7))//连接还存在

{

sprintf((char*)tcp_client_databuf,"%d\r\n",tcnt);

tcp_client_sta|=1<<5;//标记有数据需要发送

}

}else{

sprintf((char*)udp_client_databuf,"%d\r\n",tcnt);

udp_client_sta|=1<<5;//标记有数据需要发送

tcnt++;

}

}

delay_ms

(1);

}

}

4、结束语

随着数字化、智能化仪器的飞速发展,采用以太网进行通信的应用将会越来越广泛。

以太网串口服务器是网络技术与单片机技术的完美结合,用它可以方便的实现嵌入式的以太网联接,可以广泛的应用于智能交通、汽车电子、工业控制、信息家电、医学仪器等各种嵌入式系统应用场合,并且在成本、体积、功耗、灵活性等方面具有明显的优势,能为智能化仪表与

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 临床医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1