魔法书2:测试Arduino 执行速度极限

栏目: 服务器 · 发布时间: 6年前

内容简介:我是潘,曾经是个工程师。这是为 Ardui.Co 制作的 “Arduino 魔法书” 系列的专栏。上次我们介绍了如何利用底层代码高效节约Arduino存储空间。本节课将测量一下,这些底层代码究竟让 Arduino 提高了多少效能。要测量底层代码的效率,得先研究一下如何测量 Arduino 的执行速度。最简单的方法自然是示波器,但我们先从 Arduino 入手,让它测量自身的运行速度(除了自己,Arduino 也可以其他设备速度,原理一样)。值得注意的是,测量自己必定会消耗一些自身的资源影响结果,所以只能做

我是潘,曾经是个工程师。这是为 Ardui.Co 制作的 “Arduino 魔法书” 系列的专栏。上次我们介绍了如何利用底层代码高效节约Arduino存储空间。本节课将测量一下,这些底层代码究竟让 Arduino 提高了多少效能。

要测量底层代码的效率,得先研究一下如何测量 Arduino 的执行速度。最简单的方法自然是示波器,但我们先从 Arduino 入手,让它测量自身的运行速度(除了自己,Arduino 也可以其他设备速度,原理一样)。

值得注意的是,测量自己必定会消耗一些自身的资源影响结果,所以只能做相对测量,而不能做绝对测量。 先看看Arduino UNO 在一秒钟内能执行多少次循环:

void setup() {
  Serial.begin(9600);
  Serial.println("Test begins now.");
}
extern volatile unsigned long timer0_millis;
void loop() {
  unsigned long i = 0; // 测试值
  unsigned long j; // 停止时间
  j = millis() + 1000; // 当前时间
  while (timer0_millis < j) i++;
  Serial.println(i);
  while (1);
}

打开串口监视器,按下 Arduino UNO 的 Reset 按钮,显示 837173,这个数字说明Arduino 在一秒钟内执行了83万多次的循环,相当厉害!

不过,这个数字只告诉了我们 Arduino 在什么都不做时的速度,这个值不是绝对的。再强调一点,测量自身是要消耗资源的。

Arduino UNO使用了16MHz的晶振,每秒钟可以执行16,000,000条指令,或者说,CPU 每秒可以运行 16,000,000 个周期。

上面的程序中,16,000,000 / 837,173 = 19.1 周期/循环,每个while()循环大约需要19个周期的CPU资源。

时间判断使用了 timer0_millis 来计算系统时间,这个变量在上一节介绍过,属于定时器 timer0,系统每过1ms就会增加1。只要不重置它,millis() 这个Arduino 包装过的时间函数依然有效。不过,一旦重置,millis() 就失效了。

直接调用 timer0_millis,可以节省不少系统资源,如果换成millis() 效率会低很多(可尝试自行替换)。

digitalWrite() 的性能

之前提到,digitalWrite() 很占空间而且效率很低,我们拿它跟 bitSet() 对比测试一下。

void setup() {
  Serial.begin(9600);
  Serial.println("Test begins now.");
}
extern volatile unsigned long timer0_millis;
void loop() {
  unsigned long i = 0; // 测试值
  unsigned long j; // 停止时间
  j = timer0_millis + 1000; // 当前时间
  while (timer0_millis < j) {
    digitalWrite(13, HIGH); // 亮灯
    digitalWrite(13, LOW); // 灭灯
    i++;// 计数
  }
  Serial.println(i);
  while (1);
}

Arduino UNO 在这个循环上一秒钟内执行了 112,811 次,平均每个循环用了 16,000,000 / 112811 = 141.83 个CPU 周期。两个digitalWrite() ,平均每个 71 个周期。

如果用置位 bitSet() 宏,能提升多少性能呢?将 bitSet() 和 bitClear() 置换 digitalWrite():

void setup() {
  Serial.begin(9600);
  Serial.println("Test begins now.");
}
extern volatile unsigned long timer0_millis;
void loop() {
  unsigned long i = 0; // 测试值
  unsigned long j; // 停止时间
  j = timer0_millis + 1000; // 当前时间
  while (timer0_millis < j) {
    bitSet(PORTB, 5); // 亮灯
    bitClear(PORTB, 5); // 灭灯
    i++;// 计数
  }
  Serial.println(i);
  while (1);
}

这么简单的替换,每秒就增加到 691,578 次循环,足足快了6倍!

23个CPU周期即完成一个循环。但是还不够快,我们把While()循环的代码修改一下:

  while (timer0_millis < j) {
    bitSet(PORTB, 5); // 翻转LED
    i++;// 计数
  }

现在每秒执行757,443个循环,21个CPU周期即执行一个循环。LED两个循环就被反转一次,相当快了。

虽然LED疯狂地闪烁没啥用处(实际上是个高速 PWM 信号驱动),但如果在其他应用中,能这么快地收发数据肯定是一件很棒的事。

还要再快点

这就是Arduino的极限吗?肯定不是,因为测量自身就需要消耗不少资源,现在把自身测量的代码去掉,用外部的设备,示波器来测量它的速度。

void setup() {
  bitSet(DDRB, 5);
}
 
void loop() {
  bitSet(PINB, 5); // 翻转
}

这个程序很简单,设置 D13 为输出,利用 loop() 循环来执行翻转。此时,Arduino 没空帮你测量自己了,就要靠我们的大家伙示波器了: 魔法书2:测试Arduino 执行速度极限 示波器探针与 D13 连接,测出的频率是1.33MHz,16MHz / 1.33MHz = 12.03MHz,相当于12个周期执行一次翻转循环。

除了循环,Arduino 什么都不做,为什么还需要12个周期。原因是基于C构建的 Arduino IDE 隐藏了 main() 函数,每次执行loop()时,其实都是被 main() 调用。这12个周期就是loop()的开销。

能否将 loop() 的资源节省下来?可以,只要使循环在 loop() 完成即可,一个while() 就可以解决问题:

void setup() {
  bitSet(DDRB, 5);
}
 
void loop() {
  while (1) {
    bitSet(PINB, 5); // 翻转
  }
}

现在速度提高到2MHz左右,只需要8个周期就可以执行一个循环! 魔法书2:测试Arduino 执行速度极限 但还有一个问题,示波器时不时出现跳跃和毛刺。这是因为Arduino的定时器是一直开着的,每秒钟产生1000次左右的中断,中断函数执行期间,消耗CPU资源,I/O 是不会翻转的。在setup() 里面增加 noInterrputs(); 告诉程序禁止中断,即可解决问题了。

通过简单的优化,不仅可以节省Arduino 的空间,而且更有效地执行程序。


以上所述就是小编给大家介绍的《魔法书2:测试Arduino 执行速度极限》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机网络(第5版)

计算机网络(第5版)

Andrew S. Tanenbaum、David J. Wetherall / 严伟、潘爱民 / 清华大学出版社 / 2012-3-1 / 89.50元

本书是国内外使用最广泛、最权威的计算机网络经典教材。全书按照网络协议模型自下而上(物理层、数据链路层、介质访问控制层、网络层、传输层和应用层)有系统地介绍了计算机网络的基本原理,并结合Internet给出了大量的协议实例。在讲述网络各层次内容的同时,还与时俱进地引入了最新的网络技术,包括无线网络、3G蜂窝网络、RFID与传感器网络、内容分发与P2P网络、流媒体传输与IP语音,以及延迟容忍网络等。另......一起来看看 《计算机网络(第5版)》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具