上位机开发经验教训总结
--20191118更新程序,程序调整为使用状态机的方式实现
public void CircleMain() { while(true) { Thread.Sleep(100); #region 超时管理定时器计数 if (delay100Ms < int.MaxValue) { delay100Ms++; } #endregion #region 数据采集及变量映射 var result = ModbusPlc.ReadDiscrete("0", 7); if (!result.IsSuccess) { eSystemStatus = E_system_status.Error; continue; } bool[] mappingResult = result.Content; bReset = mappingResult[0]; bStop = mappingResult[1]; bBeforePrintSensor = mappingResult[2]; bPrintSensor = mappingResult[3]; bAfterPrintSensor = mappingResult[4]; bBeforeSingal = mappingResult[5]; bAfterSingal = mappingResult[6]; #endregion #region 急停按钮 if (bStop==false) { eSystemStatus = E_system_status.Error; } #endregion #region 状态机 switch (eSystemStatus) { case E_system_status.Idle: //开始前打印位置有产品,需要取出 if (bPrintSensor) { eSystemStatus = E_system_status.Error; statusMsg = "开始前打印位置有产品,需要取出后才能运行!"; } else { ModbusPlc.WriteCoil(FeedProductAddress, true); //前道要板命令 eSystemStatus = E_system_status.Feed; } break; case E_system_status.Feed: if (bBeforePrintSensor) { ModbusPlc.WriteCoil(MoveBeltAddress, true); ModbusPlc.WriteCoil(FeedProductAddress, false); ModbusPlc.WriteCoil(PrintPosCylinderAddress, true); eSystemStatus = E_system_status.Stable; delay100Ms = 0; } break; case E_system_status.Stable: //5S后还没有运行到打印位置,可能卡板或者传感器失效 if (delay100Ms > 30) { eSystemStatus = E_system_status.Error; statusMsg = "3S后还没有运行到打印位置,可能卡板或者传感器失效"; } if (bPrintSensor) { eSystemStatus = E_system_status.Ready; //正式喷码前触发一次喷印 TcpPrinter.SendData(new byte[] { 0x94, 0x00, 0x00, 0x94 }); delay100Ms = 0; } break; case E_system_status.Ready: if (delay100Ms > 10) { ModbusPlc.WriteCoil(MoveBeltAddress, false); eSystemStatus = E_system_status.Printing; statusMsg = "开始打印......"; //TcpClient.SendData(_startPrint); } break; case E_system_status.Printing: if (nRouteIndex < routeList.Count) { if (ePrintStep == EPrintStep.PrintIdle) { SendPrintPoint(impossiblePointList, false); MoveNextPoint(routeList[nRouteIndex].startX, routeList[nRouteIndex].startY, routeList[nRouteIndex].Angle); ePrintStep = EPrintStep.SendStartPoint; bMoveDone = false; } else if (ePrintStep == EPrintStep.SendStartPoint) { GetStatusOfRtexController(); if (bMoveDone) { ePrintStep = EPrintStep.MoveDoneStartPoint; } } else if (ePrintStep == EPrintStep.MoveDoneStartPoint) { ePrintStep = EPrintStep.SendEndPoint; SendPrinterData(routeList[nRouteIndex]); SendPrintPoint(routeList[nRouteIndex].printPointList, true); MoveNextPoint(routeList[nRouteIndex].endX, routeList[nRouteIndex].endY, routeList[nRouteIndex].Angle); bMoveDone = false; } else if (ePrintStep == EPrintStep.SendEndPoint) { GetStatusOfRtexController(); if (bMoveDone) { ePrintStep = EPrintStep.PrintIdle; nRouteIndex++; } } } else { eSystemStatus = E_system_status.PrintPreEnd; nRouteIndex = 0; } break; case E_system_status.PrintPreEnd: if (bAfterSingal) { MoveToHome(); ModbusPlc.WriteCoil(PrintPosCylinderAddress, false); //气缸下降 ModbusPlc.WriteCoil(MoveBeltAddress, true); //输送带启动 eSystemStatus = E_system_status.PrintEnd; delay100Ms = 0; } break; case E_system_status.PrintEnd: //卡板或者传感器失效 if (delay100Ms > 50) { eSystemStatus = E_system_status.Error; statusMsg = "输出卡板或者后端传感器失效"; } if (!bAfterSingal) { ModbusPlc.WriteCoil(MoveBeltAddress, false); eSystemStatus = E_system_status.Idle; statusMsg = "打印完成,设备等待打印"; } break; case E_system_status.Error: ModbusPlc.WriteCoil(RedLampAddress, true); ModbusPlc.WriteCoil(GreenLampAddress, false); ModbusPlc.WriteCoil(AlarmBeepAddress, true); if(bReset) { ModbusPlc.WriteCoil(RedLampAddress, false); ModbusPlc.WriteCoil(GreenLampAddress, true); ModbusPlc.WriteCoil(AlarmBeepAddress, false); eSystemStatus = E_system_status.Idle; statusMsg = "已复位"; } break; default: break; } #endregion #region 显示状态 Action<string> actionDisplayStatus = (msg) => { this.lblStatus.Text = msg; }; Invoke(actionDisplayStatus, statusMsg + " " + ePrintStep.ToString()); #endregion } }
总结下面几点
1.与下位机的连接尽量保持长连接,每次用到的时候去连接的话,过一段时间速度明显下降,什么问题并没有找到
2.C#中的BitConverter 类可以非常方便的在字节与其他类型之间进行转换
3.周期性操作使用while循环,避免使用timer定时器
4.操作一些标志位的操作,尽量放到一个线程中,多个线程同时操作变量容易产生奇怪的错误