[Arduino] 使用 Arduino Eclipse 插件进行OOP编程及类库开发

Photobucket

本文是《[Arduino] Develop Library with Arduino eclipse plugin》的中文版本,并增加一点本土内容。之所以先写英文的,是因为写作过程中,需要和插件作者保持沟通,还请各位见谅。

eclipse.baeyens.it 开发中的 Arduino Eclipse 插件,能快速将eclipse打造为Arduino的开发平台。从目前的经验看来,开发的部分基本能实现完全的替代。虽然少了串口助手的部分,但平心而论,ADE(Arduino “官方”标准开发环境)的串口助手是很弱的。因为只能传递可见字符数据,没法任意发送0-255的单字节数据。所以这个集成的Serial Monitor还是比较鸡肋的。所以用自己喜欢而且顺手的就是,并不要紧。使用 Arduino Eclipse 插件,在 eclipse 上进行开发的Arduino程序,同样能方便地移植到 ADE 上,在开源社区分享,也没有问题。而开发效率、编译速度、下载速度,都将大幅提升,爽得一塌糊涂。

在这款插件出现之前,Eclipse 就已经可以用来作 Arduino 的IDE了,但配置过程相当崩溃,有插件就爽了很多,能轻松实现平台搭建。

本文结合Arduino eclipse Plugin 英文向导 and Arduino playground 的 LibraryTutorial 做一个使用eclipse开发Arduino类库的分步骤教程。建议先查阅一下这2处的内容,这样看下文会轻松很多。


1. 安装 Eclipse 及 Arduino 插件
arduinowitheclipse_00
插件官方安装向导 ,英文很简单,E文不太熟悉的朋友,配合字典就能搞定。我的经验就是,安装带有CDT(C/C++ Development Kit)的eclipse就是了。如果之前已经在用 eclipse 进行 Java、Ruby或其它开发的朋友,并不需要重新下载,直接安装CDT插件就是了,毕竟Arduino用的是C++。使用 Arduino 插件进行开发,并不需要提前安装 AVR 插件,感觉是已经被Arduino插件集成了,所以安装配置就更简单许多。

之前根据网络上的各类资料,重新编辑过一篇安装 Eclipse 3.7 Indigo 学习 Java 的blog,里面提到了汉化如何进行,有兴趣的朋友不妨去看看,在那个基础上,安装CDT,插件,就能直接用来开发Arduino了。那个时候刚刚接触 eclipse,用起来小心翼翼,现在就放开了许多,都敢碰了,呵呵。

不过一个eclipse里面一下运行太多插件,对速度还是有影响的,为Arduino开发,我另外整理了一个较为“纯净”的eclipse: Eclipse 3.7 Indigo + CDT + Arduino Plugin + Subclipse

Eclipse是绿色软件,复制一份原始的安装包就好了。其中 Subclipse 用于版本控制以及在 Google code 进行代码托管,非常方便。

2. 从一个 Sketch 开始

在安装及配置好 Arduino Eclipse 插件之后

1) 新建一个工作空间,例如, “H:\workspace\myArduinoLibs”.
Photobucket
2) 新建一个sketch, 例如, “MorseTest”
Photobucket
Photobucket
在项目管理器窗口/工作空间目录下。会出现2个文件夹。其中一个所选用的Arduino平台型号命名,作为 Arduino Core,里面大致的内容就是与该板参数相匹配的Arduino核心库。每次使用一个新的工作空间,这个Arduino Core文件夹都会被新建。但如果再次基础上,添加一个基于同样 Arduino 平台的 Sketch 时,不会重复新建 core 文件夹,它为自动在工作空间内共享(当然,如果不是很有把握,最好也别去改它)。如果后来在同一工作空间下,使用不同的 Arduino 平台开发,将会新建一个新平台的Core文件夹。
Photobucket
3) 构建 Core(不过并不必要):点击 Core 文件夹, “Arduino_UNO”,后点击工具栏的小锤子图标。
4) 构建 sketch,点击 Sketch文件夹, “MorseTest”,后点击工具栏的小锤子图标。如果跳过了刚才的第3步,那么此刻编译器也会先构建 Core,再构建 Sketch。注:构建,Build,Make,就是编译、链接的意思。如果光点击程序文件,可能构建不出什么东西,还是要选择工程文件夹,再进行构建。因为一次构建构建的是整个Project.

Photobucket
如果插件安装正确的话,此处的构建,应该没什么问题,也就是说编译、链接都应该没问题,毕竟现在什么代码都没输入进去么。

不过值得注意的是,在使用目前的 Arduino Core 的过程中,可能会出现编译后带有警告的情况。这些或许是ADE内部自动隐藏或是降低了警告级别造成的。不必担心,程序一般情况下依然是可以运行的。相信随着 Arduino 底层库的不断完善,这些警告都会慢慢消失的。在我个人的实践中,基本都要加上 “extern HardwareSerial Serial;” 这句声明,才能正常使用串口对象,感觉内建的Serial实例,是以类似全局变量的形式保存, 而在调用的时候,是要声明一下。但是在ADE中插入这句声明,也不会影响编译。所以,就放心地加进去咯。至少从ANSI的标准来看,代码是规范了不少。

5) 建议此时,可以通过点击工具栏的“AVR”按钮,将这个空的 Sketch 下载(中文习惯都是说“下载”,就像“XX下载器”,而英文版本里面偏偏都是用上传“Upload”,比较无语)到Arduino的板子上,测试连接通讯是否正常。这里,可以理解为和 ADE 一样,编译和下载是分开的。但是ADE里面,下载还包含了编译,而且编译得很慢。Eclipse里面,这两个步骤是完全独立的,所以,一次次点击“下载”,可能下载的都是老文件,如果忘记重新编译的话。新手要注意这一点。

6) 将 librayTutorial 里的代码拷贝至 “MorseTest.cpp”. 头文件 “MorseTest.h”就不用去动它了,不需要对其进行任何编辑。

// Do not remove the include below
#include "MorseTest.h"

void dot();
void dash();

int pin = 13;

//The setup function is called once at startup of the sketch
void setup() 
{
// Add your initialization code here
	pinMode(pin, OUTPUT);
}

// The loop function is called in an endless loop
void loop()
{
//Add your repeated code here
	dot();	 dot(); dot();
	dash(); dash(); dash();
	dot();	 dot(); dot();
	delay(3000);
}

void dot()
{
	digitalWrite(pin, HIGH);
	delay(250);
	digitalWrite(pin, LOW);
	delay(250);
}

void dash()
{
	digitalWrite(pin, HIGH);
	delay(1000);
	digitalWrite(pin, LOW);
	delay(250);
}

此处较例程添加了 dot() 和 dash() 的声明,相信有C/C++编程经验的朋友都知道是为什么。因为这2个函数,都放置在 loop() 函数后,而Eclipse里面的GNU/GCC编译器是对于规范要求比较严格的,要么放在loop()之前,要么加声明,否则就是无法编译通过。ADE则相对宽松一些,感觉怎么写都行,ADE优化过的编译器会自动弥补这些问题,让规则显得更加宽松。但作为严谨的 C/C++ 开发人员来说,遵守严谨的规则,对于保证程序正确运行、排错,是相当重要的,而且一般都比较都已经是习惯了。同样,在ADE中添加声明,也同样不会影响到编译。

现在就可以开始体验到 Eclipse 的强悍之处了:

  • “Tab” 键可以正常反应了,ADE中竟然直接用2个空格替代,真是要吐槽一下。而且 Shift+Tab 也能用了,调整缩进爽很多。
  • 各种代码高亮
  • Ctrl+Shift+F 进行自动排版。排版的样式,可以在 Preferences -> C/C++ -> Formatter 里面自定义,我个人当然是喜欢花括号独占一行而且对其的样式~
  • Alt+/ 进行自动补齐,默认情况下,按“.”也会有完整的提示框弹出。有VS使用经验的人,一定非常依赖这个功能,:)
  • 实时的错误及警告提示,有的时候倒也不必惊慌,或许重新Make一下,就消失了
  • Ctrl+左键单击,查看引用,这个是我的最爱,查看Arduino库变得非常轻松,终于不用几个文档翻来倒去了。

这几条一说,基本都想把ADE扔一边了吧~ 那还不赶紧试一下~

7) 构建并下载,都没错的话,应该可以看到Arduino上Pin13的LED开始发出“三短三长三短”的SOS信号了。

4. 从 POP 面向过程 到 OOP 面向对象

1) 在 Sketch 项目内为 类库 library 新建一个文件夹,本例中,命名为“Morse”
Photobucket
2) 在这个 类库文件夹 中新建一个类,
Photobucket
会同时建立2个文件,.h的头文件,和.cpp的源文件。什么代码都还没写,eclipse 已经把构造函数,析构函数的框架都搭起来了。
Photobucket
3) 在类头文件“Morse.h”中,包含引用 “Arduino.h”

除非是建一个纯C++的类,或者是应用逻辑层的类,否则如果涉及到 Arduino 的底层硬件操作,一般也就是引用“Arduino.h”这个头文件就好了,对于IO设置,位运算都有现成的函数可用。而且作为一个Arduino的sketch,不管怎么样都会包含这个头文件的,类库中就包含一下,也不会对最终sketch的文件大小会有什么影响。而且一个“Arduino.h”似乎就包含了所有可能会用到 Arduino 函数库,很方便。写类,自然还是要学习一下C++的编程(学C++和学VC是2个概念)。不过大体上,可以想象成在写一个没有setup()和loop()的sketch。

4) 写类

librayTutorial所示, Morse.h:

/* Morser.h */

#ifndef MORSE_H_
#define MORSE_H_

#include "Arduino.h"

class Morse
{
public:
	Morse(int pin);
	virtual ~Morse();
	void dot();
	void dash();

private:
	int _pin;

};

#endif /* MORSE_H_ */

Morse.cpp:

/* Morse.cpp */

#include "Morse.h"

Morse::Morse(int pin)
{
	// TODO Auto-generated constructor stub
	_pin = pin;
	pinMode(_pin, OUTPUT);
}

Morse::~Morse()
{
	// TODO Auto-generated destructor stub
}

void Morse::dot()
{
	digitalWrite(_pin, HIGH);
	delay(250);
	digitalWrite(_pin, LOW);
	delay(250);
}

void Morse::dash()
{
	digitalWrite(_pin, HIGH);
	delay(1000);
	digitalWrite(_pin, LOW);
	delay(250);
}

例程里的代码,和Eclipse的代码的主要不同之处,在于在eclipse这边过了一个虚析构函数。这在C++程序里面是非常常见的,让类可以继续得到继承,是规范的写法。相信虽然ADE的这个例程没这个东西,但是也会欣然接受这种让类定义更加完整的做法。
Photobucket
这样,一个最简单的Morse类库就写好了。使用面向对象编程新建类,不单单可以用在编写类库,更应该用在进行应用类,或者说实现中间层逻辑类的开发,也同样适用。这样,就能把传统的面向过程的编程,转变为面向对象的编程。对于玩嵌入式底层开发的朋友来说,可能会感觉这样损失了执行效率,还增加了程序的大小。但是对于大多数用Arduino玩应用的朋友来讲,我相信还是会舍得这些硬件开销。仁者见仁智者见智。

5) 调用类

回到Sketch, “MorseTest.cpp”。因为大部分的功能代码已经转移(更专业的叫法,就是“封装”)到类中。所以主代码就立马变得整洁美观了。记得在头部,对类进行引用,#include “Morse.h”

/* MorseTest.cpp */
// Do not remove the include below
#include "MorseTest.h"

#include "Morse.h" // The header of the class just created

Morse morse(13);

//The setup function is called once at startup of the sketch
void setup()
{
// Add your initialization code here
}

// The loop function is called in an endless loop
void loop()
{
//Add your repeated code here
	morse.dot(); morse.dot(); morse.dot();
	morse.dash(); morse.dash(); morse.dash();
	morse.dot(); morse.dot(); morse.dot();
	delay(3000);
}

6) 构建OOP工程

点击小锤子图标进行构建,此时会冒出来很多错误……
Photobucket
主要原因是 Sketch 中虽然包含了类库,但链接器并不知道去哪里找它,所以要添加类库的路径。

a) 在项目管理器中,右键单击 Sketch 文件夹,”MorseTest”.
b) 点击 “Properties”.
c) 进入 “C/C++ General -> Path and Symbols”,页
d) 在 “Includes” 标签中,在左边language栏中选择”GNU C++”, 点击右侧的”Add…”按钮。
Photobucket
e) 在”Add directory path”对话框中选择 “Workspace…”
Photobucket
f) 找到类库的文件夹 “Morse”, 点击 “OK”.
Photobucket
g) 类库路径被添加进来,如下图所示。点击“OK”关闭窗口
Photobucket
h) 如果这个框框跳出来,就点“Yes”
Photobucket
i) 重新点击Sketch文件夹,并构建,现在应该是0错误,0警告了。
j) 下载到Arduino板子上,实现的功能,和早先所有程序都堆在一起的而且面向过程的Sketch是一样的。

5. 在ADE中,使用类库

1) 将类库文件夹(“Morse”)复制至ADE所在文件夹的“libraries”文件夹 (“H:\arduino-1.0\libraries\”)内。
2) 打开ADE,就可以在菜单 “Sketch->Import Library…” 中找到Morse类了。(其实ADE还是实现了很多不错的功能呢)
Photobucket
3) 点击它 “#include <Morse.h>” 这句话,就会被添加到新的这个Sketch里面。
4) 从eclipse的sketch,MorseTest.cpp, 复制代码至ADE 除了
#include “MorseTest.h” ADE会自己生成一个类似的文件,或者压根就不需要吧,反正不用这个东西了。
#include “Morse.h” 因为导入类库的时候,已经将这个头文件包含进来了。
5) 编译并下载,应该是没有问题。
Photobucket
6) 在ADE的libraries文件夹内的类库文件夹,“Morse”中,新建一个“examples”文件夹。把刚才复制过来的sketch保存进去,并命名为“SOS”
Photobucket
7) 退出 ADE, 并再次打开。 可以看到 SOS 程序作为 Morse 库的一个实例,出现在菜单里。也就是说现在Morse类,就像ADE已经集成的这么多类一样,可以被导入,并且还提供例程。
Photobucket

6. 在 eclipse 中使用类库

1 sketch = 1 main = 1 project. Main() 函数作为C/C++程序的入口,一个项目中只允许出现一次,否则编译器无法正确进行编译。所以,不能在类的项目(“MorseTest”)中,同时出现多个setup()和loop()。

如果要单独新建一个使用自定义类的Arduino工程(Sketch),最稳妥的方法,还是使用官方指南里面的方法从ADE目录中导入类。

如果希望为单个类库,编写多个示例代码。我个人的做法,就是将eclipse中的测试代码,复制到ADE中,以ino格式保存至ADE相应类库的examples文件夹内。所以,其实在开发过程中,我的测试文件,”MorseTest.cpp”是不断变化的,当测试通过后,就被另存为ino格式。个人的习惯,是不太想为开发测试中的类库,新建一个又一个的工程,毕竟大多数测试代码都是比较短小简单的,所以做个备份,或者存个INO就好。记得每次升级类库的时候,也讲ADE的libraries的老类库进行覆盖。

总结一下,ADE确实做了很多事情,让编程序看起来变得更加简单。但是作为代码编辑器来讲,有经验的程序员可能用起来会比较崩溃,或者说习惯于 VS, eclipse这类高级IDE的程序员用起来,就会感觉相当奔溃。(对于那些用记事本直接玩的孩纸,那还是伤不起……)。而借助 Arduino Eclipse 插件,使用eclipse进行开发,就会是Arduino的开发变得非常轻松、愉快,而且高效。

赶快来试试吧~

PS. 感谢 Arduino Eclipse 插件作者Jantje 鼓励我写下本文,并进行审阅。

关于aGuegu

向着更高的逼格
此条目发表在内功心法分类目录,贴了, , , , , , 标签。将固定链接加入收藏夹。