我在手臂开发板上使用串口实现RS485,使用gpio实现数据启用。
我在发送之前将数据设置为高电平,我希望在传输完成后将其设置为低电平。
可以通过写作来完成:
//fd = open("/dev/ttyO2", ...);
DataEnable.Set(true);
write(fd, data, datalen);
tcdrain(fd); //Wait until all data is sent
DataEnable.Set(false);
我想从阻止模式更改为非阻止模式,并使用fd进行轮询。但我没有看到任何与传输完成相对应的民意调查事件'。
如何在发送所有数据后收到通知?
系统:linux 语言:c ++ 董事会:BeagleBone Black
答案 0 :(得分:1)
我认为不可能。您必须在另一个线程中运行tcdrain
并让它通知主线程,或者在poll
上使用超时并轮询以查看输出是否已耗尽。
您可以使用TIOCOUTQ
ioctl获取输出缓冲区中的字节数,并根据波特率调整超时。这应该减少你需要做的一次或两次轮询的数量。类似的东西:
enum { writing, draining, idle } write_state;
while(1) {
int write_event, timeout = -1;
...
if (write_state == writing) {
poll_fds[poll_len].fd = write_fd;
poll_fds[poll_len].event = POLLOUT;
write_event = poll_len++
} else if (write == draining) {
int outq;
ioctl(write_fd, TIOCOUTQ, &outq);
if (outq == 0) {
DataEnable.Set(false);
write_state = idle;
} else {
// 10 bits per byte, 1000 millisecond in a second
timeout = outq * 10 * 1000 / baud_rate;
if (timeout < 1) {
timeout = 1;
}
}
}
int r = poll(poll_fds, poll_len, timeout);
...
if (write_state == writing && r > 0 && (poll_fds[write_event].revent & POLLOUT)) {
DataEnable.Set(true); // Gets set even if already set.
int n = write(write_fd, write_data, write_datalen);
write_data += n;
write_datalen -= n;
if (write_datalen == 0) {
state = draining;
}
}
}
答案 1 :(得分:0)
陈旧的线程,但我一直在使用RS-485与Linux下的兼容16550的UART并找到
我目前正在使用CLOCK_MONOTONIC为每个发送加时间戳,计算发送应该完成的时间,在检查下一次发送的时间时,如有必要则延迟。糟透了,但似乎工作