1.定义串口相关参数
SerialPort serialPort4 = new SerialPort();
serialPort4.PortName = "COM4"; //串口号
serialPort4.BaudRate = Convert.ToInt32(9600); //波特率
serialPort4.DataBits = Convert.ToInt32(8); //数据位
serialPort4.StopBits = (StopBits)1; //停止位
serialPort4.Parity = Parity.None; //奇偶校验位
serialPort4.ReadTimeout = 100; //超时时间
serialPort4.WriteTimeout = 100;//写入超时500毫秒
serialPort4.DataReceived += SerialPortReceiveData;//接收数据事件
2.打开和关闭串口
if (serialPort4.IsOpen)//判断串口是否已经开启
{
serialPort4.Close();//关闭串口
}
serialPort4.Open();//打开串口
3.串口发送数据
现在串口通信基本上遵循ModBus协议,
包括:
- Modbus-Rtu
- Modbus-Ascii
- Modbus-Tcp
- ModbusPlus
本人了解尚浅,只是用过Rtu模式,发送数据为十六进制数据,8个字节。RTU格式后续的命令/数据带有循环冗余校验的校验和。
数据格式一般为
从机地址 功能码 寄存器地址 数据 校验
例子: 01 03 00 01 00 01 CRC
1.在大部分情况下03为读的操作,06为写的操作。不同需要根据相关硬件通信的说明书的指令。
2.寄存器地址需要相关说明书,需要根据实际读取。
3.在功能码为03也就是只读的情况下,数据位操作串口要读取多少个寄存器。上述00 01只是读一个,读取6个改为00 06.
4.功能码为06,是写入操作,修改相关参数,这时候数据位是将某个参数值修改为多少。
5.CRC校验从网上找公式即可,代码会贴在下面
public void SendNormalString(SerialPort serialPort, string data)
{
try
{
serialPort.Encoding = Encoding.ASCII;//字节编码
byte[] buff = HexStringToBinary(data);//自定义方法,处理发过来的十六进制数据,转为十进制存储
byte[] crc = new byte[buff.Length - 2];//cRc校验码,根据实际情况是否需要
serialPort.Write(buff, 0, buff.Length);//写入串口,相当于发送数据给串口
string message = " " + serialPort.PortName + "=>" + data;
SerialPortMessageUIShow(message);//自定义方法,将串口发送的数据显示在界面
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public static byte[] HexStringToBinary(string hexstring)
{
string[] tmpary = hexstring.Trim().Split(' ');
byte[] buff = new byte[tmpary.Length];
for (int i = 0; i < buff.Length; i++)
{
buff[i] = Convert.ToByte(tmpary[i], 16);//转换
}
return buff;
}
下面是加上CRC校验码的代码
public void SendNormalString(SerialPort serialPort, string data)
{
try
{
serialPort.Encoding = Encoding.ASCII;//字节编码
byte[] buff = HexStringToBinary(data);//自定义方法,处理发过来的十六进制数据,转为十进制存储
byte[] crc = new byte[buff.Length - 2];//cRc校验码,根据实际情况是否需要
if (buff.Length == 8)
{
for (int i = 0; i < 6; i++)
{
crc[i] = buff[i];
}
crc = CRCCalc(crc);//CRC处理
buff[6] = crc[0];
buff[7] = crc[1];
}
serialPort.Write(buff, 0, buff.Length);//写入串口,相当于发送数据给串口
string message = " " + serialPort.PortName + "=>" + data;
SerialPortMessageUIShow(message);//自定义方法,将串口发送的数据显示在界面
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public static byte[] CRCCalc(byte[] data)
{
//crc计算赋初始值
int crc = 0xffff;
for (int i = 0; i < data.Length; i++)
{
crc = crc ^ data[i];
for (int j = 0; j < 8; j++)
{
int temp;
temp = crc & 1;
crc = crc >> 1;
crc = crc & 0x7fff;
if (temp == 1)
{
crc = crc ^ 0xa001;
}
crc = crc & 0xffff;
}
}
//CRC寄存器的高低位进行互换
byte[] crc16 = new byte[2];
//CRC寄存器的高8位变成低8位,
crc16[1] = (byte)((crc >> 8) & 0xff);
//CRC寄存器的低8位变成高8位
crc16[0] = (byte)(crc & 0xff);
//return crc16;
return crc16;
}
4.串口接收数据
public static void SerialPortReceiveData(object sender, SerialDataReceivedEventArgs e)
{
SerialPort serialPort = (SerialPort)sender;
if (!serialPort.IsOpen) return;
byte[] result = new byte[serialPort.BytesToRead];//读取串口缓冲区的字节数据
serialPort.Read(result, 0, serialPort.BytesToRead);
for (int i = 0; i < result.Length; i++)
{
str += result[i].ToString("X2") + " ";//将接收的数据转为大写的十六进制
}
ReceiveMessage = "\t" + serialPort.PortName + " <= " + str;
}
5.调试串口
在没有相关串口的情况下,我们可以虚拟工具模拟串口通信是否正常。
希望各位大神指点不足之处!