第26篇_源码加更 08|真机测试、编译入口和 PLC 主程序

发布时间:2026/9/29 11:23:25
第26篇_源码加更 08|真机测试、编译入口和 PLC 主程序 适合谁收藏准备复用本组源码并审查对象边界的工程师。需要把公开代码装配进目标 CodeSys 工程的人。准备重新完成编译、离线测试和真机验证的读者。开源范围本篇完整公开 4 个 ST 文件。代码直接读取已验证工程保留声明、实现、注释和缩进没有伪代码没有跨文件拼接也没有省略号。先给结论最后一组源码把公共内核、Server、Client、离线测试和真机测试装配到周期任务中形成可复现工程入口。 本篇的通过标准不是“代码已经贴出”而是每个文件的职责、调用位置、状态边界和验证入口都能对应起来并且完整代码可逐字回查源文件。读图重点先找到GVL_HttpRealTest在本组中的位置再沿图确认其余对象分别承担数据、状态、执行或诊断职责。图只给阅读顺序最终判断必须回到下面的完整 ST 代码。先看文件职责序号文件职责行数1GVL_HttpRealTest.st真机测试参数与观察量872PRG_HttpRealTest.st真机测试执行程序163PRG_HttpCompileTouch.st编译触达入口164PLC_PRG.stPLC 周期装配入口154阅读顺序不是按文件名机械展开。先看数据和状态再看公开方法最后顺着错误出口和调用对象检查边界。源码篇的目标是让读者能对照工程复现不是用大段代码制造篇幅。从协议约束到代码职责协议约束最后一组源码把公共内核、Server、Client、离线测试和真机测试装配到周期任务中形成可复现工程入口。 协议层只定义消息与状态成立的条件工程层还必须把条件分配给确定对象避免 Parser、Builder、Server、Client 和测试入口互相越权。对象分工第 1 个对象GVL_HttpRealTest.st承担“真机测试参数与观察量”。阅读时先确认输入与公开输出再追状态、长度和错误出口最后核对它被谁周期调用或被哪个对象消费。第 2 个对象PRG_HttpRealTest.st承担“真机测试执行程序”。阅读时先确认输入与公开输出再追状态、长度和错误出口最后核对它被谁周期调用或被哪个对象消费。第 3 个对象PRG_HttpCompileTouch.st承担“编译触达入口”。阅读时先确认输入与公开输出再追状态、长度和错误出口最后核对它被谁周期调用或被哪个对象消费。第 4 个对象PLC_PRG.st承担“PLC 周期装配入口”。阅读时先确认输入与公开输出再追状态、长度和错误出口最后核对它被谁周期调用或被哪个对象消费。装配与验证这组文件必须作为一个职责单元阅读和编译。先用确定输入验证“真机参数集中管理”再制造非法或容量边界验证“编译触达防止对象未被工程引用”最后在真实通信或上层调用中确认“PLC_PRG 是运行装配点而不是业务大杂烩”。如果单文件测试通过但装配后失败应优先检查结构体、常量、状态枚举和周期调用关系而不是立即重写核心算法。源码完整公开只证明读者拿到了同一事实源目标运行时是否通过仍需重新编译和真机取证。本篇从GVL_HttpRealTest.st开始审查先确认“真机参数集中管理”对应的类型、常量或公开输入再沿 CASE 或方法调用追踪成功路径随后逐个检查容量、超时和协议错误出口最后在PLC_PRG.st对应的结果或装配位置确认错误能被观测、清理并再次执行。这个顺序专门用来区分“算法正确但没有周期调用”“状态能完成但错误被覆盖”和“PLC_PRG 是运行装配点而不是业务大杂烩尚未形成验证证据”三类问题。只有本篇源码、装配和验证使用同一组对象与同一组边界完整开源才具有可复现意义。本篇完整开源代码下面按职责顺序给出本篇全部 ST 文件。每个代码块保留完整声明与实现阅读时把状态、长度、错误出口和调用对象与上面的职责表逐项对照。完整源码 1GVL_HttpRealTest.st职责真机测试参数与观察量/// 功能 : HTTP 真机联调控制和结果变量。 /// 库依赖 : CAA Net Base Services {attribute qualified_only} VAR_GLOBAL bResetResults : BOOL : FALSE; // 一次性复位真机联调结果和命令位。 udiNowMs : UDINT : 0; // 示例任务毫秒时钟按扫描周期累加。 bServerEnable : BOOL : TRUE; // Server 使能下载后默认监听便于通信猫直接访问 PLC。 bServerCloseConnection : BOOL : TRUE; // Server 响应后主动关闭连接匹配通信猫短连接调试习惯。 sServerBindIP : STRING : 0.0.0.0; // Server 绑定 IP0.0.0.0 表示任意网卡。 uiServerPort : UINT : GVL_Http.cnDefaultServerPort; // Server 监听端口默认 18088匹配通信猫访问 PLC 的 URL。 uiServerResponseStatusCode : UINT : 200; // Server 自定义响应状态码内置路由默认 200。 sServerResponseBody : STRING(GVL_Http.cnMaxBodySize) : hello from PLC Server;// Server 自定义响应 body非空时未知路径也返回 200。 sServerResponseContentType : STRING(96) : GVL_Http.cnDefaultContentType; // Server 自定义响应 Content-Type。 sServerAdditionalHeader : STRING(GVL_Http.cnMaxHeaderSize) : ; // Server 自定义响应 Header 行。 bServerListening : BOOL : FALSE; // Server 已获得监听句柄。 bServerRunning : BOOL : FALSE; // Server 正在运行。 bServerBusy : BOOL : FALSE; // Server 正在初始化或等待监听。 bServerError : BOOL : FALSE; // Server 错误锁存。 diServerErrorID : DINT : 0; // Server 错误诊断码。 sServerDiagMsg : STRING(255) : ; // Server 诊断文本。 eServerState : E_HttpServerState : E_HttpServerState.iDisabled; // Server 状态机。 eServerLastError : E_HttpError : E_HttpError.iNoError; // Server 最近 HTTP 错误。 eServerLastNbsError : NBS.ERROR; // Server 最近 NBS 错误。 uiServerActiveConnections : UINT : 0; // Server 当前活跃连接数。 uiServerLastRequestSlot : UINT : 0; // Server 最近请求槽位。 uiServerLastErrorSlot : UINT : 0; // Server 最近错误槽位。 sServerLastTarget : STRING(GVL_Http.cnMaxTargetLen) : ; // Server 最近请求路径。 sServerLastBody : STRING(GVL_Http.cnMaxBodySize) : ; // Server 最近请求 body。 sServerRxMessage : STRING(GVL_Http.cnMaxMessageSize) : ; // Server 最近一次接收报文。 sServerTxMessage : STRING(GVL_Http.cnMaxMessageSize) : ; // Server 最近一次发送报文。 udiServerAcceptedCount : UDINT : 0; // Server 累计接入连接数。 udiServerRequestCount : UDINT : 0; // Server 累计请求数。 udiServerResponseCount : UDINT : 0; // Server 累计响应数。 udiServerProtocolErrorCount : UDINT : 0; // Server 累计协议错误数。 hServerListenHandle : NBS.CAA.HANDLE; // Server 监听句柄快照。 bServerPassLatched : BOOL : FALSE; // Server 外部 client 联调通过锁存。 bClientEnable : BOOL : TRUE; // Client 使能下载后可直接向通信猫发起 HTTP 请求。 bClientSend : BOOL : TRUE; // Client 下载后默认发送一次PLC_PRG 读取后自复位。 bClientAbort : BOOL : FALSE; // Client 中止当前连接命令。 bClientCloseConnection : BOOL : TRUE; // Client 每次响应后主动关闭连接优先保证通信猫短连接调试稳定。 udiClientTimeoutUs : UDINT : 10000000; // Client 请求超时单位 [us]通信猫联调默认 10 s。 sClientURL : STRING(1024) : ; // Client URL 留空时使用下方 IP/Host/Path 分离引脚。 sClientServerIP : STRING : 192.168.20.2; // Client 远端 HTTP Server IP。 uiClientPort : UINT : 6971; // Client 远端 HTTP Server 端口匹配通信猫 HTTP 服务端口。 sClientHost : STRING(GVL_Http.cnMaxHostLen) : 192.168.20.2:6971; // Client Host 字段匹配通信猫监听端口。 sClientPath : STRING(GVL_Http.cnMaxTargetLen) : /api/tongxinmao; // Client 请求路径匹配通信猫 URL。 eClientMethod : E_HttpMethod : E_HttpMethod.iPost; // Client 请求方法默认 POST 便于发送正文。 sClientBody : STRING(GVL_Http.cnMaxBodySize) : hello from PLC; // Client 请求 body通信猫接收区可直接看到。 sClientContentType : STRING(96) : text/plain; // Client Content-Type匹配通信猫普通文本联调。 sClientAdditionalHeader : STRING(GVL_Http.cnMaxHeaderSize) : ; // Client 自定义 Header 行。 bClientTcpConnected : BOOL : FALSE; // Client TCP 连接快照。 bClientBusy : BOOL : FALSE; // Client 正在执行事务。 bClientDone : BOOL : FALSE; // Client 本次事务完成。 bClientError : BOOL : FALSE; // Client 错误锁存。 diClientErrorID : DINT : 0; // Client 错误诊断码。 sClientDiagMsg : STRING(255) : ; // Client 诊断文本。 eClientState : E_HttpClientState : E_HttpClientState.iDisabled; // Client 状态机。 eClientLastError : E_HttpError : E_HttpError.iNoError; // Client 最近 HTTP 错误。 eClientLastNbsError : NBS.ERROR; // Client 最近 NBS 错误。 uiClientStatusCode : UINT : 0; // Client 最近 HTTP 响应状态码。 sClientReason : STRING(64) : ; // Client 最近 HTTP 响应原因短语。 sClientResponseBody : STRING(GVL_Http.cnMaxBodySize) : ; // Client 最近 HTTP 响应 body。 sClientResponseHeader : STRING(GVL_Http.cnMaxHeaderSize) : ; // Client 最近 HTTP 响应 Header。 sClientTxMessage : STRING(GVL_Http.cnMaxMessageSize) : ; // Client 最近一次发送报文。 sClientRxMessage : STRING(GVL_Http.cnMaxMessageSize) : ; // Client 最近一次接收报文。 udiClientRequestCount : UDINT : 0; // Client 累计请求数。 udiClientResponseCount : UDINT : 0; // Client 累计响应数。 udiClientConnectErrorCount : UDINT : 0; // Client 累计连接错误数。 udiClientProtocolErrorCount : UDINT : 0; // Client 累计协议错误数。 bClientPassLatched : BOOL : FALSE; // Client 外部 server 联调通过锁存。 bOverallPassLatched : BOOL : FALSE; // Server 与 Client 双向联调均通过锁存。 bClientMatrixAutoEnable : BOOL : FALSE; // 真机矩阵自动运行开关发布默认关闭避免下载后自动访问外部网络。 bClientMatrixRun : BOOL : FALSE; // 真机矩阵运行命令由自动开关或在线命令置位。 bClientMatrixDone : BOOL : FALSE; // 真机矩阵完成标志。 bClientMatrixPassed : BOOL : FALSE; // 真机矩阵全部通过标志。 bClientMatrixError : BOOL : FALSE; // 真机矩阵存在失败用例标志。 uiClientMatrixTotal : UINT : 15; // 真机矩阵用例总数。 uiClientMatrixPassed : UINT : 0; // 真机矩阵通过用例数。 uiClientMatrixFailed : UINT : 0; // 真机矩阵失败用例数。 uiClientMatrixCase : UINT : 0; // 真机矩阵当前用例序号。 uiClientMatrixStep : UINT : 0; // 真机矩阵内部步骤快照。 uiClientMatrixLastStatus : UINT : 0; // 最近一次 Client 响应状态码。 eClientMatrixLastError : E_HttpError : E_HttpError.iNoError; // 最近一次 Client 协议栈错误码。 sClientMatrixCaseID : STRING(48) : ; // 当前真机矩阵用例 ID。 sClientMatrixFailedCase : STRING(48) : ; // 首个失败用例 ID。 sClientMatrixDiagMsg : STRING(255) : ; // 真机矩阵诊断文本。 END_VAR完整源码 2PRG_HttpRealTest.st职责真机测试执行程序/// 功能 : HTTP 真机联调旧入口兼容占位。 /// 库依赖 : CAA Net Base Services PROGRAM PRG_HttpRealTest VAR END_VAR // IMPLEMENTATION /// /// 名称 : PRG_HttpRealTest /// 功能 : 保留旧工程树对象名称真实 Server/Client 联调入口已统一到 PLC_PRG。 /// 库依赖 : CAA Net Base Services /// /// 使用说明 : 1. 本程序不再实例化 HTTP 功能块不再处理发送、复位或中止命令。 /// : 2. 在线联调请直接打开 PLC_PRG操作 GVL_HttpRealTest 中的全局变量。 /// // 兼容原因当前 SmartControl CLI 删除 IEC 对象能力受限保留空 PRG 可避免旧入口继续干扰在线联调。完整源码 3PRG_HttpCompileTouch.st职责编译触达入口/// 功能 : HTTP 编译触达旧入口兼容占位。 /// 库依赖 : CAA Net Base Services PROGRAM PRG_HttpCompileTouch VAR END_VAR // IMPLEMENTATION /// /// 名称 : PRG_HttpCompileTouch /// 功能 : 保留旧工程树对象名称当前 HTTP 对象由 PLC_PRG 中的完整功能块调用覆盖。 /// 库依赖 : CAA Net Base Services /// /// 使用说明 : 1. 本程序不再实例化 Client、Server 或连接槽位功能块。 /// : 2. 编译与联调以 PLC_PRG 为唯一用户入口。 /// // 兼容原因当前 SmartControl CLI 删除 IEC 对象能力受限空 PRG 仅用于保持工程树兼容。完整源码 4PLC_PRG.st职责PLC 周期装配入口/// 功能 : HTTP 示例工程任务入口。 /// 库依赖 : CAA Net Base Services PROGRAM PLC_PRG VAR fbHttpClient : FB_HttpClient; // HTTP Client 主实例。 fbHttpServer : FB_HttpServer; // HTTP Server 主实例。 stClientMetrics : ST_HttpClientMetrics; // Client 指标输出。 stServerMetrics : ST_HttpServerMetrics; // Server 指标输出。 stClientResponse : ST_HttpResponse; // Client 响应输出。 aServerSnapshots : ARRAY[1..GVL_Http.cnMaxClientSlots] OF ST_HttpConnectionSnapshot; // Server 连接快照。 END_VAR // IMPLEMENTATION /// /// 名称 : PLC_PRG /// 功能 : HTTP 示例工程主任务直接完整调用 Client 和 Server 功能块。 /// 库依赖 : CAA Net Base Services /// /// 使用说明 : 1. Client/Server 所有真实网络命令默认关闭由 GVL_HttpRealTest 在线变量触发。 /// : 2. 本主程序完整列出功能块引脚便于 CODESYS/SmartControl 用户按引脚理解用法。 /// // 工程说明本段集中处理状态、边界或诊断避免跨周期残留。 // 约束PLC_PRG 作为示例主入口直接调用 HTTP 功能块用户联调不再依赖辅助 PRG。 GVL_HttpRealTest.udiNowMs : GVL_HttpRealTest.udiNowMs 10; IF GVL_HttpRealTest.bResetResults THEN fbHttpServer.M_Reset(); fbHttpClient.M_Reset(); GVL_HttpRealTest.bClientSend : FALSE; GVL_HttpRealTest.bClientAbort : FALSE; GVL_HttpRealTest.bServerPassLatched : FALSE; GVL_HttpRealTest.bClientPassLatched : FALSE; GVL_HttpRealTest.bOverallPassLatched : FALSE; END_IF fbHttpServer( xEnable : GVL_HttpRealTest.bServerEnable, xReset : GVL_HttpRealTest.bResetResults, xCloseConnection : GVL_HttpRealTest.bServerCloseConnection, bEnable : GVL_HttpRealTest.bServerEnable, sBindIP : GVL_HttpRealTest.sServerBindIP, uiPort : GVL_HttpRealTest.uiServerPort, uiResponseStatusCode : GVL_HttpRealTest.uiServerResponseStatusCode, sResponseBody : GVL_HttpRealTest.sServerResponseBody, sResponseContentType : GVL_HttpRealTest.sServerResponseContentType, sAdditionalHeader : GVL_HttpRealTest.sServerAdditionalHeader, udiNowMs : GVL_HttpRealTest.udiNowMs, xListening GVL_HttpRealTest.bServerListening, xRunning GVL_HttpRealTest.bServerRunning, xBusy GVL_HttpRealTest.bServerBusy, xError GVL_HttpRealTest.bServerError, bListening GVL_HttpRealTest.bServerListening, bRunning GVL_HttpRealTest.bServerRunning, bBusy GVL_HttpRealTest.bServerBusy, bError GVL_HttpRealTest.bServerError, diErrorID GVL_HttpRealTest.diServerErrorID, sDiagMsg GVL_HttpRealTest.sServerDiagMsg, eLastNbsError GVL_HttpRealTest.eServerLastNbsError, eState GVL_HttpRealTest.eServerState, eLastError GVL_HttpRealTest.eServerLastError, stMetrics stServerMetrics, uiActiveConnections GVL_HttpRealTest.uiServerActiveConnections, uiLastErrorSlot GVL_HttpRealTest.uiServerLastErrorSlot, uiLastRequestSlot GVL_HttpRealTest.uiServerLastRequestSlot, sRequestTarget GVL_HttpRealTest.sServerLastTarget, sRequestBody GVL_HttpRealTest.sServerLastBody, sRxMessage GVL_HttpRealTest.sServerRxMessage, sTxMessage GVL_HttpRealTest.sServerTxMessage, sLastTarget GVL_HttpRealTest.sServerLastTarget, sLastBody GVL_HttpRealTest.sServerLastBody, hListenHandle GVL_HttpRealTest.hServerListenHandle, aConnectionSnapshots aServerSnapshots ); fbHttpClient( xEnable : GVL_HttpRealTest.bClientEnable, xExecute : GVL_HttpRealTest.bClientSend, xReset : GVL_HttpRealTest.bResetResults, xAbort : GVL_HttpRealTest.bClientAbort, xCloseConnection : GVL_HttpRealTest.bClientCloseConnection, bEnable : GVL_HttpRealTest.bClientEnable, bSend : GVL_HttpRealTest.bClientSend, udiTimeOut : GVL_HttpRealTest.udiClientTimeoutUs, sURL : GVL_HttpRealTest.sClientURL, sServerIP : GVL_HttpRealTest.sClientServerIP, uiPort : GVL_HttpRealTest.uiClientPort, sHost : GVL_HttpRealTest.sClientHost, sPath : GVL_HttpRealTest.sClientPath, eRequestType : GVL_HttpRealTest.eClientMethod, eMethod : GVL_HttpRealTest.eClientMethod, sBody : GVL_HttpRealTest.sClientBody, sContentType : GVL_HttpRealTest.sClientContentType, sAdditionalHeader : GVL_HttpRealTest.sClientAdditionalHeader, udiNowMs : GVL_HttpRealTest.udiNowMs, xActive GVL_HttpRealTest.bClientTcpConnected, xConnected GVL_HttpRealTest.bClientTcpConnected, xBusy GVL_HttpRealTest.bClientBusy, xDone GVL_HttpRealTest.bClientDone, xError GVL_HttpRealTest.bClientError, bTcpConnected GVL_HttpRealTest.bClientTcpConnected, bBusy GVL_HttpRealTest.bClientBusy, bDone GVL_HttpRealTest.bClientDone, bError GVL_HttpRealTest.bClientError, diErrorID GVL_HttpRealTest.diClientErrorID, sDiagMsg GVL_HttpRealTest.sClientDiagMsg, eLastNbsError GVL_HttpRealTest.eClientLastNbsError, eState GVL_HttpRealTest.eClientState, eLastError GVL_HttpRealTest.eClientLastError, uiStatusCode GVL_HttpRealTest.uiClientStatusCode, sTxMessage GVL_HttpRealTest.sClientTxMessage, sRxMessage GVL_HttpRealTest.sClientRxMessage, sResponseBody GVL_HttpRealTest.sClientResponseBody, sResponseHeader GVL_HttpRealTest.sClientResponseHeader, stMetrics stClientMetrics, stResponse stClientResponse ); IF GVL_HttpRealTest.bClientSend THEN GVL_HttpRealTest.bClientSend : FALSE; END_IF IF GVL_HttpRealTest.bClientAbort THEN GVL_HttpRealTest.bClientAbort : FALSE; END_IF IF GVL_HttpRealTest.bResetResults THEN GVL_HttpRealTest.bResetResults : FALSE; END_IF GVL_HttpRealTest.udiServerAcceptedCount : stServerMetrics.udiAcceptedConnections; GVL_HttpRealTest.udiServerRequestCount : stServerMetrics.udiRequestCount; GVL_HttpRealTest.udiServerResponseCount : stServerMetrics.udiResponseCount; GVL_HttpRealTest.udiServerProtocolErrorCount : stServerMetrics.udiProtocolErrorCount; GVL_HttpRealTest.udiClientRequestCount : stClientMetrics.udiRequestCount; GVL_HttpRealTest.udiClientResponseCount : stClientMetrics.udiResponseCount; GVL_HttpRealTest.udiClientConnectErrorCount : stClientMetrics.udiConnectErrorCount; GVL_HttpRealTest.udiClientProtocolErrorCount : stClientMetrics.udiProtocolErrorCount; GVL_HttpRealTest.sClientReason : stClientResponse.sReason; IF (GVL_HttpRealTest.udiServerRequestCount 0) AND (GVL_HttpRealTest.udiServerResponseCount 0) AND NOT GVL_HttpRealTest.bServerError THEN GVL_HttpRealTest.bServerPassLatched : TRUE; END_IF IF GVL_HttpRealTest.bClientDone AND NOT GVL_HttpRealTest.bClientError AND (GVL_HttpRealTest.uiClientStatusCode 200) AND (GVL_HttpRealTest.uiClientStatusCode 300) THEN GVL_HttpRealTest.bClientPassLatched : TRUE; END_IF GVL_HttpRealTest.bOverallPassLatched : GVL_HttpRealTest.bServerPassLatched AND GVL_HttpRealTest.bClientPassLatched;本篇阅读抓手真机参数集中管理。编译触达防止对象未被工程引用。PLC_PRG 是运行装配点而不是业务大杂烩。如何验证这组源码先针对GVL_HttpRealTest.st的公开输入和错误出口建立确定性用例。再把“真机参数集中管理”转成至少一个正常场景和一个失败场景。本篇 4 个文件必须一起编译避免只验证单个函数而漏掉数据结构或调用边界。真机复核时重点观察“PLC_PRG 是运行装配点而不是业务大杂烩”并保留对应状态、计数和原始报文。这一篇你最该记住真机参数集中管理。编译触达防止对象未被工程引用。PLC_PRG 是运行装配点而不是业务大杂烩。系列导航系列CodeSys HTTP 系列教程第 26/28 篇。当前源码加更第 8/8 篇。本篇完整源码文件数4。上一篇第25篇下一篇第27篇

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询