RS232通讯口发送ASCII数据

RS232 Communication Port Sending ASCII data

我有一个控制台应用程序通过 RS232 通信端口与自定义机器通信。根据机器的文档,有诸如

之类的命令
  1. 启动机器Command:DC1
    完整命令:'STX' STN 'DC1' 'ETX' BCC
    十六进制代码(02 31 11 03 47)
  2. 停止机器Command:DC2
    完整命令:'STX' STN 'DC2' 'ETX' BCC
    十六进制代码(02 31 12 03 48)

我可以用这个启动和停止机器:

byte[] _startMachine = new byte[] { 0x02, 0x31, 0x11, 0x03, 0x47 };  
        _serialPort.Write(_startMachine, 0, _startMachine.Length);

    byte[] _stopMachine = new byte[] { 0x02, 0x31, 0x12, 0x03, 0x48 };   
    _serialPort.Write(_stopMachine, 0, _stopMachine.Length);

但是我被这个命令卡住了 4. 读出批次总数 命令:DC4
完整命令:'STX'STN'DC4''ETX'BCC
十六进制代码(02 31 14 03 4A)

按照之前的逻辑,我假设这应该有效。

byte[] _getBatchTotal = new byte[] { 0x02, 0x31, 0x14, 0x03, 0x4A };  
   _serialPort.Write(_getBatchTotal, 0, _getBatchTotal.Length);

我遵循相同的逻辑,但我认为棘手的部分是命令的结尾, 我是否正确翻译了十六进制?

不确定文档中是否有错误,但也写了 到处使用的 BCC(= 块校验字符)计算为所有已读取字节的总和(包括 STX 和 ETX)。 因此,例如启动机器命令很简单 例: STX STN DC1 ETX BCC 十六进制:02+31+11+03 == 47

为什么这种奇怪格式的读取批处理命令的密件抄送是'4A'。 谢谢。

以下是我的做法。首先,我将消息格式设置为简单的字符串:

private const string StartMachineMessage = "\x02{0}\x11\x03";
private const string StopMachineMessage = "\x02{0}\x12\x03";
private const string ReadBatchMachineMessage = "\x02{0}\x14\x03";

请注意,{0} 占位符用于保存站号(在您的情况下它始终是 10x31 代表什么),但它可以是可变的)。因为这里总是一个:

private const int StationNumber = 1;

然后我需要一种方法来计算一堆字节的 BCC。这将对任何字节数组执行此操作(如果您有更长的消息,这可能会有用):

private static byte GetBccOfBytes (byte[] bytes)
{
    var bcc = 0;
    foreach (var byt in bytes)
    {
        bcc += byt;
    }
    return (byte)(bcc & 0xff);
}

我假设 BCC 是总和的低 8 位,所以我使用 0xff 作为掩码。

现在是问题的核心,格式化消息并将其转换为带有密件抄送的字节数组:

public static byte[] GetMessageWithBcc (string format, int stationNumber)
{
    var messageWithStation = string.Format(format, stationNumber);  //mix the station number into the format string
    var noBccBytes = Encoding.ASCII.GetBytes(messageWithStation);   //convert the string to an array of ASCII bytes
    var result = new byte[noBccBytes.Length + 1];                   //allocate a buffer to hold the result, note room for BCC
    for (var i = 0; i < noBccBytes.Length; ++i)                     //copy the first byte array to the result byte array
    {
        result[i] = noBccBytes[i];
    }
    result[noBccBytes.Length] = GetBccOfBytes(noBccBytes);          //calculate and append the BCC
    return result;
}    

然后我需要一种方法来查看这些字节数组的样子,因此将它们转换为一个字符串,每个字节十六进制表示之间带有 space:

private static string BytesAsHexString (byte[] bytes)
{
    bool started = false;
    var buffer = new StringBuilder(bytes.Length * 3 - 1);
    foreach (var byt in bytes)
    {
        if (started)
        {
            buffer.Append(" ");
        }
        started = true;
        buffer.Append($"{byt:x02}");
    }
    return buffer.ToString();
}

如果您想了解其他更有效的方法,How do you convert a byte array to a hexadecimal string, and vice versa?

最后,一些测试代码:

public static void Test()
{
    var messages = new Dictionary<string, string>
    {
        {nameof(StartMachineMessage), StartMachineMessage },
        {nameof(StopMachineMessage), StopMachineMessage },
        {nameof(ReadBatchMachineMessage), ReadBatchMachineMessage },
    };

    foreach (var msgPair in messages)
    {
        var result = GetMessageWithBcc(msgPair.Value, StationNumber);
        Console.WriteLine($"{msgPair.Key}: {BytesAsHexString(result)}");
    }
}

输出如下:

StartMachineMessage: 02 31 11 03 47
StopMachineMessage: 02 31 12 03 48
ReadBatchMachineMessage: 02 31 14 03 4a