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

news/2024/5/18 14:00:35 标签: stm32, udp, 单片机

在本实验中,开发板主控芯片通过 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来实现。

udp_100">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。


http://www.niftyadmin.cn/n/438961.html

相关文章

VUE项目无法启动NODE版本与NODE-SASS、SASS-LOADER版本不兼容

系列文章目录 文章目录 系列文章目录错误分析一、版本比对二、解决方案总结 错误分析 在VUE项目开发中,我们经常会遇到报错: Node Sass version 7.0.1 is incompatible with ^4.0.0。 网上解决方案也千奇百怪,最终操作下来,也是…

【已解决】“X-Content-Type-Options”头缺失或不安全

Appscan是一款安全漏洞扫描软件,由IBM公司研发,后又被卖给了印度公司HCL。 在web安全测试中,今天我们说下扫描结果中包含X-Content-Type-Options请求头header的缺失或不安全的时候,我们该如何应对。 风险:可能会收集…

Java实现TestNg+ExtentReport实现接口测试,并生成测试报告

一 在pom.xml文件中引入TestNg以及ExtentReport包 <dependencies> <!--testNg引入--> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.9.10</version> </de…

Python学习49:词频统计

类型&#xff1a;文件‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬ 描述‪‬‪‬…

dockerfile和dockercompose都有expose,听谁的?

Dockerfile 的 EXPOSE 指令和 docker-compose 的 expose 配置选项实际上具有不同的含义和目的。 在 Dockerfile 中&#xff0c;EXPOSE 指令是为了声明在容器运行时会使用的网络端口。这对于在运行或使用容器时提供了关于其网络配置的信息。然而&#xff0c;它并不会实际打开这…

Ubuntu18.04离线安装redis

因需要安装redis的服务器无法连接互联网&#xff0c;所以需要离线安装。首先需要下载redis的安装包&#xff0c;之后进行安装&#xff0c;在安装之前需要保证gcc&#xff0c;g&#xff0c;make等依赖包已经安装。 1. 安装gcc等依赖包 依赖包安装请参考&#xff1a; Ubuntu18…

【计算机网络】第一章 概述(下)

文章目录 第一章 概述1.5 计算机网络的性能指标1.5.1 速率1.5.2 带宽1.5.3 吞吐量1.5.4 时延 1.6 计算机网络体系结构1.6.1 常见的体系结构1.6.2 分层的必要性1.6.4 体系结构中的专用术语 1.8 习题 第一章 概述 1.5 计算机网络的性能指标 常用的 计算机网络 的性能指标有以下 …

Vue- mixin(混入)

mixin(混入) mixin&#xff1a;翻译过来叫混入&#xff0c;也有人叫混合&#xff0c;官方叫混入 作用&#xff1a;两个组件共享一个配置(配置必须是一样的)&#xff0c;本质就是复用配置 通过案例理解学习如何使用以及作用 1 编写案例 提出需求&#xff0c;新增一个组件&a…