解决方法:Linux串口接收字节0x11,0x0d,0x13丢失

一、问题

串口发送:
read 44 byte: 5a a5 07 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
串口接收:
read 43 byte: 5a a5 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

UART串口发送44字节数据,但实际接收只有43字节,发现0x13丢失了

二、原因

网上许多流行的linux串口编程的版本中都没对c_iflag(termios成员变量)这个变量进行有效的设置,这样传送ASCII码时没什么问题,但传送二进制数据时遇到0x0d,0x11和0x13却会被丢掉。
0x0d 回车符CR
0x11 ^Q VSTART字符
0x13 ^S VSTOP字符
被用作特殊控制了,关掉 ICRNLIXON 选项即可解决。

在《UNIX环境高级编程第二版》第18章第11小节看到把终端I/O设置为原始模式(串口通讯就是终端I/O的原始模式)时输入属性设置为
term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);

三、解决方法

修改为:c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);

四、附录

表1 c_iflag参数表

键 值说 明
IGNBRK忽略BREAK键输入
BRKINT如果设置了IGNBRK,BREAK键输入将被忽略
IGNPAR忽略奇偶校验错误
PARMRK标识奇偶校验错误
INPCK允许输入奇偶校验
ISTRIP去除字符的第8个比特
INLCR将输入的NL(换行)转换成CR(回车)
IGNCR忽略输入的回车
ICRNL将输入的回车转化成换行(如果IGNCR未设置的情况下)
IUCLC将输入的大写字符转换成小写字符(非POSIX)
IXON允许输出时对XON/XOFF流进行控制
IXANY输入任何字符将重启停止的输出
IXOFF允许输入时对XON/XOFF流进行控制
IMAXBEL当输入队列满的时候开始响铃

表2 c_oflag参数

键 值说 明
OPOST处理后输出
OLCUC将输出的小写字符转换成大写字符(非POSIX)
ONLCR将输出的NL(换行)转换成CR(回车)及NL(换行)
OCRNL将输出的CR(回车)转换成NL(换行)
ONOCR第一行不输出回车符
ONLRET不输出回车符
OFILL发送填充字符以延迟终端输出
OFDEL以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符为NUL
NLDLY换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
CRDLY回车延迟,取值范围为:CR0、CR1、CR2和 CR3
TABDLY水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
BSDLY空格输出延迟,可以取BS0或BS1
VTDLY垂直制表符输出延迟,可以取VT0或VT1
FFDLY换页延迟,可以取FF0或FF1

表3 c_cflag参数

键 值说 明
CBAUD波特率(4+1位)(非POSIX)
CBAUDEX附加波特率(1位)(非POSIX)
CSIZE字符长度,取值范围为CS5、CS6、CS7或CS8
CSTOPB设置两个停止位
CREAD使用接收器
PARENB使用奇偶校验
PARODD对输入使用奇偶校验,对输出使用偶校验
HUPCL关闭设备时挂起
CLOCAL忽略调制解调器线路状态
CRTSCTS使用RTS/CTS流控制

表4 c_lflag参数

键 值说 明
ISIG当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON使用标准输入模式
XCASE在ICANON和XCASE同时设置的情况下,终端只使用大写
ECHO显示输入字符
ECHOE如果ICANON同时设置,ERASE将删除输入的字符
ECHOK如果ICANON同时设置,KILL将删除当前行
ECHONL如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP向后台输出发送SIGTTOU信号

表5 c_cc支持的控制字符

说 明
VINTRInterrupt字符
VQUITQuit字符
VERASEErase字符
VKILLKill字符
VEOFEnd-of-file字符
VMIN非规范模式读取时的最小字符数
VEOL附加的End-of-file字符
VTIME非规范模式读取时的超时时间
VSTOPStop字符
VSTARTStart字符
VSUSPSuspend字符

• 由 Leung 写于 2019 年 8 月 28 日

• 参考:linux 串口接收不到0x11, 0x0d, 0x13

在Qt中向串口发送数据并处理接收到的数据可以通过QSerialPort类的信号和槽机制来实现。以下是一个示例代码,演示如何向串口发送数据并处理接收到的数据: ```c++ #include <QCoreApplication> #include <QSerialPort> #include <QSerialPortInfo> class SerialPort : public QObject { Q_OBJECT public: SerialPort(QObject *parent = nullptr) : QObject(parent) { serialPort.setPortName("COM1"); // 设置串口号 serialPort.setBaudRate(QSerialPort::Baud9600); // 设置波特率 serialPort.setDataBits(QSerialPort::Data8); // 设置数据位 serialPort.setParity(QSerialPort::NoParity); // 设置校验位 serialPort.setStopBits(QSerialPort::OneStop); // 设置停止位 connect(&serialPort, &QSerialPort::readyRead, this, &SerialPort::onReadyRead); } bool open() { if(serialPort.open(QIODevice::ReadWrite)) { return true; } return false; } void close() { serialPort.close(); } void write(const QByteArray &data) { serialPort.write(data); } signals: void receivedData(const QByteArray &data); private slots: void onReadyRead() { QByteArray data = serialPort.readAll(); for(int i = 0; i < data.size(); i++) { if(data.at(i) == (char)0x02 && i + 2 < data.size()) { if(data.at(i + 1) == (char)0x71 && data.at(i + 2) == (char)0x03) { QByteArray receivedData; receivedData.append(data.at(i)); receivedData.append(data.at(i + 1)); receivedData.append(data.at(i + 2)); emit receivedData(receivedData); } } } } private: QSerialPort serialPort; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 打开串口 SerialPort serialPort; if(!serialPort.open()) { qDebug() << "Failed to open serial port!"; return -1; } // 发送数据 QByteArray sendData; sendData.append((char)0x02); sendData.append((char)0x31); sendData.append((char)0x30); serialPort.write(sendData); // 处理接收到的数据 QObject::connect(&serialPort, &SerialPort::receivedData, [](const QByteArray &data) { qDebug() << "Received data:" << data.toHex(); }); return a.exec(); } ``` 在上面的代码中,首先创建了一个SerialPort类,其中包含了打开串口、关闭串口、发送数据和处理接收到的数据等函数。在SerialPort类的构造函数中,连接了QSerialPort的readyRead信号和SerialPort类的onReadyRead槽函数,当有数据可读时,onReadyRead函数将被调用。 在发送数据时,创建一个QByteArray对象sendData,并使用append()函数向其中添加0x02、0x31和0x30三个字节的数据。然后,调用SerialPort类的write()函数将sendData中的数据发送到串口上。 在处理接收到的数据时,当读取到0x02字节时,判断其后面是否有两个字节分别为0x71和0x03,如果是,将接收到的数据发送出去,通过SerialPort类的receivedData信号发送。在main函数中,使用QObject::connect()函数连接SerialPort类的receivedData信号,并在lambda表达式中打印接收到的数据。 需要注意的是,串口的参数设置必须与接收数据的设备的参数设置相匹配,否则可能会发送失败或接收数据错误。另外,在实际应用中,可能需要对接收到的数据进行更加复杂的处理。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leung_ManWah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值