前言
硬件环境:
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
|
|