1. 欧姆龙NJ/NX PLC全ST程序框架解析
在锂电新能源行业项目中,我最近完成了一套基于欧姆龙NJ/NX系列PLC的全ST语言开发框架。这套框架经过半年多的实际产线验证,已经稳定运行于多个锂电池生产车间。与传统的梯形图编程不同,全ST实现的公司级框架具有更好的可维护性和扩展性,特别适合工艺复杂的自动化产线。
1.1 框架整体架构设计
这套框架采用模块化设计思路,主要包含以下核心功能块:
- 设备状态管理(状态机实现)
- 通信协议栈(Socket客户端/服务器)
- 运动控制(汇川机器人集成)
- 生产数据统计(PPM、OEE等KPI计算)
- 人机交互(三色灯、蜂鸣器控制)
- 执行机构控制(气缸、真空系统)
每个功能块都采用标准化的接口设计,通过全局数据区进行交互。这种架构最大的优势是当需要增加新设备时,只需组合现有功能块并调整参数即可快速实现,典型场景下的模块复用率可达80%以上。
重要提示:在框架设计初期就要定义好全局变量命名规范,建议采用"模块前缀_功能描述"的格式(如IO_DI_StartButton),避免后期变量混乱。
1.2 ST语言开发优势
相比传统梯形图,ST语言在复杂逻辑实现上具有明显优势:
- 数学运算处理更直观
- 结构化编程支持更好
- 算法实现更简洁
- 代码可读性更高
- 便于版本管理
特别是在状态机实现上,ST语言的CASE语句比梯形图的跳转指令更清晰:
st复制CASE currentState OF
IDLE:
IF startSignal THEN
currentState := RUNNING;
END_IF;
RUNNING:
processTimer(IN:=TRUE, PT:=T#5s);
IF processTimer.Q THEN
currentState := FINISHED;
END_IF;
FINISHED:
currentState := IDLE;
END_CASE;
2. 核心功能模块实现细节
2.1 设备状态管理模块
产线设备的状态管理是框架的核心,我们采用分层状态机设计:
st复制TYPE T_DeviceState : (
POWER_OFF, // 断电状态
INITIALIZING, // 初始化中
READY, // 待机就绪
RUNNING, // 运行中
PAUSED, // 暂停状态
ALARM, // 报警状态
MAINTENANCE // 维护模式
);
状态切换时同步记录时间戳,用于计算设备综合效率(OEE):
st复制// 状态持续时间统计
IF currentState <> lastState THEN
stateChangeTime := NOW();
CASE lastState OF
RUNNING: totalRuntime := totalRuntime + (stateChangeTime - lastChangeTime);
ALARM: totalAlarmTime := totalAlarmTime + (stateChangeTime - lastChangeTime);
END_CASE;
lastChangeTime := stateChangeTime;
lastState := currentState;
END_IF;
2.2 Socket通信实现
NJ系列PLC的Socket通信功能非常强大,我们实现了以下通信模式:
- PLC作为客户端连接上位机
- PLC作为服务器接受HMI连接
- 断线自动重连机制
- 数据包完整性校验
典型客户端实现代码:
st复制FUNCTION_BLOCK FB_SocketClient
VAR
socketHandle : UINT;
serverAddr : sockaddr_in;
connectRetryTimer : TON;
END_VAR
// 创建Socket实例
socketHandle := SysSocketCreate(SOCKET_TYPE_STREAM);
IF socketHandle = INVALID_SOCKET THEN
// 错误处理
RETURN;
END_IF;
// 配置服务器地址
serverAddr.sin_family := AF_INET;
serverAddr.sin_port := HTONS(502);
serverAddr.sin_addr.s_addr := INET_ADDR(192,168,1,100);
// 非阻塞式连接
IF NOT connected THEN
connectResult := SysSocketConnect(socketHandle, serverAddr);
IF connectResult = SOCKET_ERROR THEN
connectRetryTimer(IN:=TRUE, PT:=T#5s);
IF connectRetryTimer.Q THEN
connectRetryTimer(IN:=FALSE);
// 重试连接
END_IF;
ELSE
connected := TRUE;
END_IF;
END_IF;
经验分享:Socket连接一定要添加心跳包机制,我们采用每30秒发送一次心跳数据包,超时3次未响应则认为连接已断开。
2.3 三色灯控制功能块
产线设备状态指示是人机交互的重要部分,三色灯控制逻辑需要考虑:
- 状态优先级(报警>警告>运行)
- 闪烁模式配置
- 远程测试功能
完整实现代码:
st复制FUNCTION_BLOCK FB_LightControl
VAR_INPUT
i_Alarm : BOOL; // 红色报警
i_Warning : BOOL; // 黄色警告
i_Running : BOOL; // 绿色运行
i_TestMode : BOOL; // 测试模式
i_BlinkPeriod : TIME := T#1s; // 闪烁周期
END_VAR
VAR_OUTPUT
q_RedLamp : BOOL;
q_YellowLamp : BOOL;
q_GreenLamp : BOOL;
END_VAR
VAR
blinkTimer : TON;
blinkState : BOOL;
END_VAR
// 闪烁信号生成
blinkTimer(IN:=TRUE, PT:=i_BlinkPeriod);
IF blinkTimer.Q THEN
blinkState := NOT blinkState;
blinkTimer(IN:=FALSE);
END_IF;
// 测试模式优先
IF i_TestMode THEN
q_RedLamp := blinkState;
q_YellowLamp := NOT blinkState;
q_GreenLamp := blinkState;
ELSE
// 正常状态控制
IF i_Alarm THEN
q_RedLamp := TRUE;
q_YellowLamp := FALSE;
q_GreenLamp := FALSE;
ELSIF i_Warning THEN
q_RedLamp := FALSE;
q_YellowLamp := TRUE;
q_GreenLamp := FALSE;
ELSE
q_RedLamp := FALSE;
q_YellowLamp := FALSE;
q_GreenLamp := i_Running;
END_IF;
END_IF;
3. 生产数据统计模块
3.1 PPM(每分钟生产件数)计算
PPM是衡量产线效率的重要指标,计算公式为:
code复制PPM = (OK数量 + NG数量) / 运行时间(分钟)
实现代码:
st复制FUNCTION_BLOCK FB_PPMCalculator
VAR_INPUT
i_CountOK : BOOL; // OK计数脉冲
i_CountNG : BOOL; // NG计数脉冲
i_Reset : BOOL; // 重置统计
END_VAR
VAR_OUTPUT
q_PPM : REAL; // 当前PPM值
q_TotalOK : UINT; // 总OK数
q_TotalNG : UINT; // 总NG数
END_VAR
VAR
runTimer : TON;
lastUpdateTime : TIME;
lastOKCount : UINT;
lastNGCount : UINT;
END_VAR
// 计数逻辑
IF i_Reset THEN
q_TotalOK := 0;
q_TotalNG := 0;
lastUpdateTime := NOW();
ELSIF i_CountOK AND NOT i_CountOK_Last THEN
q_TotalOK := q_TotalOK + 1;
ELSIF i_CountNG AND NOT i_CountNG_Last THEN
q_TotalNG := q_TotalNG + 1;
END_IF;
// 每分钟更新一次PPM
IF NOW() - lastUpdateTime >= T#1m THEN
q_PPM := (q_TotalOK - lastOKCount + q_TotalNG - lastNGCount) /
(TO_REAL(TIME_TO_SEC(NOW() - lastUpdateTime)) / 60.0);
lastOKCount := q_TotalOK;
lastNGCount := q_TotalNG;
lastUpdateTime := NOW();
END_IF;
i_CountOK_Last := i_CountOK;
i_CountNG_Last := i_CountNG;
3.2 设备综合效率(OEE)计算
OEE由三个要素组成:
- 时间利用率(Availability)
- 性能效率(Performance)
- 质量合格率(Quality)
计算公式:
code复制OEE = Availability × Performance × Quality
具体实现时需要注意:
- 计划停机时间不应计入总时间
- 小停机时间(<2分钟)需要特殊处理
- 性能基准需要根据产品类型配置
4. 运动控制模块实现
4.1 汇川机器人控制
与汇川机器人的通信采用Modbus TCP协议,主要实现以下功能:
- 点位运动控制
- 当前状态读取
- 错误代码解析
- 参数组切换
典型运动指令实现:
st复制FUNCTION_BLOCK FB_RobotMove
VAR_INPUT
i_Position : REAL; // 目标位置(mm)
i_Speed : REAL; // 运动速度(mm/s)
i_Accel : REAL; // 加速度(mm/s²)
i_Start : BOOL; // 启动信号
END_VAR
VAR_OUTPUT
q_Done : BOOL; // 运动完成
q_Busy : BOOL; // 运动中
q_Error : BOOL; // 错误状态
END_VAR
VAR
moveCmd : MC_MoveAbsolute;
axisStatus : MC_AxisStatus;
END_VAR
// 运动指令触发
IF i_Start AND NOT q_Busy THEN
moveCmd(
Axis := RobotAxis,
Position := i_Position,
Velocity := i_Speed,
Acceleration := i_Accel,
Deceleration := i_Accel,
BufferMode := MC_BUFFERED,
Execute := TRUE
);
END_IF;
// 状态监控
axisStatus(Axis := RobotAxis);
q_Busy := axisStatus.Moving;
q_Done := axisStatus.InPosition AND NOT axisStatus.Moving;
q_Error := axisStatus.Error;
4.2 轴参数动态调整
在锂电池生产过程中,不同型号产品的重量差异较大,需要动态调整运动参数:
st复制FUNCTION_BLOCK FB_DynamicAxisParam
VAR_INPUT
i_ProductType : INT; // 产品类型
i_Apply : BOOL; // 应用参数
END_VAR
VAR
paramSets : ARRAY[1..5] OF T_AxisParam;
currentParam : T_AxisParam;
END_VAR
// 参数定义
TYPE T_AxisParam : STRUCT
speed : REAL;
accel : REAL;
jerk : REAL;
END_STRUCT
// 根据产品类型选择参数集
CASE i_ProductType OF
1: currentParam := paramSets[1]; // 轻型产品
2: currentParam := paramSets[2]; // 标准产品
3: currentParam := paramSets[3]; // 重型产品
ELSE currentParam := paramSets[4]; // 默认参数
END_CASE;
// 应用参数
IF i_Apply THEN
MC_WriteParameter(
Axis := RobotAxis,
Parameter := 'Velocity',
Value := currentParam.speed
);
MC_WriteParameter(
Axis := RobotAxis,
Parameter := 'Acceleration',
Value := currentParam.accel
);
END_IF;
5. 报警管理系统
5.1 报警分级处理
我们将报警分为三个级别:
- 一级报警(紧急停止)
- 二级报警(工艺异常)
- 三级报警(提示信息)
报警处理流程:
st复制FUNCTION_BLOCK FB_AlarmManager
VAR_INPUT
i_AlarmCode : UINT; // 报警代码
i_Acknowledge : BOOL; // 确认信号
END_VAR
VAR_OUTPUT
q_EmergencyStop : BOOL; // 急停输出
q_AlarmActive : BOOL; // 报警状态
q_AlarmMessage : STRING;// 报警信息
END_VAR
VAR
activeAlarms : ARRAY[1..50] OF UINT;
alarmPriority : UINT;
END_VAR
// 报警代码解析
alarmPriority := i_AlarmCode >> 16 AND 16#FF;
// 根据优先级处理
CASE alarmPriority OF
1: // 一级报警
q_EmergencyStop := TRUE;
q_AlarmActive := TRUE;
2: // 二级报警
q_AlarmActive := TRUE;
3: // 三级报警
IF NOT i_Acknowledge THEN
q_AlarmActive := TRUE;
END_IF;
END_CASE;
// 报警信息生成
q_AlarmMessage := GetAlarmDescription(i_AlarmCode);
5.2 报警历史记录
采用环形缓冲区存储最近的100条报警记录:
st复制// 报警记录结构
TYPE T_AlarmRecord : STRUCT
code : UINT;
timestamp : DT;
acknowledged : BOOL;
END_STRUCT
VAR
alarmHistory : ARRAY[0..99] OF T_AlarmRecord;
alarmPointer : UINT;
END_VAR
// 添加新记录
IF newAlarm THEN
alarmHistory[alarmPointer MOD 100] := (
code := i_AlarmCode,
timestamp := NOW(),
acknowledged := FALSE
);
alarmPointer := alarmPointer + 1;
END_IF;
6. 框架部署经验分享
6.1 调试技巧
- 在线监视时使用变量筛选功能,按模块前缀过滤变量
- 复杂逻辑先用仿真器测试,再上机调试
- 关键变量添加注释和物理单位
- 使用交叉引用检查变量使用情况
6.2 性能优化
- 高频扫描的任务放在快速任务周期
- 大型数组操作使用BLKMOV指令
- 字符串处理尽量使用固定长度
- 网络通信采用非阻塞模式
6.3 常见问题解决
- 内存泄漏:定期检查动态分配的资源
- 通信超时:调整重试机制和超时参数
- 运动控制抖动:优化加减速曲线
- 报警误触发:添加滤波延时
这套框架在实际项目中已经过多次迭代优化,目前稳定运行于多条锂电池产线。最大的收获是标准化设计带来的维护便利性,新工程师接手项目时,只需了解功能块的接口定义就能快速开展工作。对于准备采用欧姆龙NJ/NX系列PLC开发复杂项目的团队,建议尽早建立自己的标准化功能库,长期来看将大幅提高开发效率和质量稳定性。