打印
[应用相关]

STM32:在freertos下使用lwip的入门实验

[复制链接]
188|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
前言
硬件环境:
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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

30

帖子

0

粉丝