第1章 开源硬件先驱Arduino
1.1 Arduino介绍
Arduino(见图1-1)是致力于电子产品原型设计的一种开源工具,有别于家用计算机,Arduino的目标是开发可以更加方便感知和控制现实世界的计算机系统。Arduino包括一块包含微控制器的简单电路板,以及用于为电路板进行软件编程的一套集成开发环境(即Arduino IDE)。Arduino可以用于与现实世界进行交互,通过传感器和开关感知环境变化和用户的操作,并通过控制电灯、扬声器、电机来改变光线、声音和运动。Arduino可以作为一台微型计算机独立工作,也可以与通用计算机通信并受其控制。
图1-1 Arduino标识
很多初识Arduino的朋友都会困惑于它的发音。这个单词来自意大利语,可以译为“强大的朋友”,常见的英语发音为阿德伊诺。它源于意大利伊夫雷亚交互设计学院(Interaction Design Institute Ivrea)在2005年开展的一项学生计划,当时的学生使用一款售价100美元的昂贵设备BASIC Stamp进行编程开发。后来这所学校的教师Massimo Banzi(见图1-2)连同另外两人一起开始着手设计一款廉价并且使用简单的开发板,数天后,代码和电路板相继完工,这块板子就被命名为Arduino。
图1-2 Arduino创始人之一Massimo Banzi
此后设计人员不断地对Arduino进行改进,虽然最终学校倒闭了,但是Arduino这一产品却延续了下来。因为Arduino是开源的(遵循一种CC开源协议),你可以在其基础上进行修改,并出售自己设计的产品,但如果要使用Arduino这一标识,就需要支付一定的版权费用。
目前Arduino的硬件已经演进出多种版本,包括简易的Arduino Uno(见图1-3)、基于ARM芯片的Arduino Due、集成以太网和WiFi的Arduino Yun(见图1-4)以及使用TI AM533x系列Cortex-A8芯片、功能强大的Arduino Tre(见图1-5)等。
图1-3 Arduino Uno
图1-4 Arduino Yun
图1-5 Arduino Tre
Arduino的编程语言和开发环境基于Wiring和Processing架构。Processing包含了发展自Java的编程语言和开发环境,而Wiring是用于微控制器的一种开源编程框架,可以让用户编写跨平台的程序,这些代码无需修改就可以在不同的微控制器和电路板上运行。Arduino的开发环境(见图1-6)中集成了很多代码库,通过使用库文件Maker(创客)可以绕开“如何学习使用不熟悉的外围模块”这一令人头疼的问题,比如当你需要为自己的工程添加一个点阵式的LCD显示器,用来显示一些数据和菜单,只要购买或自制一块LCD Shield,然后在IDE中添加LiquidCrystal库,就可以通过几行简单的代码在LCD上显示文字。
图1-6 Arduino IDE
Arduino可以让没有太多编程基础的人做出很酷的东西,这或许正是它的魅力所在。
1.2 Arduino的生态圈
除了核心的电路板以外,Arduino还有种类繁多的扩展功能模块。为什么需要模块呢?例如,某位Maker想要为卧室的窗户做一个每天早上自动拉开的电动窗帘,而他的手里正好有一块Arduino板,那么他只需要一个用来连接电机的电机驱动模块,外加一个可以知道当前时间的时钟模块即可。但是这位Maker的朋友也许对电动窗帘不感兴趣,他似乎更关心当他外出后谁来给他的宠物狗喂食,那么好吧,只要将电机驱动模块拿掉,换上一个控制投食口的继电器模块,即可定时定量地向宠物狗的餐盆中投放食物。
Arduino具有标准的接口,许多主板都互相兼容,因此一个兼容Arduino的模块可以供不同型号的Arduino板使用,而且多个模块也可以叠加在同一块Arduino板上。在某种意义上这种标准化接口和模块复用让Arduino成为电子积木,使用者像搭积木一样将实现不同功能的模块和电路板拼接在一起,这为Arduino建立了良好的生态圈。
上述开源的Arduino扩展功能模块囊括了各种应用领域,如光线、声音、温度、湿度等传感器模块,用于数据通信的GSM、GPRS、Bluetooth模块,用于测量距离与障碍物的红外、超声波模块,用于控制运动和姿态的电机、舵机控制模块等。除了官方推出的Shield(见图1-7)以外,很多第三方机构或个人也制作了个性鲜明的系列模块和扩展板(见图1-8)。有如此丰富的模块来实现各种功能的组合,就不用发愁如何将灵感变成实物了。本书充分汲取了Arduino的这种特性,读者将在后面内容中学到各种模块的使用方法。
图1-7 Arduino官方Shield
图1-8 拥有众多模块的第三方套件Tinker Kit
1.3 Arduino开发方法
1.3.1 Arduino开发环境搭建和使用
使用Arduino的最小化配置为:一台PC、一根A口公头转B口公头的USB线,以及一块Arduino板(比如Arduino Uno)。将Arduino板与PC通过USB线连接,安装一款Arduino IDE软件就可以开始Arduino之旅了(见图1-9)。
图1-9 通过USB线连接PC与Arduino
可以在官方网站http://arduino.cc/上下载Arduino IDE,并且针对Windows操作系统Arduino官方还提供了免安装版本。选择“Windows(ZIP file)”下载Arduino IDE压缩包,笔者使用的版本是Arduino 1.5.5Beta(见图1-10)。
解压下载好的zip文件,无需进行安装,直接双击arduino.exe运行Arduino IDE。
进入Arduino IDE(见图1-11)。软件共分为三部分,上方的菜单栏和工具栏,中间的代码编辑器,以及下方的调试信息栏和状态栏。菜单栏包含了Arduino IDE的全部功能选项。File菜单用于文件操作,如新建Sketch或打开实例;Edit菜单包含文本编辑和查找等功能;Sketch菜单包括编译和导入函数库选项;Tools菜单用于对目标板类型、编程器和串口进行选择和操作。
图1-10 下载Arduino IDE
图1-11 Arduino IDE
小贴士
通常Arduino程序不用Program表示,习惯上称为Sketch,中文意为画或草图。这是因为Arduino的编程语言是基于Processing的,而Processing的设计针对的就是视觉艺术家而不是传统意义上的程序员。
图1-12 工具栏
相比菜单栏来说,工具栏显得十分简洁,总共有6个按钮(见图1-12)。从左至右依次为“校验”、“上传”、“新建”、“打开”、“保存”和“串口监视器”按钮。“校验”(Verify)按钮通过使用编译器编译程序来检查代码的语法错误。“上传”(Upload)按钮即通常所说的下载或烧写功能,用于更新Arduino板中的程序。“串口监视器”(Serial Monitor)按钮会打开一个串口终端窗口,通过这个窗口可以使用ISP串口与Arduino通信。
Help菜单中的Getting Started选项俨然就是一个本地运行的袖珍版Arduino网站(见图1-13),用户可以在其中找到Arduino的入门教程和函数使用说明,虽然内容是全英文的但却通俗易懂,建议初学者通读一遍,对以后使用Arduino会有很大帮助。
图1-13 Arduino Getting Started页面
熟悉了Arduino IDE之后,我们来一同了解Arduino IDE的使用和开发流程。首先,通过菜单栏Tools→Board选项选择一款Arduino板。Arduino IDE支持目前市面上所有的官方Arduino板,笔者使用的是Arduino Uno R3,因此选择Arduino Uno(见图1-14)。
图1-14 选择Arduino板
选择好Arduino板之后,还要考虑如何将程序下载到Arduino板上,这就要用到编程器了。Arduino所用的MCU一般都支持ISP(In-system Programming,在线系统编程)方式下载,即通过MCU的串口或者USB接口对芯片进行编程,而无需另外购置仿真器或编程器。比如Arduino Uno就使用AVR单片机的ISP功能,在这里选择菜单栏的Tools→Programmer→AVR ISP(见图1-15)。
图1-15 选择编程器
同时,还要选择Arduino连接的串口。如果PC有多个串口,可以在Windows设备管理器中查看哪个是Arduino的串口(见图1-16)。
图1-16 选择串口
图1-17 导入函数库
使用Arduino一定要尝试它丰富的内置函数库,通过选择菜单栏中Sketch→Import Library中的选项就可以将对应的函数库导入工程中(见图1-17)。这些函数库涵盖了基本接口、网络通信、图形显示、数据存储以及电机控制等各个领域,如果这些库还不能满足你的需求,可以通过Add Library导入从网上下载的第三方库。
Arduino IDE还为初学者准备了一些Sketch实例,用户可以先学习这些教科书式的Sketch,然后再自己动手编写。这些实例在File→Examples菜单中,选择需要的实例就会打开一个该实例的新窗口(见图1-18)。
图1-18 打开Sketch实例
选择AnalogInput选项,Sketch实例的代码会显示在窗口中间的编辑器里,如图1-19所示。官方Sketch里包含了详细的注释说明,可以很好地帮助用户理解代码。
用户可以对代码进行修改,但由于实例本身是只读的,在保存修改后的Sketch时会提示出错。这时候只要将修改后的Sketch另存一份即可。
单击工具栏的按钮,即可对Sketch进行编译和烧写,下方的状态栏会显示编译和烧写的进度。代码烧写完成后,还会在调试信息栏中给出程序占用MCU的RAM和ROM大小,以及剩余空间大小(见图1-20)。
图1-19 Sketch实例
图1-20 调试信息栏和状态栏
1.3.2 实例:Hello Arduino--用Arduino控制LED
本节中我们将完成一个简单的Arduino Sketch--用Arduino来控制一个LED。无论是8051单片机还是ARM、DSP、CPLD、FPGA的学习,通常第一个程序的首选都是点亮一盏LED,这种学习过程被网友戏称为“一灯大师”。其实对于处理器或可编程数字逻辑来说,GPIO的控制是最简单的,往往只需要一两行代码,因此它是初学者的最佳入口,本书也不能免俗。本书将对这个Sketch的讲解作为pcDuino程序设计的铺垫,以帮助读者理解Arduino程序设计的一般方法。
首先了解一下LED的结构(见图1-21)。LED是发光二极管的简称。LED本质上是一个二极管,具有和二极管相同的性质,当正负极间的电压达到一定程度后(超过导通电压)会导通,同时放射出一定颜色的光线。
图1-21 LED结构和表示符号
想要点亮LED,只需要在其两端加一定的电压,去掉这个电压,LED就会熄灭。普通的LED可以直接用GPIO接口(General Purpose Input Output,通用输入/输出接口)驱动,并且常见的驱动方式有两种:阳极驱动和阴极驱动(灌电流驱动),如图1-22所示。不管采用哪种驱动方式,都要在电路中串接一个电阻,用来限制电流的大小,防止烧坏LED或其他电路。大功率LED不能直接由GPIO驱动,还需要增加MOS管或开关电源等电路,这里不做讨论。
图1-22 LED驱动方式
对于阳极驱动,当GPIO输出高电平时,LED与电源地之间出现电压差,点亮LED;当GPIO输出低电平(一般与电源地的电压相同)时,LED两端没有了电压差,因而熄灭。阴极驱动与之正好相反,低电平点亮,高电平熄灭。
Arduino Uno板上的引脚13连接了一个贴片封装的LED,这个LED已经焊接在电路板上,可以直接编程操作。
当新建一个Sketch时,编辑器里会自动添加两个函数:setup()和loop()。
void setup() { // put your setup code here, to run once: } void loop() { // put your main code here, to run repeatedly: }
这两个函数是Arduino编程的基本函数,一个Arduino Sketch会从setup()函数开始运行,setup()中的内容只运行一次,以后除了Arduino电路板复位或者重新上电,该函数中的代码都不会再运行。这个函数通常用来做一些初始化设置。
相反,loop()函数中的内容则会重复执行。当setup()中的代码运行完成后,loop()中的代码开始一遍遍重复执行,直到电路板断电。可以说,如果Arduino正常运行,loop()中的程序是永远不会结束的,这点和一般的MCU程序设计相同。
下面我们参照Arduino的Blink例子编写代码,具体代码如代码清单1-1所示。
代码清单1-1:Arduino控制LED范例代码
/******************************************** 程序名称:led_test 功能:Arduino 控制LED范例代码 版本:v1.0 作者:懒兔子 <haixiaoli2@163.com> *********************************************/ int led_pin = 13; // 定义引脚13为LED引脚 void setup() { pinMode(led_pin, OUTPUT); // 设置LED引脚为输出模式 } void loop() { digitalWrite(led_pin, HIGH); // 设置引脚为高电平,LED点亮 delay(1000); // 等待1s digitalWrite(led_pin, LOW); // 设置引脚为低电平,LED熄灭 delay(1000); // 等待1s }
这个例子定义了int型全局变量led_pin,并赋值为13,用于表示LED连接到引脚13。Arduino共有13个数字I/O,每一个都可以用来控制LED,如果没有使用板载的LED而是将LED连接在其他引脚上,就需要将这个数字设置为相应的引脚编号。
pinMode()函数用来设置led_pin变量对应引脚的模式。pinMode(led_pin,OUTPUT)表示将Arduino的13号I/O设置为OUTPUT,即输出模式。
digitalWrite()函数用于控制GPIO的电平状态,digitalWrite(led_pin,HIGH)表示led_pin变量对应的I/O输出高电平,digitalWrite(led_pin,LOW)表示输出低电平。
delay()函数用于延时一段时间,在这段时间内Arduino什么都不做,等时间过去了再执行后面的语句。delay()函数参数的单位为毫秒(ms),delay(1000)表示等待1000ms,即1s。
这段程序实现的效果是将Arduino与LED连接的引脚13设为输出后,每隔1s关闭或打开LED,实现LED周期性闪烁。
图1-23展示了Arduino IED中如何编写Sketch。
图1-23 编写Sketch
完成代码编写后,保存Sketch为HelloArduino.ino。通过USB线连接Arduino板与PC。第一次连接可能需要安装Arduino驱动程序,这一驱动程序在Arduino IDE解压文件夹中的drivers目录下,安装驱动时选择手动浏览方式,选中drivers目录即可(见图1-24)。
按下按钮编译程序,并下载到Arduino板中,下载完成时状态栏显示Done uploading。这时Arduino板上的LED就开始闪烁了,就是这么简单。
图1-24 安装Arduino驱动程序
1.4 Arduino的局限性
前面的内容中提到过,简单是Arduino的一大优点,但力求简单也给Arduino带来了很大的局限性。Arduino无法胜任大量运算和高复杂度的工程应用,只能做一些对性能要求不高的简单工作,这是受到Arduino的硬件和软件两方面限制的。
目前绝大多数的Arduino都使用MCU作为处理器,比如Arduino Uno使用的ATmega328单片机,主频为16MHz,只有2KB的SRAM和32KB的Flash,直接限制了运行速度和代码规模。虽然后来的Arduino板所使用的MCU性能不断提升,但仍然不能满足性能较高的应用,更不用说图像处理、集群服务器这样的专业领域。Arduino官方应该也意识到了这一点,因此推出了集成高通AR9331ARM9处理器的Arduino Yun和集成TI AM335x Cortex-A8处理器的Arduino Tre,不过从Yun和Tre的硬件结构来看,都是CPU+MCU,也就是说将一块高性能的ARM板和低端的Arduino画在一块电路板上,两个处理器间通过通信接口相连,并未实现“一U两用”(pcDuino与Arduino Yun和Arduino Tre的结构不同,不需要额外的MCU,可以在Linux系统中运行Arduino程序,实现Mini PC和Arduino无缝结合)。
另一方面,虽然Arduino IDE使用方便,但缺乏有效的调试手段(没有仿真功能,无法实现单步执行等操作,不能随时查看内存数据),编辑器的智能化也不够理想(缺少联想、查找定义等功能),难以有效维护规模较大的代码。
虽然Arduino有一定的局限性,但仍然无法影响其成为DIY爱好者的宠儿,而且越来越多的板卡和设计开始通过各种方式兼容Arduino,更加说明了它在世界范围内的影响力,相信Arduino会在开源硬件的道路上发挥更大的作用。