当前位置: 首页 > news >正文

imx6ull 开发板,手机,MQTT 物联网通信实验。

MQTT(Message Queuing Telemetry Transport)是物联网(IoT)领域最受欢迎的轻量级通信。

1、 通信架构

  • IMX6ULL开发板:作为MQTT客户端,每10秒发布温度数据,订阅LED控制指令。
  • 电脑/手机:作为MQTT客户端,订阅温度数据,发布LED控制指令。
  • 本地 MQTT 服务器(Mosquitto):作为消息代理,转发主题消息。

2具体功能

  • 电脑/手机:读取 imx6ull 发布的温度数据
  • 电脑/手机:向 imx6ull 发布指令 → 控制 开发板的LED:

0:关灯(brightness=0)

1:开灯(brightness=1)

2:心跳模式(trigger=heartbeat)

具体安装清单:

MQTT服务器(Broker)装在 Windows 上, 也可以安装在虚拟机,我安装在Windows 上。

1:访问 Mosquitto 官方下载页: https://mosquitto.org/download/

2: 默认 Mosquitto 只允许(127.0.0.1)本地连接,需要修改配置让开发板能连上。打开安装 Mosquitto目录下的 mosquitto.conf(用记事本打开即可),在文件末尾添加2行:

listener 1883 0.0.0.0

allow_anonymous true

添加完后,保存退出。

listener 1883 0.0.0.0 意思是:监听所有网卡的 1883 端口

allow_anonymous true 意思是:允许匿名登录(调试用,生产环境建议加密码)

3:重启服务(管理员 PowerShell)执行命令:

net stop mosquitto

net start mosquitto

也可以 鼠标点击重新启动

MQTTX客户端软件 也装在 Windows 上。

访问 https://mqttx.app/zh/downloads 下载 windows-x64.exe

三 、i.MX6ull 开发板 安装 Mosquitto客户端库,通过网络连接 Windows 的 IP 即可。

开发板nfs挂载的跟文件系统,在虚拟机用 apt命令安装 Mosquitto 客户端库。

先挂载 ./mount.sh 下面是 mount.sh 代码内容

#!/bin/bash echo "MOUNTING" sudo mount -t proc /proc /home/leo/linux/nfs/ubuntu_rootfs/proc sudo mount -t sysfs /sys /home/leo/linux/nfs/ubuntu_rootfs/sys sudo mount -o bind /dev /home/leo/linux/nfs/ubuntu_rootfs/dev sudo mount -o bind /dev/pts /home/leo/linux/nfs/ubuntu_rootfs/dev/pts sudo chroot /home/leo/linux/nfs/ubuntu_rootfs

执行命令,安装

sudo apt update
sudo apt install libmosquitto-dev mosquitto-clients build-essential

需要装吗
libmosquitto-dev✅ 必须,MQTT 开发库
mosquitto-clients✅ 推荐,调试工具
build-essential❌ 已有 gcc 就不需要
# 安装后,查看是否安装及版本号 dpkg -l | grep libmosquitto

安装结束后,exit 退出, 执行 ./unmount.sh 卸载

下面是 ./unmount.sh 代码

#!/bin/bash echo "UNMOUNTING" sudo umount /home/leo/linux/nfs/ubuntu_rootfs/proc sudo umount /home/leo/linux/nfs/ubuntu_rootfs/sys sudo umount /home/leo/linux/nfs/ubuntu_rootfs/dev/pts sudo umount /home/leo/linux/nfs/ubuntu_rootfs/dev

四 、手机安装 MQTT app客户端,向本地MQTT 服务器 收发消息。如果手机端无法安装,那就只能测试电脑和imx6ull 通信。

网络要点

确保 imx6ull 和 Windows 电脑在同一局域网(我是开发板 用网线 直连电脑,也可以连同一台路由器)。在 i.MX6ull 上 ping -> Windows IP,能通则网络没有问题,开发板的MQTT客户端就能连接 Windows 上的本地MQTT服务器。

笔记本电脑连接手机热点,这样的话,手机的MQTT客户端就能连接 Windows 上的本地MQTT服务器,在同一个局域网。

MQTTX 客户端/服务器 都就位后,电脑/手机 打开 MQTTX客户端,新建连接 "New Connection" ,填写连接信息:

字段

Name

(随意)

Host

目标IP或者127.0.0.1

Port

1883

Client ID

留空(自动生成)

Username/Password

留空(已开启匿名)

点击右上角 "Connect"(连接),连接成功后,上方状态会变绿,显示 "Connected"。

订阅:

点击 "new Subscription"(添加订阅)。

Topic 填写 要订阅的名字 → 点击确认 confirm

发布:

在底部输入框,Topic 填写 要订阅的名字。

Message 填写 要发送的信息。

点击发送图标 发送信息。

MQTTX支持同时创建多个连接,连接到同一个服务端IP

修改配置信息后,如果客户端连接成功后,总是重复弹出Reconnecting,需要重启客户端,清掉了缓存,恢复正常。

imx6ull 客户端程序代码:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <mosquitto.h> #define BROKER_ADDRESS "192.168.137.1" // 电脑IP #define BROKER_PORT 1883 /* MQTT 服务器靠这个 ID 区分不同的设备, 如果两个相同的 ID 同时连接服务器,服务器会把前一个踢下线 */ #define CLIENTID "imx6ull_client" #define WILL_TOPIC "dt_mqtt/will" #define LED_TOPIC "dt_mqtt/led" #define TEMP_TOPIC "dt_mqtt/temperature" volatile sig_atomic_t stop = 0; void handle_sigint(int sig) { stop = 1; } void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *msg) { // 防御性编程:防止空指针和空载荷 if (msg->topic == NULL || msg->payload == NULL || msg->payloadlen == 0) return; // 将 payload 转换为字符串并确保以 '\0' 结尾 char payload_str[8] = {0}; strncpy(payload_str, (char *)msg->payload, sizeof(payload_str) - 1); if (!strcmp(msg->topic, LED_TOPIC)) { int fd; if (!strcmp("2", payload_str)) { // 心跳模式 // 如果报错,检查自己开发板的trigger路径 fd = open("/sys/class/leds/red/trigger", O_WRONLY); if (fd >= 0) { write(fd, "heartbeat\n", 10); // 直接写入 heartbeat close(fd); } } else if (!strcmp("1", payload_str)) { // 开灯 (先关闭触发模式,再设置亮度) fd = open("/sys/class/leds/red/trigger", O_WRONLY); if (fd >= 0) { write(fd, "none\n", 5); close(fd); } fd = open("/sys/class/leds/red/brightness", O_WRONLY); if (fd >= 0) { write(fd, "1\n", 2); close(fd); } } else if (!strcmp("0", payload_str)) { // 关灯 fd = open("/sys/class/leds/red/trigger", O_WRONLY); if (fd >= 0) { write(fd, "none\n", 5); close(fd); } fd = open("/sys/class/leds/red/brightness", O_WRONLY); if (fd >= 0) { write(fd, "0\n", 2); close(fd); } } } } void on_connect(struct mosquitto *mosq, void *userdata, int rc) { if (rc == 0) { printf("MQTT 服务器连接成功!\n"); /* 发布上线消息: NULL 表示我不关心这条消息的发送结果追踪,(通常 QoS=0 时填 NULL) WILL_TOPIC:目标主题是WILL_TOPIC "Online":消息内容 0:QoS(服务质量) , true:Retain(保留消息) */ mosquitto_publish(mosq, NULL, WILL_TOPIC, strlen("Online"), "Online", 0, true); /* 订阅 LED 主题, NULL 表示不追踪, 0:订阅的 QoS 级别 */ mosquitto_subscribe(mosq, NULL, LED_TOPIC, 0); printf("已订阅 %s\n", LED_TOPIC); } else { printf("连接失败, 错误码: %d\n", rc); } } int main() { int i; struct mosquitto *mosq; /* 捕获 Ctrl+C 信号 */ signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); /* 初始化 MQTT 库的运行环境 */ mosquitto_lib_init(); /* 创建一个 MQTT 客户端实例(对象), true:表示这是一个全新的干净连接,服务器不保存该设备之前的订阅和离线消息,断线即丢 false:表示这是一个持久会话,断线后服务器会帮你暂存消息,重连后还能收到消息 */ mosq = mosquitto_new(CLIENTID, true, NULL); if (!mosq) { fprintf(stderr, "无法创建MQTT客户端\n"); return 1; } /* 注册“连接成功”的回调函数 */ mosquitto_connect_callback_set(mosq, on_connect); /* 注册“收到消息”时的回调函数 */ mosquitto_message_callback_set(mosq, on_message); /* 设置遗嘱消息: WILL_TOPIC: 遗嘱要发到 WILL_TOPIC 主题 遗嘱内容的长度, 遗嘱的具体内容(载荷) 0:QoS(服务质量), true:Retain(保留消息)服务器会保留这条死讯 */ mosquitto_will_set(mosq, WILL_TOPIC, strlen("Unexpected disconnection"), "Unexpected disconnection", 0, true); // 设置用户名密码(Mosquitto 当前是匿名,这两行可以注释掉) // mosquitto_username_pw_set(mosq, "mqtt1", "123456"); /* 向服务器发起连接请求, 30:Keep Alive(心跳时间),单位是秒 返回 0:表示底层网络握手请求成功发出(注意,只是拨号成功,不代表服务器验证通过) 真正的连接成功与否,是上面注册的 on_connect 回调函数来通知的 */ if (mosquitto_connect(mosq, BROKER_ADDRESS, BROKER_PORT, 30)) { printf("无法连接服务器\n"); mosquitto_destroy(mosq); // 销毁 mosquitto_lib_cleanup(); // 清理资源 return 1; } /* 在后台启动一个新线程,专门负责处理所有的网络通信, 调用这个函数后,libmosquitto 库会调用操作系统的 pthread 接口,创建一个新的线程 */ mosquitto_loop_start(mosq); // 每 10 秒发布温度 while (!stop) { char temp_str[10] = {0}; int fd = -1; fd = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY); if (fd >= 0) { ssize_t bytes_read = read(fd, temp_str, sizeof(temp_str) - 1);//预留一位给 \0 close(fd); if (bytes_read > 0) { // 去除末尾的换行符 \n,避免 printf 打印时多出一个空行 if (temp_str[bytes_read - 1] == '\n') { temp_str[bytes_read - 1] = '\0'; } mosquitto_publish(mosq, NULL, TEMP_TOPIC, strlen(temp_str), temp_str, 0, true); printf("发布温度: %s\n", temp_str); } else { perror("读取温度失败"); } } // 用循环代替纯 sleep,可以更快的响应 Ctrl+C 退出信号 for (i = 0; i < 10 && !stop; i++) { sleep(1); } } printf("\n正在断开连接...\n"); mosquitto_loop_stop(mosq, true); // 停止后台线程 mosquitto_destroy(mosq); // 销毁 mosquitto_lib_cleanup(); // 清理资源 return 0; }

在虚拟机的挂载目录,编译客户端程序:

在开发板运行测试:向服务器 发布温度数据

Windows 上的 MQTTX 客户端:收到订阅的温度数据

Windows 上的 MQTTX 客户端:监控到手机向 imx6ull 发送的 LED 控制指令

收到手机客户端 发送的指令后,红色 LED 熄灭,只剩下电源灯在亮。

http://www.jsqmd.com/news/934080/

相关文章:

  • OpenHarmony 4.0 Release版源码下载后,你的50G硬盘里到底多了些什么?
  • 【Agent】OpenCode 接入 DeepSeek-V4-Pro 开启1M上下文 保姆级教程
  • 用Python动手推导:能量守恒、勾股定理与机器学习损失函数之间的奇妙联系
  • 数字信任技术全景:从密码学基础到隐私保护实战
  • DeepSeek LeetCode 2911. 得到 K 个半回文串的最少修改次数 TypeScript实现
  • 【智能制造】- APS系列|16 生产计划与生产排程:核心概念与分类
  • Java 集成 LibreOffice 实现离线文档转换:Windows 与 Linux 环境详解
  • 快放≠质量牺牲!Sora 2 v2.3实测数据:启用motion-aware upsampling后PSNR提升11.6dB,延迟降低43%
  • Iinux:网络编程
  • 当样本量太小怎么办?Fisher精确检验实战指南(附SPSS操作避坑点)
  • 从OpenCLIP到Qwen-7B:手把手拆解Qwen-VL的视觉-语言对齐‘三明治’架构
  • DISCOUNT: Counting in Large Image Collections with Detector-Based Importance Sampling
  • 微软音频技术三十年:从语音降噪到空间音频的演进与应用
  • UE5动画重定向保姆级教程:从IK绑定到导出,手把手教你让不同体型角色共享一套动作
  • Windows环境下OpenClaw本地部署完整指南
  • AI 编程大势下,Zig 等开源项目为何坚决拒绝 AI 代码贡献?
  • 深入大模型-42-大模型交互之前端代码详解JavaScript代码
  • 基于Azure云平台的海量多媒体智能检索系统架构与实践
  • 公司日常考勤系统毕业设计
  • 为什么你的回归测试一直靠经验?因为少了这条数据链路
  • 上电后MCU从哪开始执行?深入解析工业采集卡的BOOT启动配置电路
  • HTML+fastAPI+Dify|打通前后端至智能体的路
  • 别再只跑Demo了!Grounding DINO实战:用你自己的数据集做Fine-tuning(附完整代码)
  • 索尼发布带 ‘True RGB‘ 背光的 Bravia 9 II 和 Bravia 7 II,色彩表现更出色!
  • 别再只用plt.plot了!Matplotlib面向对象接口实战:从脚本到Notebook的完整配置指南
  • 在Visual Studio中集成Python、Jupyter与.NET,打造高效研究工作站
  • 如何打造高效AI研究周报:从信息筛选到团队洞察的完整指南
  • 我为什么要使用Ollama配置通义千问大模型
  • 红相EDMI电表通信调试助手:报文拆解、CRC校验、地址与序列号互转
  • 【Sora 2教育视频制作黄金法则】:20年AI教育专家亲授5大不可绕过的生成逻辑与避坑指南