西门子TSEND_C错误代码详解:STATUS排查与实战排错

发布时间:2026/10/2 13:20:47
西门子TSEND_C错误代码详解:STATUS排查与实战排错 干自动化项目尤其是用西门子S7-1200/1500做设备间通信或对接上位机的时候TSEND_C指令基本是绕不开的。它是TIA Portal博图里开放式以太网通信的核心发送指令底层走TCP或UDP协议负责把PLC中的数据块内容发给PC服务器、第三方控制器或者另一台PLC。功能本身不算复杂真正让人血压升高的是它那一长串STATUS错误代码0x8003、0x80A1、0x80C5、0x8090……每一条背后都对应一种故障场景查手册费劲网上答案又经常各说各话。这篇文章就结合我自己的项目经历把TSEND_C常见错误代码从头到尾理一遍附带排错思路和实战复盘适合正在被通信问题折腾的电气工程师、自动化调试人员也适合刚接触博图通信的新手参考。1. 指令轮廓与错误代码产生的底层逻辑1.1 TSEND_C指令参数速览与调用方式TSEND_C在博图里的位置一般是“指令 - 通信 - 开放式通信 - 其他”下面和TRCV_C是一对搭档。它的标准输入输出参数不多但每个都直接影响排错方向REQ发送请求必须在上升沿时触发不能持续为1。LEN发送数据长度单位是字节。CONNECT连接描述是一个数据块参数在里面配置协议类型、IP地址、端口号、本地端口、连接ID等。DONE发送完成标志为1表示本次发送成功。BUSY忙碌标志为1表示指令正在执行中。ERROR错误标志为1表示本次调用出错需要查看STATUS。STATUS状态字返回具体错误代码或当前状态。调用时TSEND_C会自动生成一个背景DB用于保存连接状态和内部参数。相比老式的TCON加TSEND组合TSEND_C把“建立连接”这件事隐藏到了内部第一次调用时自动发起连接后续调用直接在这个连接上发送数据确实省了很多编程量。但这也带来一个问题连接状态不可见一旦STATUS报错很多人第一反应就是懵不知道是参数问题、网络问题还是对端问题。所以排错第一步先把这几个输出参数的时序关系搞清楚。DONE、BUSY、ERROR三者不会同时为1每个扫描周期最多只有一个为1。BUSY为1时STATUS通常是0x7000这表示指令正在处理不是错误。只有ERROR为1时STATUS的值才具有“错误代码”意义这时候需要把STATUS记录下来并按代码分类排查。1.2 状态字STATUS的读取方法从DONE、ERROR、BUSY入手很多初学者拿到程序后第一个动作是盯着STATUS看。这个方向没错但容易漏掉上下文。STATUS本身是一把“万能钥匙”但同一个值在不同阶段含义不一样。比如0x7000代表“作业正在处理中”如果你在BUSY1时看到它这是完全正常的如果在ERROR1时看到0x7000那才是异常。我的习惯是做一个通信诊断数据块把每次调用后的DONE、ERROR、BUSY、STATUS、LEN全部记录下来同时加一个触发计数器。这样调设备的时候不用一直盯着在线监视等故障出现后直接看诊断DB里的历史记录能快速锁定是哪一次调用出了问题。尤其在现场设备偶发断线的情况下这个习惯能省下大量蹲在现场等故障重现的时间。另外STATUS的值在博图在线监视里可以用十六进制显示也可以切换成十进制。S7-1200/1500里STATUS是WORD类型有些指令返回的是Integer格式比如-32766对应的实际值就是16#8002。判断的时候我建议统一按十六进制看因为手册里的错误代码表全是十六进制避免换算错误。1.3 为什么同一个错误码在不同固件版本里含义不同这一点容易被忽略。TSEND_C在S7-1200和S7-1500上虽然指令名字一样但底层实现有差异错误代码定义也不完全一致。比如某些0x80B0段的内部错误在老固件版本上不会出现新固件版本增加了更细的状态分类。甚至同一个0x8003在某些旧手册里是“连接被拒绝”在新版本手册里则细化为“连接被对端关闭”。所以排错的第一原则是以你当前使用的TIA Portal版本和CPU固件版本对应的在线帮助为准。不要拿着网上搜来的老错误码表硬套尤其是跨CPU系列的情况。我在项目里遇到过S7-1200报0x80C5而S7-1500同样场景报0x8003的情况如果只认一个版本的表很容易走弯路。实在不确定时可以直接在博图指令帮助里搜索STATUS查看当前版本自带的错误代码说明。2. 错误代码分类与逐项解析2.1 0x7000段这些不是错误只是状态先把最容易误判的一段拿出来说。STATUS以0x7开头的值基本都属于“过程状态”不代表发送失败。常见的有16#0000无任务或任务未激活。16#7000作业正在处理中对应BUSY1。16#7001连接已建立。16#7002连接正在建立中。16#7003连接已关闭。16#7004连接正在关闭。16#7005参数错误但指令未捕获为ERROR。16#7006连接正在重新建立。这段状态码的实用意义在于你可以通过STATUS判断当前连接处于什么阶段。比如第一次调用TSEND_C后STATUS长时间停在0x7002说明TCP三次握手一直没完成问题大概率在网络或对端监听上而不是发送数据本身。如果STATUS从0x7002变成0x7001说明连接已经OK后续发送正常的话STATUS会频繁出现0x7000。注意区分0x7003和0x70040x7003表示连接已经关闭0x7004表示正在执行关闭动作。如果在程序运行中经常看到0x7003说明对端主动关闭了连接或者PLC侧触发了断开逻辑。S7-1200的TSEND_C在连接关闭后不会自动重建连接需要再次触发REQ或调用相应连接管理指令。2.2 0x8000段连接层常见的报错与处置STATUS以0x8开头的值才是真正的错误代码。0x8000段集中在连接层也就是TCP/UDP连接本身出了问题。这部分错误在现场最常见我把高频的几个逐个说一遍。16#8001连接尚未建立。通常出现在你调用TSEND_C发送数据但之前连接建立失败或连接已经被关闭。处理方法先确认对端IP和端口是否可达再检查连接描述参数。16#8002参数错误。CONNECT指向的连接描述数据有误比如协议类型字段写错、连接ID重复、IP地址格式错误等。这类错误只要仔细核对连接DB里的每一项配置就能解决。16#8003连接被对端关闭或重置。这是TCP通信里的典型故障对端socket主动close或异常退出都会触发。如果数据发送过程中频繁报0x8003要重点检查对端程序是否超时断开、心跳机制是否正常。16#8004连接中断。链路层面出问题比如网线松动、交换机掉电、对端网卡重启。和0x8003的区别是0x8003通常是对端主动关闭0x8004更像是物理链路或中间设备导致的断开。16#8080协议类型错误。比如连接描述配置的是UDP但实际调用TSEND_C时使用了TCP参数或者反过来。这类错误在改过连接DB后特别容易发生。16#8081目标IP地址错误。IP不可达或者不在同一网段。先ping一下对端如果ping不通问题基本在网络配置。16#8082连接ID已被占用。连接描述里的ID和PLC里其他连接重复了需要改成唯一值。16#8083本地端口已被占用。常见于多个连接共用一个本地端口或者程序里重复调用了同一个连接实例。16#8084远程端口无法访问。IP能通但对端端口没有监听或者被防火墙拦了。用telnet测一下端口就知道。16#8085/16#8086连接描述符错误。一般是连接描述数据被破坏或者背景DB被意外修改。16#8089连接数量已达到上限。CPU支持的最大连接数已经用完需要释放不用的连接或者换更高型号的CPU。16#8090没有可用的连接资源。这个和8089有点类似但更偏向底层资源耗尽比如连接控制块不够。检查程序里是否有重复建立的连接是否有TSEND_C实例忘记释放。2.3 0x80A0/0x80C0段数据层与资源类错误过了连接层就到了数据层。这类错误往往不是网络问题而是程序参数配置问题。16#80A1数据长度无效。LEN参数大于实际可用的数据区长度或者LEN为0。比如你DB块里定义了一个100字节的数组但LEN填了120就会报这个错误。这是新手最容易踩的坑之一。16#80A2数据缓冲区无效。发送缓冲区指向了系统存储区、I/O映像区等不允许访问的区域或者指针越界。16#80A3指针错误。发送数据区的指针类型不对比如使用ANY指针时指向了未初始化的数据块。16#80B0内部软件错误。一般是程序逻辑问题比如多个TSEND_C同时操作同一个连接。16#80B1内部硬件错误。比较少出现如果反复报这个码可以先下载空程序测试CPU通信是否正常。16#80B2资源错误。系统资源不足可能是通信负载过高。16#80B3连接正在建立中。这种情况通常配合ERROR1出现说明发送请求来得太快连接还没准备好。16#80C0连接ID错误。TSEND_C本身没有R_ID参数但如果你在程序里用旧版TSEND指令的思维去操作容易在连接管理上搞混。16#80C1连接ID已被占用。同8082。16#80C2本地端口已被占用。同8083。16#80C3无可用连接资源。注意这个码在多次反复重连、频繁建立和断开连接时特别容易出现。TCP连接关闭后端口会进入TIME_WAIT状态短时间内大量重连会把资源耗尽。16#80C4远程地址错误。地址格式不正确比如端口号填成0。16#80C5连接被拒绝。对端IP可达但端口没人监听或者对端防火墙直接发送了RST包。这个码在对接第三方设备时很常见。16#80C6本地端口无效。本地端口填0或超过65535时会出现。再往下是0x80D0段主要围绕发送作业本身16#80D1发送作业被占用。同一个连接上已经有另一个发送任务在执行冲突了。16#80D2接收缓冲区溢出。这个更多出现在TRCV_C配合时如果接收缓冲区比实际到达数据小则可能丢数据或报错。16#80D3LEN长度大于有效数据长度。和80A1类似但更偏向于发送缓冲区有效范围不够。16#80D4数据指针无法访问。发送区指向了被保护的数据块或数据块未加载。16#80D5SEND参数错误。LEN、缓冲区、连接描述这三者之间的配合出了问题。2.4 错误代码速查表自己动手把高频错误码做了一张速查表现场调试时直接对照效率高很多。错误代码含义常见原因处理办法16#7000作业处理中正常状态BUSY1等待指令完成16#7001连接已建立正常状态无需处理16#7002连接建立中正在三次握手检查网络和对端监听16#8001连接尚未建立连接失败或已关闭先排查连接建立16#8002参数错误连接描述配置有误核对CONNECT参数16#8003连接被对端关闭对端断开socket检查对端程序和心跳16#8004连接中断网络链路故障检查网线、交换机16#8080协议类型错误TCP/UDP配置不匹配修改连接描述16#8081目标IP错误IP不可达ping对端16#8082连接ID重复ID冲突修改连接ID16#8083本地端口占用端口冲突修改本地端口16#8084远程端口不可达端口未监听或被防火墙拦截telnet测试端口16#8089连接数超上限CPU连接数耗尽释放连接或换CPU16#8090连接资源不足资源耗尽检查重复建连16#80A1数据长度无效LEN过大或为0修正LEN16#80A2数据缓冲区无效指针越界检查数据区定义16#80B0内部软件错误多实例冲突检查程序逻辑16#80C3无可用连接资源频繁重连耗尽资源增加重连间隔16#80C5连接被拒绝端口无人监听或防火墙RST检查对端服务16#80D1发送作业被占用同连接并发发送确保互斥调用3. 实战排错流程与案例复盘3.1 通用排错五步法遇到TSEND_C报错不要急着改程序更不要迷信“重启一下就好”。我给自己定了一套排错流程按顺序走大部分问题都能在半小时内定位。第一步确认网络可达性。在电脑上ping PLC的IP再从PLC侧ping对端S7-1500支持PING指令S7-1200部分型号也可以。ping不通的话网线、交换机、IP网段挨个查。 第二步确认端口可达性。TCP通信必须确认对端端口正在监听。Windows上用telnet命令测端口命令格式是“telnet 目标IP 端口”能进入黑屏或返回连接成功就代表端口通。 第三步确认连接描述参数。在博图里打开TSEND_C对应的连接DB逐项核对协议类型、IP地址、端口号、本地端口、连接ID。有时候只是端口号一个数字之差就能折腾半天。 第四步记录STATUS变化过程。不看单个状态的截图要看一段时间内STATUS的序列变化。比如反复出现0x7002、0x7003、0x8003的循环基本可以断定是对端主动断开。 第五步用抓包工具看TCP层。Wireshark抓包是最直接的手段重点看SYN包有没有回应、有没有RST包、数据包有没有重传。抓包不需要太深能看到TCP三次握手和四次挥手基本就够了。这套流程看起来简单但真的能解决八成以上的通信问题。我一直觉得通信调试最忌讳“猜”每一步都要有依据。3.2 案例一S7-1200作为客户端连接不上服务器这个案例来自一套设备数据采集项目S7-1200作为客户端要把设备状态数据主动发给PC端的上位机软件。现场现象是TSEND_C一直报错STATUS在0x8001和0x8084之间反复跳。我先ping了上位机IP网络是通的。再用telnet测试上位机的监听端口发现端口不通返回“无法打开到主机的连接”。到这一步基本明确问题不在PLC侧而在PC服务器的端口监听或防火墙。上位机软件确认端口确实有在监听那剩下的嫌疑就是防火墙。查看Windows防火墙入站规则发现程序监听的是TCP 5000端口但入站规则里只开放了TCP 102端口西门子PLC通信默认端口。给5000端口添加入站规则后TSEND_C立刻恢复正常STATUS稳定在0x7000到0x7001之间。这个案例看起来简单但很有代表性。很多人一看到TSEND_C报错第一反应是改PLC程序折腾半天发现是电脑防火墙的问题。记住一个原则先测端口再查程序。3.3 案例二发送能通但偶尔断线STATUS为0x8003另一个项目里PLC与PC通信已经调通数据能正常上传但运行几个小时后偶尔会出现一次断线STATUS报0x8003之后再也连不上必须重启PLC程序或手动触发重连才能恢复。0x8003表示连接被对端关闭说明PC端主动断开了socket。我第一反应是上位机软件有没有设置空闲超时时间查了一圈发现没有。再抓包看发现PC端每隔一段时间会发送FIN包主动关闭连接而PLC侧因为没有处理连接关闭后的重连逻辑就一直卡在断线状态。问题的根源是上位机软件在接收端设置了“无数据超时断开”的机制超过一定时间没有收到数据就主动关socket。但PLC这边的数据发送周期是不固定的忙的时候数据很频繁闲的时候可能超过超时时间。解决方法是两边的配合上位机侧把超时时间改大或者改成不主动断开PLC侧加一个重连状态机检测到ERROR1且STATUS为0x8003时延时触发一次REQ重建连接。两件事都做了之后断线问题彻底消失。3.4 案例三多数据块轮询发送时出现0x80A1第三个案例是PLC需要循环发送多个数据块给上位机程序里用了一个状态机按顺序切换发送不同的DB块。运行一段时间后偶发0x80A1数据长度错误。排查时发现状态机切换数据块的逻辑没问题但在一个扫描周期内TSEND_C的REQ信号和LEN信号被同时修改了。前一个数据块还没发送完LEN就变成了下一个数据块的长度导致TSEND_C内部校验时发现LEN比当前缓冲区可用长度大于是报0x80A1。这类问题本质上是数据一致性被破坏。解决办法很简单把LEN和发送数据区的指针绑定成同一个结构体用同一个索引切换或者在REQ置位的那一个周期不允许修改LEN。用“先切数据再发REQ发送完成后再切换下一个”的顺序就能避免偶发错码。4. 常见问题与避坑心得4.1 网络层面的隐藏坑防火墙、ARP缓存和子网规划网络层面的问题在TSEND_C排错里占比非常高。除了前面提到的Windows防火墙还要注意交换机端口隔离、VLAN划分、公司网络安全策略这些大环境因素。现场设备如果和上位机不在同一个VLAN即使IP在同一网段也可能不通。ARP缓存也是一个隐藏坑。PLC更换IP后电脑或交换机里可能还缓存着旧的MAC地址和IP对应关系。遇到ping不通的情况可以在电脑上用“arp -d”清空缓存再试或者重启交换机。另外S7-1200/1500的以太网口如果同时配置了Profinet和TCP通信连接资源会被Profinet占用一部分。CPU型号越入门级可用连接数越少。选型时就要算好同时在线连接数别等到现场报0x8089再换CPU。4.2 程序层面的坑REQ、LEN与指针REQ触发方式是我见过最多人写错的地方。TSEND_C的REQ必须用上升沿触发不能直接在OB1里把REQ接成常1或者每个周期都置1。我见过一个设备程序里把REQ直接接成了M0.0结果每个扫描周期都在触发发送通信卡死STATUS一直报0x80D1发送作业被占用。正确做法是用P_TRIG或自己写一个上升沿检测。比如用两个M点做边沿判断前一个周期的状态存下来当前周期为1且前一个周期为0时才给REQ置1发送完成后复位。LEN的坑主要在单位上TSEND_C的LEN单位是字节不是位也不是字。发送一个WORD数组时LEN要填“数组长度乘以2”。发送字符串时如果用的是String类型要注意西门子String的前两个字节是长度信息实际发送的字符数据需要从偏移2开始取或者直接用Byte数组来承载报文避免格式混乱。数据区指针方面建议给TSEND_C单独建一个发送缓冲区DB定义为固定长度的Byte数组所有发送数据都先拷贝到这个缓冲区再发。这样LEN和指针都是可控的不会因为源数据区结构变化导致TSEND_C参数错误。这个方法牺牲一点内存但能把偶发故障率压到很低。4.3 与TRCV_C配合时的常见误区TSEND_C和TRCV_C经常成对出现一个发一个收。但很多人在配置接收端时踩坑。TRCV_C的LEN参数是“最大接收长度”不是“固定接收长度”。如果对端发送的数据长度小于LEN接收缓冲区里只有实际收到的数据有效实际长度通过RCVD_LEN输出。如果对端发送的数据长度大于LEN多出来的部分会被丢弃而且可能报0x80A2接收缓冲区溢出。所以接收缓冲区的长度要按最大报文长度定义不能为了省内存而设得太小。同时接收侧要做好报文帧头、帧尾或长度字段的校验TCP是流式传输没有报文边界的概念一次发送可能被拆成多包多次发送也可能被合并成一包。这个特性不掌握最容易出现数据错位。还有个容易忽略的点PLC里如果同时有多个TRCV_C实例每个实例必须使用不同的背景DB和连接描述不能共用一个连接。否则后一个实例会抢掉前一个实例的连接资源导致两边都报错。4.4 几个容易被忽略的细节连接描述DB的“优化块访问”属性建议关闭。优化块访问开启后数据没有固定的偏移地址某些指令在访问连接描述时会出问题。虽然不是百分百报错但关闭后更稳。背景DB不能“仅存储在装载内存”。如果勾选了“仅存储在装载内存”PLC掉电后背景DB的数据不会被保持通信参数会丢失上电后TSEND_C可能直接报参数错误。频繁重连时注意TCP的TIME_WAIT状态。连接关掉后本地端口会在一段时间内处于TIME_WAIT不能立即被新连接复用。如果程序里反复断开重连可能报0x8083或0x80C3解决办法是重连间隔至少设到5秒以上。S7-1200和S7-1500的TSEND_C行为不完全一致。S7-1500在连接断开后会自动尝试重连S7-1200则需要程序里处理重连逻辑。写程序前先确认目标CPU的行为别把1500的程序结构原封不动搬到1200上。在线监视时修改连接参数必须重新下载并复位。有些参数是初始化时写入背景DB的在线改不会生效反而可能导致DB数据不一致。5. 写在最后的几点体会做了这么多年自动化项目我的感受是通信排错的门槛不在指令本身而在对“时序”和“状态”的理解。TSEND_C的每一个错误代码本质上都是在告诉你“当前连接走到了哪一步、哪一步出了问题”。把这个思想理顺了再复杂的通信故障也能拆解成一个个小问题逐个击破。最后分享一个个人习惯现场调试通信程序时我一般会在HMI上留一个“通信状态”页面把关键连接的STATUS、DONE、ERROR、BUSY和最近一次错误时间显示出来。这样不管是自己调试还是后续维保人员排查都不用打开博图在线监视看一眼HMI就能知道故障方向。省下的时间足够把整个系统的稳定性再打磨一遍。