C read 调用阻塞串口操作
我正在尝试在 Linux 中编写一个 C 程序,通过串行端口从微控制器发送和接收数据。作为测试,我已将微控制器配置为立即回显发送的所有字符。我已经验证这在 minicom 中有效,并且还可以使用“cat”和“echo”来发送和接收数据。
然而,当我尝试在 C 程序中执行相同操作时,我的读取调用将永远阻塞。我将串行端口设置为非规范模式,MIN 为“1”,TIME 为“0”。我的 minicom 测试证明微控制器在键入字符时返回字符,因此我希望 read 在 write 调用发送字符后返回。我将我的代码与几个在线示例进行了比较,但没有发现我遗漏的任何内容。我尝试了下面代码的几种排列,但没有成功。有人能发现问题吗?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#define UART_SPEED B115200
char buf[512];
void init_serial (int fd)
{
struct termios termios;
int res;
res = tcgetattr (fd, &termios);
if (res < 0) {
fprintf (stderr, "Termios get error: %s\n", strerror (errno));
exit (-1);
}
cfsetispeed (&termios, UART_SPEED);
cfsetospeed (&termios, UART_SPEED);
termios.c_iflag &= ~(IGNPAR | IXON | IXOFF);
termios.c_iflag |= IGNPAR;
termios.c_cflag &= ~(CSIZE | PARENB | CSTOPB | CREAD | CLOCAL);
termios.c_cflag |= CS8;
termios.c_cflag |= CREAD;
termios.c_cflag |= CLOCAL;
termios.c_lflag &= ~(ICANON | ECHO);
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 0;
res = tcsetattr (fd, TCSANOW, &termios);
if (res < 0) {
fprintf (stderr, "Termios set error: %s\n", strerror (errno));
exit (-1);
}
}
int main (int argc, char **argv)
{
int fd;
int res;
int i;
if (argc < 2) {
fprintf (stderr, "Please enter device name\n");
return -1;
}
fd = open (argv[1], O_RDWR | O_NOCTTY);
if (fd < 0) {
fprintf (stderr, "Cannot open %s: %s\n", argv[1], strerror(errno));
return -1;
}
init_serial (fd);
res = write (fd, "P=20\r\n", 6);
if (res < 0) {
fprintf (stderr, "Write error: %s\n", strerror(errno));
return -1;
}
tcdrain (fd);
res = read (fd, buf, 512);
printf ("%d\n", res);
if (res < 0) {
fprintf (stderr, "Read error: %s\n", strerror(errno));
return -1;
}
for (i=0; i<res; i++) {
printf ("%c", buf[i]);
}
return 0;
}
I am trying to write a C program in Linux to send and receive data from a microcontroller over the serial port. As a test, I have configured the microcontroller to immediately echo all characters sent. I have verified that this works in minicom and also by using "cat" and "echo" to send and receive data.
However, when I try to do the same in a C program, my read call blocks forever. I am setting the serial port to non-canonical mode, with a MIN of '1' and TIME of '0'. My minicom test proves that the microcontroller is returning characters as they are typed, so I expect read to return after the write call has sent characters. I have compared my code to several online examples, and I haven't found anything that I am missing. I have tried several permutations of the code below with no luck. Can someone spot the problem?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#define UART_SPEED B115200
char buf[512];
void init_serial (int fd)
{
struct termios termios;
int res;
res = tcgetattr (fd, &termios);
if (res < 0) {
fprintf (stderr, "Termios get error: %s\n", strerror (errno));
exit (-1);
}
cfsetispeed (&termios, UART_SPEED);
cfsetospeed (&termios, UART_SPEED);
termios.c_iflag &= ~(IGNPAR | IXON | IXOFF);
termios.c_iflag |= IGNPAR;
termios.c_cflag &= ~(CSIZE | PARENB | CSTOPB | CREAD | CLOCAL);
termios.c_cflag |= CS8;
termios.c_cflag |= CREAD;
termios.c_cflag |= CLOCAL;
termios.c_lflag &= ~(ICANON | ECHO);
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 0;
res = tcsetattr (fd, TCSANOW, &termios);
if (res < 0) {
fprintf (stderr, "Termios set error: %s\n", strerror (errno));
exit (-1);
}
}
int main (int argc, char **argv)
{
int fd;
int res;
int i;
if (argc < 2) {
fprintf (stderr, "Please enter device name\n");
return -1;
}
fd = open (argv[1], O_RDWR | O_NOCTTY);
if (fd < 0) {
fprintf (stderr, "Cannot open %s: %s\n", argv[1], strerror(errno));
return -1;
}
init_serial (fd);
res = write (fd, "P=20\r\n", 6);
if (res < 0) {
fprintf (stderr, "Write error: %s\n", strerror(errno));
return -1;
}
tcdrain (fd);
res = read (fd, buf, 512);
printf ("%d\n", res);
if (res < 0) {
fprintf (stderr, "Read error: %s\n", strerror(errno));
return -1;
}
for (i=0; i<res; i++) {
printf ("%c", buf[i]);
}
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可能想要插入一些延迟,或循环等待输入。
设置比特率后,某些类型的 UART 硬件会以新速度读取一两个字符来同步到新速度。写入时前几个字符可能会丢失。
六个字符写入后,立即发出读取操作,并有 0.1 秒的超时时间。有可能在
read()
之前,并非write()
中的所有字符都已完成传输,更不用说远程设备响应的任何时间了。例如,一种解决方案是:
另一种方法是继续读取,直到到达足够数量的字符或经过合理的时间。
You might want to insert some delays, or loop waiting for input.
After setting the bit rate, some types of UART hardware takes one or two characters at the new speed to synchronize to the new speed. It is possible the first few characters are being lost on the write.
After the six character write, the read is issued immediately with a 0.1 second timeout. It is possible that not all the characters from the
write()
have finished being transmitted before theread()
, let alone any time for the remote device to respond.For example, one solution is:
Another approach would be to continue reading until a sufficient number of characters arrive or a reasonable amount of time passes.