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

嵌入式上位机开发入门(二十二):RTU/TCP 双协议互斥访问寄存器

目录一、前言二、设计思路共享寄存器 互斥锁三、modbus_mapping_t 结构体四、TCP Server 任务初始化与调度五、RTU Server 任务复用资源六、两个任务的协作关系七、总结八、结尾一、前言大家好这里是Hello_Embed。上篇对 H5 开发板程序进行了六处针对性改进。本篇来实现最终目标让中控同时支持 Modbus RTU 和 Modbus TCP 两种协议。整体效果上位机既可以通过USB 串口RTU与中控通信也可以通过WiFi 网络TCP访问两种协议读写的是同一套寄存器并通过 LVGL 界面实现协议切换。配合写文件功能还可以进行远程 IAP 升级。改造完全基于原 RTU 工程只展示关键改动部分。二、设计思路共享寄存器 互斥锁双协议兼容的核心只需解决一个问题如何让两种协议安全地访问同一套寄存器而不发生冲突答案是用一个全局互斥锁Mutex保护寄存器访问。┌─────────────────────────────────────────┐ │ 共享寄存器 mb_mapping │ └──────────────────┬──────────────────────┘ │ 受全局 Mutex 保护 ┌───────────┴───────────┐ ↓ ↓ LibmodbusTCPServerTask LibmodbusRTUServerTask WiFi / TCP 通道 USB / RTU 通道两个任务在处理上位机请求时都要先获取互斥锁操作完寄存器后再释放锁。这样无论哪个任务在运行寄存器数据始终是一致的。数据格式的适配RTU/TCP 帧头差异在前几篇中已经完成本篇专注于任务间的资源共享与互斥。三、modbus_mapping_t 结构体两个任务共同访问的寄存器映射表其结构如下typedefstruct_modbus_mapping_t{intnb_bits;/* 线圈数量 */intstart_bits;/* 线圈起始地址 */intnb_input_bits;/* 离散输入数量 */intstart_input_bits;intnb_input_registers;/* 输入寄存器数量 */intstart_input_registers;intnb_registers;/* 保持寄存器数量 */intstart_registers;uint8_t*tab_bits;/* 线圈数据 */uint8_t*tab_input_bits;/* 离散输入数据 */uint16_t*tab_input_registers;/* 输入寄存器数据 */uint16_t*tab_registers;/* 保持寄存器数据 */}modbus_mapping_t;解析mb_mapping是整个 Modbus 数据模型的核心——上位机读写的线圈、寄存器本质上都是读写这个结构体里的数组。两个协议任务共享同一个mb_mapping实例对同一套物理数据进行操作从而实现RTU 写入、TCP 可读的双向透明。四、TCP Server 任务初始化与调度TCP Server 任务承担了所有全局资源的初始化工作然后再创建 RTU 任务voidLibmodbusTCPServerTask(void*pvParameters){uint8_t*query;modbus_t*ctx;intrc;modbus_mapping_t*mb_mapping;PChannelInfo ptChannelInfo;intchannel;interr;intheader_length;intsocket_server,socket_client;/* 显示当前运行模式 */if(isBootloader())Draw_String(150,0,Bootloader,0xff0000,0);elseDraw_String(150,0,Application,0xff0000,0);/* ① 创建共享寄存器映射表供两个任务共用 */mb_mappingmodbus_mapping_new_start_address(0,500,0,500,0,500,0,500);memset(mb_mapping-tab_bits,0,mb_mapping-nb_bits);memset(mb_mapping-tab_registers,0,mb_mapping-nb_registers*2);g_mb_mappingmb_mapping;/* 存入全局变量供 RTU 任务使用 *//* ② 创建全局互斥锁 */g_mb_lockxSemaphoreCreateMutex();/* ③ 初始化通道映射信息 */for(channel1;channelMAX_CHANNEL_NUMBER;channel){ptChannelInfog_tChannelInfos[channel];ptChannelInfo-mb_mappingmb_mapping;ptChannelInfo-xMutexxSemaphoreCreateMutex();}/* ④ 创建业务任务Bootloader 模式下不需要 */if(!isBootloader()){xTaskCreate(CH0_Task,CH0_Task,400,mb_mapping,osPriorityNormal,NULL);for(channel1;channelMAX_CHANNEL_NUMBER;channel){ptChannelInfog_tChannelInfos[channel];xTaskCreate(CHn_Task,ptChannelInfo-uart_name,400,ptChannelInfo,osPriorityNormal,NULL);}}/* ⑤ 创建 RTU Server 任务在 TCP 初始化之后确保 g_mb_mapping 已就绪 */xTaskCreate(LibmodbusRTUServerTask,LibmodbusRTUServerTask,400,NULL,osPriorityNormal,NULL);/* ⑥ 连接 WiFi 热点 */at_init(uart1);while(1){errat_connect_ap(Programmers,100asktech);if(!err)break;vTaskDelay(1000);}/* ⑦ 创建 TCP 上下文并监听 */ctxmodbus_new_tcp(NULL,1502);querypvPortMalloc(MODBUS_TCP_MAX_ADU_LENGTH);header_lengthmodbus_get_header_length(ctx);Draw_String(0,48,Waiting connect ...,0xff0000,0);while(1){socket_servermodbus_tcp_listen(ctx,1);if(socket_server0)break;}while(1){socket_clientmodbus_tcp_accept(ctx,socket_server);if(socket_client0)break;}Draw_String(0,64,Modbus client connected,0xff0000,0);/* ⑧ 主循环接收 → 加锁 → 处理 → 回复 → 解锁 */for(;;){do{rcmodbus_receive(ctx,query);}while(rc0);if(rc0){/* Socket 出错等待重连 */Draw_String(0,80,wait re-connect ...,0xff0000,0);while(1){socket_clientmodbus_tcp_accept(ctx,socket_server);if(socket_client0)break;}Draw_String(0,96,Modbus client re-connected,0xff0000,0);continue;}/* 获取互斥锁保护寄存器访问 */xSemaphoreTake(g_mb_lock,portMAX_DELAY);errprocess_emergency_cmd(ctx,query,rc,mb_mapping);if(err){modbus_reply_exception(ctx,query,MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY);xSemaphoreGive(g_mb_lock);continue;}errprocess_file_record(query[header_length-1],rc);if(err){modbus_reply_exception(ctx,query,MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY);xSemaphoreGive(g_mb_lock);continue;}rcmodbus_reply(ctx,query,rc,mb_mapping);/* 释放互斥锁 */xSemaphoreGive(g_mb_lock);}modbus_mapping_free(mb_mapping);vPortFree(query);modbus_close(ctx);modbus_free(ctx);vTaskDelete(NULL);}解析初始化顺序很关键——g_mb_mapping和g_mb_lock必须在创建 RTU 任务之前就准备好否则 RTU 任务启动后访问全局变量会拿到空指针。因此 TCP 任务先做所有初始化再拉起 RTU 任务最后自己才去连 WiFi 和监听。五、RTU Server 任务复用资源RTU 任务无需重复初始化直接从全局变量取mb_mapping和互斥锁voidLibmodbusRTUServerTask(void*pvParameters){uint8_t*query;modbus_t*ctx;intrc;modbus_mapping_t*mb_mapping;interr;intheader_length;/* RTU 上下文通过 USB 串口通信 */ctxmodbus_new_st_rtu(usb,115200,N,8,1);modbus_set_slave(ctx,1);querypvPortMalloc(MODBUS_RTU_MAX_ADU_LENGTH);/* 直接复用 TCP 任务创建的共享寄存器映射表 */mb_mappingg_mb_mapping;header_lengthmodbus_get_header_length(ctx);rcmodbus_connect(ctx);if(rc-1){modbus_free(ctx);vTaskDelete(NULL);}/* 主循环与 TCP 任务结构完全对称 */for(;;){do{rcmodbus_receive(ctx,query);}while(rc0);if(rc0){/* RTU 出错直接跳过等待下一帧 */continue;}/* 获取互斥锁保护寄存器访问 */xSemaphoreTake(g_mb_lock,portMAX_DELAY);errprocess_emergency_cmd(ctx,query,rc,mb_mapping);if(err){modbus_reply_exception(ctx,query,MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY);xSemaphoreGive(g_mb_lock);continue;}errprocess_file_record(query[header_length-1],rc);if(err){modbus_reply_exception(ctx,query,MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY);xSemaphoreGive(g_mb_lock);continue;}rcmodbus_reply(ctx,query,rc,mb_mapping);/* 释放互斥锁 */xSemaphoreGive(g_mb_lock);}modbus_mapping_free(mb_mapping);vPortFree(query);modbus_close(ctx);modbus_free(ctx);vTaskDelete(NULL);}解析RTU 任务的逻辑与 TCP 任务完全对称——都是收包 → 加锁 → 处理 → 回复 → 解锁的循环。区别只在于底层的通信接口RTU 用 USB 串口TCP 用 WiFi。RTU 出错时不需要重连直接continue等下一帧即可因为串口连接是持久的。六、两个任务的协作关系维度TCP 任务RTU 任务通信接口WiFi / W800 模块USB 串口寄存器来源创建并初始化g_mb_mapping直接使用g_mb_mapping互斥锁创建g_mb_lock直接使用g_mb_lock出错处理modbus_tcp_accept等待重连continue跳过等待下一帧任务创建顺序先启动负责全局初始化由 TCP 任务拉起两个任务通过全局互斥锁g_mb_lock实现对mb_mapping的互斥访问任何时刻只有一个任务能持有锁、操作寄存器从而保证数据一致性。七、总结双协议兼容的核心共享mb_mapping用全局互斥锁保护访问初始化顺序TCP 任务负责创建所有共享资源再拉起 RTU 任务避免竞态对称的任务结构两个任务主循环逻辑完全一致仅底层通信接口不同数据格式适配RTU/TCP 帧头差异由header_length动态处理上层逻辑无感知经过本篇改造系统已经能够上位机通过 USB 串口RTU读写寄存器上位机通过 WiFiTCP读写同一套寄存器结合写文件功能支持远程 IAP 升级八、结尾本篇完成了 RTU/TCP 双协议并行的核心设计至此整个工业物联网设备管理系统的通信层已经全部打通。下一篇将学习MQTT 协议并尝试将相关代码移植到 FreeRTOS敬请期待Hello_Embed继续带你从原理到实践掌握嵌入式上位机开发的核心技能敬请关注

相关文章:

嵌入式上位机开发入门(二十二):RTU/TCP 双协议互斥访问寄存器

目录 一、前言二、设计思路:共享寄存器 互斥锁三、modbus_mapping_t 结构体四、TCP Server 任务:初始化与调度五、RTU Server 任务:复用资源六、两个任务的协作关系七、总结八、结尾 一、前言 大家好,这里是 Hello_Embed。上篇…...

Pixel Fashion Atelier快速上手:从选择Gear到Forge!的5分钟像素时装生成体验

Pixel Fashion Atelier快速上手:从选择Gear到Forge!的5分钟像素时装生成体验 1. 认识像素时装锻造坊 Pixel Fashion Atelier是一款创新的AI图像生成工具,它将Stable Diffusion与Anything-v5的强大能力封装在一个充满复古游戏风格的界面中。这个工具特别…...

剧本工业级输出|像素剧本圣殿支持Final Draft格式导出预研进展

剧本工业级输出|像素剧本圣殿支持Final Draft格式导出预研进展 1. 像素剧本圣殿简介 Pixel Script Temple(像素剧本圣殿)是一款基于Qwen2.5-14B-Instruct大模型深度微调的专业剧本创作工具。这款工具将先进的AI推理能力与独特的8-Bit复古美…...

SmolVLA基础教程:numpy数组在state/action数据流转中的格式规范

SmolVLA基础教程:numpy数组在state/action数据流转中的格式规范 1. 引言 如果你正在尝试让机器人理解你说的话,并按照你的指令做出动作,那么SmolVLA可能就是你需要了解的工具。这是一个专门为机器人设计的视觉-语言-动作模型,简…...

GAIA-DataSet:破解AIOps算法研发中的数据瓶颈挑战

GAIA-DataSet:破解AIOps算法研发中的数据瓶颈挑战 【免费下载链接】GAIA-DataSet GAIA, with the full name Generic AIOps Atlas, is an overall dataset for analyzing operation problems such as anomaly detection, log analysis, fault localization, etc. …...

STK 12.10.0实战:用Python脚本自动化RF Channel Modeler,提升雷达仿真效率

STK 12.10.0实战:用Python脚本自动化RF Channel Modeler,提升雷达仿真效率 在卫星通信系统设计和雷达性能评估领域,仿真效率往往直接决定项目周期和研发成本。传统STK图形界面操作虽然直观,但在处理批量参数扫描、复杂场景迭代时&…...

零基础玩转Phi-4-mini-reasoning:手把手教你搭建专属数学解题助手

零基础玩转Phi-4-mini-reasoning:手把手教你搭建专属数学解题助手 1. 为什么你需要一个数学解题助手 作为一名数学爱好者或学习者,你是否经常遇到这样的困扰: 面对复杂数学题时无从下手解题步骤繁琐,容易出错需要快速验证答案的…...

全球反井钻杆:稳增6.3%,2025年1.19亿,2032年剑指1.87亿

QYResearch调研显示,2025年全球反井钻杆市场规模大约为1.19亿美元,预计2032年将达到1.87亿美元,2026-2032期间年复合增长率(CAGR)为6.3%。地区市场分析:中国市场异军突起从地区层面深入剖析,中国…...

Youtu-Parsing效果惊艳案例:毕业论文PDF截图→自动生成含图表引用的Markdown文献综述

Youtu-Parsing效果惊艳案例:毕业论文PDF截图→自动生成含图表引用的Markdown文献综述 1. 引言:当AI遇见学术文献 想象一下这个场景:你正在为毕业论文的文献综述部分焦头烂额。面前是几十篇PDF论文,你需要从中提取关键信息、整理…...

小白程序员必看:收藏这份入门级网络安全指南——IDS详解与实战部署

小白程序员必看:收藏这份入门级网络安全指南——IDS详解与实战部署 本文全面介绍了入侵检测系统(IDS)的概念、作用、功能及分类,详细解析了IDS的架构、工作流程、性能关键参数、检测技术(误用检测与异常检测&#xff0…...

Wan2.2-I2V Anaconda环境配置全指南

Wan2.2-I2V Anaconda环境配置全指南 1. 为什么选择Anaconda来跑Wan2.2-I2V 刚开始接触Wan2.2-I2V时,我试过直接在系统Python里装依赖,结果不到半小时就卡在了CUDA版本冲突上。后来发现用Anaconda管理环境简直是救命稻草——它能把不同项目的Python版本…...

小白程序员入门网络安全:收藏版,从零开始学密码学

小白程序员入门网络安全:收藏版,从零开始学密码学 本文带领读者进入网络安全的世界,从密码学的发展历史、古典密码、分组密码、流密码、杂凑函数到公钥密码,全面介绍了密码学的基础知识和应用。文章涵盖了凯撒密码、维吉尼亚密码…...

UVa 11705 Grasshopper

题目描述 我们来到游乐场,看到一个名为“蚱蜢迷宫”的蹦床阵列。每个蹦床上标有一个非负整数 zzz,表示从该蹦床起跳后,必须在同一行或同一列上,恰好跳过 zzz 个蹦床到达另一个蹦床(即距离为 zzz)。迷宫的出…...

PyTorch 2.8深度学习镜像实战:电商商品图→短视频自动生成流水线部署

PyTorch 2.8深度学习镜像实战:电商商品图→短视频自动生成流水线部署 1. 镜像环境介绍 PyTorch 2.8深度学习镜像是一个专为现代AI工作负载优化的高性能环境。这个预配置的解决方案特别适合需要处理复杂视觉任务的开发者,比如我们今天要实现的电商商品图…...

【 LangChain v1.2 入门系列教程】【一】开篇入门 | 从零开始,跑通你的第一个 AI Agent

系列文章目录 【 LangChain v1.2 入门系列教程】【一】开篇入门 | 从零开始,跑通你的第一个 AI Agent 【 LangChain v1.2 入门系列教程】【二】消息类型与提示词工程 【 LangChain v1.2 入门系列教程】【三】工具(Tools)开发,让…...

Java大厂面试场景:从Spring Boot到微服务的技术问答

场景:互联网大厂Java面试 在互联网大厂的面试场景中,谢飞机(程序员)来面试一个高级Java开发岗位。面试官提出了多轮问题,涵盖核心语言、框架、微服务和云原生技术等。 第一轮:基础技术框架 面试官&#xff…...

从ViT到MGMoE:多模态注意力参数量暴增300倍背后的架构熵危机(附2024 ACL/ICML/CVPR权威论文对比矩阵与迁移适配清单)

第一章:多模态大模型中的注意力机制 2026奇点智能技术大会(https://ml-summit.org) 多模态大模型的核心挑战在于如何对齐与融合来自图像、文本、音频等异构模态的语义表征。注意力机制——尤其是交叉注意力(Cross-Attention)——成为实现跨模…...

现在不看就晚了:2026奇点大会刚公布的多模态对话系统“实时语义蒸馏”专利技术,6个月内将成行业准入门槛

第一章:2026奇点智能技术大会:多模态对话系统 2026奇点智能技术大会(https://ml-summit.org) 多模态对话系统正从实验室走向高保真工业部署,2026奇点智能技术大会首次将语音、视觉、文本与触觉信号的联合对齐建模设为技术主线。本届大会展示…...

抗原抗体

同抗原抗体相遇,就会打架(凝血/溶血)。 细菌和病毒都可以称为抗原,包括之前的新冠病毒 一、直白解释 A抗原:红细胞表面的“身份证”(写着A)A抗体:血浆里的“警察”(专门抓…...

MySL优化全攻略:索引、SL与分库分表的最佳实践

这个代码的核心功能是:基于输入词的长度动态选择反义词示例,并调用大模型生成反义词,体现了 “动态少样本提示(Dynamic Few-Shot Prompting)” 与 “上下文长度感知的示例选择” 的能力。 from langchain.prompts impo…...

ncmdumpGUI:解锁网易云音乐NCM文件的终极指南,让音乐随处可听

ncmdumpGUI:解锁网易云音乐NCM文件的终极指南,让音乐随处可听 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾在网易云音乐下载…...

【实战指南】利用Docker快速搭建RustDesk私有中继服务器

1. 为什么需要自建RustDesk中继服务器 最近几年远程控制软件越来越火,但商业软件的各种限制让人头疼。我自己就遇到过这样的问题:用某款知名软件远程控制手机,结果免费版每天只能连接3次;换另一款又发现手机端需要额外付费插件&am…...

2025届最火的五大AI科研助手实测分析

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 基于自然语言处理跟深度学习技术的人工智能写作软件,属于智能工具,它…...

商密技术以及运用

商密技术 一、密码技术基础知识 1、 定义 专业定义:密码技术是利用数学算法,对信息进行加密、解密、认证、签名、验签等处理,实现信息的机密性、完整性、真实性、不可否认性的技术总称,是数字世界安全的核心支撑。 总体来说就是&a…...

大麦网自动抢票脚本完整指南:从零搭建你的智能购票系统

大麦网自动抢票脚本完整指南:从零搭建你的智能购票系统 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 你是否曾经为抢不到热门演唱会门票而苦恼?当心…...

在AI冲击下前端开发工程师的一些思考

前端开发工程师对AI的思考:大模型工作流程与角色转变在人工智能(AI)快速发展的时代,前端开发工程师正面临着前所未有的挑战和机遇。AI技术,特别是大型语言模型(LLM),正在深刻改变软件…...

【权威白皮书首发】:基于17个跨模态基准测试(VQA-X、MME-XAI、RefCOCO-X)的可解释性评估矩阵——92.6%的SOTA模型在细粒度归因上存在系统性失效

第一章:多模态大模型可解释性研究的范式危机与白皮书使命 2026奇点智能技术大会(https://ml-summit.org) 当前,多模态大模型正以前所未有的规模整合文本、图像、音频与视频信号,但其内部决策逻辑日益成为“黑箱中的黑箱”。传统基于单模态归…...

KeymouseGo:如何用这款免费自动化工具告别重复劳动?完整指南带你轻松上手

KeymouseGo:如何用这款免费自动化工具告别重复劳动?完整指南带你轻松上手 【免费下载链接】KeymouseGo 类似按键精灵的鼠标键盘录制和自动化操作 模拟点击和键入 | automate mouse clicks and keyboard input 项目地址: https://gitcode.com/gh_mirror…...

深入理解Sentinel:11 黑白名单限流与热点参数限流

黑白名单限流 黑白名单过滤是使用最为广泛的一种过滤规则,例如,用于实现接口安全的 IP 黑白名单规则过滤,用于防骚扰的短信、来电拦截黑白名单过滤。所以 Sentinel 中的黑白名单限流并不难理解,如果配置了黑名单,且请求…...

贾子成功定理(高阶完整版):逆熵跃迁动力学——生于忧患的数学化模型

贾子成功定理(高阶完整版):逆熵跃迁动力学——生于忧患的数学化模型摘要: 贾子成功定理高阶完整版将“生于忧患”转化为量化动力学模型,核心公式SkT/I,微分方程dS/dt kT - IS,稳态解S*kT/I。跃…...