【STM32F1】以太网通信之UDP/TCP实验

在本实验中,开发板主控芯片通过 SPI 接口与 CH395Q 以太网芯片进行通讯,从而完成对
CH395Q 以太网芯片的功能配置、数据接收等功能,同时将 CH395Q 以太网芯片的 Socket0 配
置为 UDP 模式,并可通过按键发送 UDP 广播数据至其他的 UDP 客户端,也能够接收其他 UDP
客户端广播的数据,并实时显示至串口调试助手

CH395Q进行UDP实验,实际是在移植的基础上,将ch395_socket结构体内容拷贝给ch395q_t结构体。而ch395q_socket_config函数做的便是这个功能。

1. ch395q_socket_config函数是怎么进行两个结构体的拷贝的?

网络如果正常,也就是说若可以监测到socket,那就判断dhcp状态即是否满足g_ch395q_sta.dhcp_status == DHCP_UP,满足则进行动态ip分配DHCP

这里是ch395_socket结构体:

typedef struct ch395q_socket_t
{
    uint8_t socket_enable;                                          /* Socket使能 */
    uint8_t socket_index;                                           /* Socket标号 */
    uint8_t proto;                                                  /* Socket协议 */
    uint8_t des_ip[4];                                              /* 目的IP地址 */
    uint16_t des_port;                                              /* 目的端口 */
    uint16_t sour_port;                                             /* 源端口 */
    
    struct
    {
        uint8_t *buf;                                               /* 缓冲空间 */
        uint32_t size;                                              /* 缓冲空间大小 */
    } send;                                                         /* 发送缓冲 */
    
    struct
    {
        uint8_t recv_flag;                                          /* 接收数据标志位 */
        uint8_t *buf;                                               /* 缓冲空间 */
        uint32_t size;                                              /* 缓冲空间大小 */
    } recv;                                                         /* 接收缓冲 */
    
    struct
    {
        uint8_t ip[4];                                              /* IP地址 */
        uint8_t gwip[4];                                            /* 网关IP地址 */
        uint8_t mask[4];                                            /* 子网掩码 */
        uint8_t dns1[4];                                            /* DNS服务器1地址 */
        uint8_t dns2[4];                                            /* DNS服务器2地址 */
    } net_info;                                                     /* 网络信息 */
    
    struct
    {
        uint8_t ipaddr[4];                                          /* IP地址 32bit*/
        uint8_t gwipaddr[4];                                        /* 网关地址 32bit*/
        uint8_t maskaddr[4];                                        /* 子网掩码 32bit*/
        uint8_t macaddr[6];                                         /* MAC地址 48bit*/
    } net_config;                                                   /* 网络配置信息 */

} ch395_socket;

结构体g_ch395q_sta

struct ch395q_t
{
    uint8_t version;                                                /* 版本信息 */
    uint8_t phy_status;                                             /* PHY状态 */
    uint8_t dhcp_status;                                            /* DHCP状态 */
    uint8_t  ipinf_buf[20];                                         /* 获取IP信息 */
    
    struct
    {
        ch395_socket config;                                        /* 配置信息 */
    } socket[8];                                                    /* Socket状态 */
    
    void (*ch395_error)(uint8_t i);                                 /* ch395q错误检测函数 */
    void (*ch395_phy_cb)(uint8_t phy_status);                       /* ch395q phy状态回调函数 */
    void (*ch395_reconnection)(void);                               /* ch395q 重新连接函数 */
};

extern struct ch395q_t g_ch395q_sta;

将结构体g_ch395q_sta赋给ch395_sokect,部分代码如下:

		ch395_sokect->net_info.ip[0] = g_ch395q_sta.ipinf_buf[0];
        ch395_sokect->net_info.ip[1] = g_ch395q_sta.ipinf_buf[1];
        ch395_sokect->net_info.ip[2] = g_ch395q_sta.ipinf_buf[2];
        ch395_sokect->net_info.ip[3] = g_ch395q_sta.ipinf_buf[3];
        
        ch395_sokect->net_info.gwip[0] = g_ch395q_sta.ipinf_buf[4];
        ch395_sokect->net_info.gwip[1] = g_ch395q_sta.ipinf_buf[5];
        ch395_sokect->net_info.gwip[2] = g_ch395q_sta.ipinf_buf[6];
        ch395_sokect->net_info.gwip[3] = g_ch395q_sta.ipinf_buf[7];

如果dhcp获取失败就要使用静态方式获取了:

        ch395_cmd_set_ipaddr(ch395_sokect->net_config.ipaddr);                /* 设置CH395的IP地址 */
        ch395_cmd_set_gw_ipaddr(ch395_sokect->net_config.gwipaddr);           /* 设置网关地址 */
        ch395_cmd_set_maskaddr(ch395_sokect->net_config.maskaddr);            /* 设置子网掩码,默认为255.255.255.0*/
        ch395_cmd_init();
        delay_ms(10);

接着将ch395_sokect中的内容拷贝复制给g_ch395q_sta,实现代码如下;

memcpy(&g_ch395q_sta.socket[ch395_sokect->socket_index].config, ch395_sokect, sizeof(ch395_socket));

接着进行模式判断,判断是udp还是tcp,源代码中用了个switch来实现。

2. 如何使用ch395q_socket_config配置udp进行实验

不能只依赖于DHCP,我们也要配置静态的,那根据ch395_socket结构体中的成员,要配置静态的网络信息,包括ip、网关、子网掩码、mac等。这部分代码定义如下:

/* 设置静态的网络信息,如IP地址、MAC地址、子网掩码、网关*/
uint8_t ch395q_ipaddr[4] = {192,168,1,100};
uint8_t ch395q_gwipaddr[4] = {192,168,1,1};
uint8_t ch395q_ipmask[4] = {255,255,255,0};
uint8_t ch395q_mac_addr[6] = {0xB8,0xAE,0x1D,0x00,0x00,0x00}; //正点原子申购的mac地址
/*设置远程ip地址*/
uint8_t ch395q_des_ipaddr[4] = {172,18,45,96}; //设置为本机的ip
/*设置socket的接收发送缓冲区*/
static uint8_t socket0_send_buf[] = {"This is from CH395Q DATA"};
static uint8_t socket0_recv_buf[1024];
ch395_socket ch395q_config[8];//因为有8个socket接口所以是8  

接着配置ch395_socket ch395q_config[8];这个即可:

	ch395q_config[0].socket_enable = CH395Q_ENABLE;
	ch395q_config[0].socket_index = CH395Q_SOCKET_0;
	ch395q_config[0].sour_port = 8080;
	ch395q_config[0].des_port = 8080;
	/*设置其静态ip与远程ip*/
	memcpy(ch395q_config[0].des_ip,ch395q_des_ipaddr,sizeof(ch395q_des_ipaddr));//远程
	memcpy(ch395q_config[0].net_config.ipaddr,ch395q_ipaddr,sizeof(ch395q_ipaddr));//静态
	memcpy(ch395q_config[0].net_config.gwipaddr,ch395q_gwipaddr,sizeof(ch395q_gwipaddr));//网关
	memcpy(ch395q_config[0].net_config.maskaddr,ch395q_ipmask,sizeof(ch395q_ipmask));//子网掩码
	memcpy(ch395q_config[0].net_config.macaddr,ch395q_mac_addr,sizeof(ch395q_mac_addr));//子网掩码
	/*设置发送缓冲区*/
	ch395q_config[0].recv.buf = socket0_recv_buf;
	ch395q_config[0].recv.size = sizeof(socket0_recv_buf);
	ch395q_config[0].send.buf = socket0_send_buf;
	ch395q_config[0].send.size = sizeof(socket0_send_buf);
	/*协议类型*/
	ch395q_config[0].proto = CH395Q_SOCKET_UDP;

	ch395q_socket_config(&ch395q_config[0]);

最后编写按键按下发送数据的功能:

	while(1){
		ch395q_handler();
		key = key_scan(0);
		if(key == KEY0_PRES){
			/**
			 * 第一个参数指用socket0发送还是用哪个
			 * 第二个参数是发送的数据,
			 * 第三个是发送的大小
			*/
			ch395_send_data(0,socket0_send_buf,sizeof(socket0_send_buf));
		}
	}

3. 配置TCPClient与TCPServer通信

在UDP基础上对协议类型进行修改即可:

	/*协议类型*/
	ch395q_config[0].proto = CH395Q_SOCKET_TCP_CLIENT;

4. 配置多socket口的协议

如socket0配置为udp,socket1配置为tcpclient

这里ch395_socket ch395q_config[8] 修改为ch395_socket ch395q_config;

接着代码其他部分对应修改,修改后;

	ch395q_config.socket_enable = CH395Q_ENABLE;
	ch395q_config.socket_index = CH395Q_SOCKET_0;
	ch395q_config.sour_port = 8080;
	ch395q_config.des_port = 8080;
	/*设置其静态ip与远程ip*/
	memcpy(ch395q_config.des_ip,ch395q_des_ipaddr,sizeof(ch395q_des_ipaddr));//远程
	memcpy(ch395q_config.net_config.ipaddr,ch395q_ipaddr,sizeof(ch395q_ipaddr));//静态
	memcpy(ch395q_config.net_config.gwipaddr,ch395q_gwipaddr,sizeof(ch395q_gwipaddr));//网关
	memcpy(ch395q_config.net_config.maskaddr,ch395q_ipmask,sizeof(ch395q_ipmask));//子网掩码
	memcpy(ch395q_config.net_config.macaddr,ch395q_mac_addr,sizeof(ch395q_mac_addr));//子网掩码
	/*设置发送缓冲区*/
	ch395q_config.recv.buf = socket0_recv_buf;
	ch395q_config.recv.size = sizeof(socket0_recv_buf);
	ch395q_config.send.buf = socket0_send_buf;
	ch395q_config.send.size = sizeof(socket0_send_buf);
	/*协议类型*/
	ch395q_config.proto = CH395Q_SOCKET_UDP;

	ch395q_socket_config(&ch395q_config);

这里就配置好了socket0为udp模式,注意ch395q_config.socket_index = CH395Q_SOCKET_0;这句代码,指明socket0。接着配置socket1,我们只要修改ch395q_config.socket_index的值即可,当然也要修改端口避免冲突。代码如下:

	ch395q_config.socket_enable = CH395Q_ENABLE;
	ch395q_config.socket_index = CH395Q_SOCKET_1;
	ch395q_config.sour_port = 5050;
	ch395q_config.des_port = 5050;
	/*设置发送缓冲区*/
	ch395q_config.recv.buf = socket1_recv_buf;
	ch395q_config.recv.size = sizeof(socket1_recv_buf);
	ch395q_config.send.buf = socket1_send_buf;
	ch395q_config.send.size = sizeof(socket1_send_buf);
	/*协议类型*/
	ch395q_config.proto = CH395Q_SOCKET_UDP;

	ch395q_socket_config(&ch395q_config);

上述代码中新的发送接收缓冲区定义已省略。这样就配置好了多socket。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 要在STM32H743上实现以太网通信TCP客户端,可以按照以下步骤进行操作: 1. 配置系统时钟:使用STM32CubeMX工具来配置系统时钟,确保以太网接口(ETH)和外设电源使能。 2. 配置以太网接口:使用STM32CubeMX工具选择以太网模块(ETH)并配置相应的参数,如MAC地址、速度和工作模式等。 3. 初始化TCP/IP协议栈:使用lwIP(轻型IP协议栈)作为TCP/IP协议栈,并进行相应的初始化。可以使用STM32CubeMX工具生成代码并进行初始化设置。 4. 创建TCP客户端:使用lwIP API函数创建一个TCP客户端实例,并指定目标IP地址和端口号。 5. 连接服务器:使用lwIP API函数进行TCP连接服务器。可以在连接成功前进行超时处理。 6. 发送数据:使用lwIP API函数发送需要传输的数据,可以使用lwIP的TCP发送缓冲区管理机制来实现数据传输。 7. 接收数据:使用lwIP API函数接收服务器传回的数据,可以通过轮询的方式获取接收缓冲区中的数据。 8. 关闭连接:使用lwIP API函数关闭TCP连接。 9. 错误处理:在代码中需要添加适当的错误处理机制,处理连接和数据传输过程中可能出现的错误。 10. 编译和下载:使用IAR Embedded Workbench进行编译和下载,确保代码能够正常运行。 通过以上步骤,可以在STM32H743上实现以太网通信TCP客户端。请根据具体需求和环境进行适当的配置和调整。 ### 回答2: STM32H743是意法半导体推出的高性能微控制器系列之一。它提供了以太网通信功能,并且可以通过TCP协议实现客户端通信。 在IAR环境中实现STM32H743以太网通信TCP客户端,首先需要配置以太网外设。可以通过STM32CubeMX等工具进行配置,选择以太网模块并进行相应的引脚映射与参数配置。配置完成后,将生成的代码导出到IAR工程中。 在IAR工程中,引入以太网库文件和TCP/IP协议栈相关的库文件。在主函数中,初始化以太网外设,并进行TCP客户端的配置,包括设置服务器IP地址、端口号等参数。 接下来,创建一个TCP套接字,并连接到服务器。可以使用标准的套接字API函数,如socket()、connect()等。连接成功后,可以通过send()函数发送数据给服务器,通过recv()函数接收服务器返回的数据。 在具体的应用中,可以根据需求,不断地发送和接收数据。发送数据可以使用send()函数将数据发送给服务器,接收数据可以使用recv()函数从服务器接收数据。可以根据自己的应用场景,选择阻塞式或非阻塞式的函数,并结合相关的状态判断来保证通信的稳定性。 当通信结束或需要断开连接时,可以使用close()函数关闭套接字,并释放相关资源。 需要注意的是,在实现STM32H743以太网通信TCP客户端时,要确保网络环境的正常。此外,可能需要针对具体的需求进行相应的错误处理,例如处理连接超时、连接错误等情况。 综上所述,通过以上步骤和相关函数,我们可以在IAR环境中实现STM32H743的以太网通信TCP客户端。通过配置参数、发送和接收数据,实现与服务器的通信。这样可以使STM32H743在网络应用中具备较强的通信能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐大队队长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值