| 
 
| 前言 硬件环境:
 mcu stm32f429igt(野火挑战者老款核心板+底板)
 phy芯片 lan8720
 软件版本:cubemx 6.12.0
 项目背景:设备通过网络连接和上位机通信,并且环境中存在多个设备。设备还需要获取业务数据发送给后台。
 实现方法:设备通过ucp广播和上位机通信,业务数据通过tcp发送给后台。
 
 一、cubemx的配置
 1.freertos的配置
 因为freertos需要用到系统定时器,所以系统的定时器源需要更换,
 
 
   
 说一下我需要实现的,一条udp广播通信,用来被上位机发现,并且上位机下发配置也需要通过udp广播。
 我们在cubemx中创建一条udp_task,一条tcp_task。
 
 
   
 2.eth的配置,这里我们使用中断模式
 
 
   
 
   
 3.lwip的配置
 
 
   
 我们用的lan8720的phy,这里选lan8742。
 
 
   
 cubemx中需要更改的就到这里。
 
 问题
 网上很多教程说明到这里生成的代码是直接能ping通的,但是我的不行。
 我在工作中遇到的也是如此,之前解决了,需要重启phy芯片。但是查看也说的挑战者v1原理图,没考到eth_reset。
 去看了野火的官方程序,看到了
 
 
   
 在HAL_ETH_MspInit()引脚初始化完成后,加入以下代码
 
 HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_RESET);
 HAL_Delay(200);
 HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_SET);
 HAL_Delay(200);
 
 
 
   
 试了下,ok,能ping通。
 
 二、代码
 当前代码非常简陋,最好是用个结构体来维护,不然就像我这样全局变量满天飞。
 
 1.user_tcp.c
 uint8_t dataNetIn = 0;       // 监测是否有网络数据来
 uint8_t connect_flag = FALSE;
 
 static uint8_t net_data_send_pool[512]={0};
 static uint16_t net_data_send_len=0;
 static uint8_t tcp_receive_buffer[NET_RX_BUFFER_SIZE]={0};
 static int sock=-1;
 static uint8_t g_lwip_send_flag;//是否有数据要发送
 static struct sockaddr_in address_tcp;
 
 
 
 /**************************************************************************************
 * * *@brief 讲数据放入发送池
 * * *
 **************************************************************************************/
 void Pool_In(uint8_t *net_data,uint16_t recv_data_len)
 {
 memcpy(net_data_send_pool+net_data_send_len,net_data,recv_data_len);
 net_data_send_len+=recv_data_len;
 g_lwip_send_flag |= LWIP_SEND_DATA;
 }
 
 /**************************************************************************************
 * * *@brief tcp客户端接收线程
 * * *
 * * *@param pvParameters
 **************************************************************************************/
 void lwip_recv_thread_tcp(void *pvParameters)
 {
 int recv_data_len=0;
 
 while (1)
 {
 while (1)
 {
 if(connect_flag == TRUE)
 {
 recv_data_len = recv(sock,tcp_receive_buffer,NET_RX_BUFFER_SIZE,0);
 if (recv_data_len <= 0 )
 {
 disconnect_do();//断开连接
 break;
 }
 else if(recv_data_len>0)
 {
 user_tcp_do(tcp_receive_buffer,recv_data_len);
 memset(tcp_receive_buffer,0,NET_RX_BUFFER_SIZE);
 }
 }
 vTaskDelay(1);
 }
 // shutdown(sock,SHUT_RDWR);
 closesocket(sock);
 vTaskDelay(100);
 }
 }
 sys_thread_t threasd_flag;
 /**************************************************************************************
 * * *@brief 创建tcp客户端发送线程
 * * *
 **************************************************************************************/
 void lwip_data_recv(void)
 {
 threasd_flag=sys_thread_new("lwip_recv_thread_tcp", lwip_recv_thread_tcp, NULL, 512, osPriorityAboveNormal );
 }
 
 /**************************************************************************************
 * * *@brief 重置tcp客户端接收线程
 * * *
 **************************************************************************************/
 void reset_tcp_recv_thread(void)
 {
 if(threasd_flag!=NULL)
 {
 osThreadTerminate(threasd_flag);
 threasd_flag=NULL;
 
 threasd_flag=sys_thread_new("lwip_recv_thread_tcp", lwip_recv_thread_tcp, NULL, 512, osPriorityAboveNormal );
 }
 }
 
 /**************************************************************************************
 * * *@brief clinet线程
 * * *
 * * *@param arg
 **************************************************************************************/
 static void client_socket_thread(void *arg)
 {
 char IP_ADDR[14]={0};
 err_t ERR;
 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 {
 return;
 }
 
 address_tcp.sin_family = AF_INET;
 address_tcp.sin_port = htons(Flash_Info.remote_port);
 sprintf(IP_ADDR,"%u.%u.%u.%u",Flash_Info.remote_ip[0],Flash_Info.remote_ip[1],Flash_Info.remote_ip[2],Flash_Info.remote_ip[3]);
 address_tcp.sin_addr.s_addr = inet_addr(IP_ADDR);
 memset(&(address_tcp.sin_zero), 0, sizeof(address_tcp.sin_zero));
 
 if (connect(sock, (struct sockaddr *)&address_tcp, sizeof(struct sockaddr)) == -1)
 {
 closesocket(sock);
 return;
 }
 else
 {
 connect_flag = TRUE;//连接成功
 connect_do();
 }
 
 while (1)
 {
 user_connect_do();
 if(((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA)) /* 有数据要发送 */
 {
 ERR=write(sock, net_data_send_pool, net_data_send_len);
 g_lwip_send_flag &= ~LWIP_SEND_DATA;
 net_data_send_len=0;
 if(ERR<0)
 {//发送失败,断开连接
 disconnect_do();
 break;
 }
 }
 if(!connect_flag)
 {
 break;
 }
 vTaskDelay(100);
 }
 closesocket(sock);
 }
 
 /**************************************************************************************
 * * *@brief 创建client线程
 * * *
 * * *@param argument
 **************************************************************************************/
 void StartTask_TCP(void const *argument)
 {
 /* init code for LWIP */
 MX_LWIP_Init();
 /* USER CODE BEGIN StartTask_TCP*/
 lwip_data_recv();
 /* Infinite loop */
 for (;;)
 {
 client_socket_thread((void *)1);
 vTaskDelay(tsk_delay_tbl.Delay_IF);
 }
 /* USER CODE END StartTask_TCP*/
 }
 
 /**************************************************************************************
 * * *@brief 从flash读取网络数据
 * * *@param IP_ADDRESS
 * * *@param NETMASK_ADDRESS
 * * *@param GATEWAY_ADDRESS
 **************************************************************************************/
 void lwip_get_static_netif_cfg(uint8_t *IP_ADDRESS, uint8_t *NETMASK_ADDRESS, uint8_t *GATEWAY_ADDRESS)
 {
 memcpy(IP_ADDRESS, Flash_Info.local_ip, 4);
 memcpy(NETMASK_ADDRESS, Flash_Info.net_mask, 4);
 memcpy(GATEWAY_ADDRESS, Flash_Info.gateway, 4);
 }
 
 /**************************************************************************************
 * * *@brief 外部关闭tcp套接字
 * * *
 **************************************************************************************/
 void Close_TCP_Socket(void)
 {
 if(connect_flag)
 {
 connect_flag=FALSE;
 closesocket(sock);
 // shutdown(sock,SHUT_RDWR);
 }
 }
 
 
 
 2.user_udp.c
 #define        UDP_REMOTE_PORT  1314
 
 
 /* socket信息 */
 typedef struct link_socket_info
 {
 struct sockaddr_in client_addr; /* 网络地址信息 */
 socklen_t client_addr_len;      /* 网络地址信息长度 */
 int optval;                     /* 为存放选项值 */
 int sfd;                        /* socket控制块 */
 
 struct
 {
 uint8_t *buf;               /* 缓冲空间 */
 uint32_t size;              /* 缓冲空间大小 */
 } send;                         /* 发送缓冲 */
 
 struct
 {
 uint8_t *buf;               /* 缓冲空间 */
 uint32_t size;              /* 缓冲空间大小 */
 } recv;                         /* 接收缓冲 */
 }link_socket_info;
 
 
 static uint8_t g_lwip_demo_recvbuf[0xFF] = {0};
 static uint8_t g_lwip_demo_sendbuf[0xFF] = {0};
 static link_socket_info *socket_info;
 
 uint8_t udp_bind_flag=0;
 uint8_t udp_send_flag=0;
 
 
 /**************************************************************************************
 * * *@brief udp广播发送函数
 * * *
 * * *@param pvParameters
 **************************************************************************************/
 void lwip_recv_thread_udp(void *pvParameters)
 {
 link_socket_info socket_info_recv = *(link_socket_info*)pvParameters;
 int recv_len = 0;
 
 socket_info_recv.client_addr.sin_family=AF_INET;
 socket_info_recv.client_addr.sin_port=htons(UDP_REMOTE_PORT);
 socket_info_recv.client_addr.sin_addr.s_addr=INADDR_ANY;
 udp_bind_recv(*(link_socket_info*)pvParameters);
 
 while (1)
 {
 recv_len = recv(socket_info_recv.sfd, (void *)socket_info_recv.recv.buf, socket_info_recv.recv.size, 0);
 udp_user_recv_callback();
 memset(g_lwip_demo_recvbuf,0,recv_len);
 vTaskDelay(1);
 }
 }
 
 
 void udp_bind_recv(link_socket_info socket_info_recv)
 {
 link_socket_info socket_info_recv_bind = socket_info_recv;
 
 socket_info_recv.client_addr.sin_family=AF_INET;
 socket_info_recv.client_addr.sin_port=htons(UDP_REMOTE_PORT);
 socket_info_recv.client_addr.sin_addr.s_addr=INADDR_ANY;
 udp_bind_flag=bind(socket_info_recv.sfd, (struct sockaddr *)&socket_info_recv.client_addr, sizeof(struct sockaddr));
 
 }
 sys_thread_t ret_sys;
 /**************************************************************************************
 * * *@brief udp广播接收线程
 * * *
 * * *@param argument
 **************************************************************************************/
 void StartTask_udp(void const * argument)
 {
 socket_info = mem_malloc(sizeof(link_socket_info));
 socket_info->optval = 1;
 
 /* 创建socket UDP通信 */
 socket_info->sfd = socket(AF_INET, SOCK_DGRAM, 0);
 setsockopt(socket_info->sfd, SOL_SOCKET, SO_BROADCAST, &socket_info->optval, sizeof(socket_info->optval));
 socket_info->client_addr.sin_family = AF_INET;
 socket_info->client_addr.sin_port = htons(UDP_REMOTE_PORT);
 socket_info->client_addr.sin_addr.s_addr = inet_addr("255.255.255.255");//广播地址
 socket_info->client_addr_len = sizeof(struct sockaddr_in);
 
 /* 设置接收和发送缓冲区 */
 socket_info->recv.buf = g_lwip_demo_recvbuf;
 socket_info->recv.size = sizeof(g_lwip_demo_recvbuf);
 socket_info->send.buf = g_lwip_demo_sendbuf;
 socket_info->send.size = sizeof(g_lwip_demo_sendbuf);
 
 
 ret_sys=sys_thread_new("lwip_recv_thread_udp", lwip_recv_thread_udp, (void *)socket_info, 512, osPriorityNormal );
 
 while (1)
 {
 /* 发送广播数据 */
 if(socket_info->send.size>0)
 {
 udp_send_flag=sendto(socket_info->sfd, socket_info->send.buf, socket_info->send.size, 0,
 (struct sockaddr *)&socket_info->client_addr, socket_info->client_addr_len);
 socket_info->send.size=0;
 }
 vTaskDelay(1000);
 }
 //mem_free(socket_info);
 }
 
 /**************************************************************************************
 * * *@brief 加入数据到发送缓冲区
 * * *
 * * *@param pstr
 * * *@param size
 **************************************************************************************/
 static void Insert_Send_Buffer(char* pstr,uint8_t size)
 {
 memcpy(g_lwip_demo_sendbuf+socket_info->send.size,pstr,size);
 socket_info->send.size+=size;
 }
 
 
 
 
 提问
 在stm32上似乎lan8720配置完后都是需要reset的,但是很少在别的文章中看到。
 但是在esp32上使用lan8720我看并没有这个操作。
 
 有没有能解答一下的。
 ————————————————
 
 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
 
 原文链接:https://blog.csdn.net/weixin_53950683/article/details/144906231
 
 
 | 
 |