适用于ROHM传感器评估套件的轻量级Arduino库中,我介绍了RohmMultiSensor——帮您轻松连接ROHM传感器评估套件多个传感器的Arduino库。该库的核心特征之一就是通过仅编译与所需传感器相关的库部分,显著减小程序的大小。这意味着当您使用较少的传感器时,整体程序大小和内存使用量会减小。但是,这究竟是如何实现的呢?当您#include一个库然后按下“Upload”(上传)按钮之后,幕后究竟会发生什么?

硬件

  • Arduino UNO

软件

  • Arduino IDE

几乎所有用过Arduino的人都使用过库。这就是Arduino编程对初学者来说如此简单的原因之一——您无需深入了解传感器的工作原理;库会替您完成大部分工作。将代码分成单独的文件也是一种很好的编程习惯。组织、调试和维护单个文件要比处理一大堆代码容易得多。

想必Arduino初学者都已经熟悉了将库添加到主程序中的#include命令。要了解这是如何实现的,我们首先应快速了解C/C++源代码如何编译成程序。别担心,这听起来比较复杂,其实很简单。我们来看一下编译的工作原理。

按“上传”之后

我们先做一个快速实验:启动Arduino IDE,打开其中一个示例代码(比如“Blink”),然后按“Verify”按钮。假设程序中没有语法错误,底部的控制台应该会打印出有关程序大小和内存的一些信息。嗯,刚才我们成功地将C++源代码编译成了二进制文件。在编译过程中发生了以下几件事:

  1. Arduino IDE执行了一种名为“语法检查”的操作,以确保您编写的程序是真正的C/C++源代码。此时,如果发生函数拼写错误或忘记分号,那么编译就会停止。
  2. 语法检查之后,Arduino IDE会启动另一个名为preprocessor(预处理器)的程序。这是一个非常简单的程序,如果文件是C/C++源代码,它不会怎么样。我们稍后会详细讨论这一步骤。那么现在我们假设结果是一个名为“扩展源代码”的文件——一个文本文件。
  3. 然后,该扩展源代码被移交给另一个名为compiler(编译器)的程序。该编译器(在Arduino IDE中是avr-gcc)接收文本源,并生成汇编文件。汇编一种人类可读的低级编程语言,但是更接近机器代码——适用于特定处理器的指令。这里就是您编写程序之前必须选择正确Arduino板的原因——不同的开发板具有不同的处理器,而处理器又具有不同的指令集。
  4. 处理您Arduino程序下一个的系统程序叫做assembler(汇编程序)。该程序会生成一个“目标文件”。该文件主要是机器代码,但也可以包含针对其他目标文件对象的“引用”。这允许Arduino IDE“预编译”一些编写Arduino程序时会始终用到的库,从而使整个过程更快。
  5. 最后一个阶段称为链接,由另一个名为linker(链接器,显而易见)的程序完成。链接器获取目标文件并添加缺少的内容——主要是来自其他目标文件的符号,以生产可执行文件。在此之后,程序完全转换为机器代码,并可以上传到电路板。

arduino preprocessor

现在,我们对Arduino程序编译有了一个基本的了解。但是在上述所有编译阶段中,我们将只关注第二个阶段:预处理器。

 

预处理器基本知识

在上本中,我提到预处理器本质上非常简单:接收文本输入,搜索关键字,根据找到的内容进行一些操作,然后输出不同的文本。它非常简单,同时也非常强大,因为它允许你用普通C/C++语言完成一些本来会非常复杂的事情(如果可能)。

预处理器会搜索以井号(#)开头且后面有文本的行。这种语句叫做预处理器指令,是预处理器的一种“命令”。预处理器指令的完整列表以及详细文档的地址如下所示:

https://gcc.gnu.org/onlinedocs/cpp/Index-of-Directives.html#Index-of-Directives

接下来,我将主要关注#include#define和条件指令,因为这是Arduino最有用的指令。如果您想了解一些更“奇异”的指令,比如#assert 或 #pragma, 请参阅上述地址,以获取官方信息。

 

添加额外代码:#include 指令

这可能是最著名的预处理器指令,不仅Arduino爱好者都知道,而且C/C++编程人员也都了解。原因很简单:该指令的作用是包含库。但是,这究竟是如何实现的呢?确切的语法如下所示:

 

 

 

 

两者的区别比较小,主要在于预处理器搜索file(文件)的确切位置。如果是第一句,预处理器仅搜索IDE指定的目录。如果是第二句,预处理器首先查看包含源文件的文件夹,且仅当没有在该目录下找到file(文件) 时, 它才会搜索第一句的搜索目录。由于包含库的文件夹是在Arduino IDE中指定的,因此在包含库时两者之间没有重大区别。

当预处理器找到文件时,它只是将其内容复制粘贴到源代码中,以替代程序中的#include指令。但是,如果在任何目录中都找不到此文件,就会引发致命错误,编译停止。

要记住,预处理器只处理文本——无法理解那些特殊字母和数字的含义。最重要的是,它对所包含的内容和包含次数绝对不会进行更高级别的检查。让我们来看一下使用编写不正确的库会发生什么。

了解更多关于Arduino入门指南请点击:查看详情