内容介绍
内容介绍
一、引言
本次实践旨在使用NXP FRDM-MCXN947开发板的以太网接口,实现开发板和电脑之间的数据通信。通过以太网,电脑可以获取开发板上的温度、触摸和按键信息,并可以通过电脑控制开发板上的RGB LED灯。该任务不仅展示了开发板的强大通信和数据处理能力,也对以太网通信的基本原理进行了实战演练。
二、硬件配置
- NXP FRDM-MCXN947开发板
- 以太网电缆
- 电脑(带以太网接口)
三、软件工具
- MCUXpresso IDE
- MDK
- Socket工具(用于PC端控制和数据获取)
四、架构框图
五、实现步骤
代码已开源在gitee:https://gitee.com/bigstep/mcxn947-demo
- 开发环境搭建:
- 下载并安装MCUXpresso IDE,下载对应的NXP SDK包,这个工具主要用来生成demo测试例程。NXP为这款开发板准备了非常丰富的示例,非常方便我们前期调试学习。
- 下载RT-Thread源码,创建MDK工程,将MCUXpresso IDE到处的驱动程序集成到MDK工程中
- 硬件连接:
- 使用以太网电缆将开发板和电脑连接。
- 连接开发板到电脑的USB接口,用于电源和调试。
- 初始化以太网通信:
/* 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 1static 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
- 初始化UDP客户端:使用了标准socket api接口,单独启动了UDP任务接受UDP数据包
- 获取传感器信息:
定义一个简单的JSON通信协议:type
指令类型,value
具体的值。比如下面的温度汇报json
示例{"type": "temp", "value": "31.2"}
目前type
定义有:temp
温度,touch
触摸事件,wakeup
和isp
两个按钮事件
使用了比较流行的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
字符串并通过以太网发送到电脑上。
- 使用SDK中的API获取
- PC端:
- PC端的socket工具比较多,我这里使用
TCP/UDP Socket调试工具
进行测试。 - 建立一个UDP服务器,监听端口
1234
,用于接收设备汇报的数据。
- PC端的socket工具比较多,我这里使用
- 控制RGB LED灯:
{"type": "led-r", "value": "on"}
目前type
定义有:led-r
控制红色的LED灯,led-g
控制绿色的LED灯,led-b
控制蓝色的LED灯value
:on
打开,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
基本一致,比如下面的示例
- 通过上面的UDP工具发送
六、实验结果
使用Socket工具来和设备进行交互,首先建立一个UDP Server,监听本地1234端口。设备启动后会自动通过UDP将状态汇报到服务器。数据通过JSON编码。
所有预定功能均已实现:
- 电脑成功获取到了开发板上的温度、触摸和按键信息。
- 电脑成功控制开发板上的RGB LED灯。
七、结论
通过本次实践,了解并掌握了NXP FRDM-MCXN947开发板的以太网通信功能,能够通过以太网进行数据传输及远程控制。该项目展示了以太网通信在嵌入式系统中的实际应用,并为未来更复杂的网络通信项目打下了坚实的基础。
八、未来工作
为了进一步完善系统,可以考虑:
- 加入数据加密以提高通信安全性。
- 优化传输协议以提高数据吞吐量和减少延迟。
- 扩展更多的传感器和外设功能。
- 提供一个上位机UI控制程序,更方便测试。
通过这些改进,这一系统将具有更强的实用性和安全性,能够用于更多实际应用场景。
软硬件
元器件
附件下载
mcxn947-demo-master.zip
MDK工程源代码
团队介绍
苏州大学电子信息
评论
0 / 100
查看更多
猜你喜欢
Funpack3-4 - 基于FRDM-MCXN947实现通过以太网和电脑通信该项目使用了MCUXpresso IDE,实现了FRDM-MCXN947的设计,它的主要功能为:通过以太网和电脑通信,实现数据传输,电脑可以获取到板卡上的温度,触摸和按键信息,并可以通过电脑控制板卡上的RGB LED灯。
QingSpace
97
Funpack3-4 基于FRDM-MCXN947的以太网通讯工具该项目使用了FRDM-MCXN947板卡,实现了通过以太网连接PC进行通信的设计,它的主要功能为:使用板卡上的以太网接口连接到电脑上并通过以太网和电脑通信,实现触摸按键,实体按键,led数据传输。。
反正都一样
89
【Funpack 3-4活动】基于MCX N94单片机的以太网通信开发实现该项目使用了FRDM-MCXN947开发板,实现了以太网通讯和指令控制的设计,它的主要功能为:设计并实现一个嵌入式系统,该系统能够通过以太网接口与计算机进行通信,实现数据传输及控制功能。该项目涉及网络通信协议、嵌入式系统开发等多个方面,最终目标是实现一个功能齐全、性能稳定的嵌入式系统,能够为类似应用提供参考和借鉴。。
Dong, ZhB
86