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