我在Linux中使用串口编码。
通讯的要求是5ms inter-byte time
。
根据字节的值,它要求我在write()
调用之前为每个字节更改奇偶校验模式(偶数和奇数)。
所以我编码如下(我简单描述代码)
void setWakeupMode(int fd, bool mode) {
struct termios tio;
bzero(&tio, sizeof(tio));
tcgetattr(fd, &tio);
if (mode == false) {
tio.c_cflag &= ~PARODD;
} else if (mode == true) {
tio.c_cflag |= PARODD;
}
if(tcsetattr(fd, TCSADRAIN, &tio) < 0){
perror("tcsetattr Error");
}
}
int main(){
unsigned char a[2] = {0x01, 0x0F};
write(fd, a, 1);
setWakeupMode(fd, true);
write(fd, a+1, 1);
}
但是代码不能满足字节时间,导致差不多20ms。
所以我尝试在下面的每个系统调用之间打印确切的时间。
int main(){
unsigned char a[2] = {0x01, 0x0F};
printf("write1 start : %s", /*time*/);
write(fd, a, 1);
printf("write1 end : %s", /*time*/);
setWakeupMode(fd, true);
printf("write2 start : %s", /*time*/);
write(fd, a+1, 1);
printf("write2 end : %s, /*time*/);
}
,这是结果
write1 start : 34.755201
write1 end : 34.756046
write2 start : 34.756587
write2 end : 34.757349
此结果突然满足5ms的字节间时间,从而产生1ms inter-byte time
。
所以我尝试了几种方法。
最后我认识到只有当我在tcsetattr()之前打印一些东西时,才能满足字节间时间。
例如,如果我删除printf("write1 end : %s, /*time*/);
,如下所示
int main(){
unsigned char a[2] = {0x01, 0x0F};
printf("write1 start : %s", /*time*/);
write(fd, a, 1);
// printf("write1 end : %s", /*time*/); //remove this
setWakeupMode(fd, true);
printf("write2 start : %s", /*time*/);
write(fd, a+1, 1);
printf("write2 end : %s", /*time*/);
}
结果出乎意料地不同,请参阅write1 start
和write2 start
之间的时间间隔,
它是18ms
。
write1 start : 40.210111
write2 start : 40.228332
write2 end : 40.229187
如果我使用std :: cout而不是printf,结果是一样的。
为什么这种奇怪的情境会发生?
------------------------------- EDIT ------------ --------------------
由于我看到了一些答案,有些人误解了我的问题。
我并不担心printf()
开销。
简单地说。
write()
但是write()
之间的间隔必须在5ms之内write()
之前,我必须使用tcsetattr()
18ms
,几乎在tcsetattr()
时间被阻止。printf()
之前拨打std::cout
或tcsetattr()
,则时间间隔缩短为1~2ms
。也就是说,以某种方式,在tcsetattr()
之前调用printf使tcsetattr()
更快地从阻塞中返回。
--------------------------更新----------------- -----------
我在这个问题上取得了进展。
我说我必须放printf()
或std::cout
才能在tcsetattr()
上缩短拦截时间。
但它并没有打印出影响这个问题的东西。
它只需要一些延迟,也就是说,如果我在调用usleep(500)
之前放置tcsetattr()
,它还会对1~2ms
之间的字节时减少产生影响,从{返回} {1}}更快。
我假设,如果我用tcsetattr()
标志调用tcsetattr()
,它会等到串行缓冲区中的所有数据都被传输,然后更改为我想要的设置。
它可能会有一些延迟。
但如果我在调用TCSADRAIN
之前调用特定延迟,则缓冲区状态已经为空(因为在延迟时间内,传输串行缓冲区中的数据),因此没有阻塞。
这是我假设的情景,是否可能?
答案 0 :(得分:3)
这是我假设的情景,是否可能?
你一定是对的。 sawdust写道:
drivers/tty/serial/serial_core.c
中的uart_wait_until_sent()解释了为什么在涉及“漏极”时量化字符之间的间隔:使用TIOCSER_TEMP(发送器空)状态轮询串行端口驱动程序只有毫秒级分辨率的延迟。
这几乎是正确的,除了轮询周期分辨率不是毫秒,而是jiffies:
while (!port->ops->tx_empty(port)) {
msleep_interruptible(jiffies_to_msecs(char_time));
…
因此,如果HZ为100且char_time
为1(最小值),则每10 ms检查一次状态。正如你写的那样:
但是如果我打电话给
tcsetattr()
之前特别延迟,那么 缓冲区状态已经为空(因为在延迟时间内,数据 在串行缓冲区中传输),因此没有阻塞。
换句话说,如果你把这个过程延迟到发射机空测试!port->ops->tx_empty(port)
时,发射机已经空了,就不会发生睡眠;否则它至少会睡1个小时。
答案 1 :(得分:0)
为什么不试试sprintf / snprintf而不是printf? 因为关于snprintf,你可以加快时间 你缩短了字符串字节?