我正在将二进制数据从 arduino 发送到运行此代码的串行端口。在十六进制模式下使用cutecom可以清楚地读取我对该串行端口的期望。如下所示。
00000000: 24 04 85 ab 47 43 04 04 24 04 85 ab 47 43 04 04
00000010: 24 04 85 ab 47 43 04 04 24 04 85 ab 47 43 04 04
Run Code Online (Sandbox Code Playgroud)
到这里没有问题。我不认为我需要提供 arduino 代码。
我正在尝试用 c 读同样的东西。然而下面的代码只打印这个:
24 85 ab 47 43 24 85 ab 47 43 24 85 ab 47 43
Run Code Online (Sandbox Code Playgroud)
由于某些原因,它跳过了 04。有什么想法吗?
#include <stdio.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h> /* POSIX Terminal Control Definitions */
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
#include <signal.h>
#include <string.h>
#include <stdint.h>
int open_serial(char *port, int baud);
void main(void)
{
int tty = open_serial("/dev/ttyUSB0", B115200);
uint8_t buff[256]; /* Buffer to store the data received */
int n; /* Number of bytes read by the read() system call */
while (1) {
n = read(tty, &buff, sizeof buff);
if (n > 0){
//printf("-%d-\n ", n);
for(int i=0;i<n;i++){
printf("%02x ", buff[i]);
}
fflush(stdout);
}
}
}
int open_serial(char *port, int baud)
{
int fd = open( port, O_RDWR | O_NOCTTY);
if(fd == -1) /* Error Checking */
printf("\n Error! in Opening tty ");
struct termios SerialPortSettings; /* Create the structure */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
/* Setting the Baud rate */
cfsetispeed(&SerialPortSettings,B115200); /* Set Read Speed as 115200 */
cfsetospeed(&SerialPortSettings,B115200); /* Set Write Speed as 115200 */
/* 8N1 Mode */
SerialPortSettings.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 10; /* Read at least 10 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 115200 StopBits = 1 Parity = none\n");
/*------------------------------- Read data from serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
return fd;
}
Run Code Online (Sandbox Code Playgroud)
I am sending binary data from an arduino to a serial port where this code is running.
Transmission of binary data necessitates that the POSIX serial terminal be configured for non-canonical (aka raw) mode.
For some reasons it is skipping the 04. Any ideas?
数值在 ASCII 控制字符范围内(即 0x00 到 0x1F)的数据持续丢失几乎总是表明 termios 配置不正确。
由于数据丢失似乎发生在接收端,因此首先要验证的是非规范输入模式的正确规范。
你的代码有
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
Run Code Online (Sandbox Code Playgroud)
赋值语句右侧的属性都属于c_lflagtermios 结构的属性,而不是c_iflag编码的属性。
因此,推测串行终端的默认模式是规范模式,并且由于此拼写错误,您的程序无法重新配置为非规范输入模式。
使用cfmakeraw()调用增强代码的解决方法并不理想。
使用cfmakeraw()可以很方便地避免像您遇到的错误。但是应该纠正有错误的语句,或者更好的是可以删除因cfmakeraw()
调用而变得多余的操作。
cfmakeraw() sets the terminal to something like the "raw" mode of the old
Version 7 terminal driver: input is available character by character, echoing is
disabled, and all special processing of terminal input and output characters is
disabled. The terminal attributes are set as follows:
termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
termios_p->c_cflag &= ~(CSIZE | PARENB);
termios_p->c_cflag |= CS8;
Run Code Online (Sandbox Code Playgroud)
顺便说一句,您的代码确实使用了调用tcgetattr()的推荐/首选方法,然后使用布尔运算设置/修改终端属性。使用“干净的结构”的建议不被认为是可移植的。
附录
这个c_iflag和ICANON错误的起源似乎是来自 xanthium.in 的串行端口教程。作者早在 2016 年就收到了有关该错误的通知,但并未修复它。