当前位置: 主页 > 硬件 >

ZYNQ7000系列 UDP通信

时间:2021-10-09  作者:haden   点击:
【摘要】前面介绍了官方给出的lwip协议。TCP协议在开发板中需要250ms和500ms调用一次拥塞控制和超时重传等操作,需要大量中断,程序处理速度会收到一定影响。 接下来重写main.c和几个UDP相关文

前面介绍了官方给出的lwip协议。TCP协议在开发板中需要250ms和500ms调用一次拥塞控制和超时重传等操作,需要大量中断,程序处理速度会收到一定影响。

接下来重写main.c和几个UDP相关文件,实现UDP通信。

首先系统中断头文件sys_intr.h:

#ifndef SYS_INTR_H_
#define SYS_INTR_H_
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"
#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID

int Init_Intr_System(XScuGic * IntcInstancePtr);
void Setup_Intr_Exception(XScuGic * IntcInstancePtr);

#endif /* SYS_INTR_H_ */

sys_intr.c代码如下:

#include "sys_intr.h"

//---------------------------------------------------------
//                    设置中断异常
//---------------------------------------------------------
void Setup_Intr_Exception(XScuGic * IntcInstancePtr)
{
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
            (Xil_ExceptionHandler)XScuGic_InterruptHandler,
            (void *)IntcInstancePtr);
    Xil_ExceptionEnable();
}

//---------------------------------------------------------
//                    初始化中断系统
//---------------------------------------------------------
int Init_Intr_System(XScuGic * IntcInstancePtr)
{
    int Status;

    XScuGic_Config *IntcConfig;
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    if (NULL == IntcConfig) {
        return XST_FAILURE;
    }

    Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
                    IntcConfig->CpuBaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }
    return XST_SUCCESS;
}

main.c代码如下:

#include "sleep.h"
#include "user_udp.h"
#include "sys_intr.h"

extern unsigned udp_connected_flag;
static  XScuGic Intc;   //GIC
int main(void)
{
    struct netif *netif, server_netif;
    struct ip_addr ipaddr, netmask, gw;

    /*  开发板MAC地址  */
    unsigned char mac_ethernet_address [] =
        {0x00, 0x0a, 0x35, 0x00, 0x01, 0x02};
    /*  开启中断系统  */
    Init_Intr_System(&Intc);
    Setup_Intr_Exception(&Intc);
    netif = &server_netif;
    IP4_ADDR(&ipaddr,  192, 168,   1, 10);
    IP4_ADDR(&netmask, 255, 255, 255, 0);
    IP4_ADDR(&gw,      192, 168,   1, 1);

    lwip_init();   //初始化lwIP库
    /* 添加网络接口并将其设置为默认接口 */
    if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, XPAR_XEMACPS_0_BASEADDR)) {
            xil_printf("Error adding N/W interface");
            return -1;
    }
    netif_set_default(netif);
    netif_set_up(netif);        //启动网络
    user_udp_init();            //初始化UDP

    while(1)
    {
        /*  将MAC队列中的包传输的LwIP/IP栈中   */
        xemacif_input(netif);
        if (udp_connected_flag) { //发送
            sleep(1);
            udp_printf();
        }
    }
    return 0;
}

但凡使用lwip程序,无论TCP还是UDP,进入while(1)循环前,都会有这样一个配置流程:

  • 设置开发板MAC地址
  • 启动中断系统
  • 设置本地IP地址
  • 初始化lwip
  • 添加网络接口
  • 设置默认网关接口
  • 启动网络
  • 初始化TCP或UDP连接

在while(1)循环中,第一件事必然是使用xemacif_input函数将MAC队列中的包传输到lwIP栈中,这是Xilinx适配器提供的函数。再之后才是用户代码。我们继续看UDP相关文件中是如何进行连接初始化和“Hello World”字符输出的。

user_udp.h文件代码如下:

#ifndef SRC_USER_UDP_H_
#define SRC_USER_UDP_H_
#include "lwip/err.h"
#include "lwip/udp.h"
#include "lwip/init.h"
#include "lwipopts.h"
#include "lwip/err.h"
#include "lwipopts.h"
#include "netif/xadapter.h"
#include "xil_printf.h"

int user_udp_init(void);
void udp_printf(void);

#endif /* SRC_USER_UDP_H_ */

user_udp.c文件代码如下:

#include "user_udp.h"
//---------------------------------------------------------
//                    变量定义
//---------------------------------------------------------
struct udp_pcb *connected_pcb = NULL;
static struct pbuf *pbuf_to_be_sent = NULL;

static unsigned local_port = 7;
//本地端口
static unsigned remote_port = 8080;  
//远程端口
volatile unsigned udp_connected_flag = 0;  
//连接标志
//---------------------------------------------------------
//                  UDP连接初始化函数
//---------------------------------------------------------
int user_udp_init(void)
{
    struct udp_pcb *pcb;
    struct ip_addr ipaddr;
    err_t err;
    udp_connected_flag = 0;

    /*  创建UDP控制块   */
    pcb = udp_new();
    if (!pcb) {
        xil_printf("Error Creating PCB.");
        return -1;
    }
    /*  绑定本地端口   */
    err = udp_bind(pcb, IP_ADDR_ANY, local_port);
    if (err != ERR_OK) {
        xil_printf("Unable to bind to port %d", local_port);
        return -2;
    }
    /*  连接远程地址   */
    IP4_ADDR(&ipaddr, 192, 168, 1, 100);
    err = udp_connect(pcb, &ipaddr, remote_port);
    if (err != ERR_OK) {
        xil_printf("Unable to connect remote port.");
        return -3;
    }
    else {
        xil_printf("Connected Success.");
        connected_pcb = pcb;
        udp_connected_flag = 1;
    }

    return 0;
}

//---------------------------------------------------------
//                   UDP发送数据函数
//---------------------------------------------------------
void udp_printf(void)
{
    err_t err;
    char send_buff[14] = "Hello World!";  //待发送字符
    struct udp_pcb *tpcb = connected_pcb;
    if (!tpcb) {
        xil_printf("error connect.");
    }
    /*  申请pbuf资源  */
    pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, 14, PBUF_POOL);
    memset(pbuf_to_be_sent->payload, 0, 14);
    memcpy(pbuf_to_be_sent->payload, (u8 *)send_buff, 14);
    /*  发送字符串  */
    err = udp_send(tpcb, pbuf_to_be_sent);
    if (err != ERR_OK) {
        xil_printf("Error on udp send : %d", err);
        pbuf_free(pbuf_to_be_sent);
        return;
    }
    pbuf_free(pbuf_to_be_sent);  //释放pbuf
}

user_udp_init函数中配置远程主机的IP地址和端口号,并与之连接。udp_printf函数中申请pbuf资源并发送“Hello World”。

网线连接开发板和电脑,将以太网的IPv4地址修改为UDP初始化函数中设置的地址。打开网络调试助手,选择UDP协议、IP地址和程序中设置的端口号。下载程序,开发板和电脑完成连接,串口打印消息如下:

网络调试助手可以看到,每秒收到一个”Hello World”。

原文链接:https://blog.csdn.net/FPGADesigner/article/details/88746532

顶一下
(0)
0%
踩一下
(0)
0%
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
验证码: 点击我更换图片