Arduino开发实战指南AVR篇.pdf
http://www.100md.com
2020年1月21日
![]() |
| 第1页 |
![]() |
| 第5页 |
![]() |
| 第15页 |
![]() |
| 第27页 |
![]() |
| 第48页 |
![]() |
| 第670页 |
参见附件(9683KB,804页)。
Arduino开发实战指南,这是一本Arduino开发者必看的基础巩固书籍,全书一共分为基础篇、模块篇和应用篇,作者采用图文结合的手法写作,帮助你更快理解原理逻辑。

Arduino开发实战指南内容提要
Arduino是一个注重实际动手操作的产品,所以本书以实际应用为纽带将各个章节联系起来,首先介绍Arduino的一些基础知识,接着针对具体应用介绍了一些扩展板以及Arduino扩展库,最后应用之前的内容完成了具有视频监控功能的履带车、遥控机械臂以及双足机器人的制作。
本书内容循序渐进,图文并茂,可以带领读者走入Arduino的精彩世界。本书适合电子专业、交互设计专业、新媒体技术专业学生阅读,也可以作为所有电子爱好者开展Arduino制作项目的参考手册。
Arduino开发实战指南作者资料
程晨
国内较早接触Arduino的硬件工程师,在Arduino的应用方面拥有丰富的实战经验。对Arduino的底层代码进行了长达一年的学习与研究,同时使用过大量的Arduino类库,对于Arduino的架构和实现原理有着非常深入的理解和认识。同时在PC端、手机端的应用程序开发方面也有一定的经验,应用Arduino进行过多款交互式产品制作。
Arduino开发实战指南章节目录
第一篇 基础篇
第1章 初识Arduino
第2章 编写Arduino程序
第3章 Arduino的基本函数
第4章 Arduino硬件平台
第二篇 模块篇
第5章 Arduino基本扩展模块
第6章 Arduino的扩展库
第7章 无线模块的应用
第三篇 应用篇
第8章 打造自己的遥控履带车
第9章 仿生机器人
Arduino开发实战指南截图


址:
小编自己做了一个电子书下载网站, 网
程晨 著
——AVR篇
Arduino开发实战指南目录 前言
本书的内容及面向的读者
致谢
第一篇 基础篇
第1章 初识Arduino
1.1 Arduino的历史
1.2 Arduino的家族
1.3 Arduino的资源
1.4 Arduino的开发环境
1.5 添加新硬件及设置开发环
境
1.6 Arduino开发环境的应用
第2章 编写Arduino程序
2.1 绘制流程图
2.2 C语言的标识符与关键字
2.3 控制语句
2.4 程序结构
第3章 Arduino的基本函数
3.1 数字IO
3.2 模拟IO
3.3 高级IO3.4 时间函数
3.5 数学库
3.6 随机数
3.7 位操作
3.8 中断函数
3.9 串口通信
3.10 SPI接口
第4章 Arduino硬件平台
4.1 Arduino的原理图
4.2 串行通信口的使用
4.3 数字IO口的使用
4.4 模拟IO口的使用
4.5 烧写引导程序
第二篇 模块篇
第5章 Arduino基本扩展模块
5.1 L293 Motor Shield
5.2 Input Shield
5.3 LCD Keypad Shield
5.4 Ethernet Shield
5.5 IO扩展板
第6章 Arduino的扩展库
6.1 Arduino扩展库介绍6.2 对象和类
6.3 LiquidCrystal库
6.4 Ethernet库
6.5 SoftwareSerial库
6.6 EEPROM库
6.7 Wire库
6.8 Servo库
6.9 Stepper库
6.10 TLC5940库
6.11 OneWire库
6.12 XBee库
6.13 创建自己的库
第7章 无线模块的应用
7.1 APC220
7.2 DFduino wireless
7.3 Bluetooth V3
7.4 XBee和XBee PRO
第三篇 应用篇
第8章 打造自己的遥控履带车
8.1 履带车的驱动
8.2 添加感知器件
8.3 添加无线模块8.4 制作遥控器
8.5 履带车遥控调速
8.6 添加无线摄像头
8.7 环境信息获取器件
第9章 仿生机器人
9.1 遥控机械臂
9.2 双足机器人
附录A Arduino引脚与AVR单片机管脚对应
关系
附录B Arduino扩展板
附录C 其他可扩展模块前言
在2011年举行的Google IO开发者大
会上,Google发布了基于Arduino的
Android Open Accessory标准和ADK工具,这使得大家对Arduino的前景十分看好。
Phillip Torrone大胆地预测Google将用
Android+Arduino的形式掀起自己的“Kinect
模式”浪潮。目前,国内关注Arduino的人
越来越多,但介绍Arduino的书籍却很少。
笔者由于工作的关系,接触Arduino较早,所以希望通过自己的努力让更多的人了解
Arduino,在近一年的时间里,通过不断学
习、查阅Arduino相关知识,终于完成了书
稿的撰写工作。但在书稿完成之后,心中
却一直忐忑不安,Arduino是一个介于软件
与硬件之间的产品,系统性不是很强,加
上笔者水平有限,拙著中一定存在不少的
缺点与漏洞,为此,笔者先为书中的不足
之处致以真诚的歉意,同时诚挚地欢迎广
大读者提出宝贵的意见并不吝赐教。本书的内容及面向的读者
Arduino是一个注重实际动手操作的
产品,所以本书以实际应用为纽带将各个
章节联系起来。本书共9章,首先介绍
Arduino的一些基础知识,接着针对具体应
用介绍了一些扩展板以及Arduino扩展库,最后应用之前的内容完成了具有视频监控
功能的履带车、遥控机械臂以及双足机器
人的制作。
因为Arduino本身具有简单易用的特
点,所以本书面向的读者是所有有兴趣使
用Arduino进行项目开发的人。
当然,根据读者的情况不同,本书
的阅读方式也不同。
如果读者是一个之前没有进行过单
片机开发也没有进行过软件开发的人,现
在想使用Arduino来实现自己的一些想法,那么首先要阅读本书的前两章,了解一些
简单的编程思想以及程序结构,接下来阅
读第3章的目录,了解Arduino都有什么基
本函数,具体内容可以先不用看,当你之
后使用这些函数遇到问题时再回过头来看
一看相应的函数说明。然后将Arduino接到
你的电脑上,翻开第4章,根据书中的内
容,边学习边实践,4.5节可以跳过不看。
第5~7章介绍了Arduino周边的资源,以便
帮助你尽快地实现想法,这3章的内容也可
以采用跳跃式的阅读方式。第8、9章会告
诉你前3章的内容是如何结合起来的,建议
按照书中的内容至少动手完成一个项目的
制作。
如果读者之前进行过AVR单片机的开
发,想了解Arduino一些底层的知识,那么
第2章的知识就可以跳过了,在简单地翻阅
第3章的内容后,直接进入第4章,把
Arduino连到电脑上实践一下,再回过头阅
读第3章中关于Arduino的基本函数,结合
自身已有的AVR单片机的知识了解Arduino
底层的工作机制。需要说明的是,这里需要读者自己花一些精力,可能还需要学习
一些C++方面的知识。第5章对Arduino硬
件原理进行了详细介绍,若读者之前学习
过,这一章可以选择性学习。第6章介绍的
是Arduino的扩展库,如果读者也想开发一
些Arduino扩展板,并以库的形式提供扩展
板的软件资源,那么建议先学习最后一
节,再从6.1节开始学习,深入地了解这些
扩展库是如何与Arduino结合在一起的。至
于剩下几章的内容,如果用开发单片机的
思路来完成也是不难的,所以阅读的重点
是看看如何用Arduino的思路进行项目的制
作。
如果读者之前是做纯电脑软件开发
工作的,即使用C++非常熟练,那么在阅
读完第1章后,可以直接跳到第4章,感受
一下Arduino给纯软件开发人员带来的那种
完成硬件制作的感觉,然后仔细阅读第5
章,看看目前都有哪些扩展板可以为自己
所用,控制电机、控制液晶之类的,硬件
知识哪怕我们不用,也还是要了解一些
的。接下来,对于第6章,可以仔细阅读一下与硬件关系不太大的扩展库以及如何创
建自己的库,在今后底层硬件库不断丰富
完善的情况下,开发一些注重应用、与底
层关系不是太紧密的库时,这就是我们的
用武之地。第7~9章的内容会告诉我们前面
的知识是如何结合起来的——用纯软件的
思路,同样建议按照书中的内容至少动手
完成一个项目的制作,做纯软件开发工作
的人开发硬件也是很容易的。致谢
首先要感谢本书的策划张国强先
生,是他对Arduino的关注促成了本书的出
版,同时在笔者撰写书稿时他也对本书提
出了宝贵的写作建议,并对书稿进行了仔
细审阅。
其次要感谢让我了解Arduino的庄明
波先生,他不但在技术上给予了我很多的
指导,同时也无私地提供了大量的Arduino
扩展板的资料以及实物,供我在Arduino的
程序调试中使用,同时与我共同探讨技术
上遇到的问题。
最后要感谢现在正捧着这本书的
您,感谢您肯花费时间和精力阅读本书,由于时间有限,书中难免存在疏漏与错
误,诚恳地希望您批评指正,您的意见和
建议将是我巨大的财富。希望在Arduino的
领域结识更多的朋友。第一篇 基础篇
第1章 初识Arduino
第2章 编写Arduino程序
第3章 Arduino的基本函数
第4章 Arduino硬件平台第1章 初识Arduino
Arduino是源自意大利的一个开放源
代码的硬件项目平台,该平台包括一块具
备简单IO功能的电路板以及一套程序开发
环境软件。Arduino可以用来开发交互产
品,比如它可以读取大量的开关和传感器
信号,并且可以控制电灯、电机和其他各
式各样的物理设备;Arduino也可以开发出
与PC相连的周边装置,能在运行时与PC上
的软件进行通信。Arduino的硬件电路板可
以自行焊接组装,也可以购买已经组装好
的模块,而程序开发环境的软件则可以从
网上与使用。
1.1 Arduino的历史
说到Arduino的起源似乎有点令人感
觉无心插柳柳成荫。Massimo Banzi是意大利米兰互动设计学院的教师,他的学生常
常抱怨不能找到一块价格便宜且功能强大
的控制主板来设计他们的机器人。2005年
的冬天,Banzi和David Cuartielles讨论到这
个问题,David Cuartielles是西班牙的微处
理器设计工程师,当时在这所学校做访问
研究。他们决定自己设计一块控制主板。
他们找来了Banzi的学生David Mellis,让他
来编写代码程序。David Mellis只花了两天
时间就完成了代码的编写,然后又过了3
天,板子就设计出来了,取名为Arduino。
很快,这块板子受到了广大学生的欢迎。
这些学生当中那些甚至完全不懂计算机编
程的人,都用Arduino做出了“很炫”的东
西:有人用它控制和处理传感器,有人用
它控制灯闪烁,有人用它制作机器人……
之后Banzi、Cuartielles和Mellis将设计图上
传到网上,然后花了3000欧元加工出第一
批板子。
Banzi等人当时加工了200块板子,卖
给学校50块,起初还担心剩下的150块怎么
卖出去,但是几个月后,他们的设计作品在网上得到了快速传播,接着他们收到了
几个上百块板子的订单。这时他们明白
Arduino是很有市场价值的,所以,他们决
定开始Arduino的事业,但是有个原则——
开源。他们规定任何人都可以复制、重设
计甚至出售Arduino板子。人们不用花钱购
买版权,连申请许可权都不用。但是,如
果你加工出售Arduino原板,版权还是归
Arduino团队所有。如果你是在基于
Arduino的设计上修改,你的设计必须也和
Arduino一样开源。
Arduino设计者们唯一所有的就
是Arduino这个商标。如果你的设计也想
用Arduino命名,那么你就得支付费用。这
样做是为了保护Arduino这个商标不被低
劣的作品损坏。
对于最初决定硬件开源,几位设计
者也有不同的动机。Cuartielles认为自己是
个“左倾学术主义者”,不喜欢因为赚钱而
限制大家的创造力,从而导致自己的作品
得不到广泛使用。“如果有人要复制它,没问题。复制只会让它更出名。”Cuartielles
在某次演讲中甚至说:“请你们复制它
吧!”Banzi则恰恰相反,他更像一个精明
的商人。他现在已经退休了,不再教书,开了一家科技设计公司。他猜想,如果
Arduino开源,相比那些不开源的作品,会
激发更多人的兴趣,从而得到更广泛的使
用。还有一点就是,一些电子疯狂爱好者
会去寻找Arduino的设计缺陷,然后要求
Arduino团队做出改进。利用这种免费的劳
动力,他们可以开发出更好的新产品。
实际情况也正如他所料,在接下来
的几个月内,很多人提出重新布线、改进
编程语言等建议。后来曾有销售商要求代
理Arduino产品。2006年,Arduino方案获
得了Prix Art Electronica电子通信类方面的
荣誉奖。那一年,他们销售了5000块板
子。第二年,他们销售了30000块。
Arduino被电子疯狂爱好者用来设计机器
人、调试汽车引擎、制作无人飞机模型
等。1.2 Arduino的家族
Arduino设计之初的目的是希望让设
计师和艺术家们能够很快地通过它学习电
子和传感器的基础知识,并应用到他们的
设计当中。设计中所要表现的想法和创意
才是最主要的,至于单片机如何工作,硬
件的电路是如何构成的,设计师和艺术家
们并不需要考虑。
Arduino的出现,大大降低了互动设
计的门槛,没有学过电子知识的人也能够
使用它制作出各种充满创意的作品。越来
越多的艺术家、设计师开始使用Arduino制
作交互艺术品。为了针对不同的应用领
域,目前Arduino已设计出很多不同的型号
以满足不同使用者的需要,在这里简单介
绍一下几类主要产品,详细信息可登录
Arduino的主页http:www.arduino.cc查
阅。1.Arduino Duemilanove
这是一款基本的Arduino产品,控制
器采用ATmega168或ATmega328,支持直流
电源供电和USB端口供电,如图1.1所示。
后续的很多产品都是在这款产品的基础上
发展起来的。
图 1.1 Arduino Duemilanove
2.Arduino Nano
Arduino Nano在设计中去掉了直流电
源接口,采用了Mini-B标准的USB接口来
连接电脑,除了外观变了,其他接口及功能保持不变,控制器同样采用ATmega168
或ATmega328,是一款缩小版的Arduino
Duemilanove,如图1.2所示。
图 1.2 Arduino Nano
3.Arduino mini
考虑到存在一些对空间要求十分严
格的使用者,Arduino mini(见图1.3)在
设计时甚至去掉了USB接口和复位开关,这样能减小Arduino的尺寸。唯一的问题是
连接电脑或烧写程序时需要一个USB或
RS232转换成TTL的适配座,Arduino官方
也有相应的适配座——Mini USB
Adapter(http:www.arduino.ccenMainMiniUSB上有相关的资料)。
图 1.3 Arduino mini
4.Arduino BT
Arduino BT(见图1.4)本身包含了
一个Bluegiga WT11蓝牙模块,支持蓝牙无
线串行通信,但不支持蓝牙音频设备。若
没有USB接口,连接电脑或烧写程序可以
通过蓝牙适配器与Arduino BT连接实现无
线程序下载与控制。图 1.4 Arduino BT
5.LilyPad Arduino
这是一款真正有艺术气质的产品,面向的主要使用者是从事服装设计之类工
作的设计师,它可以使用导电线或普通线
缝在衣服或布料上,LilyPad Arduino每个
引脚上的小洞大到足够缝纫针轻松穿过,如图1.5所示。如果用导电线缝纫的话,既
可以起到固定的作用,又可以起到传导的作用。比起普通的Arduino板,LilyPad
Arduino相对比较脆弱,比较容易损坏,但
它的功能基本都保留了下来,除了一点,即它没有USB接口,所以LilyPad Arduino连
接电脑或烧写程序时同Arduino mini一样需
要一个USB或RS232转换成TTL的适配座。
图 1.5 LilyPad Arduino
6.Arduino Pro和Arduino Pro Mini设计Arduino Pro的目的是为了那些
需要便利性和低成本的高级用户。为了降
低成本,它省去了USB接口、直流电源接
口和引脚排针,连接电脑或烧写程序时需
要一个USB或RS232转换成TTL的适配座。
Arduino Pro更像是一个大号的Arduino
mini,如图1.6所示。需要注意的是,Arduino Pro有3.3V8MHz和5V16MHz两个
版本,使用的时候要留心点。另外Arduino
Pro同样有一个Arduino Pro Mini的版本,如图1.7所示。图 1.6 Arduino Pro图 1.7 Arduino Pro Mini
7.Arduino Fio
Arduino Fio(见图1.8)的工作电压
是3.3V,控制器的工作频率是8MHz,采用
了Mini-B标准的USB接口,提供一个锂聚
合物电池接口,底部预留了一个XBee模块
插座(美国DIGI的zigbee模块,本书的第7
章有XBee模块的相关介绍,也可登录
http:www.digi.com.cn了解XBee模块的更多信息),XBee模块可使Arduino方便地应
用于无线网络。
图 1.8 Arduino Fio
8.Arduino Uno
Arduino Uno是最新的Arduino产品系
列,如图1.9所示,它与之前的Arduino板
最大的不同在于它不是使用FTDI USB-to-
serial串行驱动器芯片,而是采用
Atmega8U2芯片进行USB到串行数据的转
换。目前Arduino Uno已成为Arduino主推
的产品。图 1.9 Arduino Uno
9.Arduino Mega2560
Arduino Mega2560(见图1.10)的控
制器采用的是ATMega2560,它的资源要比
之前的Arduino产品丰富很多,用于满足需
使用较多资源进行产品设计与开发的用户
需求,具体资源会在下一节描述。同时,Arduino Mega2560也兼容之前基于Arduino
Duemilanove的设计。图 1.10 Arduino Mega25601.3 Arduino的资源
Arduino的硬件电路设计以创作公用
约定(creative commons)的形式提供授
权。相应的原理图和电路图都可以从
Arduino网站上免费获得。Arduino
Duemilanove具有14个数字IO口(其中6个
可提供PWM输出),6个模拟IO口,一个
复位开关,一个ICSP下载口,支持USB接
口,可通过USB接口供电,也可以使用单
独的7~12V电源供电。Arduino的资源在板
子上已经明确标注,使用者可以很方便地
了解具体的资源分配,DIGITAL一边有14
个数字IO口0~13,ANALOG IN一边有6个
模拟IO口0~5,其他还有POWER、TX、RX、PWM等标识,如图1.11所示。图 1.11 Arduino的资源
Arduino Duemilanove总体参数如表
1.1所示。各引脚定义如下:
数字引脚:0~13
模拟引脚:A0~A5(为区分数字引
脚,在引脚号前加A)串行通信:0,1(0作为RX,接收数
据;1作为TX,发送数据)
外部中断:2,3
PWM输出:3,5,6,9,10,11
SPI通信:10(SS),11(MOSI),12(MISO),13(SCK)
板上LED:13
TWI通信:A4(SDA),A5(SCL)
另外,Arduino有一个可复位的熔断
器来保护计算机的USB口,防止短路或者
过流。虽然大部分计算机都有它们内置的
保护措施,但是熔断器还是可以提供额外
的保护,如果连到USB口的电源超过
500mA,它将自动断开,直到短路或者过
流消除。
Arduino Uno的硬件资源与Arduino
Duemilanove相同,Arduino Mega2560的资源就要丰富多了,它具有54个数字IO口
(其中14个可提供PWM输出),16个模拟
IO口,4对串行数据通信口(UART),一
个复位开关,一个ICSP下载口,支持USB
接口和直流电源供电。Arduino Mega2560
总体参数如表1.2所示。各引脚定义如下:
数字引脚:0~53
模拟引脚:A0~A15(为区分数字引
脚,在引脚号前加A)
串行通信:Arduino Mega2560提供4
组串行通信端口,分别是0(RX)和
1(TX)用作串口1,19(RX)和
18(TX)用作串口2,17(RX)和
16(TX)用作串口2,15(RX)和
14(TX)用作串口3
外部中断:Arduino Mega2560提供6
个引脚作为外部中断,分别是2(外部中断
0),3(外部中断1),21(外部中断
2),20(外部中断3),19(外部中断
4),18(外部中断5)
PWM输出:0~13
SPI通信:53(SS),51(MOSI),50(MISO),52(SCK)板上LED:13
TWI通信:20(SDA),21(SCL)1.4 Arduino的开发环境
Arduino的开发环境是以AVR-GCC和
其他一些开源软件为基础,采用Java编写
的,软件无需安装,下载完成解压缩后就
可以直接打开使用了。软件可以在Arduino
的网站http:www.arduino.cc上免费下
载,目前最新版本是0022。本书中使用的
版本是0021。Arduino开发环境使用的语法
与CC++相似,非常容易使用。图1.12所示
的就是Arduino开发环境的主界面,中间的
白色区域就是程序编辑区,下方的黑色区
域为信息提示区。图 1.12 Arduino的开发环境
提示:目前的软件界面中无法输入中文字符,可在其他软件内输入中文字符
再拷贝至软件界面内。1.5 添加新硬件及设置开发环境
在应用Arduino开发环境之前,先要
在电脑端添加新硬件Arduino控制板,本节
介绍Arduino Duemilanove和Arduino Uno两
块控制板的安装。
先看看Arduino Duemilanove控制板
的添加。准备一块Arduino Duemilanove板
和一条USB连接线。第一次将Arduino板连
接到电脑上,会出现Found New Hardware
Wizard(发现新硬件向导)的提示,依照
提示完成驱动安装,步骤如图1.13~图1.18
所示。图 1.13 选择从指定目录安装图 1.14 可在Arduino开发环境目录下的
drivers文件夹中找到驱动程序图 1.15 选择Finish完成驱动安装图 1.16 在Device Manager(设备管理
器)里查看新安装的USB转串口设备所对
应的串口号图 1.17 在Arduino的开发环境中设置串
口(Tools→Serial Port→COM5)图 1.18 选择正确的Arduino板系列型号
正确设置串口和Arduino板系列型号
后,就可以开始Arduino之旅了。接下来看
一下Arduino Uno控制板的添加。准备一块
Arduino Uno板和一条USB连接线。第一次
连接到电脑,会出现“发现新硬件向导”的
提示,依照提示完成驱动安装。若错过了“发现新硬件向导”的提示,也可以在设
备管理器中找到未安装的新硬件,如图
1.19所示。
图 1.19 设备管理器中未安装的新硬件
右键选中未识别的硬件Arduino
Uno,从弹出的如图1.20所示的快捷菜单中选择Update Driver(更新驱动程序),将
会出现如图1.21所示的Hardware Update
Wizard(更新硬件驱动向导)的提示,依
照提示完成Arduino Uno驱动的安装。
图 1.20 更新驱动程序图 1.21 更新硬件驱动向导
如图1.13、图1.14所示选择正确的驱
动程序,此时电脑会出现驱动程序不被
Windows信任的提示,选择Contine
Anyway(仍然继续),如图1.22所示。图 1.22 驱动程序不被信任
最后选择Finish完成硬件驱动的更
新,如图1.23所示。图 1.23 完成硬件驱动的更新
此时设备管理器中的新硬件Arduino
Uno就被识别成串口设备,如图1.24所示。图 1.24 设备管理器中的Arduino Uno
最后要在Arduino开发环境中设置相
应的串口号以及Arduino板型号,如图1.17
和图1.18所示,注意Arduino板型号的选
择,要选择Arduino Uno,如图1.25所示。图 1.25 选择Arduino板型号
提示:本书后面的章节使用的控制
板均为Arduino Uno。1.6 Arduino开发环境的应用
Arduino开发环境中菜单栏下方的7个
按钮必须先了解一下,它们依次是
Verify(校验)、Stop(停止)、New(新
建)、Open(打开)、Save(保存)、Upload(上传)、Serial Monitor(串口监
视窗),如图1.26所示。
图 1.26 Arduino开发环境中菜单栏下方
的7个按钮
各按钮的具体功能如下:
Verify(校验),用以完成程序
的检查与编译。Stop(停止),用以停止进行的
编译操作。
New(新建),可新建一个程序
文件。
Open(打开),打开一个存在的
程序文件,Arduino开发环境下的程序文件
后缀名为.pde。
Save(保存),保存当前的程序
文件。
Upload(上传),将编译后的程
序文件上传到Arduino板中。
Serial Monitor(串口监视窗),可监视开发环境使用的串口收发的数据。
接下来通过一个Arduino开发环境中LED灯闪烁的例子(Blink)来简单应用一
下这些按钮。在Arduino Uno板的13号引脚
上已经带了一个LED灯,如图1.27所示。
Blink程序就是控制这个LED灯闪烁,我们
可以在Arduino控制板上明确地看到。
图 1.27 13号引脚及LED灯位置示意
点击Open按钮后,依次选择
1.Basics→Blink,就可以看到Blink程序已经加载到程序编辑区,如图1.28所示。
图 1.28 加载Blink程序
点击“校验” 按钮实现程序的编
译,等待一会儿后状态栏会提示Done
compiling(程序编译完成),信息提示区
内会显示程序编译完成后的大小,如图
1.29所示,此例中Blink程序编译后的大小
为1010bytes。图 1.29 Blink程序编译后的大小
编译完成后点击“上传”按钮 ,上
传一般需要等待几秒钟时间,在上传的时
候串口的指示灯(RX和TX)会不停地闪
烁。上传完成后状态栏会有上传成功的提
示:Done uploading。观察Arduino控制板
上LED灯是否在不停地闪烁,Arduino控制
板通过LED闪烁的方式告诉你,你已经会
使用Arduino了,就是这么简单。第2章 编写Arduino程序
Arduino项目很注重动手能力,只有
通过动手才会发现Arduino的优点。本章介
绍如何编写Arduino程序。
写程序就像盖房子。盖房子首先要
有图纸,然后依照图纸搭建主体,最后内
外部装修。写程序大致也需要这几步,首
先绘制流程图,然后使用控制语句搭建主
体程序,最后查错、调试、修改、添加注
释完成程序编写。
本章内容就按照这样一个次序展
开,让我们共同来搭建Arduino“大厦”。
2.1 绘制流程图
2.1.1 流程图基本符号美国国家标准化协会(American
National Standards Institute,ANSI)规定了
一些常用的流程图符号,目前已被世界各
国的多个领域普遍采用,如图2.1所示。
图 2.1 流程图基本符号
第1章的Blink程序可以用图2.2的流程
图描述。图 2.2 Blink程序流程图
通过Blink程序的流程图可以看出,一个流程图应该包括以下几部分:
表示相应操作的框。
带箭头的流程线。
框内外必要的文字说明。2.1.2 流程图的三种基本结构
起初流程图用流程线指出各框的执
行顺序,对流程线的使用没有严格的规
定,流程线在程序中随意地连接,流程图
也就没有实现使程序直观形象、简单清晰
的目的,同样,编写的程序也是逻辑混
乱、难以理解。
为了提高流程图及程序的逻辑性,使其更容易理解、更方便阅读,必须限制
流程线的使用,不允许流程线无规律地连
接,而是按照一定顺序和条件进行连接。
于是,1966年,Bohra和Jacopini提出了三
种基本结构,用这三种基本结构作为表示
一个良好算法的基本单元。
1.顺序结构
如图2.3所示,虚线框内是一个顺序
结构。其中A和B两个框是顺序执行的。顺序结构是最简单的一种基本结构。
图 2.3 顺序结构
2.选择结构
如图2.4所示,虚线框内是一个选择
结构。此结构中包含一个判断框,根据条
件是否成立而选择执行A还是B,执行完成
后,经过b点脱离选择结构。图 2.4 选择结构
3.循环结构
如图2.5所示,虚线框内是一个循环
结构。此结构中也有一个判断框用来决定
是否跳出循环结构。有两种循环结构:判
断框成立跳出循环的称为until型循环;判
断框不成立跳出循环的称为while型循环。图 2.5 循环结构
以上三种基本结构有如下特点:
结构内的每一部分都有机会被执行
到。
结构内不存在无法跳出的循环。
只有一个入口,即图中的a点。
只有一个出口,即图中的b点。注意:一个判断框有两个出口,而
一个选择结构只有一个出口,不要将二者
混为一谈。
这三种基本结构可解决任何复杂的
问题,由基本结构所构成的程序流程不存
在无规律的转向,只在本基本结构内才允
许存在分支和跳转。2.2 C语言的标识符与关键字
Arduino的开发使用的是C语言,在C
语言中使用的词汇大致可分为6类:标识
符、关键字、运算符、分隔符、常量和注
释符。
2.2.1 标识符
标识符用来标识源程序中某个对象
的名字,这些对象可以是语句、数据类
型、函数、变量、常量等。一个标识符由
字符串、数字和下划线等组成,第一个字
符必须是字母或下划线,通常以下划线开
头的标识符是编译系统专用的,因此在编
写C语言源程序时一般不要使用以下划线
开头的标识符,而将下划线用作分段符。2.2.2 关键字
关键字是编程语言保留的特殊标识
符,它们具有固定的名称和含义,ANSI C
标准一共规定了32个关键字,如表2.1所
示。2.2.3 运算符
C语言中含有相当丰富的运算符。运
算符与变量、函数一起组成表达式,表示
各种运算功能,在任意一个表达式的后面
加一个分号“;”就构成了一个表达式语
句。表2.2列出了C语言常用的运算符。注意:sizeof是一种特殊的运算符,它不是一个函数。实际上,字节数的计算
在编译时就完成了,而不是在程序执行的
过程中才计算出来的。2.2.4 分隔符
C语言中采用的分隔符有逗号和空格
两种。逗号主要用在类型说明和函数参数
表中,用于分隔各个变量。空格多用于语
句各单词之间作间隔符。在关键字、标识
符之间必须要有一个以上的空格符作间
隔。2.2.5 常量
常量就是在程序运行过程中,其值
不能改变的数据。有时候也可以用一些有
意义的符号来代替常量的值,称为符号常
量。符号常量在使用之前必须先定义,其
一般形式如下:
define标识符常量2.2.6 注释符
C语言的注释符包括两种:
以“”开头并以“”结尾的字符串。
在“”与“”之间的内容即为注释。
“”后面的字符串。
程序在编译时,不对注释作任何处
理。注释可出现在程序的任何位置。编程
时添加适当的注释对于程序员读懂该段程
序非常有用。2.3 控制语句
在程序的执行过程中,往往需要根
据某些条件来决定执行哪些语句,这就需
要选择型控制语句if和switch来实现选择结
构程序,某些情况下还会不断地重复执行
某些语句,这就需要循环型控制语句for和
while来完成循环结构程序。
2.3.1 if语句
用if语句可以实现选择结构。它根据
给定的条件进行判断,以决定执行某个分
支程序段。if语句有3种基本形式。
1.第一种基本形式
if(表达式)
语句功能描述:如果表达式的值为真,则执行其后的语句;否则,跳过该语句。
2.第二种基本形式
if(表达式)
语句1
else
语句2
功能描述:如果表达式的值为真,则执行语句1;如果表达式的值为假,则执
行语句2。
3.第三种基本形式
if(表达式1)
语句1
else if(表达式2)
语句2
else if(表达式3)
语句3……
else if(表达式n)
语句n
else
语句m功能描述:如果表达式1的结果为
真,则执行语句1,然后退出if选择语句,不执行下面的语句;否则,判断表达式2,如果表达式2的结果为真,则执行语句2,然后退出if选择语句,不执行下面的语
句,同样如果表达式2的结果为假则判断表
达式3,依次类推,最后,如果表达式n不
成立,则执行else后面的语句m。
在使用if语句时还要注意以下问题:
在3种基本形式中,if关键字后面均
为表达式。该表达式通常是逻辑表达式或
关系表达式,也可以是一个变量。
在if语句中,条件判断表达式必须用
括号括起来。在语句之后必须加分号,如
果是多行语句组成的程序段,则要用花括
号括起来。2.3.2 switch语句
switch语句可实现多分支的选择结
构,在这种情况下,判断条件表达式的值
是由几段组成或不是一个连续的值,每一
段或每一个值对应一段分支程序。switch
语句的一般形式为:
switch(表达式)
{
case常量表达式1:
语句1
case常量表达式2:
语句2……
case常量表达式n:
语句n
default:
语句m
}
switch语句的流程图如图2.6所示。图 2.6 switch语句的流程图
功能描述:计算表达式的值,并逐
个与其后的常量表达式的值进行比较。当
表达式的值与某个常量表达式的值相等
时,即执行其后的语句,然后不再进行判
断,继续执行所有case后面的语句。如果
表达式的值与所有case后的常量表达式均
不相等,则执行default后的语句。
在使用switch语句时要注意以下问
题:
表达式的计算结果必须是整型或者字符型,也就是常量表达式1到常量表达式
n必须是整型或字符型常量。
每个case的常量表达式必须互不相
同,但各个case出现的次序没有顺序。case
语句标号后面的语句可以省略不写,在关
键字case和常量表达式之间一定要有空
格。
当表达式的值与某个常量表达式的
值相等并执行完其后的语句时,如果不想
继续执行所有case后面的语句,则要在语
句后面加上break,以跳出switch结构。2.3.3 while语句
while语句能够实现“当型”循环结
构,其一般形式为:
while(表达式)语句
功能描述:计算表达式的值,当值
为真时,执行循环体语句;当表达式的值
为假时,跳出循环体,结束循环。其中,表达式是循环条件,语句是循环体。
while语句的流程图如图2.7所示。图 2.7 while语句的流程图
在使用while语句时要注意以下几
点:
不要混淆while语句构成的循环结构
与if语句构成的选择结构。while的条件表
达式为真时,其后的循环体将被重复执
行;而if的条件表达式为真时,其后的语
句只执行一次。在循环体中应有使循环趋于结束的
语句。如果没有,则会进入死循环。在编
写嵌入式应用程序时,我们经常会用到死
循环。
循环体若包含一个以上的语句,应
使用大括号括起来。2.3.4 do-while语句
do-while语句用来实现“直到型”循
环,其特点是先执行循环体,然后判断循
环条件是否成立,其一般形式为:
do
语句
while(表达式);
do-while语句流程图如图2.8所示。图 2.8 do-while语句流程图
功能描述:由于do-while循环为“直
到型”循环,它先执行循环体中的语句,然
后再判断表达式是否为真,如果为真则继
续循环;如果为假则终止循环。因此,do-
while循环至少执行一次循环体语句。
注意:do-while语句在使用时除了要
注意循环体至少执行一次的问题外,在使
用时还要注意它是以do开始,以while结
束,while(表达式)后的分号不能丢。2.3.5 for语句
for语句的使用极为灵活,可以完全
取代while语句。它既可以用于循环次数确
定的情况,又可以用于循环次数不确定而
只是给出循环条件的情况。for语句的一般
形式为:
for(表达式1;表达式2;表达式3)
语句for语句的流程图如图2.9所示。图 2.9 for语句的流程图
功能描述:先求解表达式1,一般情
况下,表达式1为循环结构的初始化语句,给循环计数器赋初值。然后求解表达式2,若其值为假,则终止循环;若其值为真,则执行for语句中的内嵌语句。内嵌语句执
行完后,求解表达式3。最后继续求解表达
式2,根据求解值进行判断,直到表达式2
的值为假。
for语句最简单也是最典型的形式如
下:
for(循环变量赋初值;循环条件;
循环变量增量)语句循环变量赋初值总是
一个赋值语句,用来给循环控制变量赋初
值。循环条件是一个关系表达式,决定什
么时候退出循环。循环变量的增量用来定
义循环控制变量每次循环后按什么方式变
化。这3个部分之间用分号分开。
for循环语句的一般形式可用while语
句进行解释,如下:
表达式1;
while(表达式2)
{
语句
表达式3;
}或者用do-while语句解释,如下:
表达式1;
do{
语句
表达式3;
}while(表达式2);
在使用for语句时要注意以下几点:
for循环中的表达式1、表达式2和表
达式3都是选择项,但是分号不能省略。
若3个表达式都省略,则for循环变成
for(;),相当于while(1)死循环。
表达式2一般是关系表达式或逻辑表
达式,但也可以是数值表达式或字符表达
式,只要其值非零,就执行循环体。2.3.6 break语句
break语句通常用在循环语句和switch
语句中。当break用在switch语句中时,可
使程序跳出switch而执行switch以后的语
句。
当break语句用在do-while、for、while循环语句中时,可使程序终止循环而
执行循环后面的语句。通常break语句总是
与if语句连在一起的,即满足条件时便跳
出循环。2.3.7 continue语句
continue语句的作用是跳过循环体中
剩余的语句而强行执行下一次循环。
continue语句只用在for、while、do-while等
循环体中,常与if条件语句一起使用,用
来加速循环。
注意:continue语句与break语句的区
别是,break语句结束整个循环过程,而
continue语句只结束本次循环,不终止整个
循环。2.3.8 goto语句
goto语句是一个无条件转向语句,它
的一般形式为:
goto语句标号;
功能描述:语句标号是一个带冒
号“:”的标识符,用于标识语句的地址。
当执行跳转语句时,使程序跳转到标识符
指向的位置继续执行。将goto语句和if语句
一起使用,可以构成一个循环结构。一般
常见的是采用goto语句来跳出多重循环。
注意,只能用goto语句从内层循环跳到外
层循环,而不允许从外层循环跳到内层循
环。
注意:由于goto语句容易使程序层次
不清,所以在结构化程序设计中不主张使
用goto语句。2.4 程序结构
一般情况下在C语言中要求一个源程
序不论由多少个文件组成,都必须有一个
主函数,即main函数,且只能有一个主函
数,C语言程序执行是从主函数开始的。
但在Arduino中,主函数main在内部定义
了,使用者只需要完成以下两个函数就能
够完成Arduino程序的编写,这两个函数分
别负责Arduino程序的初始化部分和执行部
分。
void setup
void loop
两个函数均为无返回值的函数,setup函数用于初始化,一般放在程序
开头,主要工作是用于设置一些引脚的输
出输入模式、初始化串口等,该函数只在
上电或重启时执行一次;loop函数用于执行程序,它是一个死循环,其中的代
码将被循环执行,用于完成程序的功能,如读入引脚状态、设置引脚状态等。
结合第1章的Blink程序及2.1节的程序
流程图,来看看这两个函数的作用。
void setup
{
注释:初始化Arduino的引脚13为输出,Arduino板上自带的LED连接在引脚13上
pinMode(13,OUTPUT);
}
void loop
{
digitalWrite(13,HIGH);引脚13置高,输
出+5V电压,LED点亮
delay(1000);等待1000ms
digitalWrite(13,LOW);引脚13置低,输出
0V电压,LED熄灭
delay(1000);等待1000ms
}
在setup函数中设置连接LED的引脚13
为输出,以控制LED的亮或灭,这个操作
只在上电或重启时执行一次,之后就没有
必要执行了。在loop函数中有4条语句,分别执行
的操作是:
1)设置引脚13输出高,LED点亮;
2)等待1s;
3)设置引脚13输出低,LED熄灭;
4)等待1s。
由于loop函数中的代码将被循环
执行,所以在第4步执行完成后,将回到第
1步继续执行,程序不断循环,我们就看到
了LED闪烁的效果。
setup函数和loop函数与流程图的对应
关系如图2.10所示。图 2.10 setup函数和loop函数与流程图
的对应关系第3章 Arduino的基本函数
第2章已经介绍了如何编写Arduino程
序,是不是感觉很容易上手,使用很方
便。但Arduino真正的低门槛、硬件无关性
的优点是因为在Arduino开发环境下提供了
大量的基础函数,这些基础函数涉及IO控
制、时间函数、数学函数、三角函数等,使用者可以很方便地对板上的资源进行控
制。同时,在Arduino开发环境下还提供了
许多的实例程序来使用这些基础函数,这
更加快了使用者的上手速度,这些实例程
序可以在开发环境的File→Examples菜单下
找到,其中包括之前提到的Blink程序,如
图3.1所示。图 3.1 实例程序可以在开发环境下找到提示:函数原型部分的内容建议在
单独深入学习过AVR单片机的基础上进
行,跳过函数原型的部分不会影响对
Arduino的应用。
3.1 数字IO
3.1.1 pinMode(pin,mode)
pinMode函数在第2章中已经出现过
了,用以配置引脚为输出或输出模式,它
是一个无返回值函数,函数有两个参数pin
和mode,pin参数表示所要配置的引脚,mode参数表示设置的模式——INPUT(输
入)或OUTPUT(输出)。
注意:Arduino板上的模拟引脚也可
以当做数字引脚使用,编号为14(对应模
拟引脚0)到19(对应模拟引脚5)。
由于Arduino项目是完全开源的,所以pinMode(pin,mode)函数原型可直接在
Arduino开发环境目录下的
hardware\arduino\cores\arduino文件夹里的
wiring_digital.c文件中查看。
函数原型有助于我们深入了解
Ardnino的基本函数的底层实现方式,但这
部分的内容需要在单独深入学习AVR单片
机的基础上进行,本书将这些函数原型从
文件中提取出来,有兴趣的读者可以参考
一下。一般只要能够熟练地使用这些
Arduino基本函数就可以了,本书对函数原
型没有进行过多讲解。
pinMode(pin,mode)函数原型:
void pinMode(uint8_t pin,uint8_t
mode)
{
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
volatile uint8_treg;
if(port==NOT_A_PIN)
return;
reg=portModeRegister(port);
if(mode==INPUT){
uint8_t oldSREG=SREG;
cli;
reg&=~bit;
SREG=oldSREG;
}
else
{
uint8_t oldSREG=SREG;
cli;
reg|=bit;
SREG=oldSREG;
}
}
可以在开发环境中的下列实例程序
中找到pinMode函数的应用:
ADXL3xx. pde、AnalogInput.pde、Blink.pde、BlinkWithoutDelay.pde、Button.pde、Calibration.pde、Debounce.pde、Dimmer.pde、Knock.pde、Loop.pde、Melody.pde、Memsic2125.pde、PhysicalPixel.pde、Ping.pde3.1.2 digitalWrite(pin,value)
digitalWrite函数也是在Blink程序中见
到过的,它的作用是设置引脚的输出的电
压为高电平或低电平。该函数也是一个无
返回值的函数,函数有两个参数pin和
value,pin参数表示所要设置的引脚,value
参数表示输出的电压——HIGH(高电平)
或LOW(低电平)。
注意:在使用
digitalWrite(pin,value)函数设置引脚之
前,需要将引脚设置为OUTPUT模式。
digitalWrite(pin,value)函数原型同
样也可以在wiring_digital.c文件中找到,函
数原型如下:
void digitalWrite(uint8_t pin,uint8_t
val)
{
uint8_ttimer=digitalPinToTimer(pin);
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
volatile uint8_tout;
if(port==NOT_A_PIN)return;
If the pin that support PWM
output,we need to turn it off
before doing a digital write.
if(timer!=NOT_ON_TIMER)
turnOffPWM(timer);
out=portOutputRegister(port);
if(val==LOW)
{
uint8_t oldSREG=SREG;
cli;
out&=~bit;
SREG=oldSREG;
}
else
{
uint8_t oldSREG=SREG;
cli;
out|=bit;
SREG=oldSREG;
}
}
可以在开发环境的下列实例程序中
找到digitalWrite函数的应用:ADXL3xx. pde、AnalogInput.pde、Blink.pde、BlinkWithoutDelay.pde、Button.pde、Calibration.pde、Debounce.pde、Knock.pde、Loop.pde、Melody.pde、PhysicalPixel.pde、Ping.pde3.1.3 digitalRead(pin)
digitalRead函数用在引脚为输入的情
况下,可以获取引脚的电压情况——
HIGH(高电平)或LOW(低电平),参数
pin表示所要获取电压值的引脚,该函数返
回值为int型,表示引脚的电压情况。函数
原型如下:
int digitalRead(uint8_t pin)
{
uint8_t
timer=digitalPinToTimer(pin);
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
if(port==NOT_A_PIN)return LOW;
If the pin that support PWM
output,we need to turn it off
before getting a digital reading.
if(timer!=NOT_ON_TIMER)
turnOffPWM(timer);
if(portInputRegister(port)&bit)
return HIGH;
return LOW;}
注意:如果引脚没有链接到任何地
方,那么将随机返回HIGH或LOW。
可以在开发环境的下列实例程序中
找到digitalRead函数的应用:
Button. pde、Debounce.pde3.2 模拟IO
3.2.1 analogReference(type)
analogReference函数的作用是配置模
拟引脚的参考电压。在嵌入式应用中引脚
获取模拟电压值之后,将根据参考电压将
模拟值转换到0~1023。该函数为无返回值
函数,参数为type类型,有3种类型
(DEFAULTINTERNALEXTERNAL),具
体含义如下:
DEFAULT:默认值,参考电压为
5V。
INTERNAL:低电压模式,使用片内
基准电压源。
EXTERNAL:扩展模式,通过AREF
引脚获取参考电压,AREF引脚位置见图
3.2。图 3.2 AREF引脚位置
注意:如果在AREF引脚加载外部参
考电压,需要使用一个5KΩ的上拉电阻,这会避免由于设置不当造成控制芯片的损
坏。3.2.2 analogRead(pin)
analogRead函数用于读取引脚的模拟
量电压值,每读一次需要花100μs的时间。
参数pin表示所要获取模拟量电压值的引
脚,该函数返回值为int型,表示引脚的模
拟量电压值,范围在0~1023。函数原型可
在wiring_analog.c文件中查看,如下:
int analogRead(uint8_t pin)
{
uint8_t low,high;
set the analog reference(high two
bits of ADMUX)and select
the channel(low 4 bits).this also
sets ADLAR(left-adjust
result)to 0(the default).
ADMUX=(analog_reference<<6)|(pin&
0x07);
start the conversion
sbi(ADCSRA,ADSC);
ADSC is cleared when the conversion
finishes
while(bit_is_set(ADCSRA,ADSC));
we have to read ADCL first;doing solocks both ADCL
and ADCH until ADCH is read.reading
ADCL second would
cause the results of each conversion
to be discarded,as ADCL and ADCH would be locked
when it completed.
low=ADCL;
high=ADCH;
combine the two bytes
return(high<<8)|low;
}
注意:函数的参数pin范围是0~5,表
示6个模拟量IO口中的一个。
可以在开发环境中的下列实例程序
中找到analogRead函数的应用:
ADXL3xx. pde、AnalogInput.pde、Calibration.pde、Graph.pde、Knock.pde、Smoothing.pde、VirtualColorMixer.pde3.2.3 analogWrite(pin,value)
analogWrite函数通过PWM的方式在
引脚上输出一个模拟量,较多的应用在
LED亮度控制、电机转速控制等方面。
PWM(Pulse Width Modulation,脉
冲宽度调制)方式是通过对一系列脉冲的
宽度进行调制,来等效地获得所需要的波
形或电压。脉冲宽度调制是一种模拟控制
方式,其根据相应载荷的变化调制晶体管
栅极或基极的偏置,来实现开关稳压电源
输出晶体管或晶体管导通时间的改变,这
种方式能使电源的输出电压在工作条件变
化时保持恒定,是利用微处理器的数字输
出来对模拟电路进行控制的一种非常有效
的技术。图3.3是一个简单的PWM波示意
图。图 3.3 PWM波示意图
其中,VCC是高电平值,T是PWM波
的周期,D是高电平的宽度,DT是PWM波
的占空比,当上述PWM波通过一个低通滤
波器后,波形中高频的部分被滤掉得到所
需的波形,其平均电压为VCC×DT。因
此,可通过调节D的大小来改变占空比,产生不同的平均电压;同样,调节PWM波
的周期T也可以改变占空比,从而得到不同的平均电压值。
在Arduino中执行该操作后,应该等
待一定时间后才能对该引脚进行下一次操
作。Arduino中的PWM的频率大约为
490Hz。该函数支持以下引脚:3、5、6、9、10、11。在Arduino控制板上引脚号旁
边标注~的就是可用作PWM的引脚,如图
3.4所示。
图 3.4 Arduino板上PWM引脚的标识
analogWrite函数为无返回值函数,有
两个参数pin和value,参数pin表示所要设置的引脚,只能选择函数支持的引脚;参
数value表示PWM输出的占空比,范围在
0~255的区间,对应的占空比为0%~100%,函数原型如下:
void analogWrite(uint8_t pin,int val)
{
if(digitalPinToTimer(pin)==TIMER1A)
{
connect pwm to pin on timer 1,channel A
sbi(TCCR1A,COM1A1);
set pwm duty
OCR1A=val;
}
else if(digitalPinToTimer(pin)
==TIMER1B)
{
connect pwm to pin on timer 1,channel B
sbi(TCCR1A,COM1B1);
set pwm duty
OCR1B=val;
}
else if(digitalPinToTimer(pin)
==TIMER0A)
{
if(val==0)
{
digitalWrite(pin,LOW);}
else
{
connect pwm to pin on timer 0,channel A
sbi(TCCR0A,COM0A1);
set pwm duty
OCR0A=val;
}
}
else if(digitalPinToTimer(pin)
==TIMER0B)
{
if(val==0)
{
digitalWrite(pin,LOW);
}
else
{
connect pwm to pin on timer 0,channel B
sbi(TCCR0A,COM0B1);
set pwm duty
OCR0B=val;
}
}
else if(digitalPinToTimer(pin)
==TIMER2A)
{
connect pwm to pin on timer 2,channel A
sbi(TCCR2A,COM2A1);set pwm duty
OCR2A=val;
}
else if(digitalPinToTimer(pin)
==TIMER2B)
{
connect pwm to pin on timer 2,channel B
sbi(TCCR2A,COM2B1);
set pwm duty
OCR2B=val;
}
else if(val<128)
digitalWrite(pin,LOW);
else
digitalWrite(pin,HIGH);
}
可以在开发环境的下列实例程序中
找到analogWrite函数的应用:
Calibration. pde、Dimmer.pde、Fading.pde3.3 高级IO
3.3.1
shiftOut(dataPin,clockPin,bitOrder,val)
shiftOut函数能够将数据通过串行的
方式在引脚上输出,相当于一般意义上的
同步串行通信,这是控制器与控制器、控
制器与传感器之间常用的一种通信方式。
shiftOut函数无返回值,有4个参数:
dataPin、clockPin、bitOrder、val,具体说
明如下:
dataPin:数据输出引脚,数据的每
一位将逐次输出。引脚模式需要设置成输
出。
clockPin:时钟输出引脚,为数据输
出提供时钟,引脚模式需要设置成输出。bitOrder:数据位移顺序选择位,该
参数为byte类型,有两种类型可选择,分
别是高位先入MSBFIRST和低位先入
LSBFIRST。
val:所要输出的数据值。
函数原型在wiring_shift.c文件中,如
下:
void shiftOut(uint8_t dataPin,uint8_t
clockPin,uint8_t bitOrder,uint8_t val)
{
uint8_t i;
for(i=0;i<8;i++)
{
if(bitOrder==LSBFIRST)
digitalWrite(dataPin,!(val&(1<<
i)));
else
digitalWrite(dataPin,!(val&(1<<
(7-i))));
digitalWrite(clockPin,HIGH);
digitalWrite(clockPin,LOW);
}
}另外还有shiftIn函数用于通过串行的
方式从引脚上读入数据,其函数定义如
下:
uint8_t shiftIn(uint8_t
dataPin,uint8_t clockPin,uint8_t bitOrder)
{
uint8_t value=0;
uint8_t i;
for(i=0;i<8;++i)
{
digitalWrite(clockPin,HIGH);
if(bitOrder==LSBFIRST)
value|=digitalRead(dataPin)<
else
value|=digitalRead(dataPin)<<(7-
i);
digitalWrite(clockPin,LOW);
}
return value;
}3.3.2 pulseIn(pin,state,timeout)
pulseIn函数用于读取引脚脉冲的时
间长度,脉冲可以是HIGH或LOW。如果是
HIGH,函数将先等引脚变为高电平,然后
开始计时,一直到变为低电平为止。返回
脉冲持续的时间长短,单位为ms。如果超
时还没有读到的话,将返回0。
pulseIn函数返回值类型为无符号长
整型(unsigned long),3个参数分别表示
脉冲输入的引脚、脉冲响应的状态(高脉
冲或低脉冲)和超时时间。函数原型在
wiring_pulse.c中,如下:
unsigned long pulseIn(uint8_t
pin,uint8_t state,unsigned long timeout)
{
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
uint8_t stateMask=(state?bit:0);
unsigned long width=0;keep initialization out of time
critical area
unsigned long numloops=0;
unsigned long
maxloops=microsecondsToClockCycles(timeout)16;
wait for any previous pulse to end
while((portInputRegister(port)&
bit)==stateMask)
if(numloops++==maxloops)
return 0;
wait for the pulse to start
while((portInputRegister(port)&
bit)!=stateMask)
if(numloops++==maxloops)
return 0;
wait for the pulse to stop
while((portInputRegister(port)&
bit)==stateMask)
width++;
return
clockCyclesToMicroseconds(width10+16);
}
可以在开发环境的下列实例程序中
找到pulseIn函数的应用:
Memsic2125. pde、Ping.pde3.4 时间函数
3.4.1 millis
应用millis函数可获取机器运行的时
间长度,单位ms。系统最长的记录时间为
9小时22分,如果超出时间将从0开始。函
数返回值为unsigned long型,无参数。函
数原型如下:
unsigned long millis
{
unsigned long m;
uint8_t oldSREG=SREG;
cli;
m=timer0_millis;
SREG=oldSREG;
return m;
}
注意:函数返回值为unsigned long
型,如果用int型保存时间将得到错误结果。
可以在开发环境的下列实例程序中
找到millis函数的应用:
BlinkWithoutDelay. pde、Calibration.pde、Debounce.pde3.4.2 delay(ms)
delay函数是一个延时函数,在Blink
程序中用到过,参数表示延时时长,单位
是ms。函数无返回值,原型如下:
void delay(unsigned long ms)
{
uint16_t start=(uint16_t)micros;
while(ms>0)
{
if(((uint16_t)micros-start)>
=1000)
{
ms--;
start+=1000;
}
}
}
可以在开发环境的下列实例程序中
找到delay函数的应用:
ADXL3xx. pde、AnalogInput.pde、Blink.pde、Fading.pde、Graph.pde、Knock.pde、Loop.pde、Melody.pde、Memsic2125.pde、Ping.pde3.4.3 delayMicroseconds(us)
delayMicroseconds函数同样是延时函
数,所不同的是其参数单位是
μs(1ms=1000μs)。函数原型如下:
void delayMicroseconds(unsigned int
us)
{
for a one-microsecond delay,simply
return.
the overhead of the function call
yields a delay of
approximately 1 18 us.
if(--us==0)
return;
the following loop takes a quarter
of a microsecond(4 cycles)
per iteration,so execute it four
times for each
microsecond of delay requested.
us<<=2;
account for the time taken in the
preceeding commands.
us-=2;
busy wait__asm____volatile__(
1:sbiw%0,1\n\t2 cycles
brne 1b:=w(us):0(us)2
cycles);
}
可以在开发环境中的下列实例程序
中找到delayMicroseconds函数的应用:
Melody. pde、Ping.pde3.5 数学库
3.5.1 min(x,y)
min(x,y)函数的作用是返回x、y两
者中较小的,函数原型为:
define min(a,b)((a)<(b)?(a):
(b))3.5.2 max(x,y)
max(x,y)函数的作用是返回x、y两
者中较大的,函数原型为:
define max(a,b)((a)>(b)?(a):
(b))3.5.3 abs(x)
abs(x)函数的作用是获取x的绝对
值,函数原型为:
define abs(x)((x)>0?(x):-(x))3.5.4 constrain(amt,low,high)
constrain(amt,low,high)函数的工作
过程是,如果值amt小于low,则返回low;
如果amt大于high,则返回high;否则,返
回amt。该函数一般可以用于将值归一化到
某个区间内。函数原型为:
define constrain(amt,low,high)
((amt)<(low)?(low):((amt)>
(high)?(high):(amt)))3.5.5
map(x,in_min,in_max,out_min,out_max)
map(x,in_min,in_max,out_min,out_max)
函数的作用是将[in_min,in_max]范围内的x
等比映射到[out_min,out_max]范围内。函
数返回值为long型,原型为:
long map(long x,long in_min,long
in_max,long out_min,long out_max)
{
return(x-in_min)(out_max-out_min)
(in_max-in_min)+out_min;
}3.5.6 三角函数
三角函数包括sin(rad)、cos(rad)、tan(rad),分别得到rad的正
弦值、余弦值和正切值。返回值都为
double型。3.6 随机数
3.6.1 randomSeed(seed)
randomSeed函数用来设置随机
数种子,随机种子的设置对产生的随机序
列有影响。函数无返回值,原型如下:
void randomSeed(unsigned int seed)
{
if(seed!=0)
{
srandom(seed);
}
}3.6.2 random(howsmall,howbig)
应用random函数可生成一个随机
数,两个参数howsmall和howbig决定了随
机数的范围,函数的参数及返回值均为
long型,原型如下:
long random(long howsmall,long
howbig)
{
if(howsmall>=howbig)
{
return howsmall;
}
long diff=howbig-howsmall;
return random(diff)+howsmall;
}3.7 位操作
位操作用于设置或读取字节中某一
位或几位,包括bitRead、bitSet、bitClear等,具体定义及功能可以参考
文件wiring.h。
define lowByte(w)((uint8_t)((w)&
0xff))低字节
define highByte(w)((uint8_t)((w)
>>8))高字节
读bit位的值,即保留bit位,其他位均清零
define bitRead(value,bit)(((value)
>>(bit))&0x01)
置bit位的值,即bit位置1
define bitSet(value,bit)
((value)|=(1UL<<(bit)))
清除bit位,即bit位置0
define bitClear(value,bit)((value)
&=~(1UL<<(bit)))
写bit位的值,1或者0
define bitWrite(value,bit,bitvalue)
(bitvalue?bitSet(value,bit):
bitClear(value,bit))3.8 中断函数
3.8.1 interrupts和noInterrupts
interrupts和noInterrupts函数在
Arduino中负责打开和关闭总中断,函数无
返回值,无参数,同样可在文件wiring.h中
查看到函数原型,如下:
define interruptssei
define noInterruptscli3.8.2
attachInterrupt(interrupt,function,mode)
attachInterrupt函数用于设置外部中
断,函数有3个参数:interrupt、function和
mode,分别表示中断源、中断处理函数、触发模式。参数中断源可选值0或1,在
Arduino中一般对应2号和3号数字引脚;参
数中断处理函数用来指定中断的处理函
数,参数值为函数的指针,触发模式有4种
类型:LOW(低电平触发)、CHANGE(变化时触发)、RISING(低电
平变为高电平触发)、FALLING(高电平
变为低电平触发)。
下面的例子是通过外部引脚触发中
断函数。然后控制13号引脚的LED的闪
烁。
int pin=13;
volatile int state=LOW;void setup
{
pinMode(pin,OUTPUT);
attachInterrupt(0,blink,CHANGE);中
断源:1
中断处理函数:blink
触发模式:CHANGE(变化时触发)
}
void loop
{
digitalWrite(pin,state);
}
中断处理函数
void blink
{
state=!state;
}
在使用attachInterrupt函数时要注意以
下几点:
在中断函数中delay函数不能使用。
使用millis函数始终返回进入中断前
的值。
读取串口数据的话,可能会丢失。中断函数中使用的变量需要定义为
volatile型。
attachInterrupt函数的函数原型可在文
件WInterrupts.c中找到,如下所示:
void attachInterrupt(uint8_t
interruptNum,void(userFunc)(void),int
mode)
{
if(interruptNum<
EXTERNAL_NUM_INTERRUPTS)
{
intFunc[interruptNum]=userFunc;
switch(interruptNum)
{
case 0:
EICRA=(EICRA&~((1<
|(1<
EIMSK|=(1<
break;
case 1:
EICRA=(EICRA&~((1<
|(1<
EIMSK|=(1<
break;
}
}
}另外,还有detachInterrupt函数用于
取消中断,参数interrupt表示所要取消的中
断源,函数的定义如下:
void detachInterrupt(uint8_t
interruptNum)
{
if(interruptNum<
EXTERNAL_NUM_INTERRUPTS)
{
switch(interruptNum)
{
case 0:
EIMSK&=~(1<
break;
case 1:
EIMSK&=~(1<
break;
}
intFunc[interruptNum]=0;
}
}3.9 串口通信
Arduino中串口通信是通过
HardwareSerial类来实现的,在头文件
HardwareSerial.h中定义了一个
HardwareSerial类的对象Serial,直接使用类
的成员函数就可简单地实现串口通信。对
象和类的概念与应用可参阅6.1节内容。下
面以一个串口调光器的程序为例介绍
HardwareSerial类几个较常用的公有成员函
数,程序清单如下:
Dimmer(调光器)
通过计算机发送数据控制LED灯的亮度,单字节数据发
送,数据范围0~255
使用具有pwm功能的9号引脚
created 2006
by David A.Mellis
modified 14 Apr 2009
by Tom Igoe and Scott Fitzgerald
This example code is in the public
domain.
http:www.arduino.ccenTutorialDimmer
const int ledPin=9;
the pin that the LED is attached to
void setup
{
设置串口波特率:
Serial.begin(9600);1
设置LED控制引脚:
pinMode(ledPin,OUTPUT);
}
void loop
{
byte brightness;
查询串口是否收到数据:
if(Serial.available)2
{
获取数据
brightness=Serial.read;3
控制LED亮度
analogWrite(ledPin,brightness);
}
}
串口通信相关语句分析解释。
1.Serial.begin(9600);
该语句的功能是设置串口通信波特
率为9600bps,其函数原型如下:void HardwareSerial:begin(long baud)
{
uint16_t baud_setting;
bool use_u2x;
U2X mode is needed for baud rates
higher than(CPU Hz16)
if(baud>F_CPU16)
{
use_u2x=true;
}
else
{
figure out if U2X mode would allow
for a better connection
calculate the percent difference
between the baud-rate specified and
the real baud rate for both U2X and
non-U2X mode
uint8_t nonu2x_baud_error=abs((int)
(255-
((F_CPU(16(((F_CPU8baud-
1)2)+1))255)baud)));
uint8_t u2x_baud_error=abs((int)
(255-
((F_CPU(8(((F_CPU4baud-
1)2)+1))255)baud)));
prefer non-U2X mode because it
handles clock skew better
use_u2x=(nonu2x_baud_error>
u2x_baud_error);
}
if(use_u2x){
_ucsra=1<<_u2x;
baud_setting=(F_CPU4baud-1)2;
}
else
{
_ucsra=0;
baud_setting=(F_CPU8baud-1)2;
}
assign the
baud_setting,a.k.a.ubbr(USART Baud Rate
Register)
_ubrrh=baud_setting>>8;
_ubrrl=baud_setting;
sbi(_ucsrb,_rxen);
sbi(_ucsrb,_txen);
sbi(_ucsrb,_rxcie);
}
2.if(Serial.available)
该语句用来判断Arduino串口是否收
到数据,函数Serial.available返回值为
int型,不带参数。函数原型如下:
int HardwareSerial:available(void)
{
return(RX_BUFFER_SIZE+_rx_buffer->
head-_rx_buffer->tail)%RX_BUFFER_SIZE;}
3.brightness=Serial.read;
该语句的功能是将串口数据读入到
变量brightness中,函数Serial.read也不
带参数,返回值为串口数据,int型。函数
原型如下:
int HardwareSerial:read(void)
{
if the head isn't ahead of the
tail,we don't have any characters
if(_rx_buffer->head==_rx_buffer->
tail)
{
return-1;
}
else
{
unsigned char c=_rx_buffer->
buffer[_rx_buffer->tail];
_rx_buffer->tail=(_rx_buffer->
tail+1)%RX_BUFFER_SIZE;
return c;
}
}3.10 SPI接口
3.10.1 SPI接口概述
SPI(Serial Peripheral Interface)是
由摩托罗拉公司提出的一种同步串行外设
接口总线,它可以使MCU与各种外围设备
以串行方式进行通信以及交换信息,总线
采用3根或4根数据线进行数据传输,常用
的是4根线,即两条控制线(芯片选择CS
和时钟SCLK)以及两条数据信号线SDI和
SDO。
SPI是一种高速、全双工、同步的通
信总线。在摩托罗拉公司的SPI技术规范
中,数据信号线SDI称为MISO(Master-In-
Slave-Out,主入从出),数据信号线SDO
称为MOSI(Master-Out-Slave-In,主出从
入),控制信号线CS称为SS(Slave-
Select,从属选择),将SCLK称为SCK(Serial-Clock,串行时钟)。在SPI通
信中,数据是同步进行发送和接收的。数
据传输的时钟基于来自主处理器产生的时
钟脉冲,摩托罗拉公司没有定义任何通用
的SPI时钟规范。3.10.2 SPI接口数据传输
SPI是以主从方式工作的,其允许一
个主设备和多个从设备进行通信,主设备
通过不同的SS信号线选择不同的从设备进
行通信。其典型应用示意图如图3.5所示。
当主设备选中某一个从设备后,MISO和MOSI用于串行数据的接收和发
送,SCK提供串行通信时钟,上升沿发
送,下降沿接收。在实际应用中,未选中
的从设备的MOSI信号线需处于高阻状态,否则会影响主设备与选中从设备间的正常
通信。图 3.5 SPI总线应用示意图3.10.3 SPI类及其成员函数
Arduino中的SPI通信是通过SPIClass
类来实现的,使用SPIClass类能够方便地
将Arduino作为主设备与其他从设备通信。
SPIClass类提供了6个成员函数供使用者调
用,如下:
begin
setBitOrder
setClockDivider
setDataMode
transfer
end
begin函数用于初始化SPI总线,函数
原型如下:void SPIClass:begin
{
Set direction register for SCK and
MOSI pin.
MISO pin automatically overrides to
INPUT.
When the SS pin is set as OUTPUT,it
can be used as
a general purpose output port(it
doesn't influence
SPI operations).
pinMode(SCK,OUTPUT);
pinMode(MOSI,OUTPUT);
pinMode(SS,OUTPUT);
digitalWrite(SCK,LOW);
digitalWrite(MOSI,LOW);
digitalWrite(SS,HIGH);
Warning:if the SS pin ever becomes a
LOW INPUT then SPI
automatically switches to Slave,so
the data direction of
the SS pin MUST be kept as OUTPUT.
SPCR|=_BV(MSTR);
SPCR|=_BV(SPE);
}
setBitOrder的作用是在设置串行数据
传输时是先传输低位还是先传输高位,函
数有一个type类型的参数bitOrder,有
LSBFIRST(最低位在前)和MSBFIRST(最高位在前)两种类型可
选。函数无返回值,原型如下:
void SPIClass:setBitOrder(uint8_t
bitOrder)
{
if(bitOrder==LSBFIRST)
{
SPCR|=_BV(DORD);
}
else
{
SPCR&=~(_BV(DORD));
}
}
setClockDivider函数的作用是设置
SPI串行通信的时钟,通信时钟是由系统时
钟分频而得到,分频值可选2、4、8、16、32、64及128,有一个type类型的参数rate,有7种类型,对应7个分频值分别为
SPI_CLOCK_DIV2、SPI_CLOCK_DIV4、SPI_CLOCK_DIV8、SPI_CLOCK_DIV16、SPI_CLOCK_DIV32、SPI_CLOCK_DIV64
和SPI_CLOCK_DIV128。函数默认参数设
置是SPI_CLOCK_DIV4,设置SPI串行通信时钟为系统时钟的14。函数原型如下:
void SPIClass:setClockDivider(uint8_t
rate)
{
SPCR=(SPCR&~SPI_CLOCK_MASK)|(rate&
SPI_CLOCK_MASK);
SPSR=(SPSR&~SPI_2XCLOCK_MASK)|(rate
&SPI_2XCLOCK_MASK);
}
setDataMode函数的作用是设置SPI数
据模式,由于在SPI通信中没有定义任何通
用的时钟规范,所以在具体应用中有的在
上升沿采样,有的在下降沿采样,由此SPI
存在4种数据模式,如表3.1所示。setDataMode函数的type类型的参数
mode有4种类型可选,分别是
SPI_MODE0、SPI_MODE1、SPI_MODE2
和SPI_MODE3。函数原型如下:
void SPIClass:setDataMode(uint8_t
mode)
{
SPCR=(SPCR&~SPI_MODE_MASK)|mode;
}
transfer函数用来传输一个数据,由
于SPI是一种全双工、同步的通信总线。所
以传输一个数据实际上会发送一个数据,同时接收一个数据。函数的参数为发送的
数据值,返回的参数为接收的数据值。函
数原型如下:
byte SPIClass:transfer(byte_data)
{
SPDR=_data;
while(!(SPSR&_BV(SPIF)));
return SPDR;
}end函数停止SPI总线的使用,函数原
型如下:
void SPIClass:end
{
SPCR&=~_BV(SPE);
}第4章 Arduino硬件平台
通过前几章的介绍,大家对Arduino
的软件资源和环境应该有了一定的了解,但Arduino毕竟是一个硬件项目,要想真正
用好Arduino,还需要一些必要的硬件知
识。
本章通过原理分析、资源使用等方
面介绍Arduino的硬件平台。
4.1 Arduino的原理图
Arduino Duemilanove的硬件布局如
图4.1所示。Duemilanove在意大利语中是
2009的意思,名字就取自它的发布年份。
可以在网站:http:www.arduino.cc上获
得该控制板的原理图,如图4.2所示。
Arduino Uno与Arduino Duemilanove的硬件布局相似,所不同的是Arduino Uno使用的
不是FTDI USB-to-serial串行驱动器芯片,而是采用ATmega8U2芯片进行USB到串行
数据的转换。Uno在西班牙语和意大利语
中的意思为“一”,代表着Arduino 1.0,其
原理图如图4.3所示。图 4.1 Arduino Duemilanove的硬件布局图 4.2 Arduino Duemilanove原理图图 4.3 Arduino Uno原理图
由原理图可以发现,Arduino就是一
个带USB转串口芯片的AVR板,其核心就
是AVR单片机。AVR单片机具有以下优
点:
采用RISC(精简指令集)指令系
统,32个通用工作寄存器,避免了传统
8051单片机指令系统的指令长度不够长、指令数多、CPU利用率低和执行速度慢的
缺点。
采用哈佛结构的流水线技术,提高
指令执行速度。
除支持ISP在线编程外,还支持IAP
在应用编程。
片内集成了可擦写1000次的FLASH程
序存储器,同时还有大容量的可擦写
100000次的EEPROM。
集成了丰富的外设,包括IIC、SPI、WTD、ADC、PWM和片内振荡器等。
具有较宽的工作电压范围,工作电
压在1.8~6V,电源抗干扰能力强。
IO驱动能力强,可直接驱动LED。
USART使用独特的波特率发生器,波特率可达到576Kbits。
Arduino的IO引脚直接连接单片机的
IO引脚,利用AVR单片机引脚本身具有的
功能实现PWM、ADC、IIC、驱动LED等应
用。AVR单片机硬件连接16MHz晶振采用
外部振荡方式工作。
Arduino的编程利用AVR单片机的IAP
在应用编程技术,让使用者能够直接通过
USB接口将程序上传到芯片中。每一块
Arduino板在出厂前都在单片机中烧写了引
导程序(bootloader),它能够引导芯片通
过串口完成与计算机的通信,实现在应用
编程;否则Arduino是无法通过USB口更新
程序的。我们会在4.5节详细介绍这一点。4.2 串行通信口的使用
由原理图可以看出,AVR单片机的串
行通信口(RxD和TxD)除了接在USB到串
行数据的转换芯片上之外,还作为Arduino
的0号和1号引脚,在板上有明确的标识,如图4.4所示。
图 4.4 Arduino板上的串行通信口
4.2.1 实例功能本节实例采用两条杜邦线将两块
Arduino板的通信口交叉连起来,其中一块
Arduino每隔1s发送一个值为0x55的字节,另一块Arduino收到该字节后控制13号引脚
的LED转换状态。4.2.2 硬件电路
串口通信实例电路参考图4.5。
图 4.5 串口通信实例电路4.2.3 程序设计
由于实例用到了两块Arduino,因此
程序设计分为发送端和接收端两部分。先
来看看发送端的程序,实例要求发送端每
隔1s发送一个值为0x55的字节。
串行通信实例程序——发送端
每隔1s发送一个值为0x55的字节
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
}
执行部分——loop函数
void loop
{
延时1s,delay函数见3.4.2
delay(1000);
输出0x55
Serial.print(0x55,BYTE);
}
接收端的程序的任务是收到0x55后转
换13号引脚的状态,代码如下:
串行通信实例程序——接收端
收到0x55后转换13号引脚的状态
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
int ledFlag;LED状态
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
设置13号引脚为输出pinMode(13,OUTPUT);
}
执行部分——loop函数
void loop
{
byte RXData;
if(Serial.available)
{
获取收到的数据
RXData=Serial.read;
判断收到的数据是否是0x55
if(RXData==0x55)
{
if(ledFlag==0)判断LED状态
{
ledFlag=1;
digitalWrite(13,HIGH);
}
else
{
ledFlag=0;
digitalWrite(13,LOW);
}
}
}
}
读者在开始学习Arduino串口通信
时,可以就用计算机与Arduino进行通信,原理上是一样的。在Arduino开发环境下带
有Serial Monitor(串口监视窗)功能
,可方便地进行串口通信调试,界面如图
4.6所示。
图 4.6 Serial Monitor(串口监视窗)界
面4.3 数字IO口的使用
13号引脚的LED控制就属于数字IO
输出控制,前几章已经应用过多次了,本
节介绍数字IO输入的使用。
4.3.1 实例功能
本节实例是在2号引脚加一个按键开
关,当按下按键时,13号引脚的LED点
亮,同时通过串口发送合计的按键次数,当松开按键时,LED熄灭。4.3.2 硬件电路
将按键的一端接2号引脚,另一端接
地。同时为保持2号引脚输入状态稳定,加
1个5.1KΩ的上拉电阻在2号引脚。另外不
要忘了把Arduino连接在电脑上,实例电路
如图4.7所示。图 4.7 数字IO口实例电路4.3.3 程序设计
数字IO口实例程序
按键在2号引脚
按下按键时,13号引脚的LED点亮,同时通过串口发送
合计的按键次数,当松开按键时,LED熄灭
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
int keySum=0;按键次数
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
设置13号引脚为输出
pinMode(13,OUTPUT);
设置2号引脚为输入
pinMode(2,INPUT);
}
执行部分——loop函数
void loop
{
判断按键是否按下
if(LOW==digitalRead(2))
{
延时去抖
delay(50);
if(LOW==digitalRead(2))
{
点亮LED
digitalWrite(13,HIGH);
keySum++;
发送按键次数
Serial.print(keySum,DEC);
while(1)
{
判断是否松开按键
if(HIGH==digitalRead(2))
{
延时去抖
delay(50);
if(HIGH==digitalRead(2))
break;
}
}
熄灭LED
digitalWrite(13,LOW);
}
}
}4.4 模拟IO口的使用
由原理图可以看出Arduino的6个模拟
量引脚实际上是连接的AVR单片机的6个具
有ADC功能的管脚,所以Arduino的模拟量
输入功能就是通过单片机的ADC接口实现
的,该ADC接口具有以下特点:
10位采样精度
0.5 LSB的非线性度
±2 LSB的绝对精度
13~260μs的转换时间
最高分辨率时采样率高达15ksps
0~5V的ADC输入电压范围
本节就利用ADC接口实现模拟量的
输入。4.4.1 实例功能
本节实例在0号模拟口连接电位器,通过调整电位器改变输入模拟量的大小。
Arduino板每1s进行一次AD转换,并将结
果传给计算机。4.4.2 硬件电路
将Arduino的0号模拟口接至电位器的
中点,电位器另外两端分别连接+5V和
地,USB口连接至计算机用于传送数据,模拟IO实例电路如图4.8所示。图 4.8 模拟IO口实例电路4.4.3 程序设计
模拟IO口实例程序
在0号模拟口连接电位器
每1s进行一次AD转换并将结果发送给计算机
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
}
执行部分——loop函数
void loop
{
延时1s
delay(1000);
进行AD转换并传输数据Serial.print(analogRead(0),DEC);
}4.5 烧写引导程序
在4.1节说过每一块Arduino板在出厂
前都在单片机中烧写了引导程序,它可以
让Arduino通过USB口进行程序更新。如果
我们手上有一块空的AVR单片机想用到
Arduino中,则只能自己烧写引导程序了。
在Arduino这个完全开源的硬件项目中,AVR单片机的引导程序就在开发环境的文
件夹里。本节就使用AVR的开发环境AVR
Studio和ISP下载器AVRISP烧写引导程序。
4.5.1 下载器AVRISP
给一块空芯片烧写程序需要使用烧
写器、下载器之类的工具,AVRISP就是一
款AVR单片机专用的ISP下载器。如图4.9
所示即为一个AVRISP,它采用USB接口与
电脑相连,通过一条10芯的扁平线连接目标板,并利用目标板供电,图4.10即为
AVRISP的连接示意图。为方便使用某些6
芯ISP下载口(比如这里的Arduino),AVRISP配有一个10转6的转换头将10芯ISP
下载口转换成Arduino上的6芯ISP下载口。
10芯与6芯下载口的关系如表4.1所示。
图 4.9 AVRISP图 4.10 AVRISP连接示意图4.5.2 AVR Studio
AVR Studio集成开发环境是Atmel公
司官方发布的免费软件,专门用于开发
AVR单片机的软件平台,使用者可以到
Atmel的网站(http:www.atmel.com)下
载最新版的AVR Studio。
AVR Studio的安装十分简单,依照软
件的提示就能很顺利完成,图4.11所示即
为软件的使用界面。这里我们要使用AVR
Studio完成引导程序hex文件的烧写。图 4.11 AVR Studio使用界面打开软件后,将AVRISP连接到电脑
上,如图4.12所示,在AVR Studio界面中,选择Tools→Program AVR→Connect菜单
项,弹出Select AVR Programmer对话框,如图4.13所示。
图 4.12 下载器连接图 4.13 Select AVR Programmer对话框
在Select AVR Programmer对话框中,在Platform列表中选择STK 500 or
AVRISP,在Port列表中选择Auto,然后点
击Connect按钮,将AVRISP连上AVR
Studio。4.5.3 烧写引导程序
如果下载器连接成功,AVR Studio中
就会出现AVRISP对话框,如图4.14所示。
图 4.14 AVRISP对话框
在AVRISP对话框中就可以完成引导程序hex文件的烧写。
首先配置AVR单片机的融丝位,在图
4.14中选择Fuses选项卡,按以下内容配置
融丝位:
Boot Flash section size=1024 words
Boot start address=1C00;[BOOTSZ=00];
default value
Boot Reset Vector Enabled(default
address=0000);[BOOTRST=0]
Brown-out detection disabled;
[BODLEVEL=111]
Ext.Crystal Osc.;Frequency 8.0-
MHz;Startup time PWRDWNRESET:16K
CK14 CK+64ms;[CKSEL=1111 SUT=0]
然后回到Program选项卡,选择芯片
型号及引导文件的hex文件后,点击Flash
框内的Program按钮完成引导程序的烧写。提示:引导文件在Arduino开发环境
文件夹下的\hardware\arduino\bootloaders子
文件夹中。第二篇 模块篇
第5章 Arduino基本扩展模块
第6章 Arduino的扩展库
第7章 无线模块的应用第5章 Arduino基本扩展模块
在学习了前4章的基础知识后,本章
介绍Arduino的一些扩展模块,这些扩展模
块使得Arduino功能更强大,可以控制直流
电机、伺服电机、网络通信、液晶显示,获取温度、湿度值等。通过学习本章内
容,读者能够掌握Arduino的各个功能,为
后面的项目应用作铺垫。
5.1 L293 Motor Shield
L293 Motor Shield是一款基于L293B
直流电机驱动芯片的Arduino扩展模块,模
块可驱动两个电机,采用了可堆叠的设
计,可直接插到Arduino控制板上,如图
5.1所示,4个LED分别表示两个电机的正反
转。图 5.1 电机驱动模块L293 Motor Shield
5.1.1 直流电机的工作原理
大家都知道在磁场中放入通有电流
的导体就会产生磁感应效应。直流电机是
应用磁感应原理将电能转换为机械能的装
置,其转子和定子分别由绕组和永久磁铁
组成。直流电机具有调速性能较好和启动
转矩较大等特点。如图5.2所示为一个直流电机的模
型,在一对静止的磁极N和S之间,安装一
个可绕Z轴旋转的矩形线圈abcd,这个转动
的部分通常叫做电枢,线圈的两端a和b分
别接到叫做换向片的两个半圆形铜环上,两个换向片之间彼此是绝缘的,它们和电
枢装在同一根轴上,随电枢一起转动。A
和B是两个固定不动的碳质铜刷,它们和
换向片间是滑动接触的。来自直流电源的
电流就是通过电刷和换向片流入线圈的。图 5.2 直流电机模型图
当电刷A和B分别与直流电源的正极
和负极接通时,电流从电刷A流入,而从
电刷B流出。这时线圈中的电流方向是从a
流向b,从c流向d。由于磁感应效应,当电
枢在如图5.3a所示的位置时,线圈ab边的
电流从a流向b,用圆圈中的一个加号表
示,会受到一个向左下方的力;线圈cd边的电流从c流向d,用圆圈里的一个点表
示,会受到一个向右上方的力。这样,电
枢上就产生了一个逆时针方向的转矩,电
枢就沿着逆时针方向转动起来。
图 5.3 电机工作原理
当电枢转到使线圈ab边从N极进入S
极,而cd边从S极进入N极时,与线圈a端连接的换向片跟B接触,而与线圈d端接触
的换向片跟A接触,如图5.3b所示。这样,线圈内的电流方向变为从d流向c,再从b流
向a,从而保证在N极下方的导体中电流方
向不变,因此转矩的方向也不变,电枢依
然按照原来的方向旋转。这样,再通过传
动装置,直流电机就可以带动其他部件转
动了。
由原理分析可以发现,线圈中的电
流越大,线圈在磁场中所受到的力就越
大,电机的转速就会越快;反之电流越
小,电机转速就越慢。5.1.2 H桥驱动电路
直流电机的正反转实际上是通过变
换直流电压的正负极实现的,对于图5.2所
示的直流电机模型,当电刷A和B分别与直
流电源的正极和负极接通时,电枢逆时针
旋转,若A端接直流电源负极,B端接直流
电源正极,则直流电机顺时针旋转。
在实际应用中常采用图5.4所示的电
路驱动直流电机。电路名为“H桥驱动电
路”,这是因为它的形状酷似字母H。如图
5.4所示,H桥驱动电路包括4个三极管和一
个电机。要使电机运转,必须导通对角线
上的一对三极管。根据不同三极管对的导
通情况,电流可能会从左至右或从右至左
流过电机,从而控制电机的转向。图 5.4 H桥驱动电路示意图
如图5.5a所示,当Q1管和Q4管导通
时,电流从电源正极经Q1从左至右穿过直
流电机,然后再经Q4回到电源负极,从而
驱动直流电机沿一个方向旋转(假设电流
由左向右穿过电机时,直流电机顺时针旋
转);在图5.5b中另一对三极管Q2和Q3导
通的情况下,电流将从右至左流过直流电
机,从而驱动直流电机沿另一方向转动。图 5.5 H桥驱动电路控制直流电机示意
图
注意:在实际应用中驱动直流电机
时,保证H桥上两个同侧的三极管不会同
时导通非常重要。如果三极管Q1和Q2同时
导通,那么电流就会从正极穿过两个三极
管直接回到负极。此时,电路中除了三极
管外没有其他任何负载,电路上的电流就可能达到最大值(该电流仅受电源性能限
制),甚至烧坏三极管。5.1.3 线性放大调速原理
直流电机的转速计算公式如下:
n=(U-IR)KΦ
其中U为电枢端电压;I为电枢电
流;R为电枢电路总电阻;Φ为每极磁通
量;K为电动机结构参数。
由公式可以发现对一个各参数已经
确定的直流电机调速的可控量就是电压。
通过调整电压就能够调整直流电机的转
速,电压高直流电机转速就快;反之,电
压低,直流电机转速就慢。
通过线性放大电路就能够方便地实
现调节直流电机转速的效果。线性放大电
路调速原理示意图如图5.6所示,调节电位
器的阻值大小,就会调整电位器的分压
值,从而改变电机两端的电压值。图 5.6 线性放大电路调速原理示意图
线性放大电路调速的特点是:
与直流电机的转矩无关、消耗大量
的电流,效率低。
电位器分压产生大量的热量。5.1.4 PWM调速原理
在第3章的analogWrite函数里已经介
绍过通过调节PWM的占空比在引脚上输出
不同的电压值。脉冲宽度调制(PWM)是
一种对模拟信号电平进行数字编码的方
法。通过高分辨率计数器的使用,调制方
波的占空比用来对一个具体模拟信号的电
平进行编码。PWM信号仍然是数字的,因
为在给定的任何时刻,满幅值的直流供电
要么完全有(ON),要么完全无
(OFF)。电压或电流源是以一种通
(ON)或断(OFF)的重复脉冲序列加到
模拟负载上去的。通的时候即是直流供电
加到负载上的时候,断的时候即是供电断
开的时候。只要带宽足够,任何模拟值都
可以使用PWM进行编码。
采样控制理论中有一个重要结论:
当冲量相等而形状不同的窄脉冲加在具有
惯性的环节上时,其效果基本相同。PWM控制技术就是以该结论为理论基础,对半
导体开关器件的导通和关断进行控制,使
输出端得到一系列幅值相等而宽度不相等
的脉冲,用这些脉冲来代替正弦波或其他
所需要的波形。按一定的规则对各脉冲的
宽度进行调制,既可改变逆变电路输出电
压的大小,也可改变输出频率。
PWM的一个优点是从处理器到被控
系统信号都是数字形式的,无须进行数模
转换。让信号保持为数字形式可将噪声影
响降到最小。噪声只有在强到足以将逻辑1
改变为逻辑0或将逻辑0改变为逻辑1时,才
能对数字信号产生影响。对噪声抵抗能力
的增强是PWM相对于模拟控制的另外一个
优点,而且这也是在某些时候将PWM用于
通信的主要原因。从模拟信号转化为PWM
可以极大地延长通信距离。在接收端,通
过适当的RC或LC网络可以滤除调制高频方
波并将信号还原为模拟形式。5.1.5 L293 Motor Shield的原理
电机驱动模块L293 Motor Shield驱动
直流电机就采用PWM方式,其核心是一块
直流电机驱动芯片L293B,驱动电机的电
源取自Arduino的Vin引脚,模块原理图如
图5.7所示。图 5.7 L293 MotorShield原理图
L293B直流电机驱动芯片允许的电压
范围是4.5~36V,内有四重推挽(双重H桥
集成功放电路)驱动电路,两个通道可以
向各自的电机提供1 A的驱动电流,并且如
果芯片过热,芯片能够自动关断,保障系
统不受损坏。L293B内部结构图及典型应
用如图5.8所示。图 5.8 L293B典型应用
在图5.7中,当DIRA、DIRB为高电平
时,两个电机的电流分别由3引脚流向6引
脚和11引脚流向14引脚,假设此时电机正
转;反之,当DIRA、DIRB为低电平时,电机电流分别由6引脚流向3引脚和14引脚
流向11引脚,电机反转。此时,可以用
PWM控制芯片上电机使能脚的通断时间比
来对电机进行调速。
电机驱动模块L293 Motor Shield占用
Arduino控制板的数字引脚4、5、6、7,分
别对应DIRA、PWMA、PWMB和
DIRB,DIRA和PWMA共同控制电机A,DIRB
和PWMB共同控制电机B。5.1.6 L293 Motor Shield的应用
由于L293 Motor Shield采用可堆叠设
计,因此它的应用非常方便,只要将模块
对应地插到Arduino控制板上就可以了。在
本节中,在L293 Motor Shield上连接一个直
流电机,用Arduino控制直流电机由静止逐
渐变换到快速,再逐渐变回到静止,反方
向同样变换一次。从静止到快速及从快速
到静止的变化时间均为25.5s。直流电机的
连接示意图如图5.9所示(在图5.9中未画出
Arduino控制板),对应Arduino控制板的
引脚为4和5。图 5.9 直流电机连接示意图
注意:由于电机驱动的电流较大,因此Arduino须采用单独的7~12V电源供
电。5.1.7 程序设计
直流电机驱动实例程序
占用引脚4、引脚5
控制直流电机由静止逐渐变换到快速,再逐渐变回到静
止,反方向同样变换一次
从静止到快速及从快速到静止的变化时间均为25.5s
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置4号引脚为输出,控制直流电机正反转
pinMode(4,OUTPUT);
设置5号引脚为输出,控制直流电机转速
pinMode(5,OUTPUT);
}
执行部分——loop函数
void loop{
引脚4输出高电平,直流电机正转
digitalWrite(4,HIGH);
直流电机由静止逐渐变换为快速
for(int i=0;i<255;i++)
{
控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由0变化到255需25.5s
delay(100);
}
直流电机由快速逐渐变换为静止
for(i=255;i>0;i--)
{
控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由255变化到0需25.5s
delay(100);
}
引脚4输出低电平,直流电机反转
digitalWrite(4,LOW);
直流电机由静止逐渐变换为快速
for(i=0;i<255;i++)
{
控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由0变化到255需25.5s
delay(100);
}
直流电机由快速逐渐变换为静止
for(i=255;i>0;i--)
{控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由255变化到0需25.5s
delay(100);
}
}5.1.8 程序分析
首先在setup函数中设置直流电
机驱动的两个引脚4和5为输出,然后在
loop函数中对引脚4、5进行控制。
引脚4控制直流电机的正反转,使用
数字IO控制函数digitalWrite,函数描
述见3.1节。程序中两次使用该函数对引脚
4的输出电平进行控制,用于在直流电机由
静止变为快速,再变回静止后对直流电机
旋转方向的改变。
引脚5控制直流电机的转速,使用模
拟IO控制函数analogWrite,函数描述
见3.2节。在程序的for循环内不断改变
PWM的占空比,调整直流电机的转速。调
速周期为每0.1s一次,在程序中通过
delay函数实现。
注意:在实际应用中,由于直流电机存在一个启动电压,一旦小于启动电
压,直流电机就处于静止状态,因此直流
电机静止的时间就显得较长。可根据实际
情况改变程序中的i值来缩短直流电机静止
的时长。5.1.9 程序的精练
通过对程序的分析会发现在5.1.7节的
程序代码中对直流电机速度控制的代码段
都是十分类似的,通过引脚4调整直流电机
正反转后的调速代码甚至是一样的。5.1.7
节中的代码流程固然清晰,但代码的集成
度不高,本节通过在程序中加入两条判断
语句来实现程序的精练。程序代码如下:
直流电机驱动实例程序——精练程序
占用引脚4、引脚5
控制直流电机由静止逐渐变换到快速,再逐渐变回到静
止,反方向同样变换一次
从静止到快速及从快速到静止的变化时间均为25.5s
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置4号引脚为输出,控制直流电机正反转
pinMode(4,OUTPUT);
设置5号引脚为输出,控制直流电机转速
pinMode(5,OUTPUT);
}
执行部分——loop函数
void loop
{
通过判断引脚4的电压值来对引脚4输出进行控制
if(LOW==digitalRead(4))
{
引脚4输出高电平,直流电机正转
digitalWrite(4,HIGH);
}
else
{
引脚4输出低电平,直流电机反转
digitalWrite(4,LOW);
}
对直流电机调速
for(int i=0;i<511;i++)
{
控制电机转动
if(i<255)
{
如果i小于255,则加速
analogWrite(5,i);
}else
{
如果i大于255,则减速
analogWrite(5,511-i);
}
延时0.1s
delay(100);
}
}
在上述程序中,通过
if(LOW==digitalRead(4))和if(i<
255)两条判断语句,实现了程序的精练,一条语句用在控制引脚4的输出电压之前,用来在直流电机调速完成后对正转、反转
的切换;另一条语句用在控制直流电机转
速的函数之前,用来决定是加速还是减
速。5.2 Input Shield
Input Shield是一款带有摇杆和按键
的输入扩展板,同时预留了无线通信模块
接口,采用堆叠设计,可用于Arduino的交
互设计当中。模块如图5.10所示。
图 5.10 Input Shield
5.2.1 Input Shield原理图如图5.11所示,Input Shield扩展板具
有一个摇杆(含一个按键)、两个大圆帽
按键和1个复位按键,同时预留一个无线通
信模块接口。摇杆可以理解为一个两轴的
可调电位器,它能输出两个模拟信号,以
实现上下左右的控制,分别占用Arduino控
制板的模拟口0和模拟口1,摇杆按键占用
Arduino控制板的数字引脚5;B圆帽按键
(即Input Shield上的红色按键)占用数字
引脚3;C圆帽按键(即Input Shield上的蓝
色按键)占用数字引脚4;无线通信模块接
口占用数字引脚0和1。图 5.11 Input Shield原理图5.2.2 Input Shield的实例
本节中将Input Shield扩展板对应插
到Arduino控制板上,每1s获取一次摇杆上
下方向和左右方向的模拟量数据,通过串
口通信传送到电脑上,在Arduino开发环境
下的 Serial Monitor(串口监视窗)中查
看。5.2.3 程序设计
获取摇杆模拟量实例程序
摇杆上下方向和左右方向分别占用Arduino的模拟口0
和模拟口1
每1s进行一次AD转换并将结果发送给计算机
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
}
执行部分——loop函数
void loop
{
延时1s
delay(1000);显示水平模拟量值,Serial.print(horizontal:);
Serial.print(analogRead(1),DEC);
显示垂直模拟量
Serial.print(,vertical:);
Serial.println(analogRead(0),DEC);
}5.2.4 程序分析
在程序中应用analogRead函数获
取模拟口0和模拟口1的值,传送到电脑
端,效果如图5.12所示。通过操纵摇杆可
看到模拟量数据的变化,由于Arduino采用
10位的ADC,因此模拟量的变化范围是
0~1023。在水平方向上,越向右,模拟量
的值越小;反之模拟量的值越大。在垂直
方向上,越向上模拟量的值越小,反之模
拟量的值越大。图 5.12 摇杆操纵显示效果5.2.5 使用摇杆控制直流电机转速
将Input Shield扩展板对应插到5.1节
L293 Motor Shield应用的实例中,可实现直
流电机转速的交互式控制,人为地用摇杆
控制直流电机的转速。直流电机的连接位
置依然采用5.1.6节中的连接方式,当摇杆
位于中位时,直流电机静止不动;当向上
推动摇杆时,直流电机逐渐加速正转;当
向下拉动摇杆时,直流电机逐渐加速反
转。程序清单如下:
摇杆控制直流电机转速实例程序
直流电机控制占用引脚4、5
引脚4控制直流电机的正反转——数字量输出
引脚5控制直流电机的转速——模拟量输出
摇杆垂直位置模拟量获取占用模拟量引脚0——模拟量输
入
向上推摇杆模拟量值越来越小
向下拉摇杆模拟量值越来越大
模拟量范围0~1023
当摇杆位于中位时,直流电机静止不动
当向上推动摇杆时,直流电机逐渐加速正转当向下拉动摇杆时,直流电机逐渐加速反转
摇杆位置模拟量获取频率为10Hz(每秒10次,即
0.1s一次)
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
int verticalVal;定义整型变量
verticalVal存储AD值
初始化部分——setup函数
void setup
{
设置4号引脚为输出,控制直流电机正反转
pinMode(4,OUTPUT);
设置5号引脚为输出,控制直流电机转速
pinMode(5,OUTPUT);
}
执行部分——loop函数
void loop
{
延时0.1s
delay(100);
获取模拟量AD值
verticalVal=analogRead(0);
判断电机正转还是反转
if(verticalVal<512){
如果模拟量值小于512,则直流电机正转
引脚4输出高电平,直流电机正转
digitalWrite(4,HIGH);
设置直流电机转速
analogWrite(5,map(512-verticalVal,0,511,0,255));
}
else
{
否则直流电机反转
引脚4输出低电平,直流电机反转
digitalWrite(4,LOW);
设置直流电机转速
analogWrite(5,map(verticalVal,512,1023,0,255));
}
}
在程序中对摇杆输入模拟量的值转
换成PWM输出的值时使用了map函
数,该函数是将数据进行等比映射,可参
考3.5节。这是由于在摇杆处于中间位置
时,采集到的模拟量的值为512(0~1023的
中间值),而此时直流电机是静止的;当
摇杆向上推时,模拟量的值在0~512区间,此时需要控制直流电机正转,转速范围在
0~255区间;当摇杆向下拉时,模拟量的值在512~1023区间,此时需要控制直流电机
反转,转速范围同样在0~255区间。5.3 LCD Keypad Shield
LCD Keypad Shield是一块液晶显示
扩展板,使用的是标准1602液晶,该液晶
可显示两行内容,每行可显示16个英文字
符,具有对比度调节电位器,同时提供5个
按键输入,1个复位键,扩展板如图5.13所
示。图 5.13 LCD Keypad Shield
5.3.1 液晶显示原理
液晶显示(Liquid Crystal
Display,LCD)的应用在我们的生活中已经
随处可见,如手机、MP3、仪器仪表等。
液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制:通电时
液晶排列变得有序,光线容易通过;不通
电时排列混乱,阻止光线通过。
液晶显示按其显示方式可分为线段
式、字符式、点阵式等。除了黑白显示
外,还有多灰度显示、彩色显示等。LCD
Keypad Shield扩展板使用的是字符式液
晶,这是一种专门用于显示字母、数字、符号的液晶模块。
提示:Arduino提供了类库,可方便
地实现液晶显示模块的控制,而不需要知
道液晶显示的原理、控制方式等基础知识,希望尽快进行液晶显示模块应用的读
者可直接跳到5.3.8阅读。5.3.2 标准1602液晶模块
标准1602液晶模块除了液晶显示屏
外,还包括行列驱动器、控制器及连接附
件等,它是一种将液晶显示器件、控制集
成电路、PCB板、背光源、结构件装配在
一起的集合。提供与控制芯片的简单接
口,简化了液晶显示应用的控制方式。标
准1602液晶模块实物如图5.14所示。
图 5.14 标准1602液晶模块1602液晶模块主要技术参数如下:
显示容量:16×2个字符
芯片工作电压:4.5~5.5V
工作电流:2.0mA(5V)
字符尺寸:2.95mm×4.35mm
采用单排16芯接口,引脚定义如下表
所示。5.3.3 1602液晶模块控制方式
在1602液晶模块的内部显示存储器中
预先保存好的字符图形符号,其显示工作
流程就是通过控制器向1602写入指定的显
示存储器地址,相应地址对应的字符图形
符号就分别显示在液晶屏幕上。1602内部
显示存储器保存的字符图形符号包括阿拉
伯数字、英文字母大小写、常用符号、日
文平假名和片假名等,共160个,每一个字
符图形符号都有一个固定的地址。
1602液晶模块的控制指令共有11条,如表5.2所示。1602液晶模块的读写操作、屏幕和
光标的操作都是通过控制指令实现的,表
中1表示高电平,0表示低电平,表示无
效。
指令1:清屏,指令码01H,光标复
位到地址00H。指令2:光标复位,光标返回到地址
00H。
指令3:光标和显示模式设置。
ID:光标移动方向,高电平右移,低电平左移。
S:屏幕上所有文字是否左移或右
移,高电平表示有效,低电平表示无效。
指令4:显示开关控制。
D:控制整体显示的开或者关,高电
平表示开显示,低电平表示关显示。
C:控制光标的开或者关,高电平表
示有光标,低电平表示无光标。
B:控制光标是否闪烁,高电平闪
烁,低电平不闪烁。
指令5:光标或字符移位。
SC:高电平时移动显示的文字,低电平时移动光标。
RL:高电平时向右滚动,低电平时
向左滚动。
指令6:功能设置。
DL:高电平时为8位总线,低电平时
为4位总线。 ......
小编自己做了一个电子书下载网站, 网
程晨 著
——AVR篇
Arduino开发实战指南目录 前言
本书的内容及面向的读者
致谢
第一篇 基础篇
第1章 初识Arduino
1.1 Arduino的历史
1.2 Arduino的家族
1.3 Arduino的资源
1.4 Arduino的开发环境
1.5 添加新硬件及设置开发环
境
1.6 Arduino开发环境的应用
第2章 编写Arduino程序
2.1 绘制流程图
2.2 C语言的标识符与关键字
2.3 控制语句
2.4 程序结构
第3章 Arduino的基本函数
3.1 数字IO
3.2 模拟IO
3.3 高级IO3.4 时间函数
3.5 数学库
3.6 随机数
3.7 位操作
3.8 中断函数
3.9 串口通信
3.10 SPI接口
第4章 Arduino硬件平台
4.1 Arduino的原理图
4.2 串行通信口的使用
4.3 数字IO口的使用
4.4 模拟IO口的使用
4.5 烧写引导程序
第二篇 模块篇
第5章 Arduino基本扩展模块
5.1 L293 Motor Shield
5.2 Input Shield
5.3 LCD Keypad Shield
5.4 Ethernet Shield
5.5 IO扩展板
第6章 Arduino的扩展库
6.1 Arduino扩展库介绍6.2 对象和类
6.3 LiquidCrystal库
6.4 Ethernet库
6.5 SoftwareSerial库
6.6 EEPROM库
6.7 Wire库
6.8 Servo库
6.9 Stepper库
6.10 TLC5940库
6.11 OneWire库
6.12 XBee库
6.13 创建自己的库
第7章 无线模块的应用
7.1 APC220
7.2 DFduino wireless
7.3 Bluetooth V3
7.4 XBee和XBee PRO
第三篇 应用篇
第8章 打造自己的遥控履带车
8.1 履带车的驱动
8.2 添加感知器件
8.3 添加无线模块8.4 制作遥控器
8.5 履带车遥控调速
8.6 添加无线摄像头
8.7 环境信息获取器件
第9章 仿生机器人
9.1 遥控机械臂
9.2 双足机器人
附录A Arduino引脚与AVR单片机管脚对应
关系
附录B Arduino扩展板
附录C 其他可扩展模块前言
在2011年举行的Google IO开发者大
会上,Google发布了基于Arduino的
Android Open Accessory标准和ADK工具,这使得大家对Arduino的前景十分看好。
Phillip Torrone大胆地预测Google将用
Android+Arduino的形式掀起自己的“Kinect
模式”浪潮。目前,国内关注Arduino的人
越来越多,但介绍Arduino的书籍却很少。
笔者由于工作的关系,接触Arduino较早,所以希望通过自己的努力让更多的人了解
Arduino,在近一年的时间里,通过不断学
习、查阅Arduino相关知识,终于完成了书
稿的撰写工作。但在书稿完成之后,心中
却一直忐忑不安,Arduino是一个介于软件
与硬件之间的产品,系统性不是很强,加
上笔者水平有限,拙著中一定存在不少的
缺点与漏洞,为此,笔者先为书中的不足
之处致以真诚的歉意,同时诚挚地欢迎广
大读者提出宝贵的意见并不吝赐教。本书的内容及面向的读者
Arduino是一个注重实际动手操作的
产品,所以本书以实际应用为纽带将各个
章节联系起来。本书共9章,首先介绍
Arduino的一些基础知识,接着针对具体应
用介绍了一些扩展板以及Arduino扩展库,最后应用之前的内容完成了具有视频监控
功能的履带车、遥控机械臂以及双足机器
人的制作。
因为Arduino本身具有简单易用的特
点,所以本书面向的读者是所有有兴趣使
用Arduino进行项目开发的人。
当然,根据读者的情况不同,本书
的阅读方式也不同。
如果读者是一个之前没有进行过单
片机开发也没有进行过软件开发的人,现
在想使用Arduino来实现自己的一些想法,那么首先要阅读本书的前两章,了解一些
简单的编程思想以及程序结构,接下来阅
读第3章的目录,了解Arduino都有什么基
本函数,具体内容可以先不用看,当你之
后使用这些函数遇到问题时再回过头来看
一看相应的函数说明。然后将Arduino接到
你的电脑上,翻开第4章,根据书中的内
容,边学习边实践,4.5节可以跳过不看。
第5~7章介绍了Arduino周边的资源,以便
帮助你尽快地实现想法,这3章的内容也可
以采用跳跃式的阅读方式。第8、9章会告
诉你前3章的内容是如何结合起来的,建议
按照书中的内容至少动手完成一个项目的
制作。
如果读者之前进行过AVR单片机的开
发,想了解Arduino一些底层的知识,那么
第2章的知识就可以跳过了,在简单地翻阅
第3章的内容后,直接进入第4章,把
Arduino连到电脑上实践一下,再回过头阅
读第3章中关于Arduino的基本函数,结合
自身已有的AVR单片机的知识了解Arduino
底层的工作机制。需要说明的是,这里需要读者自己花一些精力,可能还需要学习
一些C++方面的知识。第5章对Arduino硬
件原理进行了详细介绍,若读者之前学习
过,这一章可以选择性学习。第6章介绍的
是Arduino的扩展库,如果读者也想开发一
些Arduino扩展板,并以库的形式提供扩展
板的软件资源,那么建议先学习最后一
节,再从6.1节开始学习,深入地了解这些
扩展库是如何与Arduino结合在一起的。至
于剩下几章的内容,如果用开发单片机的
思路来完成也是不难的,所以阅读的重点
是看看如何用Arduino的思路进行项目的制
作。
如果读者之前是做纯电脑软件开发
工作的,即使用C++非常熟练,那么在阅
读完第1章后,可以直接跳到第4章,感受
一下Arduino给纯软件开发人员带来的那种
完成硬件制作的感觉,然后仔细阅读第5
章,看看目前都有哪些扩展板可以为自己
所用,控制电机、控制液晶之类的,硬件
知识哪怕我们不用,也还是要了解一些
的。接下来,对于第6章,可以仔细阅读一下与硬件关系不太大的扩展库以及如何创
建自己的库,在今后底层硬件库不断丰富
完善的情况下,开发一些注重应用、与底
层关系不是太紧密的库时,这就是我们的
用武之地。第7~9章的内容会告诉我们前面
的知识是如何结合起来的——用纯软件的
思路,同样建议按照书中的内容至少动手
完成一个项目的制作,做纯软件开发工作
的人开发硬件也是很容易的。致谢
首先要感谢本书的策划张国强先
生,是他对Arduino的关注促成了本书的出
版,同时在笔者撰写书稿时他也对本书提
出了宝贵的写作建议,并对书稿进行了仔
细审阅。
其次要感谢让我了解Arduino的庄明
波先生,他不但在技术上给予了我很多的
指导,同时也无私地提供了大量的Arduino
扩展板的资料以及实物,供我在Arduino的
程序调试中使用,同时与我共同探讨技术
上遇到的问题。
最后要感谢现在正捧着这本书的
您,感谢您肯花费时间和精力阅读本书,由于时间有限,书中难免存在疏漏与错
误,诚恳地希望您批评指正,您的意见和
建议将是我巨大的财富。希望在Arduino的
领域结识更多的朋友。第一篇 基础篇
第1章 初识Arduino
第2章 编写Arduino程序
第3章 Arduino的基本函数
第4章 Arduino硬件平台第1章 初识Arduino
Arduino是源自意大利的一个开放源
代码的硬件项目平台,该平台包括一块具
备简单IO功能的电路板以及一套程序开发
环境软件。Arduino可以用来开发交互产
品,比如它可以读取大量的开关和传感器
信号,并且可以控制电灯、电机和其他各
式各样的物理设备;Arduino也可以开发出
与PC相连的周边装置,能在运行时与PC上
的软件进行通信。Arduino的硬件电路板可
以自行焊接组装,也可以购买已经组装好
的模块,而程序开发环境的软件则可以从
网上与使用。
1.1 Arduino的历史
说到Arduino的起源似乎有点令人感
觉无心插柳柳成荫。Massimo Banzi是意大利米兰互动设计学院的教师,他的学生常
常抱怨不能找到一块价格便宜且功能强大
的控制主板来设计他们的机器人。2005年
的冬天,Banzi和David Cuartielles讨论到这
个问题,David Cuartielles是西班牙的微处
理器设计工程师,当时在这所学校做访问
研究。他们决定自己设计一块控制主板。
他们找来了Banzi的学生David Mellis,让他
来编写代码程序。David Mellis只花了两天
时间就完成了代码的编写,然后又过了3
天,板子就设计出来了,取名为Arduino。
很快,这块板子受到了广大学生的欢迎。
这些学生当中那些甚至完全不懂计算机编
程的人,都用Arduino做出了“很炫”的东
西:有人用它控制和处理传感器,有人用
它控制灯闪烁,有人用它制作机器人……
之后Banzi、Cuartielles和Mellis将设计图上
传到网上,然后花了3000欧元加工出第一
批板子。
Banzi等人当时加工了200块板子,卖
给学校50块,起初还担心剩下的150块怎么
卖出去,但是几个月后,他们的设计作品在网上得到了快速传播,接着他们收到了
几个上百块板子的订单。这时他们明白
Arduino是很有市场价值的,所以,他们决
定开始Arduino的事业,但是有个原则——
开源。他们规定任何人都可以复制、重设
计甚至出售Arduino板子。人们不用花钱购
买版权,连申请许可权都不用。但是,如
果你加工出售Arduino原板,版权还是归
Arduino团队所有。如果你是在基于
Arduino的设计上修改,你的设计必须也和
Arduino一样开源。
Arduino设计者们唯一所有的就
是Arduino这个商标。如果你的设计也想
用Arduino命名,那么你就得支付费用。这
样做是为了保护Arduino这个商标不被低
劣的作品损坏。
对于最初决定硬件开源,几位设计
者也有不同的动机。Cuartielles认为自己是
个“左倾学术主义者”,不喜欢因为赚钱而
限制大家的创造力,从而导致自己的作品
得不到广泛使用。“如果有人要复制它,没问题。复制只会让它更出名。”Cuartielles
在某次演讲中甚至说:“请你们复制它
吧!”Banzi则恰恰相反,他更像一个精明
的商人。他现在已经退休了,不再教书,开了一家科技设计公司。他猜想,如果
Arduino开源,相比那些不开源的作品,会
激发更多人的兴趣,从而得到更广泛的使
用。还有一点就是,一些电子疯狂爱好者
会去寻找Arduino的设计缺陷,然后要求
Arduino团队做出改进。利用这种免费的劳
动力,他们可以开发出更好的新产品。
实际情况也正如他所料,在接下来
的几个月内,很多人提出重新布线、改进
编程语言等建议。后来曾有销售商要求代
理Arduino产品。2006年,Arduino方案获
得了Prix Art Electronica电子通信类方面的
荣誉奖。那一年,他们销售了5000块板
子。第二年,他们销售了30000块。
Arduino被电子疯狂爱好者用来设计机器
人、调试汽车引擎、制作无人飞机模型
等。1.2 Arduino的家族
Arduino设计之初的目的是希望让设
计师和艺术家们能够很快地通过它学习电
子和传感器的基础知识,并应用到他们的
设计当中。设计中所要表现的想法和创意
才是最主要的,至于单片机如何工作,硬
件的电路是如何构成的,设计师和艺术家
们并不需要考虑。
Arduino的出现,大大降低了互动设
计的门槛,没有学过电子知识的人也能够
使用它制作出各种充满创意的作品。越来
越多的艺术家、设计师开始使用Arduino制
作交互艺术品。为了针对不同的应用领
域,目前Arduino已设计出很多不同的型号
以满足不同使用者的需要,在这里简单介
绍一下几类主要产品,详细信息可登录
Arduino的主页http:www.arduino.cc查
阅。1.Arduino Duemilanove
这是一款基本的Arduino产品,控制
器采用ATmega168或ATmega328,支持直流
电源供电和USB端口供电,如图1.1所示。
后续的很多产品都是在这款产品的基础上
发展起来的。
图 1.1 Arduino Duemilanove
2.Arduino Nano
Arduino Nano在设计中去掉了直流电
源接口,采用了Mini-B标准的USB接口来
连接电脑,除了外观变了,其他接口及功能保持不变,控制器同样采用ATmega168
或ATmega328,是一款缩小版的Arduino
Duemilanove,如图1.2所示。
图 1.2 Arduino Nano
3.Arduino mini
考虑到存在一些对空间要求十分严
格的使用者,Arduino mini(见图1.3)在
设计时甚至去掉了USB接口和复位开关,这样能减小Arduino的尺寸。唯一的问题是
连接电脑或烧写程序时需要一个USB或
RS232转换成TTL的适配座,Arduino官方
也有相应的适配座——Mini USB
Adapter(http:www.arduino.ccenMainMiniUSB上有相关的资料)。
图 1.3 Arduino mini
4.Arduino BT
Arduino BT(见图1.4)本身包含了
一个Bluegiga WT11蓝牙模块,支持蓝牙无
线串行通信,但不支持蓝牙音频设备。若
没有USB接口,连接电脑或烧写程序可以
通过蓝牙适配器与Arduino BT连接实现无
线程序下载与控制。图 1.4 Arduino BT
5.LilyPad Arduino
这是一款真正有艺术气质的产品,面向的主要使用者是从事服装设计之类工
作的设计师,它可以使用导电线或普通线
缝在衣服或布料上,LilyPad Arduino每个
引脚上的小洞大到足够缝纫针轻松穿过,如图1.5所示。如果用导电线缝纫的话,既
可以起到固定的作用,又可以起到传导的作用。比起普通的Arduino板,LilyPad
Arduino相对比较脆弱,比较容易损坏,但
它的功能基本都保留了下来,除了一点,即它没有USB接口,所以LilyPad Arduino连
接电脑或烧写程序时同Arduino mini一样需
要一个USB或RS232转换成TTL的适配座。
图 1.5 LilyPad Arduino
6.Arduino Pro和Arduino Pro Mini设计Arduino Pro的目的是为了那些
需要便利性和低成本的高级用户。为了降
低成本,它省去了USB接口、直流电源接
口和引脚排针,连接电脑或烧写程序时需
要一个USB或RS232转换成TTL的适配座。
Arduino Pro更像是一个大号的Arduino
mini,如图1.6所示。需要注意的是,Arduino Pro有3.3V8MHz和5V16MHz两个
版本,使用的时候要留心点。另外Arduino
Pro同样有一个Arduino Pro Mini的版本,如图1.7所示。图 1.6 Arduino Pro图 1.7 Arduino Pro Mini
7.Arduino Fio
Arduino Fio(见图1.8)的工作电压
是3.3V,控制器的工作频率是8MHz,采用
了Mini-B标准的USB接口,提供一个锂聚
合物电池接口,底部预留了一个XBee模块
插座(美国DIGI的zigbee模块,本书的第7
章有XBee模块的相关介绍,也可登录
http:www.digi.com.cn了解XBee模块的更多信息),XBee模块可使Arduino方便地应
用于无线网络。
图 1.8 Arduino Fio
8.Arduino Uno
Arduino Uno是最新的Arduino产品系
列,如图1.9所示,它与之前的Arduino板
最大的不同在于它不是使用FTDI USB-to-
serial串行驱动器芯片,而是采用
Atmega8U2芯片进行USB到串行数据的转
换。目前Arduino Uno已成为Arduino主推
的产品。图 1.9 Arduino Uno
9.Arduino Mega2560
Arduino Mega2560(见图1.10)的控
制器采用的是ATMega2560,它的资源要比
之前的Arduino产品丰富很多,用于满足需
使用较多资源进行产品设计与开发的用户
需求,具体资源会在下一节描述。同时,Arduino Mega2560也兼容之前基于Arduino
Duemilanove的设计。图 1.10 Arduino Mega25601.3 Arduino的资源
Arduino的硬件电路设计以创作公用
约定(creative commons)的形式提供授
权。相应的原理图和电路图都可以从
Arduino网站上免费获得。Arduino
Duemilanove具有14个数字IO口(其中6个
可提供PWM输出),6个模拟IO口,一个
复位开关,一个ICSP下载口,支持USB接
口,可通过USB接口供电,也可以使用单
独的7~12V电源供电。Arduino的资源在板
子上已经明确标注,使用者可以很方便地
了解具体的资源分配,DIGITAL一边有14
个数字IO口0~13,ANALOG IN一边有6个
模拟IO口0~5,其他还有POWER、TX、RX、PWM等标识,如图1.11所示。图 1.11 Arduino的资源
Arduino Duemilanove总体参数如表
1.1所示。各引脚定义如下:
数字引脚:0~13
模拟引脚:A0~A5(为区分数字引
脚,在引脚号前加A)串行通信:0,1(0作为RX,接收数
据;1作为TX,发送数据)
外部中断:2,3
PWM输出:3,5,6,9,10,11
SPI通信:10(SS),11(MOSI),12(MISO),13(SCK)
板上LED:13
TWI通信:A4(SDA),A5(SCL)
另外,Arduino有一个可复位的熔断
器来保护计算机的USB口,防止短路或者
过流。虽然大部分计算机都有它们内置的
保护措施,但是熔断器还是可以提供额外
的保护,如果连到USB口的电源超过
500mA,它将自动断开,直到短路或者过
流消除。
Arduino Uno的硬件资源与Arduino
Duemilanove相同,Arduino Mega2560的资源就要丰富多了,它具有54个数字IO口
(其中14个可提供PWM输出),16个模拟
IO口,4对串行数据通信口(UART),一
个复位开关,一个ICSP下载口,支持USB
接口和直流电源供电。Arduino Mega2560
总体参数如表1.2所示。各引脚定义如下:
数字引脚:0~53
模拟引脚:A0~A15(为区分数字引
脚,在引脚号前加A)
串行通信:Arduino Mega2560提供4
组串行通信端口,分别是0(RX)和
1(TX)用作串口1,19(RX)和
18(TX)用作串口2,17(RX)和
16(TX)用作串口2,15(RX)和
14(TX)用作串口3
外部中断:Arduino Mega2560提供6
个引脚作为外部中断,分别是2(外部中断
0),3(外部中断1),21(外部中断
2),20(外部中断3),19(外部中断
4),18(外部中断5)
PWM输出:0~13
SPI通信:53(SS),51(MOSI),50(MISO),52(SCK)板上LED:13
TWI通信:20(SDA),21(SCL)1.4 Arduino的开发环境
Arduino的开发环境是以AVR-GCC和
其他一些开源软件为基础,采用Java编写
的,软件无需安装,下载完成解压缩后就
可以直接打开使用了。软件可以在Arduino
的网站http:www.arduino.cc上免费下
载,目前最新版本是0022。本书中使用的
版本是0021。Arduino开发环境使用的语法
与CC++相似,非常容易使用。图1.12所示
的就是Arduino开发环境的主界面,中间的
白色区域就是程序编辑区,下方的黑色区
域为信息提示区。图 1.12 Arduino的开发环境
提示:目前的软件界面中无法输入中文字符,可在其他软件内输入中文字符
再拷贝至软件界面内。1.5 添加新硬件及设置开发环境
在应用Arduino开发环境之前,先要
在电脑端添加新硬件Arduino控制板,本节
介绍Arduino Duemilanove和Arduino Uno两
块控制板的安装。
先看看Arduino Duemilanove控制板
的添加。准备一块Arduino Duemilanove板
和一条USB连接线。第一次将Arduino板连
接到电脑上,会出现Found New Hardware
Wizard(发现新硬件向导)的提示,依照
提示完成驱动安装,步骤如图1.13~图1.18
所示。图 1.13 选择从指定目录安装图 1.14 可在Arduino开发环境目录下的
drivers文件夹中找到驱动程序图 1.15 选择Finish完成驱动安装图 1.16 在Device Manager(设备管理
器)里查看新安装的USB转串口设备所对
应的串口号图 1.17 在Arduino的开发环境中设置串
口(Tools→Serial Port→COM5)图 1.18 选择正确的Arduino板系列型号
正确设置串口和Arduino板系列型号
后,就可以开始Arduino之旅了。接下来看
一下Arduino Uno控制板的添加。准备一块
Arduino Uno板和一条USB连接线。第一次
连接到电脑,会出现“发现新硬件向导”的
提示,依照提示完成驱动安装。若错过了“发现新硬件向导”的提示,也可以在设
备管理器中找到未安装的新硬件,如图
1.19所示。
图 1.19 设备管理器中未安装的新硬件
右键选中未识别的硬件Arduino
Uno,从弹出的如图1.20所示的快捷菜单中选择Update Driver(更新驱动程序),将
会出现如图1.21所示的Hardware Update
Wizard(更新硬件驱动向导)的提示,依
照提示完成Arduino Uno驱动的安装。
图 1.20 更新驱动程序图 1.21 更新硬件驱动向导
如图1.13、图1.14所示选择正确的驱
动程序,此时电脑会出现驱动程序不被
Windows信任的提示,选择Contine
Anyway(仍然继续),如图1.22所示。图 1.22 驱动程序不被信任
最后选择Finish完成硬件驱动的更
新,如图1.23所示。图 1.23 完成硬件驱动的更新
此时设备管理器中的新硬件Arduino
Uno就被识别成串口设备,如图1.24所示。图 1.24 设备管理器中的Arduino Uno
最后要在Arduino开发环境中设置相
应的串口号以及Arduino板型号,如图1.17
和图1.18所示,注意Arduino板型号的选
择,要选择Arduino Uno,如图1.25所示。图 1.25 选择Arduino板型号
提示:本书后面的章节使用的控制
板均为Arduino Uno。1.6 Arduino开发环境的应用
Arduino开发环境中菜单栏下方的7个
按钮必须先了解一下,它们依次是
Verify(校验)、Stop(停止)、New(新
建)、Open(打开)、Save(保存)、Upload(上传)、Serial Monitor(串口监
视窗),如图1.26所示。
图 1.26 Arduino开发环境中菜单栏下方
的7个按钮
各按钮的具体功能如下:
Verify(校验),用以完成程序
的检查与编译。Stop(停止),用以停止进行的
编译操作。
New(新建),可新建一个程序
文件。
Open(打开),打开一个存在的
程序文件,Arduino开发环境下的程序文件
后缀名为.pde。
Save(保存),保存当前的程序
文件。
Upload(上传),将编译后的程
序文件上传到Arduino板中。
Serial Monitor(串口监视窗),可监视开发环境使用的串口收发的数据。
接下来通过一个Arduino开发环境中LED灯闪烁的例子(Blink)来简单应用一
下这些按钮。在Arduino Uno板的13号引脚
上已经带了一个LED灯,如图1.27所示。
Blink程序就是控制这个LED灯闪烁,我们
可以在Arduino控制板上明确地看到。
图 1.27 13号引脚及LED灯位置示意
点击Open按钮后,依次选择
1.Basics→Blink,就可以看到Blink程序已经加载到程序编辑区,如图1.28所示。
图 1.28 加载Blink程序
点击“校验” 按钮实现程序的编
译,等待一会儿后状态栏会提示Done
compiling(程序编译完成),信息提示区
内会显示程序编译完成后的大小,如图
1.29所示,此例中Blink程序编译后的大小
为1010bytes。图 1.29 Blink程序编译后的大小
编译完成后点击“上传”按钮 ,上
传一般需要等待几秒钟时间,在上传的时
候串口的指示灯(RX和TX)会不停地闪
烁。上传完成后状态栏会有上传成功的提
示:Done uploading。观察Arduino控制板
上LED灯是否在不停地闪烁,Arduino控制
板通过LED闪烁的方式告诉你,你已经会
使用Arduino了,就是这么简单。第2章 编写Arduino程序
Arduino项目很注重动手能力,只有
通过动手才会发现Arduino的优点。本章介
绍如何编写Arduino程序。
写程序就像盖房子。盖房子首先要
有图纸,然后依照图纸搭建主体,最后内
外部装修。写程序大致也需要这几步,首
先绘制流程图,然后使用控制语句搭建主
体程序,最后查错、调试、修改、添加注
释完成程序编写。
本章内容就按照这样一个次序展
开,让我们共同来搭建Arduino“大厦”。
2.1 绘制流程图
2.1.1 流程图基本符号美国国家标准化协会(American
National Standards Institute,ANSI)规定了
一些常用的流程图符号,目前已被世界各
国的多个领域普遍采用,如图2.1所示。
图 2.1 流程图基本符号
第1章的Blink程序可以用图2.2的流程
图描述。图 2.2 Blink程序流程图
通过Blink程序的流程图可以看出,一个流程图应该包括以下几部分:
表示相应操作的框。
带箭头的流程线。
框内外必要的文字说明。2.1.2 流程图的三种基本结构
起初流程图用流程线指出各框的执
行顺序,对流程线的使用没有严格的规
定,流程线在程序中随意地连接,流程图
也就没有实现使程序直观形象、简单清晰
的目的,同样,编写的程序也是逻辑混
乱、难以理解。
为了提高流程图及程序的逻辑性,使其更容易理解、更方便阅读,必须限制
流程线的使用,不允许流程线无规律地连
接,而是按照一定顺序和条件进行连接。
于是,1966年,Bohra和Jacopini提出了三
种基本结构,用这三种基本结构作为表示
一个良好算法的基本单元。
1.顺序结构
如图2.3所示,虚线框内是一个顺序
结构。其中A和B两个框是顺序执行的。顺序结构是最简单的一种基本结构。
图 2.3 顺序结构
2.选择结构
如图2.4所示,虚线框内是一个选择
结构。此结构中包含一个判断框,根据条
件是否成立而选择执行A还是B,执行完成
后,经过b点脱离选择结构。图 2.4 选择结构
3.循环结构
如图2.5所示,虚线框内是一个循环
结构。此结构中也有一个判断框用来决定
是否跳出循环结构。有两种循环结构:判
断框成立跳出循环的称为until型循环;判
断框不成立跳出循环的称为while型循环。图 2.5 循环结构
以上三种基本结构有如下特点:
结构内的每一部分都有机会被执行
到。
结构内不存在无法跳出的循环。
只有一个入口,即图中的a点。
只有一个出口,即图中的b点。注意:一个判断框有两个出口,而
一个选择结构只有一个出口,不要将二者
混为一谈。
这三种基本结构可解决任何复杂的
问题,由基本结构所构成的程序流程不存
在无规律的转向,只在本基本结构内才允
许存在分支和跳转。2.2 C语言的标识符与关键字
Arduino的开发使用的是C语言,在C
语言中使用的词汇大致可分为6类:标识
符、关键字、运算符、分隔符、常量和注
释符。
2.2.1 标识符
标识符用来标识源程序中某个对象
的名字,这些对象可以是语句、数据类
型、函数、变量、常量等。一个标识符由
字符串、数字和下划线等组成,第一个字
符必须是字母或下划线,通常以下划线开
头的标识符是编译系统专用的,因此在编
写C语言源程序时一般不要使用以下划线
开头的标识符,而将下划线用作分段符。2.2.2 关键字
关键字是编程语言保留的特殊标识
符,它们具有固定的名称和含义,ANSI C
标准一共规定了32个关键字,如表2.1所
示。2.2.3 运算符
C语言中含有相当丰富的运算符。运
算符与变量、函数一起组成表达式,表示
各种运算功能,在任意一个表达式的后面
加一个分号“;”就构成了一个表达式语
句。表2.2列出了C语言常用的运算符。注意:sizeof是一种特殊的运算符,它不是一个函数。实际上,字节数的计算
在编译时就完成了,而不是在程序执行的
过程中才计算出来的。2.2.4 分隔符
C语言中采用的分隔符有逗号和空格
两种。逗号主要用在类型说明和函数参数
表中,用于分隔各个变量。空格多用于语
句各单词之间作间隔符。在关键字、标识
符之间必须要有一个以上的空格符作间
隔。2.2.5 常量
常量就是在程序运行过程中,其值
不能改变的数据。有时候也可以用一些有
意义的符号来代替常量的值,称为符号常
量。符号常量在使用之前必须先定义,其
一般形式如下:
define标识符常量2.2.6 注释符
C语言的注释符包括两种:
以“”开头并以“”结尾的字符串。
在“”与“”之间的内容即为注释。
“”后面的字符串。
程序在编译时,不对注释作任何处
理。注释可出现在程序的任何位置。编程
时添加适当的注释对于程序员读懂该段程
序非常有用。2.3 控制语句
在程序的执行过程中,往往需要根
据某些条件来决定执行哪些语句,这就需
要选择型控制语句if和switch来实现选择结
构程序,某些情况下还会不断地重复执行
某些语句,这就需要循环型控制语句for和
while来完成循环结构程序。
2.3.1 if语句
用if语句可以实现选择结构。它根据
给定的条件进行判断,以决定执行某个分
支程序段。if语句有3种基本形式。
1.第一种基本形式
if(表达式)
语句功能描述:如果表达式的值为真,则执行其后的语句;否则,跳过该语句。
2.第二种基本形式
if(表达式)
语句1
else
语句2
功能描述:如果表达式的值为真,则执行语句1;如果表达式的值为假,则执
行语句2。
3.第三种基本形式
if(表达式1)
语句1
else if(表达式2)
语句2
else if(表达式3)
语句3……
else if(表达式n)
语句n
else
语句m功能描述:如果表达式1的结果为
真,则执行语句1,然后退出if选择语句,不执行下面的语句;否则,判断表达式2,如果表达式2的结果为真,则执行语句2,然后退出if选择语句,不执行下面的语
句,同样如果表达式2的结果为假则判断表
达式3,依次类推,最后,如果表达式n不
成立,则执行else后面的语句m。
在使用if语句时还要注意以下问题:
在3种基本形式中,if关键字后面均
为表达式。该表达式通常是逻辑表达式或
关系表达式,也可以是一个变量。
在if语句中,条件判断表达式必须用
括号括起来。在语句之后必须加分号,如
果是多行语句组成的程序段,则要用花括
号括起来。2.3.2 switch语句
switch语句可实现多分支的选择结
构,在这种情况下,判断条件表达式的值
是由几段组成或不是一个连续的值,每一
段或每一个值对应一段分支程序。switch
语句的一般形式为:
switch(表达式)
{
case常量表达式1:
语句1
case常量表达式2:
语句2……
case常量表达式n:
语句n
default:
语句m
}
switch语句的流程图如图2.6所示。图 2.6 switch语句的流程图
功能描述:计算表达式的值,并逐
个与其后的常量表达式的值进行比较。当
表达式的值与某个常量表达式的值相等
时,即执行其后的语句,然后不再进行判
断,继续执行所有case后面的语句。如果
表达式的值与所有case后的常量表达式均
不相等,则执行default后的语句。
在使用switch语句时要注意以下问
题:
表达式的计算结果必须是整型或者字符型,也就是常量表达式1到常量表达式
n必须是整型或字符型常量。
每个case的常量表达式必须互不相
同,但各个case出现的次序没有顺序。case
语句标号后面的语句可以省略不写,在关
键字case和常量表达式之间一定要有空
格。
当表达式的值与某个常量表达式的
值相等并执行完其后的语句时,如果不想
继续执行所有case后面的语句,则要在语
句后面加上break,以跳出switch结构。2.3.3 while语句
while语句能够实现“当型”循环结
构,其一般形式为:
while(表达式)语句
功能描述:计算表达式的值,当值
为真时,执行循环体语句;当表达式的值
为假时,跳出循环体,结束循环。其中,表达式是循环条件,语句是循环体。
while语句的流程图如图2.7所示。图 2.7 while语句的流程图
在使用while语句时要注意以下几
点:
不要混淆while语句构成的循环结构
与if语句构成的选择结构。while的条件表
达式为真时,其后的循环体将被重复执
行;而if的条件表达式为真时,其后的语
句只执行一次。在循环体中应有使循环趋于结束的
语句。如果没有,则会进入死循环。在编
写嵌入式应用程序时,我们经常会用到死
循环。
循环体若包含一个以上的语句,应
使用大括号括起来。2.3.4 do-while语句
do-while语句用来实现“直到型”循
环,其特点是先执行循环体,然后判断循
环条件是否成立,其一般形式为:
do
语句
while(表达式);
do-while语句流程图如图2.8所示。图 2.8 do-while语句流程图
功能描述:由于do-while循环为“直
到型”循环,它先执行循环体中的语句,然
后再判断表达式是否为真,如果为真则继
续循环;如果为假则终止循环。因此,do-
while循环至少执行一次循环体语句。
注意:do-while语句在使用时除了要
注意循环体至少执行一次的问题外,在使
用时还要注意它是以do开始,以while结
束,while(表达式)后的分号不能丢。2.3.5 for语句
for语句的使用极为灵活,可以完全
取代while语句。它既可以用于循环次数确
定的情况,又可以用于循环次数不确定而
只是给出循环条件的情况。for语句的一般
形式为:
for(表达式1;表达式2;表达式3)
语句for语句的流程图如图2.9所示。图 2.9 for语句的流程图
功能描述:先求解表达式1,一般情
况下,表达式1为循环结构的初始化语句,给循环计数器赋初值。然后求解表达式2,若其值为假,则终止循环;若其值为真,则执行for语句中的内嵌语句。内嵌语句执
行完后,求解表达式3。最后继续求解表达
式2,根据求解值进行判断,直到表达式2
的值为假。
for语句最简单也是最典型的形式如
下:
for(循环变量赋初值;循环条件;
循环变量增量)语句循环变量赋初值总是
一个赋值语句,用来给循环控制变量赋初
值。循环条件是一个关系表达式,决定什
么时候退出循环。循环变量的增量用来定
义循环控制变量每次循环后按什么方式变
化。这3个部分之间用分号分开。
for循环语句的一般形式可用while语
句进行解释,如下:
表达式1;
while(表达式2)
{
语句
表达式3;
}或者用do-while语句解释,如下:
表达式1;
do{
语句
表达式3;
}while(表达式2);
在使用for语句时要注意以下几点:
for循环中的表达式1、表达式2和表
达式3都是选择项,但是分号不能省略。
若3个表达式都省略,则for循环变成
for(;),相当于while(1)死循环。
表达式2一般是关系表达式或逻辑表
达式,但也可以是数值表达式或字符表达
式,只要其值非零,就执行循环体。2.3.6 break语句
break语句通常用在循环语句和switch
语句中。当break用在switch语句中时,可
使程序跳出switch而执行switch以后的语
句。
当break语句用在do-while、for、while循环语句中时,可使程序终止循环而
执行循环后面的语句。通常break语句总是
与if语句连在一起的,即满足条件时便跳
出循环。2.3.7 continue语句
continue语句的作用是跳过循环体中
剩余的语句而强行执行下一次循环。
continue语句只用在for、while、do-while等
循环体中,常与if条件语句一起使用,用
来加速循环。
注意:continue语句与break语句的区
别是,break语句结束整个循环过程,而
continue语句只结束本次循环,不终止整个
循环。2.3.8 goto语句
goto语句是一个无条件转向语句,它
的一般形式为:
goto语句标号;
功能描述:语句标号是一个带冒
号“:”的标识符,用于标识语句的地址。
当执行跳转语句时,使程序跳转到标识符
指向的位置继续执行。将goto语句和if语句
一起使用,可以构成一个循环结构。一般
常见的是采用goto语句来跳出多重循环。
注意,只能用goto语句从内层循环跳到外
层循环,而不允许从外层循环跳到内层循
环。
注意:由于goto语句容易使程序层次
不清,所以在结构化程序设计中不主张使
用goto语句。2.4 程序结构
一般情况下在C语言中要求一个源程
序不论由多少个文件组成,都必须有一个
主函数,即main函数,且只能有一个主函
数,C语言程序执行是从主函数开始的。
但在Arduino中,主函数main在内部定义
了,使用者只需要完成以下两个函数就能
够完成Arduino程序的编写,这两个函数分
别负责Arduino程序的初始化部分和执行部
分。
void setup
void loop
两个函数均为无返回值的函数,setup函数用于初始化,一般放在程序
开头,主要工作是用于设置一些引脚的输
出输入模式、初始化串口等,该函数只在
上电或重启时执行一次;loop函数用于执行程序,它是一个死循环,其中的代
码将被循环执行,用于完成程序的功能,如读入引脚状态、设置引脚状态等。
结合第1章的Blink程序及2.1节的程序
流程图,来看看这两个函数的作用。
void setup
{
注释:初始化Arduino的引脚13为输出,Arduino板上自带的LED连接在引脚13上
pinMode(13,OUTPUT);
}
void loop
{
digitalWrite(13,HIGH);引脚13置高,输
出+5V电压,LED点亮
delay(1000);等待1000ms
digitalWrite(13,LOW);引脚13置低,输出
0V电压,LED熄灭
delay(1000);等待1000ms
}
在setup函数中设置连接LED的引脚13
为输出,以控制LED的亮或灭,这个操作
只在上电或重启时执行一次,之后就没有
必要执行了。在loop函数中有4条语句,分别执行
的操作是:
1)设置引脚13输出高,LED点亮;
2)等待1s;
3)设置引脚13输出低,LED熄灭;
4)等待1s。
由于loop函数中的代码将被循环
执行,所以在第4步执行完成后,将回到第
1步继续执行,程序不断循环,我们就看到
了LED闪烁的效果。
setup函数和loop函数与流程图的对应
关系如图2.10所示。图 2.10 setup函数和loop函数与流程图
的对应关系第3章 Arduino的基本函数
第2章已经介绍了如何编写Arduino程
序,是不是感觉很容易上手,使用很方
便。但Arduino真正的低门槛、硬件无关性
的优点是因为在Arduino开发环境下提供了
大量的基础函数,这些基础函数涉及IO控
制、时间函数、数学函数、三角函数等,使用者可以很方便地对板上的资源进行控
制。同时,在Arduino开发环境下还提供了
许多的实例程序来使用这些基础函数,这
更加快了使用者的上手速度,这些实例程
序可以在开发环境的File→Examples菜单下
找到,其中包括之前提到的Blink程序,如
图3.1所示。图 3.1 实例程序可以在开发环境下找到提示:函数原型部分的内容建议在
单独深入学习过AVR单片机的基础上进
行,跳过函数原型的部分不会影响对
Arduino的应用。
3.1 数字IO
3.1.1 pinMode(pin,mode)
pinMode函数在第2章中已经出现过
了,用以配置引脚为输出或输出模式,它
是一个无返回值函数,函数有两个参数pin
和mode,pin参数表示所要配置的引脚,mode参数表示设置的模式——INPUT(输
入)或OUTPUT(输出)。
注意:Arduino板上的模拟引脚也可
以当做数字引脚使用,编号为14(对应模
拟引脚0)到19(对应模拟引脚5)。
由于Arduino项目是完全开源的,所以pinMode(pin,mode)函数原型可直接在
Arduino开发环境目录下的
hardware\arduino\cores\arduino文件夹里的
wiring_digital.c文件中查看。
函数原型有助于我们深入了解
Ardnino的基本函数的底层实现方式,但这
部分的内容需要在单独深入学习AVR单片
机的基础上进行,本书将这些函数原型从
文件中提取出来,有兴趣的读者可以参考
一下。一般只要能够熟练地使用这些
Arduino基本函数就可以了,本书对函数原
型没有进行过多讲解。
pinMode(pin,mode)函数原型:
void pinMode(uint8_t pin,uint8_t
mode)
{
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
volatile uint8_treg;
if(port==NOT_A_PIN)
return;
reg=portModeRegister(port);
if(mode==INPUT){
uint8_t oldSREG=SREG;
cli;
reg&=~bit;
SREG=oldSREG;
}
else
{
uint8_t oldSREG=SREG;
cli;
reg|=bit;
SREG=oldSREG;
}
}
可以在开发环境中的下列实例程序
中找到pinMode函数的应用:
ADXL3xx. pde、AnalogInput.pde、Blink.pde、BlinkWithoutDelay.pde、Button.pde、Calibration.pde、Debounce.pde、Dimmer.pde、Knock.pde、Loop.pde、Melody.pde、Memsic2125.pde、PhysicalPixel.pde、Ping.pde3.1.2 digitalWrite(pin,value)
digitalWrite函数也是在Blink程序中见
到过的,它的作用是设置引脚的输出的电
压为高电平或低电平。该函数也是一个无
返回值的函数,函数有两个参数pin和
value,pin参数表示所要设置的引脚,value
参数表示输出的电压——HIGH(高电平)
或LOW(低电平)。
注意:在使用
digitalWrite(pin,value)函数设置引脚之
前,需要将引脚设置为OUTPUT模式。
digitalWrite(pin,value)函数原型同
样也可以在wiring_digital.c文件中找到,函
数原型如下:
void digitalWrite(uint8_t pin,uint8_t
val)
{
uint8_ttimer=digitalPinToTimer(pin);
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
volatile uint8_tout;
if(port==NOT_A_PIN)return;
If the pin that support PWM
output,we need to turn it off
before doing a digital write.
if(timer!=NOT_ON_TIMER)
turnOffPWM(timer);
out=portOutputRegister(port);
if(val==LOW)
{
uint8_t oldSREG=SREG;
cli;
out&=~bit;
SREG=oldSREG;
}
else
{
uint8_t oldSREG=SREG;
cli;
out|=bit;
SREG=oldSREG;
}
}
可以在开发环境的下列实例程序中
找到digitalWrite函数的应用:ADXL3xx. pde、AnalogInput.pde、Blink.pde、BlinkWithoutDelay.pde、Button.pde、Calibration.pde、Debounce.pde、Knock.pde、Loop.pde、Melody.pde、PhysicalPixel.pde、Ping.pde3.1.3 digitalRead(pin)
digitalRead函数用在引脚为输入的情
况下,可以获取引脚的电压情况——
HIGH(高电平)或LOW(低电平),参数
pin表示所要获取电压值的引脚,该函数返
回值为int型,表示引脚的电压情况。函数
原型如下:
int digitalRead(uint8_t pin)
{
uint8_t
timer=digitalPinToTimer(pin);
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
if(port==NOT_A_PIN)return LOW;
If the pin that support PWM
output,we need to turn it off
before getting a digital reading.
if(timer!=NOT_ON_TIMER)
turnOffPWM(timer);
if(portInputRegister(port)&bit)
return HIGH;
return LOW;}
注意:如果引脚没有链接到任何地
方,那么将随机返回HIGH或LOW。
可以在开发环境的下列实例程序中
找到digitalRead函数的应用:
Button. pde、Debounce.pde3.2 模拟IO
3.2.1 analogReference(type)
analogReference函数的作用是配置模
拟引脚的参考电压。在嵌入式应用中引脚
获取模拟电压值之后,将根据参考电压将
模拟值转换到0~1023。该函数为无返回值
函数,参数为type类型,有3种类型
(DEFAULTINTERNALEXTERNAL),具
体含义如下:
DEFAULT:默认值,参考电压为
5V。
INTERNAL:低电压模式,使用片内
基准电压源。
EXTERNAL:扩展模式,通过AREF
引脚获取参考电压,AREF引脚位置见图
3.2。图 3.2 AREF引脚位置
注意:如果在AREF引脚加载外部参
考电压,需要使用一个5KΩ的上拉电阻,这会避免由于设置不当造成控制芯片的损
坏。3.2.2 analogRead(pin)
analogRead函数用于读取引脚的模拟
量电压值,每读一次需要花100μs的时间。
参数pin表示所要获取模拟量电压值的引
脚,该函数返回值为int型,表示引脚的模
拟量电压值,范围在0~1023。函数原型可
在wiring_analog.c文件中查看,如下:
int analogRead(uint8_t pin)
{
uint8_t low,high;
set the analog reference(high two
bits of ADMUX)and select
the channel(low 4 bits).this also
sets ADLAR(left-adjust
result)to 0(the default).
ADMUX=(analog_reference<<6)|(pin&
0x07);
start the conversion
sbi(ADCSRA,ADSC);
ADSC is cleared when the conversion
finishes
while(bit_is_set(ADCSRA,ADSC));
we have to read ADCL first;doing solocks both ADCL
and ADCH until ADCH is read.reading
ADCL second would
cause the results of each conversion
to be discarded,as ADCL and ADCH would be locked
when it completed.
low=ADCL;
high=ADCH;
combine the two bytes
return(high<<8)|low;
}
注意:函数的参数pin范围是0~5,表
示6个模拟量IO口中的一个。
可以在开发环境中的下列实例程序
中找到analogRead函数的应用:
ADXL3xx. pde、AnalogInput.pde、Calibration.pde、Graph.pde、Knock.pde、Smoothing.pde、VirtualColorMixer.pde3.2.3 analogWrite(pin,value)
analogWrite函数通过PWM的方式在
引脚上输出一个模拟量,较多的应用在
LED亮度控制、电机转速控制等方面。
PWM(Pulse Width Modulation,脉
冲宽度调制)方式是通过对一系列脉冲的
宽度进行调制,来等效地获得所需要的波
形或电压。脉冲宽度调制是一种模拟控制
方式,其根据相应载荷的变化调制晶体管
栅极或基极的偏置,来实现开关稳压电源
输出晶体管或晶体管导通时间的改变,这
种方式能使电源的输出电压在工作条件变
化时保持恒定,是利用微处理器的数字输
出来对模拟电路进行控制的一种非常有效
的技术。图3.3是一个简单的PWM波示意
图。图 3.3 PWM波示意图
其中,VCC是高电平值,T是PWM波
的周期,D是高电平的宽度,DT是PWM波
的占空比,当上述PWM波通过一个低通滤
波器后,波形中高频的部分被滤掉得到所
需的波形,其平均电压为VCC×DT。因
此,可通过调节D的大小来改变占空比,产生不同的平均电压;同样,调节PWM波
的周期T也可以改变占空比,从而得到不同的平均电压值。
在Arduino中执行该操作后,应该等
待一定时间后才能对该引脚进行下一次操
作。Arduino中的PWM的频率大约为
490Hz。该函数支持以下引脚:3、5、6、9、10、11。在Arduino控制板上引脚号旁
边标注~的就是可用作PWM的引脚,如图
3.4所示。
图 3.4 Arduino板上PWM引脚的标识
analogWrite函数为无返回值函数,有
两个参数pin和value,参数pin表示所要设置的引脚,只能选择函数支持的引脚;参
数value表示PWM输出的占空比,范围在
0~255的区间,对应的占空比为0%~100%,函数原型如下:
void analogWrite(uint8_t pin,int val)
{
if(digitalPinToTimer(pin)==TIMER1A)
{
connect pwm to pin on timer 1,channel A
sbi(TCCR1A,COM1A1);
set pwm duty
OCR1A=val;
}
else if(digitalPinToTimer(pin)
==TIMER1B)
{
connect pwm to pin on timer 1,channel B
sbi(TCCR1A,COM1B1);
set pwm duty
OCR1B=val;
}
else if(digitalPinToTimer(pin)
==TIMER0A)
{
if(val==0)
{
digitalWrite(pin,LOW);}
else
{
connect pwm to pin on timer 0,channel A
sbi(TCCR0A,COM0A1);
set pwm duty
OCR0A=val;
}
}
else if(digitalPinToTimer(pin)
==TIMER0B)
{
if(val==0)
{
digitalWrite(pin,LOW);
}
else
{
connect pwm to pin on timer 0,channel B
sbi(TCCR0A,COM0B1);
set pwm duty
OCR0B=val;
}
}
else if(digitalPinToTimer(pin)
==TIMER2A)
{
connect pwm to pin on timer 2,channel A
sbi(TCCR2A,COM2A1);set pwm duty
OCR2A=val;
}
else if(digitalPinToTimer(pin)
==TIMER2B)
{
connect pwm to pin on timer 2,channel B
sbi(TCCR2A,COM2B1);
set pwm duty
OCR2B=val;
}
else if(val<128)
digitalWrite(pin,LOW);
else
digitalWrite(pin,HIGH);
}
可以在开发环境的下列实例程序中
找到analogWrite函数的应用:
Calibration. pde、Dimmer.pde、Fading.pde3.3 高级IO
3.3.1
shiftOut(dataPin,clockPin,bitOrder,val)
shiftOut函数能够将数据通过串行的
方式在引脚上输出,相当于一般意义上的
同步串行通信,这是控制器与控制器、控
制器与传感器之间常用的一种通信方式。
shiftOut函数无返回值,有4个参数:
dataPin、clockPin、bitOrder、val,具体说
明如下:
dataPin:数据输出引脚,数据的每
一位将逐次输出。引脚模式需要设置成输
出。
clockPin:时钟输出引脚,为数据输
出提供时钟,引脚模式需要设置成输出。bitOrder:数据位移顺序选择位,该
参数为byte类型,有两种类型可选择,分
别是高位先入MSBFIRST和低位先入
LSBFIRST。
val:所要输出的数据值。
函数原型在wiring_shift.c文件中,如
下:
void shiftOut(uint8_t dataPin,uint8_t
clockPin,uint8_t bitOrder,uint8_t val)
{
uint8_t i;
for(i=0;i<8;i++)
{
if(bitOrder==LSBFIRST)
digitalWrite(dataPin,!(val&(1<<
i)));
else
digitalWrite(dataPin,!(val&(1<<
(7-i))));
digitalWrite(clockPin,HIGH);
digitalWrite(clockPin,LOW);
}
}另外还有shiftIn函数用于通过串行的
方式从引脚上读入数据,其函数定义如
下:
uint8_t shiftIn(uint8_t
dataPin,uint8_t clockPin,uint8_t bitOrder)
{
uint8_t value=0;
uint8_t i;
for(i=0;i<8;++i)
{
digitalWrite(clockPin,HIGH);
if(bitOrder==LSBFIRST)
value|=digitalRead(dataPin)<
else
value|=digitalRead(dataPin)<<(7-
i);
digitalWrite(clockPin,LOW);
}
return value;
}3.3.2 pulseIn(pin,state,timeout)
pulseIn函数用于读取引脚脉冲的时
间长度,脉冲可以是HIGH或LOW。如果是
HIGH,函数将先等引脚变为高电平,然后
开始计时,一直到变为低电平为止。返回
脉冲持续的时间长短,单位为ms。如果超
时还没有读到的话,将返回0。
pulseIn函数返回值类型为无符号长
整型(unsigned long),3个参数分别表示
脉冲输入的引脚、脉冲响应的状态(高脉
冲或低脉冲)和超时时间。函数原型在
wiring_pulse.c中,如下:
unsigned long pulseIn(uint8_t
pin,uint8_t state,unsigned long timeout)
{
uint8_t
bit=digitalPinToBitMask(pin);
uint8_t port=digitalPinToPort(pin);
uint8_t stateMask=(state?bit:0);
unsigned long width=0;keep initialization out of time
critical area
unsigned long numloops=0;
unsigned long
maxloops=microsecondsToClockCycles(timeout)16;
wait for any previous pulse to end
while((portInputRegister(port)&
bit)==stateMask)
if(numloops++==maxloops)
return 0;
wait for the pulse to start
while((portInputRegister(port)&
bit)!=stateMask)
if(numloops++==maxloops)
return 0;
wait for the pulse to stop
while((portInputRegister(port)&
bit)==stateMask)
width++;
return
clockCyclesToMicroseconds(width10+16);
}
可以在开发环境的下列实例程序中
找到pulseIn函数的应用:
Memsic2125. pde、Ping.pde3.4 时间函数
3.4.1 millis
应用millis函数可获取机器运行的时
间长度,单位ms。系统最长的记录时间为
9小时22分,如果超出时间将从0开始。函
数返回值为unsigned long型,无参数。函
数原型如下:
unsigned long millis
{
unsigned long m;
uint8_t oldSREG=SREG;
cli;
m=timer0_millis;
SREG=oldSREG;
return m;
}
注意:函数返回值为unsigned long
型,如果用int型保存时间将得到错误结果。
可以在开发环境的下列实例程序中
找到millis函数的应用:
BlinkWithoutDelay. pde、Calibration.pde、Debounce.pde3.4.2 delay(ms)
delay函数是一个延时函数,在Blink
程序中用到过,参数表示延时时长,单位
是ms。函数无返回值,原型如下:
void delay(unsigned long ms)
{
uint16_t start=(uint16_t)micros;
while(ms>0)
{
if(((uint16_t)micros-start)>
=1000)
{
ms--;
start+=1000;
}
}
}
可以在开发环境的下列实例程序中
找到delay函数的应用:
ADXL3xx. pde、AnalogInput.pde、Blink.pde、Fading.pde、Graph.pde、Knock.pde、Loop.pde、Melody.pde、Memsic2125.pde、Ping.pde3.4.3 delayMicroseconds(us)
delayMicroseconds函数同样是延时函
数,所不同的是其参数单位是
μs(1ms=1000μs)。函数原型如下:
void delayMicroseconds(unsigned int
us)
{
for a one-microsecond delay,simply
return.
the overhead of the function call
yields a delay of
approximately 1 18 us.
if(--us==0)
return;
the following loop takes a quarter
of a microsecond(4 cycles)
per iteration,so execute it four
times for each
microsecond of delay requested.
us<<=2;
account for the time taken in the
preceeding commands.
us-=2;
busy wait__asm____volatile__(
1:sbiw%0,1\n\t2 cycles
brne 1b:=w(us):0(us)2
cycles);
}
可以在开发环境中的下列实例程序
中找到delayMicroseconds函数的应用:
Melody. pde、Ping.pde3.5 数学库
3.5.1 min(x,y)
min(x,y)函数的作用是返回x、y两
者中较小的,函数原型为:
define min(a,b)((a)<(b)?(a):
(b))3.5.2 max(x,y)
max(x,y)函数的作用是返回x、y两
者中较大的,函数原型为:
define max(a,b)((a)>(b)?(a):
(b))3.5.3 abs(x)
abs(x)函数的作用是获取x的绝对
值,函数原型为:
define abs(x)((x)>0?(x):-(x))3.5.4 constrain(amt,low,high)
constrain(amt,low,high)函数的工作
过程是,如果值amt小于low,则返回low;
如果amt大于high,则返回high;否则,返
回amt。该函数一般可以用于将值归一化到
某个区间内。函数原型为:
define constrain(amt,low,high)
((amt)<(low)?(low):((amt)>
(high)?(high):(amt)))3.5.5
map(x,in_min,in_max,out_min,out_max)
map(x,in_min,in_max,out_min,out_max)
函数的作用是将[in_min,in_max]范围内的x
等比映射到[out_min,out_max]范围内。函
数返回值为long型,原型为:
long map(long x,long in_min,long
in_max,long out_min,long out_max)
{
return(x-in_min)(out_max-out_min)
(in_max-in_min)+out_min;
}3.5.6 三角函数
三角函数包括sin(rad)、cos(rad)、tan(rad),分别得到rad的正
弦值、余弦值和正切值。返回值都为
double型。3.6 随机数
3.6.1 randomSeed(seed)
randomSeed函数用来设置随机
数种子,随机种子的设置对产生的随机序
列有影响。函数无返回值,原型如下:
void randomSeed(unsigned int seed)
{
if(seed!=0)
{
srandom(seed);
}
}3.6.2 random(howsmall,howbig)
应用random函数可生成一个随机
数,两个参数howsmall和howbig决定了随
机数的范围,函数的参数及返回值均为
long型,原型如下:
long random(long howsmall,long
howbig)
{
if(howsmall>=howbig)
{
return howsmall;
}
long diff=howbig-howsmall;
return random(diff)+howsmall;
}3.7 位操作
位操作用于设置或读取字节中某一
位或几位,包括bitRead、bitSet、bitClear等,具体定义及功能可以参考
文件wiring.h。
define lowByte(w)((uint8_t)((w)&
0xff))低字节
define highByte(w)((uint8_t)((w)
>>8))高字节
读bit位的值,即保留bit位,其他位均清零
define bitRead(value,bit)(((value)
>>(bit))&0x01)
置bit位的值,即bit位置1
define bitSet(value,bit)
((value)|=(1UL<<(bit)))
清除bit位,即bit位置0
define bitClear(value,bit)((value)
&=~(1UL<<(bit)))
写bit位的值,1或者0
define bitWrite(value,bit,bitvalue)
(bitvalue?bitSet(value,bit):
bitClear(value,bit))3.8 中断函数
3.8.1 interrupts和noInterrupts
interrupts和noInterrupts函数在
Arduino中负责打开和关闭总中断,函数无
返回值,无参数,同样可在文件wiring.h中
查看到函数原型,如下:
define interruptssei
define noInterruptscli3.8.2
attachInterrupt(interrupt,function,mode)
attachInterrupt函数用于设置外部中
断,函数有3个参数:interrupt、function和
mode,分别表示中断源、中断处理函数、触发模式。参数中断源可选值0或1,在
Arduino中一般对应2号和3号数字引脚;参
数中断处理函数用来指定中断的处理函
数,参数值为函数的指针,触发模式有4种
类型:LOW(低电平触发)、CHANGE(变化时触发)、RISING(低电
平变为高电平触发)、FALLING(高电平
变为低电平触发)。
下面的例子是通过外部引脚触发中
断函数。然后控制13号引脚的LED的闪
烁。
int pin=13;
volatile int state=LOW;void setup
{
pinMode(pin,OUTPUT);
attachInterrupt(0,blink,CHANGE);中
断源:1
中断处理函数:blink
触发模式:CHANGE(变化时触发)
}
void loop
{
digitalWrite(pin,state);
}
中断处理函数
void blink
{
state=!state;
}
在使用attachInterrupt函数时要注意以
下几点:
在中断函数中delay函数不能使用。
使用millis函数始终返回进入中断前
的值。
读取串口数据的话,可能会丢失。中断函数中使用的变量需要定义为
volatile型。
attachInterrupt函数的函数原型可在文
件WInterrupts.c中找到,如下所示:
void attachInterrupt(uint8_t
interruptNum,void(userFunc)(void),int
mode)
{
if(interruptNum<
EXTERNAL_NUM_INTERRUPTS)
{
intFunc[interruptNum]=userFunc;
switch(interruptNum)
{
case 0:
EICRA=(EICRA&~((1<
|(1<
EIMSK|=(1<
break;
case 1:
EICRA=(EICRA&~((1<
|(1<
EIMSK|=(1<
break;
}
}
}另外,还有detachInterrupt函数用于
取消中断,参数interrupt表示所要取消的中
断源,函数的定义如下:
void detachInterrupt(uint8_t
interruptNum)
{
if(interruptNum<
EXTERNAL_NUM_INTERRUPTS)
{
switch(interruptNum)
{
case 0:
EIMSK&=~(1<
break;
case 1:
EIMSK&=~(1<
break;
}
intFunc[interruptNum]=0;
}
}3.9 串口通信
Arduino中串口通信是通过
HardwareSerial类来实现的,在头文件
HardwareSerial.h中定义了一个
HardwareSerial类的对象Serial,直接使用类
的成员函数就可简单地实现串口通信。对
象和类的概念与应用可参阅6.1节内容。下
面以一个串口调光器的程序为例介绍
HardwareSerial类几个较常用的公有成员函
数,程序清单如下:
Dimmer(调光器)
通过计算机发送数据控制LED灯的亮度,单字节数据发
送,数据范围0~255
使用具有pwm功能的9号引脚
created 2006
by David A.Mellis
modified 14 Apr 2009
by Tom Igoe and Scott Fitzgerald
This example code is in the public
domain.
http:www.arduino.ccenTutorialDimmer
const int ledPin=9;
the pin that the LED is attached to
void setup
{
设置串口波特率:
Serial.begin(9600);1
设置LED控制引脚:
pinMode(ledPin,OUTPUT);
}
void loop
{
byte brightness;
查询串口是否收到数据:
if(Serial.available)2
{
获取数据
brightness=Serial.read;3
控制LED亮度
analogWrite(ledPin,brightness);
}
}
串口通信相关语句分析解释。
1.Serial.begin(9600);
该语句的功能是设置串口通信波特
率为9600bps,其函数原型如下:void HardwareSerial:begin(long baud)
{
uint16_t baud_setting;
bool use_u2x;
U2X mode is needed for baud rates
higher than(CPU Hz16)
if(baud>F_CPU16)
{
use_u2x=true;
}
else
{
figure out if U2X mode would allow
for a better connection
calculate the percent difference
between the baud-rate specified and
the real baud rate for both U2X and
non-U2X mode
uint8_t nonu2x_baud_error=abs((int)
(255-
((F_CPU(16(((F_CPU8baud-
1)2)+1))255)baud)));
uint8_t u2x_baud_error=abs((int)
(255-
((F_CPU(8(((F_CPU4baud-
1)2)+1))255)baud)));
prefer non-U2X mode because it
handles clock skew better
use_u2x=(nonu2x_baud_error>
u2x_baud_error);
}
if(use_u2x){
_ucsra=1<<_u2x;
baud_setting=(F_CPU4baud-1)2;
}
else
{
_ucsra=0;
baud_setting=(F_CPU8baud-1)2;
}
assign the
baud_setting,a.k.a.ubbr(USART Baud Rate
Register)
_ubrrh=baud_setting>>8;
_ubrrl=baud_setting;
sbi(_ucsrb,_rxen);
sbi(_ucsrb,_txen);
sbi(_ucsrb,_rxcie);
}
2.if(Serial.available)
该语句用来判断Arduino串口是否收
到数据,函数Serial.available返回值为
int型,不带参数。函数原型如下:
int HardwareSerial:available(void)
{
return(RX_BUFFER_SIZE+_rx_buffer->
head-_rx_buffer->tail)%RX_BUFFER_SIZE;}
3.brightness=Serial.read;
该语句的功能是将串口数据读入到
变量brightness中,函数Serial.read也不
带参数,返回值为串口数据,int型。函数
原型如下:
int HardwareSerial:read(void)
{
if the head isn't ahead of the
tail,we don't have any characters
if(_rx_buffer->head==_rx_buffer->
tail)
{
return-1;
}
else
{
unsigned char c=_rx_buffer->
buffer[_rx_buffer->tail];
_rx_buffer->tail=(_rx_buffer->
tail+1)%RX_BUFFER_SIZE;
return c;
}
}3.10 SPI接口
3.10.1 SPI接口概述
SPI(Serial Peripheral Interface)是
由摩托罗拉公司提出的一种同步串行外设
接口总线,它可以使MCU与各种外围设备
以串行方式进行通信以及交换信息,总线
采用3根或4根数据线进行数据传输,常用
的是4根线,即两条控制线(芯片选择CS
和时钟SCLK)以及两条数据信号线SDI和
SDO。
SPI是一种高速、全双工、同步的通
信总线。在摩托罗拉公司的SPI技术规范
中,数据信号线SDI称为MISO(Master-In-
Slave-Out,主入从出),数据信号线SDO
称为MOSI(Master-Out-Slave-In,主出从
入),控制信号线CS称为SS(Slave-
Select,从属选择),将SCLK称为SCK(Serial-Clock,串行时钟)。在SPI通
信中,数据是同步进行发送和接收的。数
据传输的时钟基于来自主处理器产生的时
钟脉冲,摩托罗拉公司没有定义任何通用
的SPI时钟规范。3.10.2 SPI接口数据传输
SPI是以主从方式工作的,其允许一
个主设备和多个从设备进行通信,主设备
通过不同的SS信号线选择不同的从设备进
行通信。其典型应用示意图如图3.5所示。
当主设备选中某一个从设备后,MISO和MOSI用于串行数据的接收和发
送,SCK提供串行通信时钟,上升沿发
送,下降沿接收。在实际应用中,未选中
的从设备的MOSI信号线需处于高阻状态,否则会影响主设备与选中从设备间的正常
通信。图 3.5 SPI总线应用示意图3.10.3 SPI类及其成员函数
Arduino中的SPI通信是通过SPIClass
类来实现的,使用SPIClass类能够方便地
将Arduino作为主设备与其他从设备通信。
SPIClass类提供了6个成员函数供使用者调
用,如下:
begin
setBitOrder
setClockDivider
setDataMode
transfer
end
begin函数用于初始化SPI总线,函数
原型如下:void SPIClass:begin
{
Set direction register for SCK and
MOSI pin.
MISO pin automatically overrides to
INPUT.
When the SS pin is set as OUTPUT,it
can be used as
a general purpose output port(it
doesn't influence
SPI operations).
pinMode(SCK,OUTPUT);
pinMode(MOSI,OUTPUT);
pinMode(SS,OUTPUT);
digitalWrite(SCK,LOW);
digitalWrite(MOSI,LOW);
digitalWrite(SS,HIGH);
Warning:if the SS pin ever becomes a
LOW INPUT then SPI
automatically switches to Slave,so
the data direction of
the SS pin MUST be kept as OUTPUT.
SPCR|=_BV(MSTR);
SPCR|=_BV(SPE);
}
setBitOrder的作用是在设置串行数据
传输时是先传输低位还是先传输高位,函
数有一个type类型的参数bitOrder,有
LSBFIRST(最低位在前)和MSBFIRST(最高位在前)两种类型可
选。函数无返回值,原型如下:
void SPIClass:setBitOrder(uint8_t
bitOrder)
{
if(bitOrder==LSBFIRST)
{
SPCR|=_BV(DORD);
}
else
{
SPCR&=~(_BV(DORD));
}
}
setClockDivider函数的作用是设置
SPI串行通信的时钟,通信时钟是由系统时
钟分频而得到,分频值可选2、4、8、16、32、64及128,有一个type类型的参数rate,有7种类型,对应7个分频值分别为
SPI_CLOCK_DIV2、SPI_CLOCK_DIV4、SPI_CLOCK_DIV8、SPI_CLOCK_DIV16、SPI_CLOCK_DIV32、SPI_CLOCK_DIV64
和SPI_CLOCK_DIV128。函数默认参数设
置是SPI_CLOCK_DIV4,设置SPI串行通信时钟为系统时钟的14。函数原型如下:
void SPIClass:setClockDivider(uint8_t
rate)
{
SPCR=(SPCR&~SPI_CLOCK_MASK)|(rate&
SPI_CLOCK_MASK);
SPSR=(SPSR&~SPI_2XCLOCK_MASK)|(rate
&SPI_2XCLOCK_MASK);
}
setDataMode函数的作用是设置SPI数
据模式,由于在SPI通信中没有定义任何通
用的时钟规范,所以在具体应用中有的在
上升沿采样,有的在下降沿采样,由此SPI
存在4种数据模式,如表3.1所示。setDataMode函数的type类型的参数
mode有4种类型可选,分别是
SPI_MODE0、SPI_MODE1、SPI_MODE2
和SPI_MODE3。函数原型如下:
void SPIClass:setDataMode(uint8_t
mode)
{
SPCR=(SPCR&~SPI_MODE_MASK)|mode;
}
transfer函数用来传输一个数据,由
于SPI是一种全双工、同步的通信总线。所
以传输一个数据实际上会发送一个数据,同时接收一个数据。函数的参数为发送的
数据值,返回的参数为接收的数据值。函
数原型如下:
byte SPIClass:transfer(byte_data)
{
SPDR=_data;
while(!(SPSR&_BV(SPIF)));
return SPDR;
}end函数停止SPI总线的使用,函数原
型如下:
void SPIClass:end
{
SPCR&=~_BV(SPE);
}第4章 Arduino硬件平台
通过前几章的介绍,大家对Arduino
的软件资源和环境应该有了一定的了解,但Arduino毕竟是一个硬件项目,要想真正
用好Arduino,还需要一些必要的硬件知
识。
本章通过原理分析、资源使用等方
面介绍Arduino的硬件平台。
4.1 Arduino的原理图
Arduino Duemilanove的硬件布局如
图4.1所示。Duemilanove在意大利语中是
2009的意思,名字就取自它的发布年份。
可以在网站:http:www.arduino.cc上获
得该控制板的原理图,如图4.2所示。
Arduino Uno与Arduino Duemilanove的硬件布局相似,所不同的是Arduino Uno使用的
不是FTDI USB-to-serial串行驱动器芯片,而是采用ATmega8U2芯片进行USB到串行
数据的转换。Uno在西班牙语和意大利语
中的意思为“一”,代表着Arduino 1.0,其
原理图如图4.3所示。图 4.1 Arduino Duemilanove的硬件布局图 4.2 Arduino Duemilanove原理图图 4.3 Arduino Uno原理图
由原理图可以发现,Arduino就是一
个带USB转串口芯片的AVR板,其核心就
是AVR单片机。AVR单片机具有以下优
点:
采用RISC(精简指令集)指令系
统,32个通用工作寄存器,避免了传统
8051单片机指令系统的指令长度不够长、指令数多、CPU利用率低和执行速度慢的
缺点。
采用哈佛结构的流水线技术,提高
指令执行速度。
除支持ISP在线编程外,还支持IAP
在应用编程。
片内集成了可擦写1000次的FLASH程
序存储器,同时还有大容量的可擦写
100000次的EEPROM。
集成了丰富的外设,包括IIC、SPI、WTD、ADC、PWM和片内振荡器等。
具有较宽的工作电压范围,工作电
压在1.8~6V,电源抗干扰能力强。
IO驱动能力强,可直接驱动LED。
USART使用独特的波特率发生器,波特率可达到576Kbits。
Arduino的IO引脚直接连接单片机的
IO引脚,利用AVR单片机引脚本身具有的
功能实现PWM、ADC、IIC、驱动LED等应
用。AVR单片机硬件连接16MHz晶振采用
外部振荡方式工作。
Arduino的编程利用AVR单片机的IAP
在应用编程技术,让使用者能够直接通过
USB接口将程序上传到芯片中。每一块
Arduino板在出厂前都在单片机中烧写了引
导程序(bootloader),它能够引导芯片通
过串口完成与计算机的通信,实现在应用
编程;否则Arduino是无法通过USB口更新
程序的。我们会在4.5节详细介绍这一点。4.2 串行通信口的使用
由原理图可以看出,AVR单片机的串
行通信口(RxD和TxD)除了接在USB到串
行数据的转换芯片上之外,还作为Arduino
的0号和1号引脚,在板上有明确的标识,如图4.4所示。
图 4.4 Arduino板上的串行通信口
4.2.1 实例功能本节实例采用两条杜邦线将两块
Arduino板的通信口交叉连起来,其中一块
Arduino每隔1s发送一个值为0x55的字节,另一块Arduino收到该字节后控制13号引脚
的LED转换状态。4.2.2 硬件电路
串口通信实例电路参考图4.5。
图 4.5 串口通信实例电路4.2.3 程序设计
由于实例用到了两块Arduino,因此
程序设计分为发送端和接收端两部分。先
来看看发送端的程序,实例要求发送端每
隔1s发送一个值为0x55的字节。
串行通信实例程序——发送端
每隔1s发送一个值为0x55的字节
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
}
执行部分——loop函数
void loop
{
延时1s,delay函数见3.4.2
delay(1000);
输出0x55
Serial.print(0x55,BYTE);
}
接收端的程序的任务是收到0x55后转
换13号引脚的状态,代码如下:
串行通信实例程序——接收端
收到0x55后转换13号引脚的状态
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
int ledFlag;LED状态
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
设置13号引脚为输出pinMode(13,OUTPUT);
}
执行部分——loop函数
void loop
{
byte RXData;
if(Serial.available)
{
获取收到的数据
RXData=Serial.read;
判断收到的数据是否是0x55
if(RXData==0x55)
{
if(ledFlag==0)判断LED状态
{
ledFlag=1;
digitalWrite(13,HIGH);
}
else
{
ledFlag=0;
digitalWrite(13,LOW);
}
}
}
}
读者在开始学习Arduino串口通信
时,可以就用计算机与Arduino进行通信,原理上是一样的。在Arduino开发环境下带
有Serial Monitor(串口监视窗)功能
,可方便地进行串口通信调试,界面如图
4.6所示。
图 4.6 Serial Monitor(串口监视窗)界
面4.3 数字IO口的使用
13号引脚的LED控制就属于数字IO
输出控制,前几章已经应用过多次了,本
节介绍数字IO输入的使用。
4.3.1 实例功能
本节实例是在2号引脚加一个按键开
关,当按下按键时,13号引脚的LED点
亮,同时通过串口发送合计的按键次数,当松开按键时,LED熄灭。4.3.2 硬件电路
将按键的一端接2号引脚,另一端接
地。同时为保持2号引脚输入状态稳定,加
1个5.1KΩ的上拉电阻在2号引脚。另外不
要忘了把Arduino连接在电脑上,实例电路
如图4.7所示。图 4.7 数字IO口实例电路4.3.3 程序设计
数字IO口实例程序
按键在2号引脚
按下按键时,13号引脚的LED点亮,同时通过串口发送
合计的按键次数,当松开按键时,LED熄灭
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
int keySum=0;按键次数
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
设置13号引脚为输出
pinMode(13,OUTPUT);
设置2号引脚为输入
pinMode(2,INPUT);
}
执行部分——loop函数
void loop
{
判断按键是否按下
if(LOW==digitalRead(2))
{
延时去抖
delay(50);
if(LOW==digitalRead(2))
{
点亮LED
digitalWrite(13,HIGH);
keySum++;
发送按键次数
Serial.print(keySum,DEC);
while(1)
{
判断是否松开按键
if(HIGH==digitalRead(2))
{
延时去抖
delay(50);
if(HIGH==digitalRead(2))
break;
}
}
熄灭LED
digitalWrite(13,LOW);
}
}
}4.4 模拟IO口的使用
由原理图可以看出Arduino的6个模拟
量引脚实际上是连接的AVR单片机的6个具
有ADC功能的管脚,所以Arduino的模拟量
输入功能就是通过单片机的ADC接口实现
的,该ADC接口具有以下特点:
10位采样精度
0.5 LSB的非线性度
±2 LSB的绝对精度
13~260μs的转换时间
最高分辨率时采样率高达15ksps
0~5V的ADC输入电压范围
本节就利用ADC接口实现模拟量的
输入。4.4.1 实例功能
本节实例在0号模拟口连接电位器,通过调整电位器改变输入模拟量的大小。
Arduino板每1s进行一次AD转换,并将结
果传给计算机。4.4.2 硬件电路
将Arduino的0号模拟口接至电位器的
中点,电位器另外两端分别连接+5V和
地,USB口连接至计算机用于传送数据,模拟IO实例电路如图4.8所示。图 4.8 模拟IO口实例电路4.4.3 程序设计
模拟IO口实例程序
在0号模拟口连接电位器
每1s进行一次AD转换并将结果发送给计算机
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
}
执行部分——loop函数
void loop
{
延时1s
delay(1000);
进行AD转换并传输数据Serial.print(analogRead(0),DEC);
}4.5 烧写引导程序
在4.1节说过每一块Arduino板在出厂
前都在单片机中烧写了引导程序,它可以
让Arduino通过USB口进行程序更新。如果
我们手上有一块空的AVR单片机想用到
Arduino中,则只能自己烧写引导程序了。
在Arduino这个完全开源的硬件项目中,AVR单片机的引导程序就在开发环境的文
件夹里。本节就使用AVR的开发环境AVR
Studio和ISP下载器AVRISP烧写引导程序。
4.5.1 下载器AVRISP
给一块空芯片烧写程序需要使用烧
写器、下载器之类的工具,AVRISP就是一
款AVR单片机专用的ISP下载器。如图4.9
所示即为一个AVRISP,它采用USB接口与
电脑相连,通过一条10芯的扁平线连接目标板,并利用目标板供电,图4.10即为
AVRISP的连接示意图。为方便使用某些6
芯ISP下载口(比如这里的Arduino),AVRISP配有一个10转6的转换头将10芯ISP
下载口转换成Arduino上的6芯ISP下载口。
10芯与6芯下载口的关系如表4.1所示。
图 4.9 AVRISP图 4.10 AVRISP连接示意图4.5.2 AVR Studio
AVR Studio集成开发环境是Atmel公
司官方发布的免费软件,专门用于开发
AVR单片机的软件平台,使用者可以到
Atmel的网站(http:www.atmel.com)下
载最新版的AVR Studio。
AVR Studio的安装十分简单,依照软
件的提示就能很顺利完成,图4.11所示即
为软件的使用界面。这里我们要使用AVR
Studio完成引导程序hex文件的烧写。图 4.11 AVR Studio使用界面打开软件后,将AVRISP连接到电脑
上,如图4.12所示,在AVR Studio界面中,选择Tools→Program AVR→Connect菜单
项,弹出Select AVR Programmer对话框,如图4.13所示。
图 4.12 下载器连接图 4.13 Select AVR Programmer对话框
在Select AVR Programmer对话框中,在Platform列表中选择STK 500 or
AVRISP,在Port列表中选择Auto,然后点
击Connect按钮,将AVRISP连上AVR
Studio。4.5.3 烧写引导程序
如果下载器连接成功,AVR Studio中
就会出现AVRISP对话框,如图4.14所示。
图 4.14 AVRISP对话框
在AVRISP对话框中就可以完成引导程序hex文件的烧写。
首先配置AVR单片机的融丝位,在图
4.14中选择Fuses选项卡,按以下内容配置
融丝位:
Boot Flash section size=1024 words
Boot start address=1C00;[BOOTSZ=00];
default value
Boot Reset Vector Enabled(default
address=0000);[BOOTRST=0]
Brown-out detection disabled;
[BODLEVEL=111]
Ext.Crystal Osc.;Frequency 8.0-
MHz;Startup time PWRDWNRESET:16K
CK14 CK+64ms;[CKSEL=1111 SUT=0]
然后回到Program选项卡,选择芯片
型号及引导文件的hex文件后,点击Flash
框内的Program按钮完成引导程序的烧写。提示:引导文件在Arduino开发环境
文件夹下的\hardware\arduino\bootloaders子
文件夹中。第二篇 模块篇
第5章 Arduino基本扩展模块
第6章 Arduino的扩展库
第7章 无线模块的应用第5章 Arduino基本扩展模块
在学习了前4章的基础知识后,本章
介绍Arduino的一些扩展模块,这些扩展模
块使得Arduino功能更强大,可以控制直流
电机、伺服电机、网络通信、液晶显示,获取温度、湿度值等。通过学习本章内
容,读者能够掌握Arduino的各个功能,为
后面的项目应用作铺垫。
5.1 L293 Motor Shield
L293 Motor Shield是一款基于L293B
直流电机驱动芯片的Arduino扩展模块,模
块可驱动两个电机,采用了可堆叠的设
计,可直接插到Arduino控制板上,如图
5.1所示,4个LED分别表示两个电机的正反
转。图 5.1 电机驱动模块L293 Motor Shield
5.1.1 直流电机的工作原理
大家都知道在磁场中放入通有电流
的导体就会产生磁感应效应。直流电机是
应用磁感应原理将电能转换为机械能的装
置,其转子和定子分别由绕组和永久磁铁
组成。直流电机具有调速性能较好和启动
转矩较大等特点。如图5.2所示为一个直流电机的模
型,在一对静止的磁极N和S之间,安装一
个可绕Z轴旋转的矩形线圈abcd,这个转动
的部分通常叫做电枢,线圈的两端a和b分
别接到叫做换向片的两个半圆形铜环上,两个换向片之间彼此是绝缘的,它们和电
枢装在同一根轴上,随电枢一起转动。A
和B是两个固定不动的碳质铜刷,它们和
换向片间是滑动接触的。来自直流电源的
电流就是通过电刷和换向片流入线圈的。图 5.2 直流电机模型图
当电刷A和B分别与直流电源的正极
和负极接通时,电流从电刷A流入,而从
电刷B流出。这时线圈中的电流方向是从a
流向b,从c流向d。由于磁感应效应,当电
枢在如图5.3a所示的位置时,线圈ab边的
电流从a流向b,用圆圈中的一个加号表
示,会受到一个向左下方的力;线圈cd边的电流从c流向d,用圆圈里的一个点表
示,会受到一个向右上方的力。这样,电
枢上就产生了一个逆时针方向的转矩,电
枢就沿着逆时针方向转动起来。
图 5.3 电机工作原理
当电枢转到使线圈ab边从N极进入S
极,而cd边从S极进入N极时,与线圈a端连接的换向片跟B接触,而与线圈d端接触
的换向片跟A接触,如图5.3b所示。这样,线圈内的电流方向变为从d流向c,再从b流
向a,从而保证在N极下方的导体中电流方
向不变,因此转矩的方向也不变,电枢依
然按照原来的方向旋转。这样,再通过传
动装置,直流电机就可以带动其他部件转
动了。
由原理分析可以发现,线圈中的电
流越大,线圈在磁场中所受到的力就越
大,电机的转速就会越快;反之电流越
小,电机转速就越慢。5.1.2 H桥驱动电路
直流电机的正反转实际上是通过变
换直流电压的正负极实现的,对于图5.2所
示的直流电机模型,当电刷A和B分别与直
流电源的正极和负极接通时,电枢逆时针
旋转,若A端接直流电源负极,B端接直流
电源正极,则直流电机顺时针旋转。
在实际应用中常采用图5.4所示的电
路驱动直流电机。电路名为“H桥驱动电
路”,这是因为它的形状酷似字母H。如图
5.4所示,H桥驱动电路包括4个三极管和一
个电机。要使电机运转,必须导通对角线
上的一对三极管。根据不同三极管对的导
通情况,电流可能会从左至右或从右至左
流过电机,从而控制电机的转向。图 5.4 H桥驱动电路示意图
如图5.5a所示,当Q1管和Q4管导通
时,电流从电源正极经Q1从左至右穿过直
流电机,然后再经Q4回到电源负极,从而
驱动直流电机沿一个方向旋转(假设电流
由左向右穿过电机时,直流电机顺时针旋
转);在图5.5b中另一对三极管Q2和Q3导
通的情况下,电流将从右至左流过直流电
机,从而驱动直流电机沿另一方向转动。图 5.5 H桥驱动电路控制直流电机示意
图
注意:在实际应用中驱动直流电机
时,保证H桥上两个同侧的三极管不会同
时导通非常重要。如果三极管Q1和Q2同时
导通,那么电流就会从正极穿过两个三极
管直接回到负极。此时,电路中除了三极
管外没有其他任何负载,电路上的电流就可能达到最大值(该电流仅受电源性能限
制),甚至烧坏三极管。5.1.3 线性放大调速原理
直流电机的转速计算公式如下:
n=(U-IR)KΦ
其中U为电枢端电压;I为电枢电
流;R为电枢电路总电阻;Φ为每极磁通
量;K为电动机结构参数。
由公式可以发现对一个各参数已经
确定的直流电机调速的可控量就是电压。
通过调整电压就能够调整直流电机的转
速,电压高直流电机转速就快;反之,电
压低,直流电机转速就慢。
通过线性放大电路就能够方便地实
现调节直流电机转速的效果。线性放大电
路调速原理示意图如图5.6所示,调节电位
器的阻值大小,就会调整电位器的分压
值,从而改变电机两端的电压值。图 5.6 线性放大电路调速原理示意图
线性放大电路调速的特点是:
与直流电机的转矩无关、消耗大量
的电流,效率低。
电位器分压产生大量的热量。5.1.4 PWM调速原理
在第3章的analogWrite函数里已经介
绍过通过调节PWM的占空比在引脚上输出
不同的电压值。脉冲宽度调制(PWM)是
一种对模拟信号电平进行数字编码的方
法。通过高分辨率计数器的使用,调制方
波的占空比用来对一个具体模拟信号的电
平进行编码。PWM信号仍然是数字的,因
为在给定的任何时刻,满幅值的直流供电
要么完全有(ON),要么完全无
(OFF)。电压或电流源是以一种通
(ON)或断(OFF)的重复脉冲序列加到
模拟负载上去的。通的时候即是直流供电
加到负载上的时候,断的时候即是供电断
开的时候。只要带宽足够,任何模拟值都
可以使用PWM进行编码。
采样控制理论中有一个重要结论:
当冲量相等而形状不同的窄脉冲加在具有
惯性的环节上时,其效果基本相同。PWM控制技术就是以该结论为理论基础,对半
导体开关器件的导通和关断进行控制,使
输出端得到一系列幅值相等而宽度不相等
的脉冲,用这些脉冲来代替正弦波或其他
所需要的波形。按一定的规则对各脉冲的
宽度进行调制,既可改变逆变电路输出电
压的大小,也可改变输出频率。
PWM的一个优点是从处理器到被控
系统信号都是数字形式的,无须进行数模
转换。让信号保持为数字形式可将噪声影
响降到最小。噪声只有在强到足以将逻辑1
改变为逻辑0或将逻辑0改变为逻辑1时,才
能对数字信号产生影响。对噪声抵抗能力
的增强是PWM相对于模拟控制的另外一个
优点,而且这也是在某些时候将PWM用于
通信的主要原因。从模拟信号转化为PWM
可以极大地延长通信距离。在接收端,通
过适当的RC或LC网络可以滤除调制高频方
波并将信号还原为模拟形式。5.1.5 L293 Motor Shield的原理
电机驱动模块L293 Motor Shield驱动
直流电机就采用PWM方式,其核心是一块
直流电机驱动芯片L293B,驱动电机的电
源取自Arduino的Vin引脚,模块原理图如
图5.7所示。图 5.7 L293 MotorShield原理图
L293B直流电机驱动芯片允许的电压
范围是4.5~36V,内有四重推挽(双重H桥
集成功放电路)驱动电路,两个通道可以
向各自的电机提供1 A的驱动电流,并且如
果芯片过热,芯片能够自动关断,保障系
统不受损坏。L293B内部结构图及典型应
用如图5.8所示。图 5.8 L293B典型应用
在图5.7中,当DIRA、DIRB为高电平
时,两个电机的电流分别由3引脚流向6引
脚和11引脚流向14引脚,假设此时电机正
转;反之,当DIRA、DIRB为低电平时,电机电流分别由6引脚流向3引脚和14引脚
流向11引脚,电机反转。此时,可以用
PWM控制芯片上电机使能脚的通断时间比
来对电机进行调速。
电机驱动模块L293 Motor Shield占用
Arduino控制板的数字引脚4、5、6、7,分
别对应DIRA、PWMA、PWMB和
DIRB,DIRA和PWMA共同控制电机A,DIRB
和PWMB共同控制电机B。5.1.6 L293 Motor Shield的应用
由于L293 Motor Shield采用可堆叠设
计,因此它的应用非常方便,只要将模块
对应地插到Arduino控制板上就可以了。在
本节中,在L293 Motor Shield上连接一个直
流电机,用Arduino控制直流电机由静止逐
渐变换到快速,再逐渐变回到静止,反方
向同样变换一次。从静止到快速及从快速
到静止的变化时间均为25.5s。直流电机的
连接示意图如图5.9所示(在图5.9中未画出
Arduino控制板),对应Arduino控制板的
引脚为4和5。图 5.9 直流电机连接示意图
注意:由于电机驱动的电流较大,因此Arduino须采用单独的7~12V电源供
电。5.1.7 程序设计
直流电机驱动实例程序
占用引脚4、引脚5
控制直流电机由静止逐渐变换到快速,再逐渐变回到静
止,反方向同样变换一次
从静止到快速及从快速到静止的变化时间均为25.5s
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置4号引脚为输出,控制直流电机正反转
pinMode(4,OUTPUT);
设置5号引脚为输出,控制直流电机转速
pinMode(5,OUTPUT);
}
执行部分——loop函数
void loop{
引脚4输出高电平,直流电机正转
digitalWrite(4,HIGH);
直流电机由静止逐渐变换为快速
for(int i=0;i<255;i++)
{
控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由0变化到255需25.5s
delay(100);
}
直流电机由快速逐渐变换为静止
for(i=255;i>0;i--)
{
控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由255变化到0需25.5s
delay(100);
}
引脚4输出低电平,直流电机反转
digitalWrite(4,LOW);
直流电机由静止逐渐变换为快速
for(i=0;i<255;i++)
{
控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由0变化到255需25.5s
delay(100);
}
直流电机由快速逐渐变换为静止
for(i=255;i>0;i--)
{控制电机转动,i表示转速
analogWrite(5,i);
延时0.1s,i由255变化到0需25.5s
delay(100);
}
}5.1.8 程序分析
首先在setup函数中设置直流电
机驱动的两个引脚4和5为输出,然后在
loop函数中对引脚4、5进行控制。
引脚4控制直流电机的正反转,使用
数字IO控制函数digitalWrite,函数描
述见3.1节。程序中两次使用该函数对引脚
4的输出电平进行控制,用于在直流电机由
静止变为快速,再变回静止后对直流电机
旋转方向的改变。
引脚5控制直流电机的转速,使用模
拟IO控制函数analogWrite,函数描述
见3.2节。在程序的for循环内不断改变
PWM的占空比,调整直流电机的转速。调
速周期为每0.1s一次,在程序中通过
delay函数实现。
注意:在实际应用中,由于直流电机存在一个启动电压,一旦小于启动电
压,直流电机就处于静止状态,因此直流
电机静止的时间就显得较长。可根据实际
情况改变程序中的i值来缩短直流电机静止
的时长。5.1.9 程序的精练
通过对程序的分析会发现在5.1.7节的
程序代码中对直流电机速度控制的代码段
都是十分类似的,通过引脚4调整直流电机
正反转后的调速代码甚至是一样的。5.1.7
节中的代码流程固然清晰,但代码的集成
度不高,本节通过在程序中加入两条判断
语句来实现程序的精练。程序代码如下:
直流电机驱动实例程序——精练程序
占用引脚4、引脚5
控制直流电机由静止逐渐变换到快速,再逐渐变回到静
止,反方向同样变换一次
从静止到快速及从快速到静止的变化时间均为25.5s
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置4号引脚为输出,控制直流电机正反转
pinMode(4,OUTPUT);
设置5号引脚为输出,控制直流电机转速
pinMode(5,OUTPUT);
}
执行部分——loop函数
void loop
{
通过判断引脚4的电压值来对引脚4输出进行控制
if(LOW==digitalRead(4))
{
引脚4输出高电平,直流电机正转
digitalWrite(4,HIGH);
}
else
{
引脚4输出低电平,直流电机反转
digitalWrite(4,LOW);
}
对直流电机调速
for(int i=0;i<511;i++)
{
控制电机转动
if(i<255)
{
如果i小于255,则加速
analogWrite(5,i);
}else
{
如果i大于255,则减速
analogWrite(5,511-i);
}
延时0.1s
delay(100);
}
}
在上述程序中,通过
if(LOW==digitalRead(4))和if(i<
255)两条判断语句,实现了程序的精练,一条语句用在控制引脚4的输出电压之前,用来在直流电机调速完成后对正转、反转
的切换;另一条语句用在控制直流电机转
速的函数之前,用来决定是加速还是减
速。5.2 Input Shield
Input Shield是一款带有摇杆和按键
的输入扩展板,同时预留了无线通信模块
接口,采用堆叠设计,可用于Arduino的交
互设计当中。模块如图5.10所示。
图 5.10 Input Shield
5.2.1 Input Shield原理图如图5.11所示,Input Shield扩展板具
有一个摇杆(含一个按键)、两个大圆帽
按键和1个复位按键,同时预留一个无线通
信模块接口。摇杆可以理解为一个两轴的
可调电位器,它能输出两个模拟信号,以
实现上下左右的控制,分别占用Arduino控
制板的模拟口0和模拟口1,摇杆按键占用
Arduino控制板的数字引脚5;B圆帽按键
(即Input Shield上的红色按键)占用数字
引脚3;C圆帽按键(即Input Shield上的蓝
色按键)占用数字引脚4;无线通信模块接
口占用数字引脚0和1。图 5.11 Input Shield原理图5.2.2 Input Shield的实例
本节中将Input Shield扩展板对应插
到Arduino控制板上,每1s获取一次摇杆上
下方向和左右方向的模拟量数据,通过串
口通信传送到电脑上,在Arduino开发环境
下的 Serial Monitor(串口监视窗)中查
看。5.2.3 程序设计
获取摇杆模拟量实例程序
摇杆上下方向和左右方向分别占用Arduino的模拟口0
和模拟口1
每1s进行一次AD转换并将结果发送给计算机
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
初始化部分——setup函数
void setup
{
设置串口波特率为9600bps
Serial.begin(9600);
}
执行部分——loop函数
void loop
{
延时1s
delay(1000);显示水平模拟量值,Serial.print(horizontal:);
Serial.print(analogRead(1),DEC);
显示垂直模拟量
Serial.print(,vertical:);
Serial.println(analogRead(0),DEC);
}5.2.4 程序分析
在程序中应用analogRead函数获
取模拟口0和模拟口1的值,传送到电脑
端,效果如图5.12所示。通过操纵摇杆可
看到模拟量数据的变化,由于Arduino采用
10位的ADC,因此模拟量的变化范围是
0~1023。在水平方向上,越向右,模拟量
的值越小;反之模拟量的值越大。在垂直
方向上,越向上模拟量的值越小,反之模
拟量的值越大。图 5.12 摇杆操纵显示效果5.2.5 使用摇杆控制直流电机转速
将Input Shield扩展板对应插到5.1节
L293 Motor Shield应用的实例中,可实现直
流电机转速的交互式控制,人为地用摇杆
控制直流电机的转速。直流电机的连接位
置依然采用5.1.6节中的连接方式,当摇杆
位于中位时,直流电机静止不动;当向上
推动摇杆时,直流电机逐渐加速正转;当
向下拉动摇杆时,直流电机逐渐加速反
转。程序清单如下:
摇杆控制直流电机转速实例程序
直流电机控制占用引脚4、5
引脚4控制直流电机的正反转——数字量输出
引脚5控制直流电机的转速——模拟量输出
摇杆垂直位置模拟量获取占用模拟量引脚0——模拟量输
入
向上推摇杆模拟量值越来越小
向下拉摇杆模拟量值越来越大
模拟量范围0~1023
当摇杆位于中位时,直流电机静止不动
当向上推动摇杆时,直流电机逐渐加速正转当向下拉动摇杆时,直流电机逐渐加速反转
摇杆位置模拟量获取频率为10Hz(每秒10次,即
0.1s一次)
created 2011
by Nille
Email:chenille@126.com
This example code is in the public
domain.
int verticalVal;定义整型变量
verticalVal存储AD值
初始化部分——setup函数
void setup
{
设置4号引脚为输出,控制直流电机正反转
pinMode(4,OUTPUT);
设置5号引脚为输出,控制直流电机转速
pinMode(5,OUTPUT);
}
执行部分——loop函数
void loop
{
延时0.1s
delay(100);
获取模拟量AD值
verticalVal=analogRead(0);
判断电机正转还是反转
if(verticalVal<512){
如果模拟量值小于512,则直流电机正转
引脚4输出高电平,直流电机正转
digitalWrite(4,HIGH);
设置直流电机转速
analogWrite(5,map(512-verticalVal,0,511,0,255));
}
else
{
否则直流电机反转
引脚4输出低电平,直流电机反转
digitalWrite(4,LOW);
设置直流电机转速
analogWrite(5,map(verticalVal,512,1023,0,255));
}
}
在程序中对摇杆输入模拟量的值转
换成PWM输出的值时使用了map函
数,该函数是将数据进行等比映射,可参
考3.5节。这是由于在摇杆处于中间位置
时,采集到的模拟量的值为512(0~1023的
中间值),而此时直流电机是静止的;当
摇杆向上推时,模拟量的值在0~512区间,此时需要控制直流电机正转,转速范围在
0~255区间;当摇杆向下拉时,模拟量的值在512~1023区间,此时需要控制直流电机
反转,转速范围同样在0~255区间。5.3 LCD Keypad Shield
LCD Keypad Shield是一块液晶显示
扩展板,使用的是标准1602液晶,该液晶
可显示两行内容,每行可显示16个英文字
符,具有对比度调节电位器,同时提供5个
按键输入,1个复位键,扩展板如图5.13所
示。图 5.13 LCD Keypad Shield
5.3.1 液晶显示原理
液晶显示(Liquid Crystal
Display,LCD)的应用在我们的生活中已经
随处可见,如手机、MP3、仪器仪表等。
液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制:通电时
液晶排列变得有序,光线容易通过;不通
电时排列混乱,阻止光线通过。
液晶显示按其显示方式可分为线段
式、字符式、点阵式等。除了黑白显示
外,还有多灰度显示、彩色显示等。LCD
Keypad Shield扩展板使用的是字符式液
晶,这是一种专门用于显示字母、数字、符号的液晶模块。
提示:Arduino提供了类库,可方便
地实现液晶显示模块的控制,而不需要知
道液晶显示的原理、控制方式等基础知识,希望尽快进行液晶显示模块应用的读
者可直接跳到5.3.8阅读。5.3.2 标准1602液晶模块
标准1602液晶模块除了液晶显示屏
外,还包括行列驱动器、控制器及连接附
件等,它是一种将液晶显示器件、控制集
成电路、PCB板、背光源、结构件装配在
一起的集合。提供与控制芯片的简单接
口,简化了液晶显示应用的控制方式。标
准1602液晶模块实物如图5.14所示。
图 5.14 标准1602液晶模块1602液晶模块主要技术参数如下:
显示容量:16×2个字符
芯片工作电压:4.5~5.5V
工作电流:2.0mA(5V)
字符尺寸:2.95mm×4.35mm
采用单排16芯接口,引脚定义如下表
所示。5.3.3 1602液晶模块控制方式
在1602液晶模块的内部显示存储器中
预先保存好的字符图形符号,其显示工作
流程就是通过控制器向1602写入指定的显
示存储器地址,相应地址对应的字符图形
符号就分别显示在液晶屏幕上。1602内部
显示存储器保存的字符图形符号包括阿拉
伯数字、英文字母大小写、常用符号、日
文平假名和片假名等,共160个,每一个字
符图形符号都有一个固定的地址。
1602液晶模块的控制指令共有11条,如表5.2所示。1602液晶模块的读写操作、屏幕和
光标的操作都是通过控制指令实现的,表
中1表示高电平,0表示低电平,表示无
效。
指令1:清屏,指令码01H,光标复
位到地址00H。指令2:光标复位,光标返回到地址
00H。
指令3:光标和显示模式设置。
ID:光标移动方向,高电平右移,低电平左移。
S:屏幕上所有文字是否左移或右
移,高电平表示有效,低电平表示无效。
指令4:显示开关控制。
D:控制整体显示的开或者关,高电
平表示开显示,低电平表示关显示。
C:控制光标的开或者关,高电平表
示有光标,低电平表示无光标。
B:控制光标是否闪烁,高电平闪
烁,低电平不闪烁。
指令5:光标或字符移位。
SC:高电平时移动显示的文字,低电平时移动光标。
RL:高电平时向右滚动,低电平时
向左滚动。
指令6:功能设置。
DL:高电平时为8位总线,低电平时
为4位总线。 ......
您现在查看是摘要介绍页, 详见PDF附件(9683KB,804页)。





