去年接手了一个食品加工厂的自动化改造项目,他们需要一套能同时管理16种原料配比的自动化控制系统。作为从业十多年的工控老鸟,我决定采用三菱FX3U PLC作为主控,搭配ST语言与梯形图混合编程的方案。这个系统最核心的挑战在于要同时处理两台电子秤的实时数据、控制16台变频器,还要实现配方灵活配置和生产数据追溯。经过三个月的开发和调试,最终完成的程序达到12984步,支持1-16种配方的自由配置,通过条形码或触摸屏都能快速切换生产模式。
系统采用FX3U-48MT/ES-A作为主控单元,这是三菱中型PLC中的经典款。考虑到要处理16个仓位的配料控制,我特别扩展了以下模块:
硬件选型心得:485ADP模块一定要选带MB后缀的版本,这是专门为MODBUS协议优化的型号,通讯稳定性比普通485模块高30%以上。
整个程序采用分层设计:
st复制// 典型的结构体定义示例
TYPE T_Recipe :
STRUCT
MaterialNo : ARRAY[1..16] OF INT; // 原料编号
TargetWeight : ARRAY[1..16] OF REAL; // 目标重量
FastFeedSpeed : ARRAY[1..16] OF REAL; // 快加速度
SlowFeedSpeed : ARRAY[1..16] OF REAL; // 慢加速度
END_STRUCT
END_TYPE
配方数据采用结构体数组存储,支持16种配方的动态加载。每个配方包含:
st复制// 配方数据初始化示例
VAR
RecipeDB : ARRAY[1..16] OF T_Recipe;
CurrentRecipe : INT := 1;
END_VAR
// 加载配方函数
FUNCTION LoadRecipe : BOOL
VAR_INPUT
RecipeNo : INT;
END_VAR
BEGIN
IF (RecipeNo >= 1) AND (RecipeNo <= 16) THEN
CurrentRecipe := RecipeNo;
RETURN TRUE;
ELSE
RETURN FALSE;
END_IF
END_FUNCTION
采用MODBUS RTU协议通过FX3U-485ADP读取电子秤数据。关键点在于:
st复制// 电子秤读取函数块
FUNCTION_BLOCK FB_ScaleReader
VAR_INPUT
ScaleAddr : INT; // 从站地址
RegAddr : INT; // 寄存器地址
Timeout : TIME := T#1S; // 超时时间
END_VAR
VAR_OUTPUT
Weight : REAL; // 实际重量
Status : INT; // 状态码
END_VAR
VAR
TempData : WORD;
END_VAR
BEGIN
// 使用ADPRW指令读取数据
ADPRW(
S1 := ScaleAddr,
S2 := RegAddr,
D := @TempData,
N := 2
);
// 数据转换(假设电子秤返回值为整数,单位0.01kg)
Weight := WORD_TO_REAL(TempData) / 100.0;
END_FUNCTION_BLOCK
采用三段式控制策略:
st复制// 变频器控制函数
FUNCTION ControlFeeder : BOOL
VAR_INPUT
Channel : INT; // 通道号
CurrentWeight : REAL; // 当前重量
TargetWeight : REAL; // 目标重量
END_VAR
VAR
OutputValue : REAL;
BEGIN
// 计算剩余量
VAR
Remaining : REAL := TargetWeight - CurrentWeight;
END_VAR
// 三段式控制逻辑
IF Remaining > (TargetWeight * 0.1) THEN
OutputValue := 100.0; // 全速运行
ELSIF Remaining > (TargetWeight * 0.02) THEN
OutputValue := 30.0; // 低速运行
ELSE
OutputValue := 10.0; // 点动模式
END_IF
// 调用模拟量输出
DA_Output(
Channel := Channel,
Value := OutputValue
);
RETURN TRUE;
END_FUNCTION
FX3U-4DA模块输出配置要点:
st复制// 模拟量输出函数块
FUNCTION_BLOCK FB_DA_Output
VAR_INPUT
Channel : INT; // 通道号1-4
Value : REAL; // 输出值0-100%
END_VAR
VAR
OutputCode : INT;
END_VAR
BEGIN
// 将百分比转换为输出代码(FX3U-4DA为0-4000对应0-10V)
OutputCode := REAL_TO_INT(Value * 40.0);
// 写入输出通道(以通道1为例)
CASE Channel OF
1: TO D1000 := OutputCode;
2: TO D1001 := OutputCode;
3: TO D1002 := OutputCode;
4: TO D1003 := OutputCode;
END_CASE
END_FUNCTION_BLOCK
采用循环存储方式记录以下数据:
st复制// 生产记录结构体
TYPE T_ProductionRecord :
STRUCT
RecipeNo : INT; // 配方号
MaterialNo : INT; // 原料号
TargetWeight : REAL; // 目标值
ActualWeight : REAL; // 实际值
Error : REAL; // 误差
Timestamp : DT; // 时间戳
END_STRUCT
END_TYPE
// 数据记录函数
FUNCTION RecordData : BOOL
VAR_INPUT
Record : T_ProductionRecord;
END_VAR
VAR
Index : INT;
END_VAR
BEGIN
// 寻找空记录位(最多存储1000条记录)
FOR Index := 0 TO 999 DO
IF ProductionDB[Index].RecipeNo = 0 THEN
ProductionDB[Index] := Record;
RETURN TRUE;
END_IF
END_FOR
// 存储空间已满,覆盖最早记录
ProductionDB[OldestIndex] := Record;
OldestIndex := (OldestIndex + 1) MOD 1000;
RETURN TRUE;
END_FUNCTION
主屏MT8101IE与从屏MT6071IP通过以太网连接,关键配置:
st复制// 触摸屏数据同步处理
FUNCTION SyncHMI : BOOL
VAR
i : INT;
END_VAR
BEGIN
// 同步配方数据
FOR i := 1 TO 16 DO
HMI_Recipe[i] := RecipeDB[i];
END_FOR
// 同步生产状态
HMI_Status := SystemStatus;
RETURN TRUE;
END_FUNCTION
将报警分为三个级别:
st复制// 报警处理函数
FUNCTION ProcessAlarm : INT
VAR_INPUT
AlarmCode : INT;
AlarmMsg : STRING[50];
END_VAR
BEGIN
// 记录报警信息
AlarmHistory[AlarmIndex].Code := AlarmCode;
AlarmHistory[AlarmIndex].Message := AlarmMsg;
AlarmHistory[AlarmIndex].Time := NOW();
AlarmIndex := (AlarmIndex + 1) MOD 100;
// 根据报警代码确定等级
CASE AlarmCode OF
1..100: RETURN 1; // 警告级
101..200: RETURN 2; // 故障级
ELSE: RETURN 3; // 紧急级
END_CASE
END_FUNCTION
常见故障及处理方法:
电子秤通讯超时:
变频器无响应:
配方数据异常:
命名规则:
注释要求:
st复制// 典型函数注释示例
/*
* 函数名称:ControlFeeder
* 功能描述:控制给料机运行速度
* 输入参数:
* Channel - 通道号(1-16)
* CurrentWeight - 当前重量(kg)
* TargetWeight - 目标重量(kg)
* 返回值:BOOL - 执行结果
* 创建日期:2023-05-10
* 修改记录:
* //MOD20230615 增加点动模式控制
*/
FUNCTION ControlFeeder : BOOL
// 函数体...
END_FUNCTION
扫描周期优化:
内存管理建议:
通讯优化方案:
这个项目让我深刻体会到结构化编程的重要性。当程序规模超过1万步时,良好的架构设计能节省至少50%的调试时间。特别是将设备控制、业务逻辑、人机界面分层处理的做法,使得后期维护和功能扩展变得非常方便。