极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 11545|回复: 7

【教程】为何定时做事的ISR或中断程序內不可用Serial.print

[复制链接]
发表于 2015-4-13 23:02:49 | 显示全部楼层 |阅读模式
常常有人用到定时器的中断(或外部中断),
然后想要使用 Serial.print 或 Serial.println 送数据到串口监视器查看,
可是却常常有人发现加了一些 Serial.println  之后可能很快就不动了 !?

官方网站也建议在 ISR( ) 內或是在用 attachInterrupt 连接的中断处理程序內,
最好不要使用 Serial.print 或 Serial.println 这类函数 (function) !

那到底在 中断处理程序內 可不可以用 Serial.print 和 Serial.println 呢 ?
其实答案是勉强可以用 Serial.print( ) 与 Serial.println( ) 的 !
为何说勉强可以, 不是说不可以, 也不说可以 ?


因为,  只要你的中断请求的间隔时间不是太短, 那使用 Serial.print 其实並不会有问题 !
怎样才叫做太短呢? 就是短到 Serial.print 来不及或快要来不及也可能会有问题!
如果你的中断一秒才来一次或更久才来一次, 那用 Serial.println应该没问题

如果你的中断请求是 1ms 来一次,那肯定来不及 !!
原因很简单, 来不及打印 Serial.println( ) 要求送出的字符串。
奇怪!?
不是说 Arduino CPU 在 16MHz 的时脉 (Clock)之下, 最快 1us 可以做 16 个指令,
那 1ms 就可以做 16000 个指令了,怎会小小 Serial.print 一下就来不及呢?
原因当然就是 Serial.print 很慢很慢 !


    其实, 所谓 1us (micro second)可以做 16 个指令是指最简单的机器指令,
对於 C/C++ 写的每句指令因为相当於数个到数十个机器指令,
所以 C/C++ 每句指令大多数要 0.5 us 到 1 us甚至更多的时间(例如调用 millis( )  或调用 micros( ) 就大约要 2 us)。

聪明的你已经算出那这样 1ms 还是可以做大约数百甚至多到两千个 C/C++ 指令 !
没错, 可是, 在 Baud rate (波特率) 9600 的情况下, 打印一个 char 就要大约  1ms = 1000us 的时间。
这是可以算的, 9600bps 意思就是每秒 9600 bit,
一个 char 要用 10 bit,包括內容 8 bit,开始(Start) 1 bit,结束(STOP) 1 bit,
所以,9600bps 意思就是每秒大约 9600/10 = 960 char (Byte);
这意思就是 1 char 大约要 1ms = 1000 us 的时间 (1秒/960 = 1.04ms)  !
P.S.
  Serial.print 本身要花时间且传送要做一点准备工作也要一点时间,
   还有, 1秒 / 960 char 这样 1 char 是 1.04ms, 所以印 100 char 要大约 104.03 ms
回复

使用道具 举报

发表于 2015-4-14 11:10:52 | 显示全部楼层
自己建立缓冲,单字符记字节发送?
回复 支持 反对

使用道具 举报

发表于 2015-4-14 13:28:46 | 显示全部楼层
我准备用这个方法做一个简单的逻辑分析仪呢!
躺枪了,看来没搞头了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 16:27:33 | 显示全部楼层

补充一下
虽然说打印印 100 char 要大约 104.03 ms
不过幸好这些时间大部分不是 CPU  的时间 !
或者应该说:
只要来得及印出, 就几乎不太花 CPU 的时间,
或说只要 Buffer 永远没满掉, 就不太花 CPU 的时间 !
只有当 Buffer 满了之时,
Serial.print( ) 只能等 buffer 有空才会导致 CPU 无法做任何事 !
因为此时 Serial.print( ) 回不來 !!

回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 16:52:08 | 显示全部楼层
tsaiwn 发表于 2015-4-14 16:27
补充一下
虽然说打印印 100 char 要大约 104.03 ms
不过幸好这些时间大部分不是 CPU  的时间 !



前面说了, 用 Serial.begin(115200);
大约 .begin(9600)的 12 倍快;
这样 1ms 大约可印 10 char;

另外,
Output buffer 是 64 bytes
所以还要注意 .print 的间隔,
不要有让 buffer 满的时机,
否则 Serila.print( ) 回不来就浪费 CPU 时间!


如果 RAM 够用,
必要时可把 Output buffer 偷偷改为 大一些
例如 128 甚至 256
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 16:52:44 | 显示全部楼层
tsaiwn 发表于 2015-4-14 16:52
前面说了, 用 Serial.begin(115200);
大约 .begin(9600)的 12 倍快;
这样 1ms 大约可印 10 char;
...

不过请注意,
Buffer 改再大每秒可以印出的 char 还是一样的 !!
回复 支持 反对

使用道具 举报

发表于 2015-4-14 20:55:19 | 显示全部楼层
谢谢分享,学习啦
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 23:27:20 | 显示全部楼层
tsaiwn 发表于 2015-4-14 16:52
不过请注意,
Buffer 改再大每秒可以印出的 char 还是一样的 !!

既然 Buffer 改再大每秒可以印出的 char 还是一样
那把 buffer 改大不是没任何用处吗 ?
错 !
有用处 !!
下次再告诉大家 
欢迎知道的大神帮忙说明 :- )
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-19 04:03 , Processed in 0.035315 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表