CH32V208系列TCP_Server例程解读

 

首先使用电脑,按以下步骤进行配置IP。

 

 


 

接着单片机下载好程序,用网线连接电脑和单片机即可,使用TCP调试工具创建客户端设置好目标IP(单片机使用的IP地址),端口号一定要选择单片机程序中所定义的端口。

        

测试发送是否能够成功接收。

 


 

看完现象,我们再来看下程序中是如何实现的,

(1) WCHNET_NUM_IPRAW
用于配置 IPRAW(IP 原始套接字)连接的个数,最小值为 1。用于 IPRAW 通讯。
 
(2) WCHNET_NUM_UDP
用于配置 UDP 连接的个数,最小值为 1。用于 UDP 通讯。
 
(3) WCHNET_NUM_TCP
用于配置 TCP 连接的个数,最小值为 1。用于 TCP 通讯。
 
(4) WCHNET_NUM_TCP_LISTEN
用于配置 TCP 监听的个数,最小值为 1。TCP 监听的 socket 仅仅用于监听,一旦监听到TCP 连接,会立即分配一个 TCP 连接,占用 WCHNET_NUM_TCP 的个数。
 
(5) WCHNET_MAX_SOCKET_NUM
用于配置 socket 个数,等于 WCHNET_NUM_IPRAW、WCHNET_NUM_UDP、WCHNET_NUM_TCP、WCHNET_NUM_TCP_LISTEN 之和。

/*********************************************************************
 * @fn      ETH_LibInit(以太网配置初始化)
 *
 * @brief   Ethernet library initialization program
 *
 * @return  command status
 */
uint8_t ETH_LibInit( uint8_t *ip, uint8_t *gwip, uint8_t *mask, uint8_t *macaddr )
{
    uint8_t s;
    struct _WCH_CFG  cfg;

    memset(&cfg,0,sizeof(cfg));
    cfg.TxBufSize = ETH_TX_BUF_SZE;        /* 以太网发送缓存区大小 */
    cfg.TCPMss   = WCHNET_TCP_MSS;         /* TCP最大报文段的长度,此值最大为1460,最小为60。综合传输和资源考虑,建议此值不要小于536字节 */ 
    cfg.HeapSize = WCHNET_MEM_HEAP_SIZE;     /* 堆分配内存大小,主要用于一些不定长度的内存分配,例如发送数据。如果 TCP 有大批量数据收发,则此值应该设置大些 */
    cfg.ARPTableNum = WCHNET_NUM_ARP_TABLE;   /*ARP缓存,存放IP和MAC,此值最小可以设置为1,最大为0x7F。如果WCHNET需要和4台PC进行网络通讯,其中两台会大批量收发数据,
                             则建议设置为4。如果小于2,则会严重影响通讯效率 */
    cfg.MiscConfig0 = WCHNET_MISC_CONFIG0;    
cfg.MiscConfig1 = WCHNET_MISC_CONFIG1;
    
    cfg.led_link = ETH_LedLinkSet;         /* 以太网连接指示灯 */
    cfg.led_data = ETH_LedDataSet;         /* 以太网数据传输指示灯 */
    cfg.net_send = ETH_TxPktChainMode;      /* 数据发送包发送结果 */
    cfg.CheckValid = WCHNET_CFG_VALID;      /* 配置值有效标志 */
    s = WCHNET_ConfigLIB(&cfg);
    if(s)
   {
return (s); } s = WCHNET_Init(ip,gwip,mask,macaddr);    /* 对IP地址,Gwip网关地址,Mask子网掩码,MAC地址进行初始化配置 */ ETH_Init(macaddr); return (s);   }

 

/*********************************************************************
 * @fn      WCHNET_MainTask
 *
 * @brief   library main task function
 *
 * @return  none.
 */
void WCHNET_MainTask(void)
{
    WCHNET_NetInput( );         /* Ethernet data input */
    WCHNET_PeriodicHandle( );   /* Protocol stack time-related task processing */
    WCHNET_HandlePhyNegotiation( );        /* 主要用来处理连接过程中出现的异常情况,每隔一定时间重连一次 */
}

 

/*Query the Ethernet global interrupt,
* if there is an interrupt, call the global interrupt handler*/
全局中断
if(WCHNET_QueryGlobalInt()) { WCHNET_HandleGlobalInt(); }

 

/*********************************************************************
 * @fn      WCHNET_HandleGlobalInt
 *
 * @brief   Global Interrupt Handle
 *
 * @return  none
 */
void WCHNET_HandleGlobalInt(void)
{
    u8 intstat;
    u16 i;
    u8 socketint;

    intstat = WCHNET_GetGlobalInt();                              /* 获取全局中断标志位 */
       /* 识别到中断请求 */
    if (intstat & GINT_STAT_UNREACH)                              /* Unreachable interrupt */
{ printf("GINT_STAT_UNREACH\r\n");                }

/* GINT_STAT_UNREACH,不可达中断。 当库收到 ICMP 不可达中断报文后,将不可达 IP数据包的 IP 地址,端口,协议类型保存到不可达信息表中,然后产生此中断,应用程序
可以通过查询_NET_SYS 结构中的 UnreachCode,UnreachProto 和 UnreachPort 来获取不可达的相关信息 */
    if (intstat & GINT_STAT_IP_CONFLI)                            /* IP conflict,当相互连接的两个设备IP相同是会出现IP冲突提示 */
    {
        printf("GINT_STAT_IP_CONFLI\r\n");
    }
    if (intstat & GINT_STAT_PHY_CHANGE)                           /* PHY status change */
    {
        i = WCHNET_GetPHYStatus();           /* 当 WCHNET 的 PHY 连接有变化时产生此中断,例如 PHY 状态由连接状态变化为断开状态或者由断开状态变化为连接状态。
                               应用程序可以通过 WCHNET_GetPHYStatus 来获取当前的 PHY 状态 */
      if (i & PHY_Linked_Status)
         printf("PHY Link Success\r\n");
    }
    if (intstat & GINT_STAT_SOCKET)      /* socket related interrupt,当 socket 有中断事件时库会产生此中断,
                              应用程序可以通过 WCHNET_GetSocketInt 来获取 socket 的中断状态 */ 
    {
for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) /* 此处作为以太网接收到了数据后,进入中断,i从0取到最大Socket数量时,逐个端口判别数据来源以达到数据准确发送的目的 */
        {
            socketint = WCHNET_GetSocketInt(i);
   if (socketint)
        WCHNET_HandleSockInt(i, socketint);
        }
    }
}
 

 

 

接下来看下WCHNET_HandleSockInt函数,

/*********************************************************************
 * @fn      WCHNET_HandleSockInt
 *
 * @brief   Socket Interrupt Handle
 *
 * @param   socketid - socket id.
 *          intstat - interrupt status
 *
 * @return  none
 */
void WCHNET_HandleSockInt(u8 socketid, u8 intstat)
{
    u8 i;

    if (intstat & SINT_STAT_RECV)                                 /* receive data,接收数据事件 */
    {
        WCHNET_DataLoopback(socketid);                            /* Data loopback,通过此函数进行数据的收发过程 */
    }
if (intstat & SINT_STAT_CONNECT)                              /* connect successfully,判断是否连接成功事件 */
    {
#if KEEPLIVE_ENABLE
        WCHNET_SocketSetKeepLive(socketid, ENABLE);
#endif
        WCHNET_ModifyRecvBuf(socketid, (u32) SocketRecvBuf[socketid],
        RECE_BUF_LEN);
        for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {
            if (socket[i] == 0xff) {                              /* save connected socket id */
                socket[i] = socketid;
                break;
            }
        }
        printf("TCP Connect Success\r\n");
        printf("socket id: %d\r\n",socket[i]);
    }
    if (intstat & SINT_STAT_DISCONNECT)                           /* disconnect,失联事件 */
    {
        for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {             /* delete disconnected socket id */
            if (socket[i] == socketid) {
                socket[i] = 0xff;
                break;
            }
        }
        printf("TCP Disconnect\r\n");
    }
    if (intstat & SINT_STAT_TIM_OUT)                              /* timeout disconnect,以太网连接超时 */
    {
        for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {             /* delete disconnected socket id */
            if (socket[i] == socketid) {
                socket[i] = 0xff;
                break;
            }
        }
        printf("TCP Timeout\r\n");
    }
}
(1)SINT_STAT_RECV,接收缓冲区非空中断,当 socket 收到数据后,会产生此中断,应用层收到此中断后,应该使用 WCHNET_SocketRecvLen 来获取接收数据长度,根据长度使用WCHNET_SocketRecv 来读取接收缓冲区的数据。
(2) SINT_STAT_CONNECT,TCP 连接中断,仅在 TCP 模式下有效。TCP 连接成功后,会产生此中断。应用层必须在产生此中断后,才可以进行数据传输。
(3) SINT_STAT_DISCONNECT,TCP 连接断开中断,仅在 TCP 模式下有效。TCP 连接断开后,会产生此中断。连接断开后,应用层不得再进行数据传输。
(4) SINT_STAT_TIM_OUT,TCP 模式下, TCP 连接、断开、发送数据等过程中出现超时,会产生此中断。如果发生某些异常情况,库内部会关闭此连接时,也会产生该中断。TCP 模式下一旦产生此中断,socket 将会被关闭,且 socket 的相关配置被清除,所以应用层如果需要再次使用此 socket 必须重新初始化并连接或者监听。
posted @ 2022-10-24 16:57  oTvTo  阅读(1026)  评论(0编辑  收藏  举报