嵌入式以太网串口服务器.docx
- 文档编号:11446202
- 上传时间:2023-03-01
- 格式:DOCX
- 页数:17
- 大小:421.57KB
嵌入式以太网串口服务器.docx
《嵌入式以太网串口服务器.docx》由会员分享,可在线阅读,更多相关《嵌入式以太网串口服务器.docx(17页珍藏版)》请在冰豆网上搜索。
嵌入式以太网串口服务器
嵌入式以太网串口服务器
摘要:
本文提出了一种以高性能微处理器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、结束语 随着数字化、智能化仪器的飞速发展,采用以太网进行通信的应用将会越来越广泛。 以太网串口服务器是网络技术与单片机技术的完美结合,用它可以方便的实现嵌入式的以太网联接,可以广泛的应用于智能交通、汽车电子、工业控制、信息家电、医学仪器等各种嵌入式系统应用场合,并且在成本、体积、功耗、灵活性等方面具有明显的优势,能为智能化仪表与
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式 以太网 串口 服务器