tsaiwn 发表于 2015-4-5 16:49
补充..
其实, 所谓 1us (micro second)可以做 16 个指令是指最简单的机器指令,
对於 C/C++ 写的每句 ...
不相信, 写个 Arduino 程序来测试: - // measure Serial.print cost
- unsigned long begt, endt; // for record micros( )
- int baud = 9600;
- char ggyy[ ] = "-2-4567890ABCD56"; // 字符串用来测 60..66 char
- void setup( ) {
- Serial.begin(baud);
- Serial.println(String("Test Baud Rate = ") + baud);
- Serial.println("----------\nNow test print 50 chars immediate return");
- test1( );
- Serial.println("\n\n==========\nNow test with .flush( )");
- test2( );
- test3( );
- } // setup(
- void loop( ) {;}
- void test1( ) {
- Serial.flush( );
- delay(258);
- begt = micros( );
- //Serial.print(ggyy); // 用来测 60 .. 66 char
- Serial.print("123456789x123456789X");
- Serial.print("..34567890-x-4567890F234F678\r\n");
- endt = micros( );
- Serial.println(String("Run time = ")+ (endt-begt)+ "micro seconds = "+
- (endt-begt)/1000.0 + "milli seconds");
- }
- void test2( ) {
- Serial.flush( );
- delay(258);
- begt = micros( );
- //Serial.print(ggyy); // 用来测 60 .. 66 char
- Serial.print("123456789x123456789X");
- Serial.print("..34567890-x-4567890F234F678\r\n");
- Serial.flush( ); // 確定都已经打印出去
- endt = micros( );
- Serial.println(String("Run time = ")+ (endt-begt)+ "micro seconds = "+
- (endt-begt)/1000.0 + "milli seconds");
- }
- void test3( ) {
- Serial.println(String("\n\nPrint 100 char with flush at Baud rate ") +baud);
- Serial.flush( );
- delay(258);
- begt = micros( );
- //Serial.print(ggyy); // 用来测 60 .. 66 char
- Serial.print("123456789x123456789X");
- Serial.print("..34567890-x-4567890F234F678\r\n");
- ///
- Serial.print("123456789x123456789X");
- Serial.print("..34567890-x-4567890F234F678\r\n");
- Serial.flush( ); // 確定都已经打印出去
- endt = micros( );
- Serial.println(String("Run time = ")+ (endt-begt)+ "micro seconds = "+
- (endt-begt)/1000.0 + "milli seconds");
- }
复制代码 大家可以自己测试看看, 以下我把我测的各种结果跟大家分享:
(1)测试在 9600 bps 打印 50, 60, 61, .. 68 char, 100 char, 200char, 300char, 500char, 600char, 1000char;
以下两栏结果分別是在 Serial.print 之后立即抓时间, 以及 test2( ) 是用 .flush( ) 之后再抓时间:
打印字符数 test1( ) test2( )
50 char 0.51 ms 52.03ms (相差 51.52)
-------------------------------------------------------
60 char 0.61 ms 62.43ms (相差 61.82)
61 char 0.62 ms 63.47ms (相差 62.85)
62 char 0.62 ms 64.51ms (相差 63.89)
63 char 0.64 ms 65.55ms (相差 64.91)
64 char 0.64 ms 66.59ms (相差 65.95)
65 char 0.66 ms 67.63ms (相差 66.97)
66 char 1.08 ms 68.67ms (相差 67.59)
67 char 2.12 ms 69.72ms (相差 67.6)
68 char 3.16 ms 70.76ms (相差 67.6)
---
100 char 36.44 ms 104.03ms (相差 67.59)
200 char 140.44 ms 208.03ms (相差 67.59)
300 char 244.44 ms 312.03ms (相差 67.59)
500 char 452.44 ms 520.03ms (相差 67.59)
600 char 556.44 ms 624.03ms (相差 67.59)
1000 char 972.44 ms 1040.03ms (相差 67.59)
========================= 请注意, 0.64ms 可能是 0.636ms 或 0.640ms 或 0.644ms, 因印出时自动四捨五入!
(2)改用 Baud Rate 19200 bps,
发现所需时间就是大约一半, 很合理 !
(3)改用 Baud Rate 57600 bps,
发现所用时间就是 9600bps 的大约七分之一,
(4)改用 Baud Rate 115200 bps, 时间又是 57600bps 的大约一半 !
(5)回头解释刚刚(1)的结果, 以下先討论 test1( )的方式,
你会发现, 如果不使用 Serial.flush( ); 把打印数据冲刷出去.
则印 50char 要 0.51ms (且这答案在各种 Baud Rate 几乎都一样 !!),
印 60 char 要 0.61ms, 印 64 char 要 0.64ms, 印 65 char 要 0.66ms (因为只印到小数点后两位, 是把小数点后第三位做四捨五入)
意思是大约每个 char 要大约 0.1ms (不是 1msㄟ, 怎会这么快 !?),
別高兴, 事实上这时间不是真正打印出去的时间, 是复製字符串到 Serial 的输出缓存区(Buffer)的时间,
所以, 你会发现, 即使提高 Baud Rate 到 57600, 打印 50 char 也是要 0.51 ms
那为何 65 char 是 0.66ms, 可是 66 char 却是 1.08ms, 67 char 要 2.12ms, 68 char 要 3.16ms ???
这是因为输出缓存区(Output buffer)只有 64 bytes (chars),
当缓存区满的时后, Serial.print 必须等有空位才可以把剩下的字符串复製进去缓存区,
必须都已经把参数的字符串复製进去缓存区了, 然后 Serial.print 才能返回!
因此, 你可以发现, 打印 50 char 要 0.51ms, 但是打印 500char, 却要高达 452.44ms, 不是 5.1ms !!!
如果你把系统 Serial 的输出缓存区改为 500 bytes 则打印 500char 就会是大约 5.1ms, 就是复製到缓存区的时间 !!
(6)再来討论(1)的结果, 但重点放在用 test2( ), 也就是 Serial.flush( ); 之后再做 endt = micros( ); 取时间:
如果没使用 Serial.flush( ); 则表示可能还会有最多 63 bytes 在输出缓存区还没真的被送出去!!
现在如 test2( ) 內的做法, 等 Serial.flush( ); 確定都送出之后再取得 micros( ) 时间, 结果 ..
你会发现 50char 要 52.03ms, 60char 要 62.43ms, 64 char 要 66.59ms, 印 65 char 要 67.64ms, 印 66 char 要 68.67ms, 印 67 char 要 69.72ms,
印 100 char 要 104.03ms, 印 200 char 要 208.04ms, 印 300 char 要 312.06ms, 印 500 char 要 520.08ms,
看到没, 几乎就是 1 char 要 1 ms 啦 !!
那为何是比 1ms 略大呢?
首先 Serial.print 本身要花时间且传送要做一点准备工作也要一点时间,
还有, 1秒 / 960 char 这样 1 char 是 1.04ms, 所以印 100 char 要大约 104.03 ms 完全合理 !!!
另外, 打印 66 char 以上, 不论是 67 char, 100 char, 200char, 300 char, 500 char,甚至1000char,
你会发现没有 Serial.flush( ); 只是比有写 Serial.flush( ); 少了大约 67.5 ms, 且 66 char 以上后几乎都是这样!
这是因为缓存区只有 64 bytes, 所以在打印字数小於 65 char 时,
因第一 char 立即送出, 剩下的字符都可复製到缓存区然后就可从 print 或 println 立即返回!
但是打印太多字在缓存区满了之后, Serial.print 必须等到有一个 char 被抓走空出一byte的位置才可再把一个 char 填进去缓存区,
这大约要 1ms 的时间, 必须把要 print( ) 的所有字符都填入缓衝区之后 Serial.print 才会结束;
而此时缓存区內就是还有 64 char 还没送出, 这是有 .flush( ) 和没有 .flush( ) 差异时间的最主要来源 !!
所以, 打印 1000 char, 没有 .flush( )时间是 972.44ms, 有 .flush( ) 確定打印完毕则是 1040.03ms, 相差大约67.5ms !
,,,。。。,,,。。。,,,。。。!
(7)补充一下, 虽然 int 只有两个 byte, 但是:
int k = 12345;
Serial.println(k); 这句会送出 7 个 char:
包括 "12345" 以及 "\r\n" 这两个字符;
但请注意: Serial.print( (char)123); 这样只有送出 1 个 char !!
还有:
float ggyy = 1.25612345;
Serial.println(ggyy); 这句会送出 6 个 char:
包括 "1.26" 以及 "\r\n" 这两个字符;
注意 float 和 double 的数值打印时, 小数点之后预设(默认)只印两位(但会从没印出的第一位四捨五入到有印的最后一位):
http://arduino.cc/en/serial/print
|