1. 三菱PLC ST语言入门:从Modbus通讯开始
第一次接触三菱PLC的ST语言时,我被它的灵活性震惊了。相比传统的梯形图编程,ST语言更像是在用高级编程语言写代码,特别适合处理复杂的工业自动化逻辑。Modbus通讯是工业现场最常见的需求之一,我们就从这里开始实战。
在GX Works2中新建一个结构化工程,选择ST语言作为编程方式。Modbus RTU通讯需要先配置串口参数,这里有个小技巧:波特率建议设为9600,数据位8位,停止位1位,无校验。实际项目中遇到过通讯不稳定的情况,后来发现是校验位设置错误导致的。
// Modbus RTU主站初始化程序 IF NOT bInitDone THEN // 设置通讯参数 COM_Port[0].BaudRate := 9600; COM_Port[0].DataBits := 8; COM_Port[0].StopBits := 1; COM_Port[0].Parity := 0; // 无校验 COM_Port[0].Timeout := 1000; // 超时1秒 // 初始化完成标志 bInitDone := TRUE; END_IF;读取变频器频率的典型代码是这样的:
// 读取变频器频率(Modbus功能码03H) IF NOT bReading AND (uiCounter MOD 100 = 0) THEN // 每100ms读取一次 usSlaveAddr := 1; // 从站地址 usRegAddr := 100; // 寄存器地址 usLength := 1; // 读取长度 // 调用Modbus读取函数 iResult := MB_READ_HOLD_REG( Channel := 0, Slave := usSlaveAddr, Addr := usRegAddr, Length := usLength, DataPtr := ADR(uiFreqValue), Timeout := 1000 ); bReading := TRUE; END_IF; // 处理读取完成 IF bReading AND (iResult = 0) THEN // 频率值在uiFreqValue中 rActualFreq := uiFreqValue / 100.0; // 转换为实际频率值 bReading := FALSE; END_IF;调试Modbus通讯时,我习惯先用Modbus调试助手测试硬件线路和参数配置是否正确。遇到过最头疼的问题是终端电阻没接导致信号反射,通讯时好时坏。后来在总线两端各加了一个120Ω电阻,问题立刻解决。
2. 伺服控制实战:从单轴到多轴联动
伺服控制是工业自动化的核心,三菱的QD77MS模块配合ST语言能实现复杂的运动控制。第一次做伺服项目时,我花了三天才搞明白伺服参数的设置逻辑。
伺服使能的正确顺序应该是:
- 伺服ON
- 报警复位
- 等待伺服准备就绪
- 开始运动控制
// 伺服使能控制 IF NOT bServoReady THEN // 1. 伺服ON IF NOT bServoOn THEN ServoAxis[0].ServoOn := TRUE; bServoOn := TRUE; END_IF // 2. 报警复位 IF bServoOn AND ServoAxis[0].Alarm THEN ServoAxis[0].Reset := TRUE; END_IF // 3. 等待准备就绪 IF bServoOn AND NOT ServoAxis[0].Alarm AND ServoAxis[0].Ready THEN bServoReady := TRUE; END_IF END_IF;多轴联动的关键在于同步启动和位置同步。电子齿轮比设置是个容易出错的地方,我曾经因为分子分母设反导致轴运动方向相反。正确的设置应该是:
// 设置电子齿轮比(主轴到从轴) ServoAxis[1].GearRatioNumerator := 1; // 分子 ServoAxis[1].GearRatioDenominator := 2; // 分母 ServoAxis[1].GearMaster := 0; // 主轴编号 ServoAxis[1].GearMode := 1; // 电子齿轮模式凸轮曲线设计是另一个难点。三菱的CAM曲线可以用数组定义位置关系,我通常会在Excel里先计算好位置点,再导入到PLC中:
// 电子凸轮定义 CamCurve[0].MasterStart := 0; // 主轴起始位置 CamCurve[0].MasterEnd := 360; // 主轴结束位置 CamCurve[0].SlaveStart := 0; // 从轴起始位置 CamCurve[0].SlaveEnd := 100; // 从轴结束位置 CamCurve[0].CurveType := 2; // S曲线加减速3. 高级应用:电子凸轮与飞剪控制
电子凸轮在包装机械上应用广泛,它能实现机械凸轮难以达到的灵活性和精度。我做过一个饼干包装机的项目,需要根据饼干长度动态调整切刀位置。
飞剪控制的核心算法:
// 飞剪控制逻辑 IF bProductionRunning THEN // 计算切刀同步位置 rCutPosition := rProductLength * (iProductCount + 1); // 设置凸轮同步点 CamCurve[0].SlaveEnd := rCutPosition; // 触发切刀动作 IF rMasterPosition >= rCutPosition - rDecelDistance THEN bCutCommand := TRUE; END_IF; END_IF;PID参数调节是运动控制的另一个关键点。经过多次调试,我总结出一个实用的调试步骤:
- 先将积分时间Ti设为很大,微分时间Td设为0
- 逐步增大比例增益Kp直到系统开始振荡
- 将Kp设为振荡值的50%
- 逐步减小Ti直到消除静差
- 最后根据需要加入微分作用Td
// PID参数设置 ServoAxis[0].PID.Kp := 2.5; // 比例增益 ServoAxis[0].PID.Ti := 0.5; // 积分时间(s) ServoAxis[0].PID.Td := 0.1; // 微分时间(s)4. 工程实践中的代码优化技巧
在大型项目中,ST代码的组织方式直接影响维护效率。我习惯把程序分成几个部分:
- 设备控制层:直接操作硬件
- 工艺逻辑层:实现具体工艺
- 报警处理层:集中处理异常情况
结构体的使用可以大幅提高代码可读性:
// 定义伺服轴结构体 TYPE AxisStatus : STRUCT bEnabled : BOOL; // 使能状态 bAlarm : BOOL; // 报警状态 rPosition : REAL; // 当前位置 rSpeed : REAL; // 当前速度 END_STRUCT; END_TYPE // 使用结构体数组管理多轴 VAR Axis : ARRAY[0..3] OF AxisStatus; END_VAR功能块(FB)封装是另一个重要技巧。比如把Modbus通讯封装成可重用的功能块:
FUNCTION_BLOCK FB_ModbusReader VAR_INPUT bExecute : BOOL; // 执行触发 usSlaveAddr : UINT; // 从站地址 usRegAddr : UINT; // 寄存器地址 usLength : UINT; // 读取长度 END_VAR VAR_OUTPUT bDone : BOOL; // 完成标志 bError : BOOL; // 错误标志 iErrorCode : INT; // 错误代码 END_VAR VAR // 内部变量... END_VAR // 实现部分... END_FUNCTION_BLOCK调试复杂系统时,我通常会添加详细的调试信息输出:
// 调试信息记录 IF bDebugMode THEN sDebugMsg := CONCAT('Axis1 Pos:', REAL_TO_STRING(Axis[0].rPosition)); sDebugMsg := CONCAT(sDebugMsg, ' Speed:'); sDebugMsg := CONCAT(sDebugMsg, REAL_TO_STRING(Axis[0].rSpeed)); DebugLog(sDebugMsg); // 记录到调试缓冲区 END_IF;最后,分享一个实际项目中的经验:在编写关键运动控制逻辑时,一定要考虑异常情况的处理。比如伺服突然断电、通讯中断等情况,系统应该能够安全停止并报警。这比实现正常功能更重要,因为现场总会出现各种意想不到的情况。