ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

线程邮箱项目整合

线程邮箱项目整合 线程邮箱整体架构数据的收发在这个项目中每个线程节点挂载着自己的消息队列消息主体如下消息队列为单向链表为什么不用共享内存在线程邮箱中最需要处理的是几个外接模块的整合每个模块的接口类型完全不同且各自的“响应速度”和“读取方式”都不一样BH1750/dev/i2c-X较慢必须等180ms读取频率不能太高。DHT11/dev/ptadxl345(自己的驱动)慢必须等至少1秒才能读一次。ADXL345/dev/misc_dht11(自己的驱动)快几乎无延时实时性好。MQ135/sys/bus/iio/.../in_voltage0_raw快读文件即可无硬性延时。SPT660/dev/ttymxc2(串口 Modbus)中必须按主从轮询发指令收回复约耗时 10~20ms。数据收集线程void* data_collect_th(void* arg) { int loop_count 0; while (1) { /* 1. 高频ADXL345 和 MQ135 每次都读因为它们的读取速度极快 */ read_adxl345(fd_adxl, data); read_mq135(data); // 【新增】读 MQ135 烟雾传感器 /* 2. 中频BH1750 每2次读一次需要180ms延时 */ if (loop_count % 2 0) { read_bh1750(fd_bh1750, data); } /* 3. 低频DHT11 每5次读一次需要1秒延时 */ if (loop_count % 5 0) { read_dht11(fd_dht11, data); } /* 4. 统一发送给三个消费线程 */ send_msg(mbs, show, data); send_msg(mbs, sock, data); send_msg(mbs, db, data); loop_count; usleep(200000); // 200ms } return NULL; }关于lvgllvgl配置void* lvgl_th(void* arg) { init_my_lvgl(); while (1) { lv_timer_handler(); process_lvgl_tasks(); usleep(5000); } return NULL; } void* show_th(void* arg) { while (1) { char sendname[256]; FactoryData data; recv_msg(mbs, sendname, data); FactoryData* pData (FactoryData*)malloc(sizeof(FactoryData)); *pData data; add_lvgl_task(update_first_page, pData); usleep(200000); } return NULL; }无论采集频率多高无论网络或存储消费多慢LVGL 都能以自身最安全的节奏持续、稳定地呈现最新的生产数据。show线程作用mqttMQTT 是一种“报纸订阅”模式的通信协议Broker经纪人/服务器在您项目里就是OneNet 平台。它负责接收和转发消息相当于“邮局”。Publisher发布者在您的项目里就是i.MX6ULL 开发板。它负责把温湿度、光照、加速度这些数据打包发给 Broker也就是mqtt_send做的事。Subscriber订阅者在您的项目里OneNet 云端或您手机上的 APP就在“订阅”您开发板发来的数据。void* sock_th(void* arg) { mqtt_init(); while (1) { char sendname[256]; FactoryData data; recv_msg(mbs, sendname, data); mqtt_send(data); usleep(500000); } return NULL; }首先通过mqtt-init建立起与云端的长连接在mqtt_init里先进行tcp的三次握手然后发送mqtt的连接报文报文里就包括我的身份信息ID设备名Token秘钥等。OneNet回复连接确认报文长连接便正式建立成功。建立连接后我设置了keepAliveInterval 20。也就是说我每 20 秒会发送一次 MQTT 心跳包PINGREQ告诉云端‘我还活着’。如果没有心跳包云端会判定设备掉线连接会自动断开。mqtt的工作流程先把收来的数据打包成json格式然后封装MQTT消息将这个json字符串装入message结构体设置好Qos服务质量和服务等级接着通过 MQTTClient_publishMessage将消息发送到预定义好的设备属性上报主题Topic上。底层 Paho 库会帮我封装好 MQTT 协议帧自动按照 MQTT 协议规范封装好固定报头Fixed Header、主题长度、数据长度等字节流将消息打包成一个标准的 MQTT 数据帧PUBLISH 包并通过已经建立的 TCP 长连接 推送给 OneNet。最后通过 MQTTClient_waitForCompletion 等待云端回执PUBACK确保数据安全送达。mqtt与http的区别而且HTTP 的报文头Headers通常很大包含 Cookie、User-Agent 等非常占用带宽。在发送数据时MQTT 的固定报头Topic 长度和 ID只有 2 个字节。您的核心数据传感器值通过 MQTT 传输几乎没有额外的控制信息浪费极大降低了带宽占用。JSON报文里面有什么paho库是什么呢数据库相关存到哪/mnt在 Linux 中是一个标准的“挂载点Mount Point”目录专门用来挂载外部的存储设备如 SD 卡、U 盘、硬盘、网络共享文件夹。/mnt是您的“外接物理硬盘”用来存放断电不丢失的数据根目录 / 是您的“系统内部空间”是易碎的。在嵌入式 Linux 中根文件系统/通常有以下两种存储形式NFS 网络挂载您的开发板现在就是这样文件存在您 Ubuntu 电脑的网络文件夹里一旦网络断开或开发板断电正在写入的文件极容易损坏。内存盘ramfs/initramfs文件存在内存里一旦断电内存里的数据瞬间全部消失数据库实例问题ret-5在 Linux 的 I2C 通信中代表-EIOInput/Output Error即“I2C 总线上根本没找到设备”或者“总线被卡死”检查 BH1750 的地址您驱动里用的地址是多少如果您的模块上 ADDR 引脚接了高电平地址是0x5C如果悬空地址是0x23。请确认您的代码里用对了。查一下总线上有没有设备在开发板终端执行bashi2cdetect -y 1如果看到23或5c说明硬件在线如果全是--说明BH1750 根本没接好拔掉重插检查线序VCC 接 3.3VSDA 和 SCL 有没有接反如果您在跑 LVGL 时频繁读写可能是因为 I2C 总线被挂起导致超时。把排线重新插紧试试。光照跳变严重原因是在采集线程里面加了memset段错误排查思路让代码在板子上生成core文件拷贝到Ubnutu下使用GDB调试首先修改makefile加入-g 表示允许gdb调试生成调试信息ulimit -c unlimited崩溃会生成一个core文件拷贝到ubuntu下进行gdb调试权限不够给core权限!!这是 Shell 的“历史扩展”语法代表“上一条命令”定位到错误 recv_msg发送错误错误的接了字符串字符串常量如db通常被存放在只读内存区.rodata 段。如果你把db直接传给recv_msg而recv_msg内部试图去修改这个参数比如写入从别处接收到的数据或者调用strcpy、sprintf等就会发生以下情况尝试写入只读内存程序会尝试向只读区写入数据操作系统会立即拦截触发SIGSEGV信号导致程序直接崩溃。缓冲区溢出Buffer Overflow即使recv_msg只读不写它可能也会期待传入一个合法的字符串指针。如果传入的db长度不够或者recv_msg内部有strlen误判都可能引发意外的内存访问。用数组接住gdb相关命令gdb ./demo core启动 GDB并同时加载可执行文件./demo和它崩溃时生成的core文件用于直接查看崩溃现场。bt查看程序崩溃或暂停时函数调用的“历史记录GDB 会把这些“函数调用层级”从上到下依次打印出来让你清楚地看到“是谁一步一步把程序带到了崩溃的地方”。命令缩写功能说明gdb ./程序名-启动 GDB 并加载可执行文件gdb ./程序名 core-启动 GDB 并加载崩溃产生的 core 文件runr运行程序start-运行程序并在main函数处暂停continuec继续运行程序直到遇到断点或结束nextn单步执行不进入函数内部steps单步执行进入函数内部finish-运行直到当前函数返回quitq退出 GDB命令缩写功能说明gdb ./程序名-启动 GDB 并加载可执行文件gdb ./程序名 core-启动 GDB 并加载崩溃产生的 core 文件runr运行程序start-运行程序并在main函数处暂停continuec继续运行程序直到遇到断点或结束nextn单步执行不进入函数内部steps单步执行进入函数内部finish-运行直到当前函数返回quitq退出 GDBlistl列出当前执行的源代码print 变量名p 变量名打印变量的当前值ptype 变量名-查看变量的数据类型/结构体定义display 变量名-自动跟踪变量每次单步时自动打印info locals-打印当前函数内所有的局部变量set 变量名 值-调试时强制修改某个变量的值x/10wx 地址-以十六进制查看指定地址的内存内容x/s 地址-将指定地址的内容当作字符串打印
返回列表