新闻详情

新闻详情

首页 / 资讯中心 / 详情

C#上位机与三菱PLC通信:McProtocol协议原理与高性能实现

发布时间:2026/10/2 7:52:56来源:尧图网络
C#上位机与三菱PLC通信:McProtocol协议原理与高性能实现
在工控上位机开发这个圈子里三菱PLC的通信一直是个既基础又绕不开的话题。最近又有不少朋友在群里问关于C#如何高效读写三菱PLC数据的问题尤其是McProtocol这个协议。市面上关于这方面的资料其实不少但大多碎片化要么是装完库就跑个demo要么是贴一堆报文让人看得云里雾里。今天我就把这些年在三菱PLC通信上踩过的坑、总结的经验一次性说透从通信库选型到报文原理从实战封装到并发优化手把手带你写出一套真正能上产线跑的C#上位机通信模块。这篇文章适合正在用C#开发上位机、需要对接FX系列或Q系列三菱PLC的工程师也适合那些想在HslCommunication、自研TCP通信和官方MX Component之间做出正确选择的开发者。即使你之前没接触过McProtocol只要跟着思路走也能在最短的时间内写出稳定、高效的PLC通信代码。1. 通信库选型为什么我不推荐一上来就选MX Component1.1 三种主流方案的本质区别先聊最实际的问题。C#想跟三菱PLC通信市面上常见方案基本就三种三菱官方提供的MX Component、开源社区活跃的HslCommunication以及自己基于TCP/IP裸报文实现。很多新手一上来就选MX Component因为它是官方的、免费的而且资料全。但在实际项目里我见过太多用MX Component把自己坑了的案例。MX Component本质是一个COM组件库它封装了对三菱PLC的全系列通信支持包括串口、以太网、CC-Link等。但它的“官方”身份在工业现场反而成了双刃剑。你用C#调用它时往往要通过COM互操作这会带来性能损耗和线程安全问题。尤其是需要高频轮询大量寄存器时MX Component的内部调度机制会让你觉得像是隔着毛玻璃在操作PLC。HslCommunication则是一个纯C#实现的开源库它在国内工控圈非常流行作者一直在更新对三菱全系列PLC的支持都很完整而且其内部对帧格式、超时重试、异步IO的处理都已经过大量项目验证。最关键的一点它的API设计非常贴合C#工程师的习惯你几乎不需要理解复杂的报文结构就能上手。而自己写TCP报文看着最麻烦但其实这才是最能让你“掌控一切”的方案。三菱PLC的MeProtocol协议帧结构并不复杂一旦你自己实现了报文封装、发送、校验和解析你对通信性能的优化空间会远超任何第三方库。而且自研方案不受任何库的版本影响不会出现升级库导致已上线项目崩溃的问题。1.2 选型关键决策点在做技术选型时我建议你从三个维度去评估项目周期、运行环境、以及扩展需求。如果项目周期非常紧比如一周内要完成和PLC的联调且业务逻辑并不复杂HslCommunication是性价比最高的选择。它开箱即用能让你把精力集中在上位机的业务上。但如果你的项目是一个需要长期维护、通信点数多、对读写频率和响应时延都有指标要求的设备管理系统那我强烈建议你至少要理解裸报文通信的原理甚至直接用自研方案。运行环境也很关键。如果用MX Component它必须安装在目标机器上而且版本必须与编程软件GX Works兼容。那种动不动弹注册框、DLL版本冲突的体验很多工控老鸟都经历过。而自研或使用纯托管的HslCommunication你只需要一个.NET环境部署时干净清爽。扩展需求容易被忽视。做上位机开发的人经常会遇到这种情况今天只连三菱PLC明天就可能要接西门子、欧姆龙或者一堆仪表传感器。选择HslCommunication或自研报文时你可以很容易地抽象出一个通用通信层接口保持一致后续对接新硬件时只需要扩展实现类。但MX Component想抽象就很难了因为它的接口被COM模型牢牢限制住了。1.3 我个人的选型建议直接说结论如果你的项目是面向生产线的数据采集与监控SCADA首选HslCommunication。它的泛型接口、异步支持、以及内置的日志和状态管理能让你少写很多基础代码。而如果你的项目是专用设备控制例如固晶机、贴片机、检测设备这种由你本家定义的整机控制场景那么自研McProtocol报文通信会让你在处理高速IO时更有底气。我把三者的核心差异整理成了下面的表格方便你对照选择维度MX ComponentHslCommunication自研TCP报文上手难度低低中高通信性能中COM互操作有损耗高最高部署复杂度高需装官方环境低纯DLL低纯代码多线程支持弱COM线程模型限制强最强报文可控性弱黑盒中完全可控后续扩展差优优适合场景简单单机演示中小型系统高性能、定制化系统2. McProtocol通信原理与报文结构拆解2.1 McProtocol是什么它到底能做什么McProtocol是三菱PLC的一种通信协议全称是Mitsubishi Communication Protocol。它支持串口和以太网两种物理介质。串口版本的叫法很多A兼容1C帧、QnA兼容2C帧等而以太网版本中最常用的是3E帧。这个帧格式专门用于以太网通信也是C#上位机开发中最应该掌握的。很多人把McProtocol和“三菱PLC寄存器读写”画等号这其实不够准确。McProtocol不止能读写寄存器它还能控制PLC运行、停止读取CPU状态、报警历史甚至远程上下载程序。但在我们的实际应用中读写寄存器数据是绝对的核心。一个设备的有无、一个计数器到了多少、一个温度值是多少都是通过这个协议从PLC的软元件D寄存器、M继电器、X输入、Y输出中实时拿到的。说个热词相关的细节我看到热搜里有C51中spi通信库文件这类词很多人会把PLC通信和单片机通信混为一谈。二者底层确实是类似的都是通过特定的帧结构在物理链路上传输数据。但PLC通信更上层它不需要你关注电平时序和芯片寄存器而是直接面向“读D100这个寄存器”这种业务级别的操作。理解这个层次关系有助于你把握PLC通信的学习深度。2.2 详解以太网3E帧报文格式自研McProtocol的核心就是构造和解析3E帧。3E帧的结构大致可以分为三个部分帧头、命令部、数据部。帧头占用10个字节。子帧头固定为D0 00代表这是一帧以太网帧。网络号Network No.一般设置为00PC号PC No.通常设置为FF代表模块化的IO编号。请求目标模块IO编号固定为03 FF意思是指向CPU模块。请求目标模块站号设置为00。这10个字节是固定套路大多数情况下不需要修改。命令部是报文的灵魂。命令Command占用2个字节读取寄存器的命令是01 01写入寄存器的命令是01 02。紧随其后的是子命令Subcommand占用2个字节对于软元件寄存器而言通常设置为00 00代表按字访问。比如我想读取D100-D110这11个字的数据命令部的构造就是01 01 00 00。数据部则根据你要访问的软元件类型不同而变化。三菱PLC的软元件编址其实是有一套编码体系的。以D寄存器为例其对应的软元件代码是A8也就是十进制的168。当你需要读取某一个D寄存器时你要在报文中指定它的起始地址偏移量。比如访问D100你应该填写的地址是100但这个地址还要换算成十六进制字节序且要区分“是否按位访问”的翻倍规则。报文示例读D100开始的3个字D0 00 00 FF FF 03 00 00 00 00 01 01 00 00 00 00 A8 00 64 00 00 00 03 00我来拆解一下。前10个字节是帧头。然后是01 01命令00 00子命令。接着是数据部00 00是起始地址的扩展段A8 00是软元件代码注意这里是反字节序64 00是对应十六进制地址0x64的低位在前、高位在后。00 00表示访问的软元件编号03 00则表示读取3个字。末尾这4个字节都是小端序即低字节在前。发给PLC后如果正常它会返回帧头、命令部、正常完成码00 00紧随其后就是你要的数据。每个字占2字节也是低位在前。比如返回83 2E那实际数值就是0x2E83十进制的11907。2.3 FX系列与Q系列的区别实际上FX系列如FX3U、FX5U与Q系列如Q03UDV在报文结构上大体一致但软元件地址的处理存在细微差异。FX系列的输入X、输出Y是按十六进制编号的比如X0到XF、X10到X1F你在报文里填地址时需要把十六进制编号转为二进制再换算。Q系列则通常是十六进制地址并且支持更多的软元件类型比如特殊继电器SD、特殊寄存器SD。这也意味着除非你写一个非常底层且全面的地址解析器否则直接用同一个通信函数去对接FX和Q系列PLC时大概率会踩坑。比如FX3U的D寄存器地址范围是D0-D7999而Q系列的D寄存器地址空间更大。当年我在一个项目里用一套自研通信类同时对接FX5U和Q03UDE结果在地址赋值的边界检查上耗费了大量调试时间。所以如果你不是只想浅浅地写个示例而是想做一个“抗造”的通信模块我建议把PLC型号也封装进地址计算逻辑中。3. 实战代码从零构建一个高性能McProtocol通信器3.1 以太网通信基类设计在C#中实现TCP客户端通信最核心的就是System.Net.Sockets.TcpClient和System.Net.Sockets.NetworkStream。我见有不少人会用Socket直接收发但抽象层次更低容易在处理半包和粘包时写出繁琐逻辑。直接使用TcpClient配合其GetStream()获取的NetworkStream更适合PLC这种“一问一答”的简单交互模型。我会先写一个基础的PLC通信类内部持有TcpClient和NetworkStream并加入锁对象保证同一时刻只有一个请求在链路中流转。这里强烈建议你为每次读写操作加上SemaphoreSlim或lock不然后续多线程轮询时会出现帧交叉错乱PLC直接给你返回乱码或错误码。下面给出核心框架代码。这只是骨架但我把关键注释都写清楚了public class PlcMcTcpClient : IDisposable { private TcpClient _tcpClient; private NetworkStream _stream; private readonly object _lockObj new object(); private readonly string _ip; private readonly int _port; private readonly int _timeout 2000; public PlcMcTcpClient(string ip, int port 6000) { _ip ip; _port port; } public bool Connect() { try { _tcpClient new TcpClient(); _tcpClient.Connect(_ip, _port); _tcpClient.NoDelay true; // 禁用Nagle算法降低延迟 _stream _tcpClient.GetStream(); _stream.ReadTimeout _timeout; _stream.WriteTimeout _timeout; return true; } catch { return false; } } private byte[] SendAndReceive(byte[] request) { lock (_lockObj) { if (_stream null || !_tcpClient.Connected) throw new InvalidOperationException(PLC连接已断开请重新连接。); _stream.Write(request, 0, request.Length); _stream.Flush(); // 先读10字节帧头帧尾再根据长度读取数据体 byte[] header new byte[9]; ReadFullBytes(header, 9); // 根据实际协议判断响应完整性 byte[] body ReadResponseBody(); return Combine(header, body); } } private void ReadFullBytes(byte[] buffer, int count) { int offset 0; while (offset count) { int read _stream.Read(buffer, offset, count - offset); if (read 0) throw new IOException(连接被PLC关闭。); offset read; } } // 省略ReadResponseBody、Combine等实现 public void Dispose() { ... } }这段代码有几个细节值得留意。NoDelay true要设置上这是为了禁用Nagle算法。Nagle算法会等待缓冲区满或收到ACK才发送数据在工业PLC这种高频短报文场景下它会把写操作延迟几十毫秒这对某些高速响应场景是无法接受的。而ReadTimeout和WriteTimeout在连上之后立刻设置能防止上位机因为PLC掉线而无限期卡死。3.2 构建读请求与解析响应现在来写用户层的方法比如读取D寄存器整数。这里最核心的就是地址换算函数ConvertToDeviceCode根据PLC型号和软元件类型返回其在报文中的编码。我提供一个轻量的实现在请求数据部分我们只关心软元件类型和起始地址其余头部拼装逻辑抽取成独立方法BuildReadRequest。private byte[] BuildReadRequest(ushort deviceCode, int address, ushort length) { Listbyte buffer new Listbyte(); // 帧头 buffer.AddRange(new byte[] { 0xD0, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00 }); // 命令读取 01 01 buffer.AddRange(new byte[] { 0x01, 0x01 }); // 子命令字单位 00 00 buffer.AddRange(new byte[] { 0x00, 0x00 }); // 起始地址扩展通常填0 buffer.Add(0x00); buffer.Add(0x00); // 软元件代码2字节反序 byte[] codeBytes BitConverter.GetBytes(deviceCode); buffer.Add(codeBytes[0]); buffer.Add(codeBytes[1]); // 起始地址3字节反序 byte[] addrBytes BitConverter.GetBytes(address); buffer.Add(addrBytes[0]); buffer.Add(addrBytes[1]); buffer.Add(addrBytes[2]); // 访问点数2字节反序 byte[] lenBytes BitConverter.GetBytes(length); buffer.Add(lenBytes[0]); buffer.Add(lenBytes[1]); return buffer.ToArray(); }解析响应时需要注意响应帧会比请求帧多出2字节的“完成码”。如果你的请求成功完成码为00 00。判断完成码是否为0可以帮你快速定位读错误是来自通信链路还是来自PLC本身。读取D寄存器的公开方法public int[] ReadD(int startAddress, int count) { byte[] request BuildReadRequest(0xA8, startAddress, (ushort)count); byte[] response SendAndReceive(request); // 跳过帧头9字节 命令/子命令4字节 完成码2字节 15 int dataOffset 15; int[] result new int[count]; for (int i 0; i count; i) { result[i] BitConverter.ToInt16(response, dataOffset i * 2); } return result; }这里顺便提一句如果你读的是32位数据需要的长度是数据的2倍并且要自己处理两个16位整数的高低字组合顺序。三菱PLC默认的32位双字D寄存器存储是高字在前、低字在后例如D100和D101组合成32位D101存放高16位。这是很多C#开发者在转换时最容易搞反的地方。3.3 写请求的实现与细节写请求的命令是01 02。数据部结构分两种情况一种是“按字写入”直接拼接起始地址、软元件代码、写入字数然后把每个数据转换成2字节附加到末尾另一种是“按位写入”用于写M继电器或Y输出。但在大多数设备控制项目中写入时都使用“按字写入”即使你只想把某个M置ON也可以通过读取当前M状态、改写对应位再写回D寄存器的某一位来模拟。但如果在自控要求极高的场合还是应当采用软元件的“按位写入”命令01 02配合“位软元件”编码例如M继电器的编码通常是0x90。以写M0为ON为例它的请求帧数据部分应该是00 00 90 00 00 00 00 01 10 00。最后两个字节10 00表示置ON如果置OFF则是00 00。写回的响应非常简单正常时只返回帧头和完成码。有一个我实测下来的经验三菱PLC的写入响应极快通常在1ms以内。所以如果你发现写入耗时超过了20ms大概率是链路质量不好或TCP节点延迟而不是PLC本身的问题。4. 性能优化与多线程并发通信卡顿的罪魁祸首与对策4.1 为什么你的程序越跑越卡很多C#上位机程序在开发机上一切正常一接入工厂实际网络就变慢甚至卡死。原因之一就是你用的通信库在多线程环境中没有处理好锁粒度导致高频请求排队严重。尤其是轮询各个工位的数据、同时又要响应界面操作和报警处理时一个慢请求会堵住后续所有请求。用自研报文时锁的设计很关键。你在SendAndReceive里加的lock能够保证一帧请求必须完整地收到对应响应后下一帧才能发出这避免了协议帧错乱。但这种串行化同时限制了吞吐。你想想如果一个读写平均耗时5ms每秒钟就只能执行200个请求加上网络延迟和IO调度实际的吞吐会更低。优化方式主要有两种一是缩短超时时间让卡死请求快速失败二是不要在锁粒度内做无意义的重量级操作。例如不要在锁内做日志记录或UI通知日志IO和UI线程刷新很耗时一旦加入锁中会放大通信延迟。4.2 线程模型与轮询策略在实际应用中我通常会采用一个后台线程维护一块“数据缓存区”专门负责周期性地从PLC读取所有需要监控的寄存器然后对外提供GetVariableValue之类的查询方法。界面线程或业务线程只读取缓存不直接发起PLC通信。这样就能避免多个线程同时访问PLC导致的锁竞争。这个缓存刷新线程的优先级建议设置为ThreadPriority.AboveNormal。但前提是你的PLC通信代码本身是线程安全的并且读取周期要留有余量。举个例子一个温控检测系统需要每500ms采样30个温度数据。一次批量读取30个字的数据可能只需要5ms那500ms的周期内你有充足的时间完成多次读写重试。批量读取是提高性能的另外一个关键手段。不要一个地址一个地址地单个读取而是把连续的寄存器一次性读取回来。比如你要读D100-D150只需要发起一次建立起始地址D100、读取长度51的请求报文长度只是比单个读取多了一点数据但省去了每次请求的握手和排队时间。4.3 连接管理与断线重试PLC通信的稳定性很大程度上取决于连接管理。很多新手写的是“收到异常就直接返回失败”而没有实现自动重连机制。在生产环境中交换机重启、网线接触不良、PLC固件升级都会导致连接断开。如果不处理上位机就成了一块死屏。我建议在通信层加入心跳检测和自动重连。心跳可以简单地每隔几秒读取PLC的特殊寄存器SD801或者一个你约定的公共寄存器来确认链路通畅。一旦发现链路异常通信线程便进入重连状态使用指数退避算法例如1s、2s、4s...最大30s不断尝试重新连接直到成功。private async Task EnsureConnectedAsync() { if (_tcpClient ! null _tcpClient.Connected) return; int retryDelay 1000; while (true) { try { Connect(); return; } catch { await Task.Delay(retryDelay); retryDelay Math.Min(retryDelay * 2, 30000); } } }对了在写重连逻辑时一定要记得在重连成功后重新初始化通信状态并触发一次事件通知上层业务系统。这个事件可以用于更新界面上的“PLC连接状态”指示灯。相信我工厂里的操作员非常依赖这个指示灯来判断设备是否正常。5. 常见问题与排查技巧实录5.1 通信超时与响应异常我调试过程中遇到最多的错误就是PLC返回5C或51开头的异常码。51表示起始地址和点数不合法5C代表请求长度超出范围。遇到这类错误首先检查地址是否超出了PLC型号的软元件范围。比如FX3U的D寄存器最大到8199你读D9000一定会报错。其次检查地址换算是否正确尤其是X/Y这类十六进制编号很容易算错。还有一种情况响应帧返回正常但数据一直是0。这种多半是数据位数不匹配。比如你用读16位的函数去读32位浮点寄存器或者反之。遇到D寄存器里存的是单精度浮点的情况我习惯在解析层单独写一个公共方法public float ToFloat32(int d1, int d2) { // 三菱PLC 32位浮点在高位字和低位字的顺序 uint lowWord (uint)(ushort)d1; uint highWord (uint)(ushort)d2; uint raw (highWord 16) | lowWord; return BitConverter.ToSingle(BitConverter.GetBytes(raw), 0); }5.2 大小端与数据类型转换的坑C#中BitConverter默认使用本机小端序但三菱协议里的字内字节序是低位在前符合小端而32位数据的“高字前、低字后”又与常规小端不同。很多工程师栽在这里。处理时我建议在通信层内部约定好所有从PLC读取出来的原始字节统一转为UInt16数组再由业务层通过上面ToFloat32这一类转换函数去组合。不要在通信层直接转成float或int那样会难以排查问题。5.3 网络层排查三板斧如果你的代码逻辑没问题联调时还是不通那就回归到网络层。先用网线直连PLC和PC设置好PC的IP为192.168.3.250之类的地址配置好端口号然后用ping命令测试连通性。注意PLC通常不允许“ping通”就不代表TCP端口开放因为有些PLC的默认端口6000是关闭的需要你在PLC参数里显式开启MELSOFT连接或MC协议。我曾经遇到过一个案例PLC和上位机在同一个交换机下但是无论如何都连接不上。最后检查发现是PLC端的“允许连接数”设置成了1被GX Works软件占用了连接。这种问题不抓包根本找不到原因。学会抓包是一个重要技能。用Wireshark抓一下TCP 6000端口的中文报文能清晰地看到每次请求和响应。如果你是自研报文强烈建议在开发阶段开着Wireshark校验帧格式是否正确。5.4 编码规范与日志记录不要小看日志记录。在高性能通信模块中日志是排查杀手级问题的最好帮手。我在通信层加入了一个极简的环形缓存日志只记录最近100条通信原始帧内容以及每次通信耗时。当现场出问题时我先导出缓存日志看耗时曲线通常几秒钟就能定位到是网络问题、代码问题还是PLC响应问题。6. 扩展思考从三菱到全品牌PLCs的上位机通信架构写完一套稳定的McProtocol通信模块后你可能会有一个疑问这套代码是不是只能用于三菱其实不是。如果你把BuildReadRequest、ParseResponse这些方法抽象成接口把地址转换部分独立成策略类那么当你需要对接西门子的S7协议或欧姆龙的FINS协议时只需要重新实现这套接口即可其他业务层代码几乎不用改动。这也是一种“面向接口编程”的思想。从热词看很多C#开发者同时在关注“C#上位机”“C#多线程”“C#高性能”。通信模块本质上就是一个高并发的IO密集型系统它和Web API在后端处理请求的逻辑非常相似——接收请求、构造报文、发送、等待响应、解析、返回结果。区别只是协议栈从HTTP换成了PLC的私有协议而解析和控制并发的方式套路其实是一脉相承的。聊到这里我回想这几年做过的几个完整项目最深的体会是不管用什么通信库真正决定系统稳定性的不是你选了哪个库而是你对通信链路的每一帧数据是否都了如指掌。自研报文会让你开始关注每一个字节的流动而这份掌控感会在后续排障和性能调优时给你带来巨大的回报。最后再分享一个小技巧。如果你不想从零开始写协议解析又想对底层报文有绝对掌控权可以先用HslCommunication跑通业务然后开着它的日志分析报文再逐步替换成自研实现。这种“先跑通、再深挖”的路线是学习PLC通信性价比最高的方式。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

PT100三线制测温电路设计与LTspice仿真:消除导线电阻误差 2026/10/2 8:34:55

PT100三线制测温电路设计与LTspice仿真:消除导线电阻误差

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
基于LSTM+Attention的本地化聊天机器人毕设方案 2026/10/2 8:34:55

基于LSTM+Attention的本地化聊天机器人毕设方案

简介:本资源是一套面向本科毕业设计与课程设计的Python深度学习聊天机器人完整实现方案,适用于计算机、人工智能相关专业学生开展毕设开发或项目实践。项目基于Django框架构建Web前后端,集成深度学习模型(如Seq2Seq或Transformer变…

阅读更多 →
VOC格式人脸表情数据集:8279张图+YOLO转换全流程 2026/10/2 8:34:48

VOC格式人脸表情数据集:8279张图+YOLO转换全流程

简介:本资源是面向计算机视觉初学者与深度学习实践者的VOC格式人脸表情识别目标检测数据集,专为YOLO等主流检测模型训练设计。数据集涵盖8种基础情绪类别(fear、sad、surprised、contempt、anger、neutral、disgust、happy)&#…

阅读更多 →
电影在线观看系统Java毕设:SSM+JSP+Layui全流程开发实战 2026/10/2 8:34:48

电影在线观看系统Java毕设:SSM+JSP+Layui全流程开发实战

简介:资源为基于 Java SSM 体系开发的电影在线观看系统完整项目,适合正在学习 SSM 整合、JSP 前端交互及 Maven 项目构建的 Java 初学者,也便于课程设计或毕业设计参考。项目采用 JSP Spring SpringMVC MyBatis Layui 技术栈,…

阅读更多 →
牦牛行为识别数据集实战:YOLO与VOC双格式转换及训练避坑指南 2026/10/2 8:34:48

牦牛行为识别数据集实战:YOLO与VOC双格式转换及训练避坑指南

简介:这份数据集面向目标检测与畜牧业视觉应用,提供草原耗牛8种行为类别的标注图像,覆盖吃草、打架、站立、躺卧、交配、移动等动作,且包含牛体本身目标类别,适合作为YOLO、Faster R-CNN等模型的训练与评测数据。压缩包…

阅读更多 →
CVI串口通信可靠性实战:FIFO控制与超时策略 2026/10/2 8:34:48

CVI串口通信可靠性实战:FIFO控制与超时策略

简介:这是一套基于LabWindows/CVI开发的轻量级串口调试工具资源包,面向工业自动化、测试测量领域的嵌入式工程师与高校实验开发者,解决CVI环境下串口通信调试难、FIFO配置不直观、数据收发缺乏可视化等问题。资源共27个文件,包含2…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉