新闻详情

新闻详情

首页 / 资讯中心 / 详情

C#上位机与松下PLC串口通讯实战:Mewtocol协议解析与机器视觉集成

发布时间:2026/9/13 7:11:45来源:尧图网络
C#上位机与松下PLC串口通讯实战:Mewtocol协议解析与机器视觉集成
做机器视觉上位机开发的早晚要面对一件事视觉结果怎么交给产线去执行。相机拍完照、算法出结果OK还是NG如果不送到PLC里后面的剔除机构、气缸、报警灯全都不会动。我在实际项目里最常用的方案就是用C#写上位机通过串口跟Panasonic松下PLC做通讯把视觉判定结果写进PLC的寄存器同时读取产线当前状态。这篇文章把我自己在松下FP系列PLC串口通讯上的完整经验整理出来从Mewtocol协议、报文格式、C#代码实现再到现场踩过的坑一次性讲透。适合正在做机器视觉集成、或者手里有松下PLC想接上位机的朋友也适合第一次接触工控通讯、对着协议手册一头雾水的C#开发者。内容偏实战看完能直接照着写。1. 项目背景与整体设计思路1.1 为什么是“串口通讯”而不是网口先聊一个方向问题。现在很多PLC都带以太网口松下FP系列里也有一部分型号支持TCP/IP通讯那为什么还要用串口答案很简单老设备存量太大串口方案便宜又稳定。我接触过的不少产线PLC型号是FP0R、FP-X这类老款默认配置就是COM口没有网口或者网口被厂家程序占用了。就算有新设备一个RS232/RS485串口模块也就几十块钱而上位机这边随便一个USB转串口就能解决布线和配置都简单。对于视觉结果这种“每次就传几字节”的场景串口的速度完全够用——哪怕9600波特率一秒也能传几百个数据帧视觉检测的节拍一般在几十毫秒到几百毫秒串口根本不是瓶颈。所以方向选择上我的建议是能用串口解决的问题优先串口等到需要大数据量、多设备组网的时候再考虑以太网。这跟有些人一上来就追求高大上不一样工控项目里稳定和够用永远是第一位的。1.2 机器视觉与PLC的典型交互流程机器视觉上位机跟PLC的交互说白了就是三件事收指令、给结果、查状态。视觉相机拍照的触发信号往往就是PLC通过串口发给上位机的。比如PLC检测到产品到位发送“请拍照”的命令上位机收到之后控制相机拍照、跑算法得出OK/NG结果再写回PLC。PLC拿到结果之后驱动气缸把不合格品剔除。整个过程像一条流水线两边的配合完全靠通讯协议维持。这类交互里有几个关键点要注意命令要带超时判断因为相机拍照偶尔会失败结果写入要确认不能发出去就不管了循环采集状态下UI不能卡顿不然操作员看界面会很难受。这些我在第3章和第4章都会详细展开。1.3 松下PLC串口通讯的协议选择Mewtocol松下PLC的串口通讯有它自己的一套协议叫Mewtocol官方手册全称是《松下电工 可编程控制器FP系列 通信命令手册》。ASCII格式报文清晰调试起来比Modbus RTU那堆十六进制字符直观多了。注意Mewtocol跟Modbus不是一回事。C#社区里常用的NModbus4库那是走Modbus协议用的。松下FP系列老型号的串口默认走Mewtocol如果你想用Modbus得看具体型号支不支持而且还要在PLC系统寄存器里改协议类型。所以做松下串口先老老实实把Mewtocol用熟练这是基本功。还有一点Mewtocol不仅支持读取写入数据寄存器D区还支持直接读线圈触点X、Y、R区甚至可以远程操作PLC的程序状态。这意味着上位机能做的操作非常灵活不只是传数据还可以控制PLC启停、读取运行状态这对产线上位机来说非常实用。2. Mewtocol报文协议核心拆解2.1 帧格式与BCC校验原理Mewtocol的报文格式非常固定读懂了就一通百通。一帧完整的命令由这几部分组成起始符%ASCII 0x25表示这是一条上位机发出的命令如果返回的响应帧起始符是%表示正常响应也可能是!那代表出错了后面会说。站号两位十进制数范围00到99。PLC侧有对应的系统寄存器设置默认是01可以改。如果你的产线上挂了多台松下PLC靠站号区分。命令类型两个大写字母比如RD读数据、WD写数据、RCS读触点、WCS写触点。文本区地址、数量、数据等具体信息。BCC校验这是松下Mewtocol特别有意思的地方它不像Modbus RTU用CRC16而是用非常简单的异或XOR。计算方法从“%”之后、BCC之前的所有字符按ASCII码逐字节异或得到一个8位字节再转成两位大写十六进制ASCII字符拼到帧尾部。终止符回车符\r0x0D。我举个例子读Y0触点状态的命令完整帧是这样的%01#RCS050\r拆开来看%起始符01站号#固定分隔符RCS读触点命令0是触点编号50是BCC校验。BCC怎么来的把“01#RCS0”这7个字符的ASCII码逐个异或正好算出0x50转换成ASCII字符就是“50”。C#里计算BCC就一行代码的事后面代码部分会写。但如果用串口调试助手手工发命令验证这个手算过程还是得会不然现场临时没电脑、没法跑程序的时候就抓瞎了。2.2 常用命令详解读数据、写数据、读写触点Mewtocol的命令不少但我实际项目中90%以上只用四个RD、WD、RCS、WCS。RD读数据寄存器格式是%站号#RD起始地址 数据个数。比如读D100开始的一字数据地址用四位十六进制表示命令帧就是%01#RD01000001**\r其中0100是D100的地址0001是读取1个字。正常响应格式是%01$RD0100数据**\r比如返回%01$RD01001234**\r那D100的当前值就是0x1234。WD写数据寄存器格式是%站号#WD起始地址 数据个数 数据内容。比如要把D100写成1命令帧就是%01#WD010000010001**\r写完之后PLC会返回一个不带数据区的响应帧%01$WD**\r收到它就知道写入成功了。RCS/WCS读/写单个触点触点包括输入继电器X、输出继电器Y、内部继电器R。比如读Y0输出状态发%01#RCS0**\r返回%01$RC0状态 校验状态是0就是OFF1就是ON。写Y0同理%01#WCS01**\r表示把Y0置ON。这里有个细节D区地址从0000开始映射R区地址规则跟D区不完全一样不同型号也略有差异。我一般直接参考对应型号的手册里的地址映射表别靠记忆容易踩坑。比如老款FP0的D区和FP-X的D区在某些特殊地址上就不同。2.3 寄存器地址映射与数据类型Mewtocol里寄存器地址映射这件事新手最容易懵。其实逻辑不复杂数据寄存器D、链接寄存器L、文件寄存器FL等都有各自的编号规则。以最常见的D区为例D100在协议里对应的地址就是0100直接用十进制转十六进制就行。而W写入指令发送的数据区前面说的四个十六进制字符表示一个字它是一个无符号十六进制数。做视觉上位机的时候我通常会把“检测结果”“产品编号”“测试时间戳”这些放到固定的D区地址。比如约定D100 当前产品结果1表示OK2表示NGD101 产品计数D102-D110 根据实际需要扩展。这样PLC工程师那边也好写上位机这边也好维护。另外数据类型转换方面要留意从PLC读回来的原始数据是字符串形式的十六进制C#里要转成ushort、int或者float要根据PLC里面存的是什么类型来决定。如果PLC那边是32位浮点那就得连续读两个寄存器再手动拼成float这个我在代码部分会给出示例。3. C#串口通讯模块的完整实现3.1 搭建一个松下PLC通讯类我用C#写松下串口通讯一般会封装成一个独立的类库比如叫PanasonicMewtocolClient。这样视觉算法、业务逻辑、UI层都可以调用它而且以后换PLC型号只要改这个类就行。先看最基础的结构包括串口初始化、打开关闭、BCC计算、报文拼接这几个功能using System; using System.IO.Ports; using System.Text; public class PanasonicMewtocolClient : IDisposable { private SerialPort _port; private byte _stationNo 0x01; // 站号默认1 private readonly object _lockObj new object(); public PanasonicMewtocolClient(string portName, int baudRate 9600) { _port new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One); _port.ReadTimeout 500; _port.WriteTimeout 500; } public void Open() { if (_port.IsOpen) return; _port.Open(); } public void Close() { if (_port ! null _port.IsOpen) _port.Close(); } /// summary /// 计算BCC校验从%之后到BCC之前的字符做异或 /// /summary private byte CalculateBcc(string framePart) { byte result 0; byte[] bytes Encoding.ASCII.GetBytes(framePart); foreach (byte b in bytes) { result ^ b; } return result; } /// summary /// 拼装完整命令帧起始符 % 内容 BCC \r /// /summary private string BuildFrame(string bodyWithoutPercent) { byte bcc CalculateBcc(bodyWithoutPercent); return % bodyWithoutPercent bcc.ToString(X2) \r; } }这里有几个细节需要注意串口参数波特率不一定是9600得跟PLC系统寄存器里设置的一致否则发出去全是乱码这个我在第4章展开。还有站号默认是1如果现场改了PLC站号这里也要对应改。3.2 读寄存器与写寄存器的完整方法有了基础类接下来实现最常用的两个方法读数据寄存器ReadRegister和写数据寄存器WriteRegister。/// summary /// 读取数据寄存器例如读取D100一个寄存器 /// /summary public ushort ReadRegister(int address) { lock (_lockObj) { string body ${_stationNo:D2}#RD{address:X4}0001; string frame BuildFrame(body); _port.DiscardInBuffer(); _port.Write(frame); string response ReadResponse(); if (string.IsNullOrEmpty(response) || response[0] !) throw new Exception($读寄存器失败响应{response}); // 响应格式示例%01$RD01001234**\r // 截取数据区地址4位 数据4位 string dataPart response.Substring(9, 4); return Convert.ToUInt16(dataPart, 16); } } /// summary /// 写入数据寄存器例如把D100写为1 /// /summary public void WriteRegister(int address, ushort value) { lock (_lockObj) { string data value.ToString(X4); string body ${_stationNo:D2}#WD{address:X4}0001{data}; string frame BuildFrame(body); _port.DiscardInBuffer(); _port.Write(frame); string response ReadResponse(); if (string.IsNullOrEmpty(response) || response[0] !) throw new Exception($写寄存器失败响应{response}); } }这里我用了lock _lockObj原因很现实产线上位机往往是多线程的视觉线程在写结果UI线程在轮询状态如果不加锁两个线程同时往串口写数据报文就会互相穿插PLC那边收到的就是乱帧。串口操作必须串行化这是工控通讯的基本素养。接收响应的ReadResponse这里我用了一个简单但可靠的循环读取方式读直到遇到\r结尾为止private string ReadResponse() { StringBuilder sb new StringBuilder(); int start Environment.TickCount; while (Environment.TickCount - start 500) { int count _port.BytesToRead; if (count 0) { byte[] buffer new byte[count]; _port.Read(buffer, 0, count); sb.Append(Encoding.ASCII.GetString(buffer)); if (sb.Length 0 sb[sb.Length - 1] \r) break; } else { Thread.Sleep(10); } } return sb.ToString(); }注意这个方法是阻塞等待响应的适合命令/响应模式的场景。如果你的上位机需要全双工、PLC会主动上报数据那得换事件驱动的方式用DataReceived事件加队列后面会讲。3.3 循环采集数据与UI刷新卡顿的解决思路做上位机的人基本都遇到过这个热搜问题C#循环采集串口数据时UI界面卡成PPT。原因很简单串口数据接收是在后台线程或者说DataReceived事件线程里触发的如果你在这个线程里直接去改文本框、图表控件UI线程忙不过来自然卡顿。再加上有些人图省事用Thread.Sleep死循环去轮询那更卡。我常用的解决方案是“生产者-消费者”模式串口接收线程只管把原始数据塞进队列UI线程用定时器按固定频率去队列里取数据刷新界面。private ConcurrentQueuestring _receiveQueue new ConcurrentQueuestring(); private void OnDataReceived(object sender, SerialDataReceivedEventArgs e) { SerialPort sp (SerialPort)sender; int count sp.BytesToRead; byte[] buffer new byte[count]; sp.Read(buffer, 0, count); string chunk Encoding.ASCII.GetString(buffer); _receiveQueue.Enqueue(chunk); }UI这边在窗体加载时启动一个System.Windows.Forms.Timer间隔50ms在Tick事件里批量取出队列数据并解析、刷新控件private void TimerRefresh_Tick(object sender, EventArgs e) { while (_receiveQueue.TryDequeue(out string chunk)) { _rawBuffer.Append(chunk); // 尝试从缓冲区里取出完整的一帧以\r结尾 int endIndex; while ((endIndex _rawBuffer.ToString().IndexOf(\r)) 0) { string frame _rawBuffer.ToString().Substring(0, endIndex 1); _rawBuffer.Remove(0, endIndex 1); ProcessFrame(frame); } } }这样做的核心思想是UI永远只做轻量级的事情重活解析、校验、业务处理都放到后台线程或者至少不要在控件里堆积大量数据。实测下来就算每秒几百帧数据界面也稳如老狗。3.4 读取32位浮点数据与批量地址封装机器视觉项目里经常会遇到需要读取PLC里Float数据的情况比如相机曝光值、位置坐标、温度值等。PLC侧如果存的是32位浮点数那它实际占用了两个连续寄存器比如D200和D201。Mewtocol读回的是两个16位的十六进制字符串我们需要拼起来再转成C#的float。public float ReadFloat(int startAddress) { // 连续读两个寄存器 string body ${_stationNo:D2}#RD{startAddress:X4}0002; string frame BuildFrame(body); _port.DiscardInBuffer(); _port.Write(frame); string response ReadResponse(); if (string.IsNullOrEmpty(response) || response[0] !) throw new Exception($读浮点失败响应{response}); // 假设响应数据区是 8 个十六进制字符如 0100 0200 string dataPart response.Substring(9, 4) response.Substring(13, 4); uint raw Convert.ToUInt32(dataPart, 16); return BitConverter.ToSingle(BitConverter.GetBytes(raw), 0); }这里有个很容易出错的点大小端顺序。松下PLC和C#的内存字节序不一定一致如果直接转出来的浮点数完全不对多半就是寄存器高低字顺序反了。我一般会先把读到的两个寄存器值打印出来跟PLC侧比对确认顺序后再封装避免现场瞎试。4. 工程上的坑与排查实录4.1 PLC串口参数不匹配数据全乱码这是最开始最常见的坑。上位机串口默认参数一般设置成9600、8、N、1但PLC侧的系统寄存器里通信格式可能是19200甚至有校验位、停止位不同。两边参数只要有一个不一致收到的就是乱码或者根本没响应。排查方法很简单先在PLC编程软件FPWIN GR里查看系统寄存器No.20~No.26确认协议类型是不是“计算机链接”确认波特率、数据位、校验位、停止位然后让上位机的SerialPort参数跟它严格一致。特别提醒松下PLC的串口协议一定要设置成“计算机链接”如果还停在编程口模式你发的Mewtocol命令它会当没看见。我遇到过两次这种问题都以为代码写错了最后发现是系统寄存器没改。4.2 通信模式没切换命令石沉大海接上文很多人配好了波特率发送数据还是没反应那就要检查PLC系统寄存器里有没有把通信模式设成“计算机链接”。松下PLC的编程口默认是用于编程软件上传下载程序的如果不切换模式上位机发过去的数据PLC根本不会按Mewtocol解析。这问题最坑的地方在于串口参数全对、硬件接线也没问题、代码看着也没问题但它就是不回你。所以这块我建议在项目启动前就先确认好别等联调的时候浪费时间。改完系统寄存器之后PLC需要重新上电生效这一点也要跟现场电工打好招呼。4.3 粘包、半包与数据校验失败串口通讯天生没有“消息边界”的概念它只是一串字节流。PLC返回的数据可能会两帧粘在一起也可能一帧被拆成两半这是串口编程里永远躲不开的问题。好在Mewtocol有\r作为帧结束符所以解析时以\r为边界把数据切分成完整帧就能解决90%的问题。我在第3章代码里用的_rawBuffer字符串缓冲区就是这个思路不断追加新收到的数据然后循环找\r找到一个就切走一帧。这里有个小技巧收到的数据不要直接当字符串处理最好先按ASCII解码然后统一用\r分割。响应帧结尾的\r就是天然的帧分隔符不需要自己去猜帧长。另外如果BCC校验失败PLC会返回!开头的错误响应帧常见错误码有这几个具体以手册为准错误码含义常见原因21BCC校验错误帧尾校验值算错或通讯干扰22格式错误报文格式不对缺字符或多字符32超出范围地址或数据数量超出PLC可访问范围41密码保护PLC设置了密码禁止远程操作调试时看到!响应别慌对照错误码就能定位到问题。4.4 现场串口频繁断开USB转串口不稳定的处理产线上用的上位机很多是普通工控机不带原生COM口几乎全靠USB转串口。这种方案便宜但偶尔会遇到串口假死、无法打开、拔插之后端口号变了这类问题。我的处理经验是选用FTDI芯片或CH340芯片的USB转串口线兼容性好驱动稳定国内有些几块钱的转接线芯片太杂现场干扰一大就容易掉。上位机代码里要处理SerialPort打开失败、读写异常等情况不要一崩溃就退出最好加自动重连机制。固定USB端口号在设备管理器里给USB转串口设置固定COM号避免每次插到不同USB口导致COM号变化上位机配的端口对不上。程序启动时做一次端口检测不依赖固定COM号最好可以自动枚举可用串口并匹配。自动重连的逻辑不复杂定时检测串口是否IsOpen如果关闭了就尝试重新打开。我一般用一个后台线程来做这个检查间隔2秒实时性好也不影响主逻辑。4.5 机器视觉联调中的典型问题视觉程序和PLC联调最典型的一个问题就是通讯时序。比如PLC这边发了一个“拍照”命令结果视觉程序因为上电启动慢、算法初始化没完成没有及时响应PLC那边就超时报错了。解决办法是上位机启动完成后主动向PLC发送一个“上位机就绪”状态PLC收到之后才允许产线启动双方约定好握手流程。还有一个常见问题就是“结果写进去PLC没反应”。这时候先别怀疑通讯先用串口调试助手手动发一帧写寄存器命令比如把D100写成1看PLC那边对应的寄存器值变没变。如果变了说明通讯链路和协议都没问题问题出在PLC程序逻辑里没有去读这个地址或者地址映射错了。这种排查思路能帮你快速缩小范围而不是反复改上位机代码又看不到效果。5. 调试环境搭建与辅助工具5.1 使用串口调试助手手动验证协议写代码之前我强烈建议先用串口调试助手把Mewtocol命令完整跑通一遍。新建一个连接选择对应的COM口和波特率然后手动发送一帧比如%01#RCS050\r如果PLC正常响应应该会返回类似%01$RC0**\r的内容这就说明物理链路、协议设置都OK了。然后你再把同样的命令拿到C#代码里发一切水到渠成。手动验证的价值在于它把“硬件问题”“协议问题”“代码问题”这三层一次切干净。串口助手发命令PLC有反应那问题一定在代码侧串口助手发命令都没反应那就要查接线、查PLC参数、查站号了。5.2 虚拟串口工具与本地调试有时候PLC不在身边或者实验室里只有一台电脑怎么写代码用虚拟串口工具。我现在常用的方案是com0com这类虚拟串口软件创建一对绑定端口比如COM3和COM4然后让C#程序打开COM3另一个串口调试助手打开COM4两边就能互发数据。这样开发阶段就可以把协议解析、界面刷新这些逻辑先跑通拿到现场再对接真PLC。不过要注意虚拟串口只能模拟字节流的收发PLC的响应逻辑、错误码返回这些模拟不了。所以本地调试只能验证上位机的“发送-接收-解析”链路真正的BCC计算对不对、帧格式对不对还是得拿真实PLC过一遍。5.3 日志系统工控上位机必备的调试手段做上位机通讯日志系统真的不能省。我见过太多项目现场出了问题上位机界面又不能随便停最后一堆人围在那里猜。所以我在所有通讯模块里都加了一套简单的文本日志记录每一帧发出的命令、每一帧收到的响应、异常信息、耗时。日志级别大概分3类调试级记录全部收发帧原文开发阶段开现场关闭避免日志文件疯狂膨胀。信息级记录读写寄存器成功、结果写入OK这类关键动作。错误级记录超时、BCC校验失败、串口异常等。日志文件按天切割保留最近30天。现场出了问题翻日志几秒钟就能定位到是哪一帧通讯异常、是PLC没响应还是数据校验不对。这套习惯帮我排掉过无数莫名其妙的现场问题。6. 从通讯到项目落地的几点体会代码写完之后最后聊点我的个人经验。第一个体会通讯协议要尽早定下来。视觉程序、PLC程序的开发往往是并行的如果等到联调那天才坐下来对地址表两边都会很痛苦。我一般会牵头出一份简单的通讯地址表列出每个寄存器的地址、读写方向、数据类型、含义发给PLC工程师确认双方照着实现联调效率能提升一大截。第二个体会代码里要有容错但不要过度重试。串口通讯偶尔丢一帧很正常重试机制可以做但比如写结果这种操作重试3次都失败就该停下来报错而不是无限重试否则产品已经流到下一工位了结果还没写进去产线上会出现漏剔。第三个体会松下的Mewtocol协议看着简单但现场工控环境千奇百怪地线干扰、USB供电不足、线缆过长都会导致偶发通讯异常。如果产线通讯不稳定先查硬件、换线、换USB口别急着怀疑协议。我见过一个项目最后问题是出在一条用了五年、内部已经折断的串口线上换线立马就好了这种事情见得多了你也会把“硬件优先”放在第一位。第四个体会如果有人问我做机器视觉上位机最值得提前储备的通讯技能是什么我的答案不是某个具体协议而是串口通讯这一整套思维帧格式、校验、缓冲、超时、重试、多线程访问。这套东西学会了Mewtocol、Modbus、三菱、西门子无非就是换一套报文规则而已底层逻辑完全相通。最后再说一个小技巧调试串口命令的时候串口助手上如果开的是“文本模式 发送新行\r\n”记得把波特率、停止位这些挨个跟代码里的配置核对一遍再开始怀疑协议。松下这个系列的PLC我踩过的坑一半都在参数不匹配上。把这个问题先排掉很多“疑难杂症”其实都不是问题。
网站建设高端定制企业官网
RELATED

相关资讯

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

较早相关资讯

最新相关资讯

慕尼黑工业大学用 Zulip 为 1400+ 名学生授课:大型课程沟通平台的选型、自托管与规模化实战 2026/9/13 7:53:50

慕尼黑工业大学用 Zulip 为 1400+ 名学生授课:大型课程沟通平台的选型、自托管与规模化实战

慕尼黑工业大学用 Zulip 为 1400 名学生授课:大型课程沟通平台的选型、自托管与规模化实战 【免费下载链接】zulip Zulip server and web application. Open-source team chat that helps teams stay productive and focused. 项目地址: https://gitcode.com/GitH…

阅读更多 →
SpringBoot+Vue毕业生追踪系统开发实践 2026/9/13 7:53:50

SpringBoot+Vue毕业生追踪系统开发实践

1. 项目概述"springboot毕业生追踪系统vue"是一个基于SpringBoot后端框架和Vue.js前端框架开发的毕业生信息管理系统。这个系统旨在帮助高校或培训机构高效管理毕业生信息,追踪他们的就业情况和发展轨迹。作为一名有多年全栈开发经验的工程师,…

阅读更多 →
LangChain.js MCP 适配器版本演进:@langchain/mcp-adapters 从 0.1 到 1.1.4 的变更全解 2026/9/13 7:53:50

LangChain.js MCP 适配器版本演进:@langchain/mcp-adapters 从 0.1 到 1.1.4 的变更全解

LangChain.js MCP 适配器版本演进:langchain/mcp-adapters 从 0.1 到 1.1.4 的变更全解 【免费下载链接】langchainjs The agent engineering platform 项目地址: https://gitcode.com/GitHub_Trending/la/langchainjs 本文以 libs/langchain-mcp-adapters 包…

阅读更多 →
MCP协议在远程教育中的优化与应用实践 2026/9/13 7:53:50

MCP协议在远程教育中的优化与应用实践

1. MCP技术概述与远程教育场景适配性MCP(Multimedia Communication Protocol)作为一种专为多媒体数据传输优化的通信协议,其核心价值在于解决了传统教育平台中音视频同步延迟、数据包丢失率高等痛点。在线上教学场景中,教师端的PP…

阅读更多 →
Claude-Red项目架构解析:技能文件结构与扩展开发指南 2026/9/13 7:53:50

Claude-Red项目架构解析:技能文件结构与扩展开发指南

Claude-Red项目架构解析:技能文件结构与扩展开发指南 【免费下载链接】Claude-Red claude-red is a curated library of offensive security skills designed for the Claude skills system. Each skill is a structured SKILL.md file that primes Claude with exp…

阅读更多 →
Linux系统镜像与固件的本质区别:运行位置、更新方式与实操避坑 2026/9/13 7:50:49

Linux系统镜像与固件的本质区别:运行位置、更新方式与实操避坑

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

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

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