1126|2

510

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【兆易GD32H759I-EVAL】--10.以太网TCP/UDP通讯 [复制链接]

 
本帖最后由 dirty 于 2024-6-10 11:53 编辑

      本篇讲述板载以太网TCP/UDP通讯功能.

一.硬件原理与准备

      开发板以太网模块功能原理如下

图1:以太网原理图

      开发板外挂一颗以太网芯片DP83848CVV,芯片使用RMII(Reduced Media Independant Interface)精简介质无关接口。RMI收发使用2位数据进行传输,收发时钟均采用50MHz时钟源。信号定义如下:

图2:RMII信号定义

      准备工作,将跳线帽JP48, JP51, JP57, JP59, JP60, JP70接到以太网侧。可以看到开发板以太网功能与LCD/摄像头引脚不兼容,开发板跳线帽灵活切换还是很方便的。

图3:以太网跳线帽选择

 

二.了解TCP/UDP

      TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。传输层是计算机网络中的一层,位于网络层和应用层之间。它主要负责在网络中的两个端系统之间提供可靠的、端到端的数据传输服务。简单理解,传输层就是负责在源主机和目标主机之间提供端到端的数据传输。

      TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;

      UDP是一种无连接的协议,不提供可靠性保证,但传输效率较高。它将数据分割成数据报,每个数据报都是独立的,可以独立传输,因此没有复杂的连接建立和维护过程。

 

三.代码准备

      lwip协议栈资源可在:http://download.savannah.nongnu.org/releases/lwip/网址下载,本工程上FreeRTOS系统,并会使用到该网络协议栈。

1.关于宏的定义使用。这里使能动态分配IP,使用NET0,并配置服务端IP(电脑作为服务端,通过控制台使用命令ipconfigj即可查到)。

#define USE_DHCP    /* enable DHCP, if disabled static address is used */

/*The USE_ENET0 and USE_ENET1 macros cannot be opened at the same time*/
#define USE_ENET0
//#define USE_ENET1

#define IP_S_ADDR0   192
#define IP_S_ADDR1   168
#define IP_S_ADDR2   3
#define IP_S_ADDR3   5

1.网络硬件接口初始化。包括了引脚配置和网络事件中断使能

void enet_system_setup(void)
{
    nvic_configuration();

    /* configure the GPIO ports for ethernet pins */
    enet_gpio_config();

    /* configure the ethernet MAC/DMA */
    enet_mac_dma_config();

    if(0 == enet_init_status) {
        while(1) {
        }
    }


#ifdef USE_ENET0
    enet_interrupt_enable(ENET0, ENET_DMA_INT_NIE);
    enet_interrupt_enable(ENET0, ENET_DMA_INT_RIE);

#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
    enet_desc_select_enhanced_mode(ENET0);
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */

#endif /* USE_ENET0 */
#ifdef USE_ENET1
    enet_interrupt_enable(ENET1, ENET_DMA_INT_NIE);
    enet_interrupt_enable(ENET1, ENET_DMA_INT_RIE);

#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
    enet_desc_select_enhanced_mode(ENET1);
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */

#endif /* USE_ENET1 */
}

/*!
    \brief      this function handles ethernet interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void ENET0_IRQHandler(void)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    /* frame received */
    if(SET == enet_interrupt_flag_get(ENET0, ENET_DMA_INT_FLAG_RS)){ 
        /* give the semaphore to wakeup LwIP task */
        xSemaphoreGiveFromISR(g_rx_semaphore, &xHigherPriorityTaskWoken);
    }
    //printf("ENET0_IRQHandler\r\n");

    /* clear the enet DMA Rx interrupt pending bits */
    enet_interrupt_flag_clear(ENET0, ENET_DMA_INT_FLAG_RS_CLR);
    enet_interrupt_flag_clear(ENET0, ENET_DMA_INT_FLAG_NI_CLR);

    /* switch tasks if necessary */
    if(pdFALSE != xHigherPriorityTaskWoken){
        portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
    }
}

2.LwIP 协议栈初始化。包含了tcp ip任务栈初始化, IP分配,网络芯片寄存器配置,网络状态事件回调注册及设置生效网络。

/*!
    \brief      initializes the LwIP stack
    \param[in]  none
    \param[out] none
    \retval     none
*/
void lwip_stack_init(void)
{
    ip_addr_t ipaddr;
    ip_addr_t netmask;
    ip_addr_t gw;

    /* create tcp_ip stack thread */
    tcpip_init( NULL, NULL );

    /* IP address setting */
#ifdef USE_DHCP
    ipaddr.addr = 0;
    netmask.addr = 0;
    gw.addr = 0;
#else
    IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
    IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
    IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
  
#endif /* USE_DHCP */

#ifdef USE_ENET0
    /* - netif_add(struct netif *netif, ip_addr_t *ipaddr,
              ip_addr_t *netmask, ip_addr_t *gw,
              void *state, err_t (* init)(struct netif *netif),
              err_t (* input)(struct pbuf *p, struct netif *netif))

     Adds your network interface to the netif_list. Allocate a struct
    netif and pass a pointer to this structure as the first argument.
    Give pointers to cleared ip_addr structures when using DHCP,
    or fill them with sane numbers otherwise. The state pointer may be NULL.

    The init function pointer must point to a initialization function for
    your ethernet netif interface. The following code illustrates it's use.*/

    netif_add(&g_mynetif0, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
    /* registers the default network interface */
    netif_set_default(&g_mynetif0);
    netif_set_status_callback(&g_mynetif0, lwip_netif_status_callback);

    /* when the netif is fully configured this function must be called */
    netif_set_up(&g_mynetif0);

#endif /* USE_ENET0 */

#ifdef USE_ENET1
    /* - netif_add(struct netif *netif, ip_addr_t *ipaddr,
              ip_addr_t *netmask, ip_addr_t *gw,
              void *state, err_t (* init)(struct netif *netif),
              err_t (* input)(struct pbuf *p, struct netif *netif))

     Adds your network interface to the netif_list. Allocate a struct
    netif and pass a pointer to this structure as the first argument.
    Give pointers to cleared ip_addr structures when using DHCP,
    or fill them with sane numbers otherwise. The state pointer may be NULL.

    The init function pointer must point to a initialization function for
    your ethernet netif interface. The following code illustrates it's use.*/

    netif_add(&g_mynetif1, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
    /* registers the default network interface */
    netif_set_default(&g_mynetif1);
    netif_set_status_callback(&g_mynetif1, lwip_netif_status_callback);

    /* when the netif is fully configured this function must be called */
    netif_set_up(&g_mynetif1);

#endif /* USE_ENET1 */
}

3.网络状态回调。这里实现TCP/UDP 客户端服务端功能,每一个创建任务并予以实现.

/*!
    \brief      after the netif is fully configured, it will be called to initialize the function of telnet, client and udp
    \param[in]  netif: the struct used for lwIP network interface
    \param[out] none
    \retval     none
*/
void lwip_netif_status_callback(struct netif *netif)
{
    if(((netif->flags & NETIF_FLAG_UP) != 0) && (0 != netif->ip_addr.addr)) {
        printf("%s\r\n",__func__);
        /* initilaize the tcp server: telnet 8000 */
        hello_gigadevice_init();
        printf("initilaize the tcp server: telnet 8000\r\n");
        /* initilaize the tcp client: echo 10260 */
        tcp_client_init();
        printf("initilaize the tcp client: echo 10260\r\n");
        /* initilaize the udp: echo 1025 */
        udp_echo_init();
        printf("initilaize the udp: echo 1025\r\n");
        
    }
}

      这里以TCP Client为例,讲解并添加写日志,打印接收数据。开发板作为客户端,电脑作为服务端。ipaddr就是前面讲过电脑端IP,tcp 端口定义为10260,创建socket后,绑定IP及端口,然后连接。如连接上服务端后接收数据等待,如接收到数据,将接受的数据原样发回给服务端,这里添加了接收数据打印。其他,TCP Server 端口号为8000,UDP 端口1025.

static void tcp_client_task(void *arg)
{
    int  ret, recvnum, sockfd = -1;
    int tcp_port = 10260;
    struct sockaddr_in svr_addr, clt_addr;
    char buf[100];
    ip_addr_t ipaddr;

    IP4_ADDR(&ipaddr, IP_S_ADDR0, IP_S_ADDR1, IP_S_ADDR2, IP_S_ADDR3);

    /* set up address to connect to */
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(tcp_port);
    svr_addr.sin_addr.s_addr = ipaddr.addr;


    clt_addr.sin_family = AF_INET;
    clt_addr.sin_port = htons(tcp_port);
    clt_addr.sin_addr.s_addr = htons(INADDR_ANY);

    while(1) {
        /* create the socket */
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(sockfd < 0) {
            continue;
        }
        // printf("create tcp_client socket ok\r\n");
        ret = bind(sockfd, (struct sockaddr *)&clt_addr, sizeof(clt_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }
        // printf("bind server ok\r\n");
        /* connect */
        ret = connect(sockfd, (struct sockaddr *)&svr_addr, sizeof(svr_addr));
        if(ret < 0) {
            lwip_close(sockfd);
            sockfd = -1;
            continue;
        }
        printf("connect server ok\r\n");
        while(-1 != sockfd) {
            /* reveive packets, and limit a reception to MAX_BUF_SIZE bytes */
            recvnum = recv(sockfd, buf, MAX_BUF_SIZE, 0);
			
            if(recvnum <= 0) {
                lwip_close(sockfd);
                sockfd = -1;
                break;
            }
			printf("receive tcp server data ,len:%d\r\n",recvnum);
			for(int i=0;i<recvnum;i++)
			{
				printf("0x%02x ",buf[i]);
			}
            printf("\r\nreceive data and send to\r\n");
            send(sockfd, buf, recvnum, 0);
        }

        lwip_close(sockfd);
        sockfd = -1;
    }

}

4.dhcp实现。这里通过创建任务dhcp_task,启动dhcp配置,等待路由IP分配,获取到动态IP.

void dhcp_task(void * pvParameters)
{
    ip_addr_t ipaddr;
    ip_addr_t netmask;
    ip_addr_t gw;
#ifdef USE_ENET0
    struct dhcp *dhcp_client0;
#endif /* USE_ENET0 */
#ifdef USE_ENET1
    struct dhcp *dhcp_client1;
#endif /* USE_ENET1 */
  printf("dhcp task run\r\n");
    for(;;){
 #ifdef USE_ENET0
        switch(dhcp_state){
        case DHCP_START:
            dhcp_start(&g_mynetif0);
            /* IP address should be set to 0 every time we want to assign a new DHCP address*/
            dhcp_state = DHCP_WAIT_ADDRESS;
            break;

        case DHCP_WAIT_ADDRESS:    
            /* read the new IP address */
            ip_address.addr = g_mynetif0.ip_addr.addr;

            if(0 != ip_address.addr){ 
                dhcp_state = DHCP_ADDRESS_ASSIGNED;
                printf("\r\nDHCP -- eval board ip address: %d.%d.%d.%d \r\n", ip4_addr1_16(&ip_address), \
                        ip4_addr2_16(&ip_address), ip4_addr3_16(&ip_address), ip4_addr4_16(&ip_address));
            }else{
                /* DHCP timeout */
                dhcp_client0 = netif_dhcp_data(&g_mynetif0);
                if (dhcp_client0->tries > MAX_DHCP_TRIES){
                    dhcp_state = DHCP_TIMEOUT;
                    /* stop DHCP */
                    dhcp_stop(&g_mynetif0);

                    /* static address used */
                    IP4_ADDR(&ipaddr, IP_ADDR0 ,IP_ADDR1 , IP_ADDR2 , IP_ADDR3 );
                    IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
                    IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
                    netif_set_addr(&g_mynetif0, &ipaddr , &netmask, &gw);
                }
            }
            break;

        default: 
            break;
        }
#endif /* USE_ENET0 */
#ifdef USE_ENET1
        switch(dhcp_state){
        case DHCP_START:
            dhcp_start(&g_mynetif1);
            /* IP address should be set to 0 every time we want to assign a new DHCP address*/
            dhcp_state = DHCP_WAIT_ADDRESS;
            break;

        case DHCP_WAIT_ADDRESS:    
            /* read the new IP address */
            ip_address.addr = g_mynetif1.ip_addr.addr;

            if(0 != ip_address.addr){ 
                dhcp_state = DHCP_ADDRESS_ASSIGNED;
                printf("\r\nDHCP -- eval board ip address: %d.%d.%d.%d \r\n", ip4_addr1_16(&ip_address), \
                        ip4_addr2_16(&ip_address), ip4_addr3_16(&ip_address), ip4_addr4_16(&ip_address));
            }else{
                /* DHCP timeout */
                dhcp_client1 = netif_dhcp_data(&g_mynetif1);
                if (dhcp_client1->tries > MAX_DHCP_TRIES){
                    dhcp_state = DHCP_TIMEOUT;
                    /* stop DHCP */
                    dhcp_stop(&g_mynetif1);

                    /* static address used */
                    IP4_ADDR(&ipaddr, IP_ADDR0 ,IP_ADDR1 , IP_ADDR2 , IP_ADDR3 );
                    IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
                    IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
                    netif_set_addr(&g_mynetif1, &ipaddr , &netmask, &gw);
                }
            }
            break;

        default: 
            break;
        }
#endif /* USE_ENET1 */
        /* wait 250 ms */
        vTaskDelay(250);
    }   
}

 

四.调试测验

      编译烧录。准备一根网线,一端接到路由器网口,一端接到开发板网口。准备网络调试助手工具,个人用的NetAssist。

图4:开发板与路由器连接好网线

      上电,等待获取到开发板IP,开发板作为TCP Server,配置如下图所示.

图5:开发板作为TCP Server工具配置

      点击连接,在工具发送数据,可以看到通讯如下

图6:开发板作为TCPServer通讯

      开发板作为TCP Client,配置通讯如下图所示

图7:开发板作为TCPClient工具配置与通讯

      开发板作为UDP,配置如下图所示

图8:UDP通讯

   

       

        至此,实现开发板以太网TCP/UDP通讯功能。

 

最新回复

楼主,跑了RTOS吗?如果跑OS是采用什么样的OS呢?   详情 回复 发表于 2024-6-10 18:57
点赞 关注
个人签名

保持热爱

 
 

回复
举报

6992

帖子

11

TA的资源

版主

沙发
 

楼主,跑了RTOS吗?如果跑OS是采用什么样的OS呢?

点评

上面第三项代码准备  开头那里有说,上的FreeRTOS  详情 回复 发表于 2024-6-10 23:14
 
 
 

回复

510

帖子

0

TA的资源

纯净的硅(初级)

板凳
 
lugl4313820 发表于 2024-6-10 18:57 楼主,跑了RTOS吗?如果跑OS是采用什么样的OS呢?

上面第三项代码准备  开头那里有说,上的FreeRTOS

个人签名

保持热爱

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
推荐帖子
IPTV数字电视和网络电视的区别与联系

IPTV是以家用电视机为主要显示设备,集互联网、多媒体、通信等多种技术于一体,通过IP协议向家庭用户提供多种交互式媒体服务的业 ...

IC设计领域介绍及工程师未来出路规划

一、 IC 设计领域简介 (一)模拟与混号讯号电路设计 IC 电路可分为为模拟 IC 与数字 IC 两大类,以及两者兼具的混合讯号等三种 ...

当代最有竞争力的模拟技术和产品大看台

当代最有竞争力的模拟技术和产品大看台:前置放大器 前置放大器一般位于信号调理电路的最高端,它主要用于放大从传感器过来的 ...

ubuntu下修改内核发生“ncurses libraries“错误(解决方法)

BSEC@bsec-server:~/kernel/Kernel$ make menuconfig HOSTCC scripts/basic/fixdep HOSTCC scripts/basic/docproc HOSTCC script ...

学习笔记分享】【MSP430学习笔记】IAR开发环境中的数据、函数定位方法

IAR集成开发环境下,变量和函数的定位方法。 71081 qq:906411450 triton.zhang 本帖最后由 Triton.zhang 于 2011-9-2 ...

【MSP430F5529测评】2. UART串口通信

本帖最后由 wuguangtao 于 2020-10-27 22:17 编辑 # MSP430F5529LP UART 串口通信测试 由于energia很容易上手和测试, 这 ...

华为电磁兼容性结构设计规范 V2.0

本规范规定了电磁兼容性结构设计(屏蔽和搭接等)的主要原理 、设计原则和详细设计方法。 如果要深入理解电磁兼容的理论 ...

【安信可UWB室内定位模组NodeMCU-BU01】02.AT指令测距

1、NodeMCU-BU01开发板跳帽设置 NodeMCU-BU01开发板板载了一颗STM32 MCU作为主控制芯片,集成了AT调试指令功能,方便在线实时 ...

理论知识指导

各位朋友,前段时间用TAS5630B这颗集成内部MOS的D类运放芯片做了个D类功放,前前后后用了十几片,没有一块板子活过10分钟,既 ...

【得捷电子Follow me第1期】任务1 熟悉thonny软件与micropython的基本语法

本帖最后由 爱吃鱼的加菲猫 于 2023-5-29 22:00 编辑 第一步,开箱及排针焊接 先来两张焊接完成照片,我用了彩色排针区分 ...

关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表