工业软件里,顺序程序控制最常见、最稳妥的是:
👉「状态机(Step / State) + 周期扫描(Timer/Loop) + 条件推进」
👉 延时用 TON(或等效逻辑),而不是 Thread.Sleep / await Delay
这就是PLC 思想在上位机里的延续。
工业顺序控制常见写法排名(按"真实使用率")
✅ 第一名(⭐⭐⭐⭐⭐):
状态机(Step)+ 周期扫描(Timer)【最常见】
写法特征
switch (Step)
{
case 10:
if (条件A)
Step = 20;
break;
case 20:
if (ton.Q(3000))
{
ton.Reset();
Step = 30;
}
break;
}
//----------------------------下面用一个简单的示例,说明此种写法的好处---------------------------------
第一步:先定义一个定时器类
public sealed class Ton
{
private bool _running = false;
private long _startTick = 0;
public void Reset()
{
_running = false;
_startTick = 0;
}
// 返回 true 表示"到时了"(相当于 TON.Q)
public bool Q(int presetMs)
{
if (!_running)
{
_running = true;
_startTick = Environment.TickCount64;
}
long elapsed = Environment.TickCount64 - _startTick;
return elapsed >= presetMs;
}
}
第二步:定义步序枚举类型和定时器实例化、枚举实例化
// ===== 步序枚举 =====
private enum Step
{
step10 = 0,
step20 = 10,
step30 = 20,
step40 = 30,
step50 = 40,
step60 = 50,
step70 = 900
}
// ===== TON 定时器(PLC 的 TON)=====
private readonly Ton _ton = new Ton();
//枚举实例化
private Step stepNumber = Step.step10;
第三步:开始在定时器中编写顺序控制逻辑
private async void timer1_Tick(object sender, EventArgs e)
{
switch (stepNumber)
{
case Step.step10:
_ton.Reset();
if (stepNumber == Step.step10)
{
richTextBox1.AppendText(DateTime.Now + " step10" + "\r\n");
}
stepNumber = Step.step20;
break;
case Step.step20:
stepNumber = Step.step30;
Step1 = 100; //标志位赋值
if (stepNumber == Step.step20)
{
richTextBox1.AppendText(DateTime.Now + " step20" + "\r\n");
}
break;
case Step.step30:
if (Step1==100)
{
Step1= 0; //标志位清零
richTextBox1.AppendText(DateTime.Now + " step30" + "\r\n");
}
if(_ton.Q(4000))
{
stepNumber = Step.step40;
}
break;
case Step.step40:
if (stepNumber == Step.step40)
{
richTextBox1.AppendText(DateTime.Now + " step40" + "\r\n");
stepNumber = Step.step50;
}
break;
case Step.step50:
if (stepNumber == Step.step50)
{
richTextBox1.AppendText(DateTime.Now + " step50" + "\r\n");
stepNumber = Step.step60;
}
break;
}
}
//-----------下面是输出的结果----------------
打印出来的结果如下:
