private void BroadcastTimer_Elapsed(object sender, ElapsedEventArgs e) { TxRxStatus = TranmitingStatus.Idle; BroadcastTimer.Enabled = false; Console.Write("Broadcasting done!"); IsBroadcastTimeout = true; }
private void ACKTimer_Elapsed(object sender, ElapsedEventArgs e) { TxRxStatus = TranmitingStatus.Idle; ACKTimer.Enabled = false; Console.Write("NO ACK!"); IsACKTimeout = true; }
public void ModbusReceiveData_SerialPort(object sender, SerialDataReceivedEventArgs e) //供外部SerialPort调用的数据接收事件 { RxDataTimer.Enabled = false; //定时器停止计数并将计数值归零 RxDataTimer.Enabled = true; //定时器重新开始计数 TxRxStatus = TranmitingStatus.Receiving; //Modbus状态为标记为“接收中” UInt16 n = (UInt16)((SerialPort)sender).BytesToRead; //先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致 ((SerialPort)sender).Read(TxRxBuffer, Pointer, n); //读取缓冲数据 Pointer += n; //增加接收计数 RxLength = Pointer; }
public byte Disassemble_ReceivedADU() { if (IsMaster == true) { if (StationID != TxRxBuffer[0]) //站号错误不进行任何处理,立即返回(ACKTimeout定时器继续定时) { return((byte)ErrorStatus.ERR_Station); } ACKTimer.Enabled = false; //通过上面站号检测的说明是期望子节点发送来的响应帧,因而停止ACKTimeout倒计时。 TxRxStatus = TranmitingStatus.Idle; //总线状态置为空闲,允许发送其他帧(会不会放在本函数最后好,不然要是Modbus发送了其他的帧,并接收了返回的帧,上一次此处的处理还未完成怎么办?) if (RxLength < 5) { return((byte)ErrorStatus.ERR_BreakFrame); } TempWord.HByte = TxRxBuffer[RxLength - 2]; TempWord.LByte = TxRxBuffer[RxLength - 1]; if (TempWord.Word != CRCCaculation.CRC16(TxRxBuffer, (UInt16)(RxLength - 2))) { return((byte)ErrorStatus.ERR_CRCCode); //检测CRC是否错误 } FunctionCode = TxRxBuffer[1]; //记录功能码 switch (FunctionCode) { case (byte)ModbusFuncCode.WriteSingleCoil: case (byte)ModbusFuncCode.WriteCoils: case (byte)ModbusFuncCode.WriteRegs: case (byte)ModbusFuncCode.WriteSingleReg: TempWord.HByte = TxRxBuffer[2]; //检查地址是否正确 TempWord.LByte = TxRxBuffer[3]; if (TempWord.Word != Address) { return((byte)ErrorStatus.ERR_Address); } TempWord.HByte = TxRxBuffer[4]; //检查写入单元数量或写入的单个数据是否正确 TempWord.LByte = TxRxBuffer[5]; if (TempWord.Word != NumOrData) { return((byte)ErrorStatus.ERR_NumOrData); } ModbusWriteSuccessEvent(); //(事件引发)如果以上均正确,说明Modbus主向外写操作成功,引发“写成功”事件 break; case (byte)ModbusFuncCode.ReadCoils: case (byte)ModbusFuncCode.ReadDistrbuteBits: case (byte)ModbusFuncCode.ReadStorageRegs: case (byte)ModbusFuncCode.ReadInputRegs: DataByteNumber = TxRxBuffer[2]; DataStorage[TempControlIndex] = new byte[DataByteNumber]; for (byte i = 0; i < DataByteNumber; i++) { DataStorage[TempControlIndex][i] = TxRxBuffer[i + 3]; } ModbusReadSuccessEvent(); //(事件引发)如果以上均正确,说明Modbus主读输入寄存器成功,引发“读输入寄存器成功”事件 break; case ((byte)ModbusFuncCode.ReadCoils + 0x80): case ((byte)ModbusFuncCode.ReadDistrbuteBits + 0x80): case ((byte)ModbusFuncCode.ReadStorageRegs + 0x80): case ((byte)ModbusFuncCode.ReadInputRegs + 0x80): case ((byte)ModbusFuncCode.WriteSingleCoil + 0x80): case ((byte)ModbusFuncCode.WriteSingleReg + 0x80): case ((byte)ModbusFuncCode.WriteCoils + 0x80): case ((byte)ModbusFuncCode.WriteRegs + 0x80): ModbusReceiveExceptionEvent(); //(事件引发)接收到异常帧 return((byte)ErrorStatus.ERR_Response); default: return((byte)ErrorStatus.ERR_FunctionCode); //检测FunctionCode是否错误 } } else { //Slaver To Do... } return((byte)ErrorStatus.ERR_OK); }
private Boolean MasterSendFrame() { byte[] TxBuffer; Console.Write(TxRxStatus + "\n"); if (TxRxStatus == TranmitingStatus.Idle) { if ((HighPriorityFrameRdy == true) || (LowPriorityFrameRdy == true)) { Console.Write(LowPriorityTxBufferQueue.Count + " " + LPControlsIndexQueue.Count + "\n"); if (HighPriorityFrameRdy == true) { if (HighPriorityTxBufferQueue.Count <= 0)//如过FIFO空,则复位Ready标志位,禁止周期行为 { HighPriorityFrameRdy = false; return(true); } lock (HighPriorityTxBufferQueue)//锁定,防止线程间串扰(非常重要) { lock (HPControlsIndexQueue) { TxBuffer = HighPriorityTxBufferQueue.Dequeue(); //从FIFO中取用待发送的帧 TempControlIndex = HPControlsIndexQueue.Dequeue(); //取用待发送帧对应的控件的索引 } } } else { if (LowPriorityTxBufferQueue.Count <= 0) { LowPriorityFrameRdy = false; return(true); } lock (LowPriorityTxBufferQueue) { lock (LPControlsIndexQueue) { TxBuffer = LowPriorityTxBufferQueue.Dequeue(); TempControlIndex = LPControlsIndexQueue.Dequeue(); } } } //Console.Write(TxBuffer.Length); try //此处不能用if语句简化 { ModbusSendFrame(TxBuffer, 0, TxBuffer.Length); //调用发送函数(委托) } catch { Console.Write("Error:ModbusSendFrame未关联 或 Serialport未打开!\n"); return(false); } TxRxStatus = TranmitingStatus.Sending; //Modbus收发标志位置 “发送中” if (TxBuffer[0] == 0) //此处用到StationID,说明全局的StationID变量是必要的,不可弃用 { IsBroadcastTimeout = false; //如果是广播帧,先清广播帧超时标志位(其实没必要,只是为了以防不可预知的改变) BroadcastTimer.Enabled = true; //打开广播帧超时定时器 } else { IsACKTimeout = false; ACKTimer.Enabled = true; } } } return(true); }
private void ModbusRTU_ModbusReadSuccessEvent() { DataStorageFlag[TempControlIndex] = true; TxRxStatus = TranmitingStatus.Idle; }