Linux和Windows之间的串行通信

3
我正在通过串行RS232从Linux向Windows发送数据字节,一切正常,只需处理来自Linux的0xa,因为Windows将其视为0xd + 0xa。 但是当我从Windows向Linux发送数据字节时,一些字节会被替换为“-”: Windows发送 - 0xd,Linux收到0xa Windows发送 - 0x11,Linux收到整数中的垃圾tyte值,大约为8200。
请解释一下从Windows向Linux发送数据时出了什么问题。 提前感谢您。
Windows串行端口初始化。
char *pcCommPort = "COM1";
    hCom = CreateFile( TEXT("COM1"),
                       GENERIC_READ | GENERIC_WRITE,
                       0,    // must be opened with exclusive-access
                       NULL, // no security attributes
                       OPEN_EXISTING, // must use OPEN_EXISTING
                       0,    // not overlapped I/O
                       NULL  // hTemplate must be NULL for comm devices
                       );
fSuccess = GetCommState(hCom, &dcb);
 FillMemory(&dcb, sizeof(dcb),0);


    dcb.DCBlength = sizeof(dcb);
    dcb.BaudRate = CBR_115200;     // set the baud rate
    dcb.ByteSize = 8;             // data size, xmit, and rcv
    dcb.Parity = NOPARITY;        // no parity bit
    dcb.StopBits = ONESTOPBIT;    // one stop bit
    dcb.fOutxCtsFlow = false;

    fSuccess = SetCommState(hCom, &dcb);
 buff_success = SetupComm(hCom, 1024, 1024);
COMMTIMEOUTS cmt;
    // ReadIntervalTimeout in ms
    cmt.ReadIntervalTimeout = 1000;
    cmt.ReadTotalTimeoutMultiplier = 1000;
    cmt.ReadTotalTimeoutConstant=1000;
    timeout_flag = SetCommTimeouts(hCom, &cmt);

Windows写串口 -

WriteFile(hCom, buffer, len, &write, NULL);

Linux串口初始化-

_fd_port_no = open("//dev//ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
tcgetattr(_fd_port_no, &options);
        cfsetispeed(&options, B115200);
        cfsetospeed(&options, B115200);
        options.c_cflag |= (CS8);
        options.c_cflag|=(CLOCAL|CREAD);
        options.c_cflag &=~PARENB;
        options.c_cflag &= ~CSTOPB;
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        options.c_iflag |= (IXON | IXOFF | IXANY);
        options.c_cflag &= ~ CRTSCTS;
        tcsetattr(_fd_port_no, TCSANOW, &options);

阅读Linux串口-

while(read(_fd_port_no,buffer+_buffer_len,sizeof(buffer))>0)
    {
        _buffer_len = _buffer_len+sizeof(buffer);

    }

是的,正如我所说的,从Linux到Windows只有NL/CR问题,但我通过字节替换解决了这个问题, 但你有没有关于从Windows发送串行数据到Linux(字节替换策略)的想法。 实际上,我必须将200 KB文件以200字节块的形式通过串行端口发送,因此如果从Windows发送到Linux,则可以替换哪个字节。


所以你发送的是原始字节,而不是文本?展示发送和接收的代码;当然要尽可能少的代码。 - meaning-matters
请注意,0x0a 是换行符,0x0d 是回车符。这听起来像是典型的 NL/CR 问题。 - meaning-matters
如果你正在从Windows发送文件,你是否已经以文本模式或二进制模式打开了该文件?确保两端的串口设置相同,例如,你似乎在Linux端使用了XON/XOFF,但在Windows端没有(不要使用XON/XOFF)。 - nos
我以二进制模式打开了文件。 - pritesh
好的,我会检查这件事情,谢谢你的建议。 - pritesh
4个回答

3
如果你在Windows上使用ReadFileWrietFile,在Linux上使用readwrite,那么行尾符号并不重要,除了“在接收后必须在某个时刻进行翻译”。
这看起来不正确:
while(read(_fd_port_no,buffer+_buffer_len,sizeof(buffer))>0)
{
    _buffer_len = _buffer_len+sizeof(buffer);

}

你应该考虑到read返回的大小。

如果sizeof(buffer)是实际读取的缓冲区,当_buffer_len >= sizeof(buffer)时,添加+ _buffer_len将写入缓冲区之外。

同时还有点担忧:

    options.c_iflag |= (IXON | IXOFF | IXANY);
    options.c_cflag &= ~ CRTSCTS;

你确定要使用XOFF/CTRL-S (0x13)来停止数据流吗?通常这意味着包含CTRL-S的数据将不被允许,这在发送文本数据时可能不是问题,但如果您需要发送二进制数据,则肯定会有问题。IXOFF也意味着另一端将必须响应XOFF和XON(CTRL-Q, 0x11)来停止/开始数据流。通常情况下,在现代系统中我们不希望出现这种情况...如果你的两端线路正确连接,使用RTS/CTS应该是安全的。

1
为了避免换行符转换,您可能需要添加以下内容:
options.c_iflag &= ~IGNCR;  // turn off ignore \r 
options.c_iflag &= ~INLCR;  // turn off translate \n to \r 
options.c_iflag &= ~ICRNL;  // turn off translate \r to \n

options.c_oflag &= ~ONLCR;  // turn off map \n  to \r\n
options.c_oflag &= ~OCRNL;  // turn off map \r to \n 
options.c_oflag &= ~OPOST;  // turn off implementation defined output processing

另外,以下行:

options.c_iflag |= (IXON | IXOFF | IXANY);

将启用XON / XOFF处理,因此tty驱动程序将处理Ctrl-S(XOFF)和Ctrl-Q(XON)字符作为流控制(这可能是您发送0x11时看到意外情况的原因,即Ctrl-Q)。我希望您希望关闭这些位:

options.c_iflag &= ~(IXON | IXOFF | IXANY);

事实上,在调用 tcgetattr() 后,我认为你可能想要调用 cfmakeraw(),这将禁用所有输入和输出字符的特殊处理。

1
谢谢大家
这个更改解决了我的问题
fd_port_no = open("//dev//ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
tcgetattr(_fd_port_no, &options);
        cfsetispeed(&options, B115200);
        cfsetospeed(&options, B115200);
        options.c_cflag |= (CS8);
        options.c_cflag|=(CLOCAL|CREAD);
        options.c_cflag &=~PARENB;
        options.c_cflag &= ~CSTOPB;
        options.c_cflag &= ~ CRTSCTS;
        options.c_iflag |= (IXON | IXOFF | IXANY);
        options.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | ECHOE | ECHOK);
        options.c_cflag &= ~ OPOST;
        tcsetattr(_fd_port_no, TCSANOW, &options);

但从技术上讲,我不知道它是如何工作的,但我的问题已经解决并且测试良好。 - pritesh
实际上,服务器和客户端机器已经转移到Linux,因此该代码在Linux到Linux串行通信上运行。 - pritesh

1

我认为在从串口读取流之前,你需要先刷新一下。

tcflush(_fd_port_no TCIFLUSH);

此外,您尝试使用控制台命令 cat < dev/ttyS0 查看通量了吗?该内容涉及编程。请注意保留HTML标签,但应将其翻译为中文。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接