[应用相关] STM32CUBEMX配置LAN8720a实现UDP通信

[复制链接]
460|0
Jiangxiaopi 发表于 2025-9-8 12:03 | 显示全部楼层 |阅读模式
环境
STM32CUBEMX 6.15
单片机:STM32F767VIT6

Cube配置
1/启用freertos,并新建一个udp任务。

8508468be54ce884be.png


2/启用ETH,选择接口为RMII,因为LAN8720a支持这个接口,注意引脚与实际硬件要一致。

3269168be54c72ad33.png


3/配置LAN8720的复位引脚,任选一个引脚,用于复位芯片。

1496168be54c032326.png


4/启用lwip,并禁用DHCP,使用手动配置一个IP地址及网关。

2368468be54bab77de.png


至此,芯片配置完成,可以进入到代码编辑了。

代码编辑
1/使用keil进行编辑,首先打开魔术棒,勾选微库

9402668be54b373cc8.png


2/在MX_LWIP_Init()函数里面,加入LAN8720的复位代码

8216468be54abf40bc.png


至此,应该就可以ping通网络了(我已经把我的电脑网卡地址改为192.168.3.109了)

6749868be54a654096.png


3/在freertos文件里面,包含如下头文件

223268be549ea5fdb.png


#include "lwip/udp.h"
#include "lwip/api.h"
#include "string.h"


4/声明功能函数

9598568be5497541fc.png


static void udp_receive_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p,const ip_addr_t *addr, u16_t port);
void udp_send_data(const char *data, const char *ip_addr, uint16_t port);


5/默认任务,发送数据

2517568be5490b607d.png


6/udp任务,处理数据接收

6829468be548b7e0dd.png


void StartUdpTask(void const * argument)
{
  /* USER CODE BEGIN StartUdpTask */
  /* Infinite loop */
        osDelay(1000);
  struct udp_pcb *upcb;
  err_t err;

  // 创建UDP控制块
  upcb = udp_new();
  if (!upcb)
    {
//      printf("Error creating PCB.\n");
      return;
    }

  // 绑定到本地IP和端口
  err = udp_bind(upcb, IP_ADDR_ANY, 1234); // 使用1234端口
  if (err != ERR_OK)
    {
//      printf("Error binding to port. Error: %d\n", err);
      udp_remove(upcb);
      return;
    }

  // 设置接收回调函数
  udp_recv(upcb, udp_receive_callback, NULL);

//  printf("UDP server started on port 1234\n");

  // 任务主循环
  for(;;)
    {
      // 可以在这里添加其他处理逻辑
      osDelay(1000);
    }
  /* USER CODE END StartUdpTask */
}





7/在/* USER CODE BEGIN Application /和/ USER CODE END Application */之间,补充UDP的回调函数和发送函数。

6893968be547ce75ec.png


// UDP接收回调函数
static void udp_receive_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p,
                                const ip_addr_t *addr, u16_t port)
{
    // 检查是否有数据
    if (p != NULL) {
        // 打印接收到的数据
//        printf("Received %d bytes from %s:%d\n", p->tot_len,
//               ipaddr_ntoa(addr), port);
//        printf("Data: %s\n", (char*)p->payload);

        // 发送响应(可选)
        char response[] = "Hello from STM32!";
        struct pbuf *resp_pbuf = pbuf_alloc(PBUF_TRANSPORT, strlen(response), PBUF_RAM);
        if (resp_pbuf) {
            memcpy(resp_pbuf->payload, response, strlen(response));
            udp_sendto(pcb, resp_pbuf, addr, port);
            pbuf_free(resp_pbuf);
        }

        // 释放接收到的数据包
        pbuf_free(p);
    }
}

void udp_send_data(const char *data, const char *ip_addr, uint16_t port)
{
    struct udp_pcb *upcb;
    err_t err;
    struct pbuf *p;

    // 创建UDP控制块
    upcb = udp_new();
    if (!upcb) {
//        printf("Error creating PCB.\n");
        return;
    }

    // 解析目标IP地址
    ip_addr_t dest_addr;
    IP4_ADDR(&dest_addr,
             (uint8_t)(ip_addr[0]),
             (uint8_t)(ip_addr[1]),
             (uint8_t)(ip_addr[2]),
             (uint8_t)(ip_addr[3]));

    // 分配缓冲区
    p = pbuf_alloc(PBUF_TRANSPORT, strlen(data), PBUF_RAM);
    if (!p) {
//        printf("Error allocating pbuf.\n");
        udp_remove(upcb);
        return;
    }

    // 复制数据到缓冲区
    memcpy(p->payload, data, strlen(data));

    // 发送数据
    err = udp_sendto(upcb, p, &dest_addr, port);
    if (err != ERR_OK) {
//        printf("Error sending data: %d\n", err);
    } else {
//        printf("Data sent successfully.\n");
    }

    // 清理
    pbuf_free(p);
    udp_remove(upcb);
}


测试
连接好网线,打开sscom软件,配置好参数,就可以每秒收到数据China,点击发送后,会反馈Hello from stm32!(注意发送前,先点击“连接”按键).

1032068be5455797c0.png


————————————————
版权声明:本文为CSDN博主「路过羊圈的狼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39649731/article/details/151110845

您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

250

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部