I am coding with serial port in Linux.
我正在用Linux的串口编码。
And the requirement of the communication is 5ms inter-byte time
.
并且通信的要求是5ms的字节间时间。
And It requires me to change parity mode(even and odd) for each byte before write()
call, according to what the byte's value is.
它要求我在write()调用之前为每个字节修改奇偶模式(偶数和奇数),根据字节的值。
So I code like below(i describe code simply)
我的代码如下(我简单地描述代码)
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);
}
But the code doesn't satisfy inter-byte time resulting in almost 20ms.
但是代码不满足字节间的时间,导致大约20ms。
So i tried print exact time between each system call like below.
所以我尝试在每个系统调用之间打印准确的时间。
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*/);
}
and This is the result
这就是结果
write1 start : 34.755201
write1 end : 34.756046
write2 start : 34.756587
write2 end : 34.757349
This result suddenly satisfy the 5ms inter-byte time, resulting in 1ms inter-byte time
.
这个结果突然满足了5ms的字节间时间,导致1ms的字节间时间。
So i tried several ways.
所以我尝试了几种方法。
And finally i recognize that only when i print something right before tcsetattr(), inter-byte time is satisfied.
最后我认识到,只有当我在tcsetattr()之前打印一些东西时,字节间的时间才会满足。
for example, if i remove printf("write1 end : %s, /*time*/);
like below
例如,如果我删除printf(“write1结尾:%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*/);
}
The result is surprisingly different, See the interval between write1 start
and write2 start
, It is 18ms
.
结果惊人的不同,从write1开始到write2开始的间隔是18ms。
write1 start : 40.210111
write2 start : 40.228332
write2 end : 40.229187
If i use std::cout instead of printf, the result is same.
如果我使用std::cout而不是printf,结果是一样的。
Why does this weird situration happen?
为什么会发生这种奇怪的场景?
-------------------------------EDIT--------------------------------
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -编辑- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Since i see some answers, some are misunderstanding my problem.
因为我看到了一些答案,有些误解了我的问题。
I am not worrying printf()
overhead.
我并不担心printf()开销。
simply saying.
简单地说。
- I want to call
write()
s with 1byte But the interval betweenwrite()
s must be within 5ms - 我想用1byte调用write()s,但是write()s之间的间隔必须在5ms以内
- And Before calling
write()
, I have to change parity mode usingtcsetattr()
- 在调用write()之前,我必须使用tcsetattr()修改奇偶模式
- But The interval result is
18ms
, being blocked attcsetattr()
almost time. - 但是间隔结果是18ms,几乎在tcsetattr()时被阻塞。
- But If i call
printf()
orstd::cout
right beforetcsetattr()
, the interval reduce to1~2ms
. - 但是如果我在tcsetattr()之前调用printf()或std: cout,那么间隔就会减少到1~2ms。
that is, somehow, calling printf before tcsetattr()
make tcsetattr()
return from blocking faster.
也就是说,在tcsetattr()使tcsetattr()更快地从阻塞返回之前调用printf。
--------------------------Update----------------------------
- - - - - - - - - - - - - - - - - - - - - - - - - - - -更新- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
I have progress on this problem.
我在这个问题上取得了进展。
I said that i had to put printf()
or std::cout
to make blocking time short on tcsetattr()
.
我说过我必须在tcsetattr()上使用printf()或std::cout来缩短阻塞时间。
But It was not printing something to affect to that problem.
但它并没有印刷什么东西来影响这个问题。
It just needed some delay, that is, if i put usleep(500)
before calling tcsetattr()
, it also make an affect on inter-byte-time reducing by 1~2ms
, returning from tcsetattr()
faster.
它只需要一些延迟,也就是说,如果我在调用tcsetattr()之前输入usleep(500),它也会影响间隔时间减少1~2ms,从而更快地从tcsetattr()返回。
I assume, if i call tcsetattr()
with TCSADRAIN
flag, it wait until all data in serial buffer is transmitted, and change to the setting i want.
我假设,如果我使用TCSADRAIN标志调用tcsetattr(),它将等待到串行缓冲区中的所有数据被传输,并更改为我想要的设置。
and it could make some delay.
它可能会造成一些延迟。
but if i calling specifically delay, before i call tcsetattr()
, the buffer state is already empty(because during the delay time, the data in serial buffer is transmitted), so that there is no blocking.
但是,如果我在调用tcsetattr()之前调用特定的delay,那么缓冲区状态已经是空的(因为在延迟时间内,串行缓冲区中的数据被传输),因此没有阻塞。
this is the scenario i assume, is it possible?
这是我假设的情形,可能吗?
2 个解决方案
#1
3
this is the scenario i assume, is it possible?
这是我假设的情形,可能吗?
You must be quite right. sawdust wrote:
你一定是对的。锯末写道:
uart_wait_until_sent() in
drivers/tty/serial/serial_core.c
explains why the interval between characters is quantized when a "drain" is involved: the serial port driver is polled for the TIOCSER_TEMP (transmitter empty) status using a delay with only millisecond resolution.司机uart_wait_until_sent()/电传/串行/ serial_core。c解释了为什么在涉及“排液”时,字符之间的间隔是量化的:串行端口驱动程序使用一个只有毫秒级分辨率的延迟来轮询TIOCSER_TEMP(发送器空)状态。
That's almost right, except that the polling cycle resolution is not milliseconds, but jiffies:
这几乎是正确的,除了轮询周期解析不是毫秒,而是jiffies:
while (!port->ops->tx_empty(port)) {
msleep_interruptible(jiffies_to_msecs(char_time));
…
So if HZ is 100 and char_time
is 1 (the minimum), the status is checked every 10 ms. As you wrote:
如果HZ是100,char_time是1(最小值),则每10毫秒检查状态。当你写道:
but if i calling specifically delay, before i call
tcsetattr()
, the buffer state is already empty(because during the delay time, the data in serial buffer is transmitted), so that there is no blocking.但是,如果我在调用tcsetattr()之前调用特定的delay,那么缓冲区状态已经是空的(因为在延迟时间内,串行缓冲区中的数据被传输),因此没有阻塞。
In other words, if you delay the process long enough that by the time it gets to the transmitter empty test !port->ops->tx_empty(port)
the transmitter is already empty, no sleep occurs; otherwise it sleeps for at least 1 jiffy.
换句话说,如果你将进程延迟到足够长的时间,当进程到达发射机空测试时!端口->操作->tx_empty(端口)发射机已经空了,没有睡眠;否则它至少会睡1个瞬间。
#2
0
Why don't you try sprintf / snprintf instead printf?? Because about snprintf, you may Speed the time if you shortened the string-Byte?
你为什么不试试sprintf / snprintf呢?因为关于snprintf,如果你缩短了字符串字节,你可以加快时间。
#1
3
this is the scenario i assume, is it possible?
这是我假设的情形,可能吗?
You must be quite right. sawdust wrote:
你一定是对的。锯末写道:
uart_wait_until_sent() in
drivers/tty/serial/serial_core.c
explains why the interval between characters is quantized when a "drain" is involved: the serial port driver is polled for the TIOCSER_TEMP (transmitter empty) status using a delay with only millisecond resolution.司机uart_wait_until_sent()/电传/串行/ serial_core。c解释了为什么在涉及“排液”时,字符之间的间隔是量化的:串行端口驱动程序使用一个只有毫秒级分辨率的延迟来轮询TIOCSER_TEMP(发送器空)状态。
That's almost right, except that the polling cycle resolution is not milliseconds, but jiffies:
这几乎是正确的,除了轮询周期解析不是毫秒,而是jiffies:
while (!port->ops->tx_empty(port)) {
msleep_interruptible(jiffies_to_msecs(char_time));
…
So if HZ is 100 and char_time
is 1 (the minimum), the status is checked every 10 ms. As you wrote:
如果HZ是100,char_time是1(最小值),则每10毫秒检查状态。当你写道:
but if i calling specifically delay, before i call
tcsetattr()
, the buffer state is already empty(because during the delay time, the data in serial buffer is transmitted), so that there is no blocking.但是,如果我在调用tcsetattr()之前调用特定的delay,那么缓冲区状态已经是空的(因为在延迟时间内,串行缓冲区中的数据被传输),因此没有阻塞。
In other words, if you delay the process long enough that by the time it gets to the transmitter empty test !port->ops->tx_empty(port)
the transmitter is already empty, no sleep occurs; otherwise it sleeps for at least 1 jiffy.
换句话说,如果你将进程延迟到足够长的时间,当进程到达发射机空测试时!端口->操作->tx_empty(端口)发射机已经空了,没有睡眠;否则它至少会睡1个瞬间。
#2
0
Why don't you try sprintf / snprintf instead printf?? Because about snprintf, you may Speed the time if you shortened the string-Byte?
你为什么不试试sprintf / snprintf呢?因为关于snprintf,如果你缩短了字符串字节,你可以加快时间。