基于NXP FRDM-MCXN947开发板的以太网通信实践报告
该项目使用了FRDM-MCXN947,实现了以太网通信实践的设计,它的主要功能为:通过以太网,电脑可以获取开发板上的温度、触摸和按键信息,并可以通过电脑控制开发板上的RGB LED灯。
标签
嵌入式系统
rt-thread
FRDM-MCXN947
bigzhu
更新2024-09-09
苏州大学
80

一、引言

本次实践旨在使用NXP FRDM-MCXN947开发板的以太网接口,实现开发板和电脑之间的数据通信。通过以太网,电脑可以获取开发板上的温度、触摸和按键信息,并可以通过电脑控制开发板上的RGB LED灯。该任务不仅展示了开发板的强大通信和数据处理能力,也对以太网通信的基本原理进行了实战演练。

二、硬件配置

  1. NXP FRDM-MCXN947开发板
  2. 以太网电缆
  3. 电脑(带以太网接口)

三、软件工具

  1. MCUXpresso IDE
  2. MDK
  3. Socket工具(用于PC端控制和数据获取)

四、架构框图

五、实现步骤

代码已开源在gitee:https://gitee.com/bigstep/mcxn947-demo

  1. 开发环境搭建
    • 下载并安装MCUXpresso IDE,下载对应的NXP SDK包,这个工具主要用来生成demo测试例程。NXP为这款开发板准备了非常丰富的示例,非常方便我们前期调试学习。
    • 下载RT-Thread源码,创建MDK工程,将MCUXpresso IDE到处的驱动程序集成到MDK工程中
  2. 硬件连接
    • 使用以太网电缆将开发板和电脑连接。
    • 连接开发板到电脑的USB接口,用于电源和调试。
  3. 初始化以太网通信
    /* Network */
    #define RT_USING_NETDEV
    #define NETDEV_USING_IFCONFIG
    #define NETDEV_USING_PING
    #define NETDEV_USING_NETSTAT
    #define NETDEV_USING_AUTO_DEFAULT
    #define NETDEV_USING_IPV6
    #define NETDEV_IPV4 1
    #define NETDEV_IPV6 1
    #define NETDEV_IPV6_SCOPES
    #define RT_USING_LWIP
    #define RT_USING_LWIP212
    #define RT_USING_LWIP_VER_NUM 0x20102
    #define RT_USING_LWIP_IPV6
    #define RT_LWIP_MEM_ALIGNMENT 4
    #define RT_LWIP_IGMP
    #define RT_LWIP_ICMP
    #define RT_LWIP_DNS
    #define RT_LWIP_DHCP
    #define IP_SOF_BROADCAST 1
    #define IP_SOF_BROADCAST_RECV 1
    static int rt_hw_imxrt_eth_init(void)
    {
       rt_err_t state = RT_EOK;

       stm32_eth_device.dev_addr[0] = 0x00;
       stm32_eth_device.dev_addr[1] = 0x80;
       stm32_eth_device.dev_addr[2] = 0xE1;
       stm32_eth_device.dev_addr[3] = 0x01;
       stm32_eth_device.dev_addr[4] = 0x02;
       stm32_eth_device.dev_addr[5] = 0x03;

       stm32_eth_device.parent.parent.init       = rt_stm32_eth_init;
       stm32_eth_device.parent.parent.open       = RT_NULL;
       stm32_eth_device.parent.parent.close      = RT_NULL;
       stm32_eth_device.parent.parent.read       = RT_NULL;
       stm32_eth_device.parent.parent.write      = RT_NULL;
       stm32_eth_device.parent.parent.control    = rt_stm32_eth_control;
       stm32_eth_device.parent.parent.user_data  = &stm32_eth_device;

       stm32_eth_device.parent.eth_rx     = rt_stm32_eth_rx;
       stm32_eth_device.parent.eth_tx     = rt_stm32_eth_tx;

       /* register eth device */
       state = eth_device_init(&(stm32_eth_device.parent), "e0");
       if (RT_EOK != state)
      {
           LOG_E("emac device init faild: %d", state);
           state = -RT_ERROR;
      }

       /* start phy monitor */
       rt_thread_startup(rt_thread_create("phy", phy_monitor_thread_entry, RT_NULL, 1024, RT_THREAD_PRIORITY_MAX - 2, 2));
       return state;
    }

    INIT_DEVICE_EXPORT(rt_hw_imxrt_eth_init);

    #include <rtthread.h>
    #include <string.h>
    #include <rtdevice.h>
    #include <stdbool.h>
    #include "app.h"
    #include <lwip/sockets.h>
    #include <lwip/sys.h>

    #define BUFFER_SIZE 1024
    #define CLIENT_PORT 888

    static int sockfd = -1;
    static char g_rx_buf[BUFFER_SIZE];

    static void init_udp(void) {
       struct sockaddr_in client_addr;

       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
       if (sockfd < 0) {
           rt_kprintf("Socket creation failed\n");
           return;
      }

       // bind client
       memset(&client_addr, 0, sizeof(client_addr));  
       client_addr.sin_family = AF_INET;  
       client_addr.sin_port = htons(CLIENT_PORT); // Set the fixed client port  
       client_addr.sin_addr.s_addr = htonl(INADDR_ANY); // Bind to any interface  
       if (bind(sockfd, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) {  
           perror("Bind failed");
           lwip_close(sockfd);
           sockfd = -1;
           return;
      }
    }

    int send_udp_data(char *server, uint16_t port, char *data) {
       struct sockaddr_in server_addr;
       if (sockfd < 0) return -1;
       // bind server
       memset(&server_addr, 0, sizeof(server_addr));
       server_addr.sin_family = AF_INET;
       server_addr.sin_port = htons(port);
       inet_aton(server, &server_addr.sin_addr);  // Convert IP address from text to binary

       return sendto(sockfd, data, strlen(data), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
    }

    static void thread_entry(void *parameter) {
       rt_kprintf("udp thread start...\n");
       init_udp();

       if (sockfd < 0) return;

       for (;;) {
           ssize_t recv_len = recvfrom(sockfd, g_rx_buf, BUFFER_SIZE - 1, 0, NULL, NULL);
           if (recv_len < 0) {
               rt_kprintf("Recvfrom failed\n");
          } else {
               g_rx_buf[recv_len] = '\0';
               rt_kprintf("%s\n", g_rx_buf);
               char *data = rt_malloc(recv_len + 1);
               memcpy(data, g_rx_buf, recv_len + 1);
               send_rt_msg(APP_MSG_RECV_UDP_CMD, (uint32_t)data, recv_len);
          }
      }
    }

    static int app_udp_thread_init(void) {
    rt_thread_t thread_id;

    thread_id = rt_thread_create("udp", thread_entry, RT_NULL, 2048, APP_NORMAL_PRIORITY, 10);
    if (thread_id != RT_NULL) rt_thread_startup(thread_id);

    return RT_EOK;
    }

    INIT_APP_EXPORT(app_udp_thread_init);
    • 配置rt-thread,集成网络模块
    • 初始化以太网
    • 初始化UDP客户端:使用了标准socket api接口,单独启动了UDP任务接受UDP数据包recvfrom
  4. 获取传感器信息
    定义一个简单的JSON通信协议:type 指令类型,value 具体的值。比如下面的温度汇报json示例
    {"type": "temp", "value": "31.2"}
    目前type定义有:temp 温度,touch 触摸事件,wakeupisp 两个按钮事件
    使用了比较流行的cJSON第三方库来生成和解析json,生成json函数:
    // {"type": "temp", "value": "31.2"}
    static char *gen_json_cmd(char *type, char *value) {
       cJSON *root = cJSON_CreateObject();
       if (root == NULL) return NULL;
       cJSON *valueJson = cJSON_CreateString(value);
       cJSON_AddItemToObject(root, type, valueJson);
       char *p_json = cJSON_PrintUnformatted(root);
       // free JSON object
       cJSON_Delete(root);
       return p_json;
    }
    • 使用SDK中的API获取P3T1755DP温度、触摸和按键数据。数据使用JSON进行编码,方便后期扩展。
    • 将这些数据整合为json字符串并通过以太网发送到电脑上。
  5. PC端
    • PC端的socket工具比较多,我这里使用TCP/UDP Socket调试工具进行测试。
    • 建立一个UDP服务器,监听端口1234,用于接收设备汇报的数据。
  6. 控制RGB LED灯
    {"type": "led-r", "value": "on"}
    目前type定义有:led-r 控制红色的LED灯,led-g 控制绿色的LED灯,led-b 控制蓝色的LED灯
    valueon 打开,off 关闭
    使用 handle_json_cmd 处理上位机发送过来的json字段
    static void handle_json_cmd(cJSON *root) {
       char *type;
       char *value;
       int ctrl = 0;
       // {"type": "led-r", "value": "on"}
       cJSON *typeItem = cJSON_GetObjectItem(root, "type");
       if (!typeItem) {
           return;
      }
       cJSON *valueItem = cJSON_GetObjectItem(root, "value");
       if (!valueItem) {
           return;
      }
       type = cJSON_GetStringValue(typeItem);
       value = cJSON_GetStringValue(valueItem);
       if (strcmp(value, "on") == 0) ctrl = 1;
       if (strcmp(value, "off") == 0) ctrl = 0;
       if (strcmp(type, "led-r") == 0) {
           if (ctrl) {
               rt_pin_write(LEDR_PIN, PIN_LOW);
          } else {
               rt_pin_write(LEDR_PIN, PIN_HIGH);
          }
      } else if (strcmp(type, "led-g") == 0) {
           if (ctrl) {
               rt_pin_write(LEDG_PIN, PIN_LOW);
          } else {
               rt_pin_write(LEDG_PIN, PIN_HIGH);
          }
      } else if (strcmp(type, "led-b") == 0) {
           if (ctrl) {
               rt_pin_write(LEDB_PIN, PIN_LOW);
          } else {
               rt_pin_write(LEDB_PIN, PIN_HIGH);
          }
      }
    }
    • 通过上面的UDP工具发送json控制指令。
    • 和发送的 json 基本一致,比如下面的示例

六、实验结果

使用Socket工具来和设备进行交互,首先建立一个UDP Server,监听本地1234端口。设备启动后会自动通过UDP将状态汇报到服务器。数据通过JSON编码。

所有预定功能均已实现:

  • 电脑成功获取到了开发板上的温度、触摸和按键信息。
  • 电脑成功控制开发板上的RGB LED灯。

七、结论

通过本次实践,了解并掌握了NXP FRDM-MCXN947开发板的以太网通信功能,能够通过以太网进行数据传输及远程控制。该项目展示了以太网通信在嵌入式系统中的实际应用,并为未来更复杂的网络通信项目打下了坚实的基础。

八、未来工作

为了进一步完善系统,可以考虑:

  • 加入数据加密以提高通信安全性。
  • 优化传输协议以提高数据吞吐量和减少延迟。
  • 扩展更多的传感器和外设功能。
  • 提供一个上位机UI控制程序,更方便测试。

通过这些改进,这一系统将具有更强的实用性和安全性,能够用于更多实际应用场景。


附件下载
mcxn947-demo-master.zip
MDK工程源代码
团队介绍
苏州大学电子信息
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号