51单片机 ENC28J60 TCP/IP通信

51单片机 ENC28J60 TCP/IP通信

  • 单片机:STC90C516RD+
  • ENC28J60模块:mini(3.3V供电)
  • 设备:PC、开发板、两个网线、路由器

首先先介绍一下本文的移植针对于单片机做TCP Server,PC端为TCP Client,实现单片机和PC(网络太调试助手)之间的相互通信,并没有涉及到http和远程端口服务。

一、ENC28J60的配置
 1.ENC28J60模块的介绍
 ![VCC、GND 我用的VCC是3.3V,接5V发烫 管脚主要有4根 SPI协议 控制4根线 ](https://img-blog.csdn.net/20171018200003917?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQV9BNjY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
 2.ENC28J60的函数详细说明可以在CSDN上的博客找到,写的十分详细,买到的模块所带的例程包含ENC28J60.c以及ENC28J60.h文件,这两个文件基本上不需要做出更改。不需要用的部分可以进行删减,以实现代码容量减小。
 3.在主函数中调用即可。
 在这里我的调用函数是dev_init();这是因为在ENC28J60.c文件中对初始化函数进行了封装。
//主函数
dev_init();//通过该函数调用网卡初始化
//ENC28J60.c
void dev_init(void)
{
    enc28j60_init();
}

二、UIP的移植
这是因为TCP协议是分层,uip的协议栈是在底层的,也就相当于底层程序,是不需要自己写的,一般的例程里面都有,这里根据我项目的需要,我将uip.c、uipopt.h以及uip_arp.c和uip_arch.c移植到工程当中。需要修改的地方主要在uipopt.h当中,该文件主要用于配置IP地址(单片机的),网关以及网络掩码的,这些可以进入命令窗口,输入configip,按Enter键,IP的参数就有了。注意:板子的IP和电脑的IP是不相同的。
在这里主要介绍比较重要的uip使用

//使用是注意将uip_popt.h中的UIP_FIXEDADDR更改为0,不然会报错这是主动配置IP
    uip_ipaddr(ipaddr,192,168,1,113);  //配置板子ip
    uip_sethostaddr(ipaddr);// uip_sethostaddr(ipaddr);
    uip_ipaddr(ipaddr,192,168,1,1);    //配置网关
    uip_setdraddr(ipaddr);
    uip_ipaddr(ipaddr,255,255,255,0);   //配置子网掩码
    uip_setnetmask(ipaddr);
uip_send(neirong,len);首先这个函数比较特别,一开始使用的时候,以为和普通的发送函数没有什么区别,调用完之后就能发送了,可是没有想到这个函数并不能主动发送数据,在TCP事件的处理函数appcall()中,可以使用发送数据,然而这个函数只能将最后一次发送的内容发送出去。网上百度了一下,发现没有什么好的方法让单片机主动发送,最后,找到一个可以主动发送内容TCP协议框架,等具体到后面介绍TCP服务时再详细说。
uip_listen(HTONS(8000)); //监听本地端口8000,在TCP网络调试助手上TCP Client的那个端口设置
 先说些必须要使用的
 三、TCP Sever程序
 这部分内容可以说是IP往上一层的配置
 最主要的就是Allcall函数
//这是一个TCP 服务器应用回调函数。
//该函数通过UIP_APPCALL(tcp_demo_appcall)调用,实现Web Server的功能.
//当uip事件发生时,UIP_APPCALL函数会被调用,根据所属端口(1200),确定是否执行该函数。
//例如 : 当一个TCP连接被创建时、有新的数据到达、数据已经被应答、数据需要重发等事件
void tcp_server_demo_appcall(void)
{
    struct tcp_demo_appstate *s = (struct tcp_demo_appstate *)&uip_conn->appstate;
    if(uip_aborted())tcp_server_aborted();      //连接终止
    if(uip_timedout())tcp_server_timedout();    //连接超时 
    if(uip_closed())tcp_server_closed();        //连接关闭 
    if(uip_connected())tcp_server_connected();  //连接成功 
    if(uip_acked())tcp_server_acked();          //发送的数据成功送达 
    //接收到一个新的TCP数据包 
    if (uip_newdata())//收到客户端发过来的数据
    {
        if((tcp_server_sta&(1<<6))==0)//还未收到数据
        {
            if(uip_len>199)
            {          
                ((unsigned char*)uip_appdata)[199]=0;
            }   
            strcpy((char*)tcp_server_databuf,uip_appdata);                        
            tcp_server_sta|=1<<6;//表示收到客户端数据
        }
    }else if(tcp_server_sta&(1<<5))//有数据需要发送
    {
        s->textptr=tcp_server_databuf;
        s->textlen=strlen((const char*)tcp_server_databuf);
        tcp_server_sta&=~(1<<5);//清除标记
    }   
    //当需要重发、新数据到达、数据包送达、连接建立时,通知uip发送数据 
    if(uip_rexmit()||uip_newdata()||uip_acked()||uip_connected()||uip_poll())
    {
        tcp_server_senddata();
    }
}
最后、放上主函数的程序
#include "uip.h" 
#include "uip_arp.h"
#include "enc28j60.h"
#include "tcp_demo.h"
#include "USART.h"
#include "stdio.h"
#include 
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])

#ifndef NULL
#define NULL (void *)0
#endif /* NULL */
/*-----------------------------------------------------------------------------------*/
int
main(void)
{
    unsigned char tcnt=0;
    unsigned char tcp_server_tsta=0XFF;
    idata u8_t i, arptimer;
    idata u16_t j;
    idata u16_t ipaddr[2];
    USART_Init();
    SendString("ENC28J60 Test Start...\r\n");
    /* Initialize the device driver. */ 
    dev_init();
    uip_arp_init();
    /* Initialize the uIP TCP/IP stack. */
    uip_init();
    SendString("http://ag-embeded.taobao.com\r\n");
    /* Initialize the HTTP server. */
    uip_ipaddr(ipaddr,192,168,1,113);  //配置ip
    uip_sethostaddr(ipaddr);//  uip_sethostaddr(ipaddr);
    uip_ipaddr(ipaddr,192,168,1,1);    //配置网关
    uip_setdraddr(ipaddr);
    uip_ipaddr(ipaddr,255,255,255,0);   //配置子网掩码
    uip_setnetmask(ipaddr);
    uip_listen(HTONS(8000));//tcp_server_init();
    arptimer = 0;
    SendString("http://shop64454242.taobao.com\r\n");
thanks"));
  while(1) {
    /* Let the tapdev network device driver read an entire IP packet
       into the uip_buf. If it must wait for more than 0.5 seconds, it
       will return with the return value 0. If so, we know that it is
       time to call upon the uip_periodic(). Otherwise, the tapdev has
       received an IP packet that is to be processed by uIP. */
    uip_len = dev_poll();
    for(j=0;j<500;j++);
    if(uip_len == 0) {
      for(i = 0; i < UIP_CONNS; i++) {
    uip_periodic(i);
    /* If the above function invocation resulted in data that
       should be sent out on the network, the global variable
       uip_len is set to a value > 0. */
    if(uip_len > 0) {
      uip_arp_out();
      dev_send();
    }
      }

#if UIP_UDP
      for(i = 0; i < UIP_UDP_CONNS; i++) {
    uip_udp_periodic(i);
    /* If the above function invocation resulted in data that
       should be sent out on the network, the global variable
       uip_len is set to a value > 0. */
    if(uip_len > 0) {
      uip_arp_out();
      dev_send();
    }
      }
#endif /* UIP_UDP */

      /* Call the ARP timer function every 10 seconds. */
      if(++arptimer == 20) 
      { 
            uip_arp_timer();
            arptimer = 0;
      }
      } else {
      if(BUF->type == htons(UIP_ETHTYPE_IP)) {
    uip_arp_ipin();
    uip_input();
    /* If the above function invocation resulted in data that
       should be sent out on the network, the global variable
       uip_len is set to a value > 0. */
    if(uip_len > 0) {
      uip_arp_out();
      dev_send();
    }
      } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
    uip_arp_arpin();
    /* If the above function invocation resulted in data that
       should be sent out on the network, the global variable
       uip_len is set to a value > 0. */    
    if(uip_len > 0) {   
      dev_send();
    }
      }
    }
    if(tcp_server_tsta!=tcp_server_sta)//TCP Server状态改变
    {                                                            
        if(tcp_server_sta&(1<<7))   SendString("TCP Server Connected   ");
        else    SendString("TCP Server Disconnected");
        if(tcp_server_sta&(1<<6))   //收到新数据
        {
            SendString("in up");//打印数据
            tcp_server_sta&=~(1<<6);       //标记数据已经被处理 
        }
        tcp_server_tsta=tcp_server_sta;
    }   
  }
    if(Button == 0)//TCP Server 请求发送数据Button按下发送数据
    {
        if(tcp_server_sta&(1<<7))   //连接还存在
        {
            sprintf((char*)tcp_server_databuf,"TCP Server OK \r\n");     
            tcp_server_sta|=1<<5;//标记有数据需要发送
            tcnt++;
        }
    }

  return 0;
}

转载一些资料
http://blog.csdn.net/kjlrzzyffmx/article/details/47292135
http://www.360doc.com/content/14/1127/15/20642619_428506515.shtml
http://m.eeworld.com.cn/ic_article/267/33638.html

你可能感兴趣的:(51单片机,ENC28J60)