using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;
namespace xxxxx
{
class MODBUS_RTU
{
SerialPort serialPort;
object obj;//用来接收寄存器的数据,因为寄存器的数据有3种情况,所以不能直接用byte接收
//仅提供给monitorThread线程使用,多线程访问数据可能会发生错误
public byte r_data;//线圈的数据
public float dt_Fdata;//2个寄存器的数据(小数)
public short dt_Int16;//单个寄存器的数据
public int dt_Int32;//2个寄存器的数据(整数)
public void ComConfig()
{
if (serialPort != null) return;
serialPort = new SerialPort();
serialPort.PortName = "COM7";
serialPort.BaudRate = 9600;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
serialPort.Parity = Parity.None;
serialPort.Open();
}
#region PLC读写
/// <summary>
/// 从缓冲区拿数据
/// </summary>
/// <returns></returns>
public byte[] GetSerialPortData(int dataLength)
{
while (true)
{
if (serialPort.BytesToRead == dataLength)
{
int reallength = serialPort.BytesToRead;
byte[] refbyte = new byte[reallength];
serialPort.Read(refbyte, 0, reallength);
return refbyte;
}
}
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="sendbyte"></param>
/// <returns></returns>
public bool ComSend(byte[] sendbyte)
{
lock (this)
{
try
{
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
serialPort.Write(sendbyte, 0, sendbyte.Length);
//Thread.Sleep(10);
}
catch
{
//System.Windows.Forms.MessageBox.Show("下位机连接异常,发送数据失败!", "连接异常");
return false;
}
return true;
}
}
/// <summary>
/// 读取DT寄存器数据数据
/// </summary>
/// <param name="station">PLC地址</param>
/// <param name="addres">数据地址</param>
/// <param name="addres_cout">数据地址个数</param>
// dataType:0,int32;1,float,只有在addres_cout为2的时候才生效
public void DT_ReadData(int station, int addres, int addres_cout, int dataType)
{
lock (this)
{
if (!serialPort.IsOpen) return;
int dataLength = addres_cout * 2 + 5;//返回的数据长度
#region 发送数据
//松下PLC的数据在发送前要做右移和异或校验
byte g_add = (byte)(addres >> 8);
byte d_add = (byte)(addres & 0xFF);
byte g_data = (byte)(addres_cout >> 8);
byte d_data = (byte)(addres_cout & 0xFF);
byte[] L_Data = new byte[] { (byte)station, 0x03, g_add, d_add, g_data, d_data };
byte[] crcdata = RsCrc(L_Data);
byte[] L_DL = new byte[] { (byte)station, 0x03, g_add, d_add, g_data, d_data, crcdata[0], crcdata[1] };
ComSend(L_DL);
#endregion
#region 接收数据
byte[] readData = GetSerialPortData(dataLength);
if (readData == null) return;
if (addres_cout == 1)
{
//读取单个寄存器
byte[] k = { readData[4], readData[3] };
dt_Int16 = System.BitConverter.ToInt16(k, 0);
}
else if (addres_cout == 2)
{
//读取2个寄存器
byte[] k2 = { readData[4], readData[3], readData[6], readData[5] };
if (dataType == 0)
{
dt_Int32 = BitConverter.ToInt32(k2, 0);
}
if (dataType == 1)
{
dt_Fdata = BitConverter.ToSingle(k2, 0);
}
}
#endregion
}
}
/// <summary>
/// 设置单个DT寄存器数据
/// </summary>
/// <param name="station">PLC地址</param>
/// <param name="addres">数据地址</param>
/// <param name="ata">数据</param>
/// <returns></returns>
public void DT_SetData(int station, int addres, int data)
{
if (!serialPort.IsOpen) return;
byte g_add = (byte)(addres >> 8);
byte d_add = (byte)(addres & 0xFF);
byte g_data = (byte)(data >> 8);
byte d_data = (byte)(data & 0xFF);
byte[] L_Data = new byte[] { (byte)station, 0x06, g_add, d_add, g_data, d_data };
byte[] crcdata = RsCrc(L_Data);
byte[] senddata = new byte[] { (byte)station, 0x06, g_add, d_add, g_data, d_data, crcdata[0], crcdata[1] };
ComSend(senddata);
//Thread.Sleep(20);
}
/// <summary>
/// 读取R内部继电器(单线圈)数据
/// </summary>
/// <param name="station">PLC地址</param>
/// <param name="addres">数据地址</param>
/// <param name="wei">地址位</param>
/// <param name="addres_cout">读取个数</param>
/// <returns></returns>
public void R_ReadData(int station, int addres, int wei, int addres_cout)
{
lock(this)
{
if (!serialPort.IsOpen) return;
#region 发送数据
addres = addres * 16 + 2048 + wei;
byte g_add = (byte)(addres >> 8);
byte d_add = (byte)(addres & 0xFF);
byte g_data = (byte)(addres_cout >> 8);
byte d_data = (byte)(addres_cout & 0xFF);
byte[] L_Data = new byte[] { (byte)station, 0x01, g_add, d_add, g_data, d_data };
byte[] crcdata = RsCrc(L_Data);
ComSend(new byte[] { (byte)station, 0x01, g_add, d_add, g_data, d_data, crcdata[0], crcdata[1] });
#endregion
//接收到数据才会出来,所以这里不用加延时
byte[] readData = GetSerialPortData(6);
if (readData == null) return;
r_data = readData[3];
}
}
public void R_GetManyData()
{
#region 获取多个线圈数据
//地址中有ABCDEF时需要单独获取
int[] test = { 0, 1, 4, 5, 6, 400, 800, 1200, 1600, 2493, 2000, 2400, 2800, 3200 };
int remainer = 0;//位数
for (int i = 0; i < test.Length; i++)
{
int address = 0;//R线圈地址
//地址小于16时,线圈地址为0,余数为它本身
if (test[i] < 16)
{
address = 0;
remainer = test[i];
}
else
{
remainer = test[i] % 10;//获取各位数
address = test[i] / 10;//获取线圈地址
}
R_ReadData(1, address, remainer, 1);
//richTextBox1.AppendText("R:" + test[i] + "\tValue:" + obj.ToString() + "\n");
}
#endregion
}
/// <summary>
/// 写入R内部继电器(单线圈)数据
/// </summary>
/// <param name="station">PLC地址</param>
/// <param name="addres">数据地址</param>
/// <param name="wei">数据地址位</param>
/// <param name="addres_cout">1、0
/// </param>
/// <returns></returns>
public void R_SetData(int station, int addres, int wei, int value)
{
lock (this)
{
if (!serialPort.IsOpen) return;
addres = addres * 16 + 2048 + wei;
byte g_data;
byte d_data = 0x00;
if (value == 1)
{
g_data = 0xFF;//开1
}
else
{
g_data = 0x00; //关0
}
byte g_add = (byte)(addres >> 8);
byte d_add = (byte)(addres & 0xFF);
byte[] L_Data = new byte[] { (byte)station, 0x05, g_add, d_add, g_data, d_data };
byte[] crcdata = RsCrc(L_Data);
byte[] senddata = new byte[] { (byte)station, 0x05, g_add, d_add, g_data, d_data, crcdata[0], crcdata[1] };
ComSend(senddata);
}
}
#endregion
#region CRC
/// <summary>
/// CRC校验计算查表法,高位在前0,低位在后1
/// </summary>
/// <param name="a">校验数组</param>
/// <returns>高位在前0,低位在后1</returns>
public static byte[] RsCrc(byte[] a)
{
//A 01 03 01 (E1 30)
//B 01 03 02 (A1 31)
//C 01 03 03 (60 F1)
//D 01 03 04 (21 33)
//CRC循环中的索引
int j = 0; //
byte crc_h = 0xFF; //高CRC字节初始化
byte crc_l = 0xFF; //低CRC字节初始化
for (int i = 0; i < a.Length; i++)
{
j = crc_h ^ a[i];
crc_h = Convert.ToByte(crc_l ^ auchCRCHi[j]);
crc_l = Convert.ToByte(auchCRCLo[j]);
}
return new byte[] { crc_h, crc_l };
}
//CRC校验表
//===============================================
private static byte[] auchCRCHi = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
};
private static byte[] auchCRCLo ={
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
};
#endregion
}
}