admin 管理员组

文章数量: 1184232


2024年4月27日发(作者:下载链接的软件app)

Arduino教程一: 数字输出

Arduino, 教程

11 Comments »

Arduino的数字I/O被分成两个部分,其中每个部分都包含有6个可用的I/O管脚,即管脚2到管脚7和管脚8到管脚13。除了管脚

13上接了一个1K的电阻之外,其他各个管脚都直接连接到ATmega上。我们可以利用一个6位的数字跑马灯,来对Arduino数字I/O

的输出功能进行验证,以下是相应的原理图:

电路中在每个I/O管脚上加的那个1K电阻被称为限流电阻,

由于发光二极管在电路中没有等效电阻值,使用限流电阻可

以使元件上通过的电流不至于过大,能够起到保护的作用。

该工程对应的代码为:

int BASE = 2;

int NUM = 6;

int index = 0;

void setup()

{

for (int i = BASE; i < BASE + NUM; i ++)

{

pinMode(i, OUTPUT);

}

}

void loop()

{

for (int i = BASE; i < BASE + NUM; i ++) {

digitalWrite(i, LOW);

}

digitalWrite(BASE + index, HIGH);

index = (index + 1) % NUM;

delay(100);

}

下载并运行该工程,连接在Arduino数字I/O管脚2到管脚7上的发光二极管会依次点亮0.1秒,然后再熄灭:

1

这个实验可以用来验证数字I/O输出的正确性。Arduino上一共有十二个数字I/O管脚,我们可以用同样的办法验证其他六个管脚的正

确性,而这只需要对上述工程的第一行做相应的修改就可以了:

int BASE = 8;

SEP

01

Arduino教程二: 数字输入

Arduino, 教程

3 Comments »

在数字电路中开关(switch)是一种基本的输入形式,它的作用是保持电路的连接或者断开。Arduino从数字I/O管脚上只能读出高电

平(5V)或者低电平(0V),因此我们首先面临到的一个问题就是如何将开关的开/断状态转变成Arduino能够读取的高/低电平。解

决的办法是通过上/下拉电阻,按照电路的不同通常又可以分为正逻辑(Positive Logic)和负逻辑(Inverted Logic)两种。

在正逻辑电路中,开关一端接电源,另一端则通过一个10K的

下拉电阻

接地,输入信号从开关和电阻间引出。当开关断开的时候,

输入信号被电阻“拉”向地,形成低电平(0V);当开关接通的时候,输入信号直接与电源相连,形成高电平。对于经常用到的按压式

开关来讲,就是按下为高,抬起为低。

在负逻辑电路中,开关一端接地,另一端则通过一个

10K的

上拉电阻

接电源,输入信号同样也是从开关

和电阻间引出。当开关断开时,输入信号被电阻“拉”

向电源,形成高电平(5V);当开关接通的时候,输

入信号直接与地相连,形成低电平。对于经常用到的

按压式开关来讲,就是按下为低,抬起为高。

为了验证Arduino数字I/O的输入功能,我们可以将

开关接在Arduino的任意一个数字I/O管脚上(13除

外),并通过读取它的接通或者断开状态,来控制其

它数字I/O管脚的高低。本实验采用的原理图如下所

示,其中开关接在数字I/O的7号管脚上,被控的发

光二极管接在数字I/O的13号管脚上:

Arduino教程三: 模拟输入

Arduino, 教程

5 Comments »

2

Arduino的优势在于对数字信号的识别和处理,但我们所生活的真实世界并不是数字(digital)化的,简单到只要用0和1就能够表示

所有的现象。例如温度这一我们已经司空见惯的概念,它只能在一个范围之内连续变化,而不可能发生像从0到1这样的瞬时跳变,

类似这样的物理量被人们称为是模拟(analog)的。Arduino是无法理解这些模拟量的,它们必须在经过模数转换后变成数字量后,才

能被Arduino进一步处理。

像温度这样的数据必须先被转换成微处理器能够处理的形式(比如电压),才能被Arduino处理,这一任务通常由各类传感器(sensor)

来完成的。例如,电路中的温度传感器能够将温度值转换成0V到5V间的某个电压,比如0.3V、3.27V、4.99V等。由于传感器表达

的是模拟信号,它不会像数字信号那样只有简单的高电平和低电平,而有可能是在这两者之间的任何一个数值。至于到底有多少可能

的值则取决于模数转换的精度,精度越高能够得到的值就会越多。

Arduino所采用的ATmega8微处理器一其有6个模数转换器(ADC,Analog to Digital Converter),每一个模数转换器的精度都是10bit,

也就是说能够读取1024(2^10 = 1024)个状态。在Arduino的每一个模拟输入管脚上,电压的变化范畴是从0V到5V,因此Arduino

能够感知到的最小电压变化是4.8毫伏(5/1024 = 4.8mV)。

电位计(potentiometer)是一种最简单的模拟输入设备,它实际上就是一个可变电阻箱,通过控制滑块所在的位置我们可以得到不同

的电压值,而输入信号正是从滑块所在的位置接入到电路中的。

这一实验我们将通过改变电位计的值来控制发光二极管闪烁的频率。电位计上一

共有三个管脚,分别连接到Arduino的电源、地和模拟输入的5号管脚上,发光二极管则连接到数字I/O的13号管脚上,原理图如下

所示:

相应的代码为:

int ledPin = 13;

int potPin = 5;

int value = 0;

void setup() {

3

pinMode(ledPin, OUTPUT);

}

void loop() {

value = analogRead(potPin);

digitalWrite(ledPin, HIGH);

delay(value);

digitalWrite(ledPin, LOW);

delay(value);

}

在Arduino中,对模拟输入端口不需要调用pinMode()函数将其指定为输入或者是输出模式,这点同数字I/O端口是有所不同的。

通过旋转电位计的轴,我们能改变电位计中间那根连线同地之间的电阻量,从而也就能改变从模拟输入的5号管脚上所读入的模拟量

的值。当电位计完全旋转到头时,输入到模拟输入管脚上的电压为0V,用analogRead()函数读出的值为0;当电位计完全旋转到另一

头时,输入到模拟I/O管脚上的电压为5V,此时用analogRead()函数读出的值为1023;当电位计旋转到中间的某个位置时,输入到

模拟输入管脚上的电压是0V到5V之间的某个值,而用analogRead()函数读出的则是位于0到1023之间的某个对应值。读出的模拟

量在我们的实验中被用来确定发光二极管点亮和熄灭的时间,以反映模拟量的变化。

电位计运用的是分压原理,通过旋转到不同的位置来得到不同的电压值。从这

种意义上讲,它能够被用来对当前旋转到的位置进行度量,因此可以被用在转

向轮等旋转装置中。

今天发现PCB板上另外一个错误,就是将模拟输入对应管脚号标反了,试了

好久才意识到是这一问题。加上之前电源设计上的两个小缺陷, 一共有三个

需要修改的地方。如果有机会再做PCB板的话,试着将这些问题解决一下:-)

相应的代码为:

int ledPin = 13;

int switchPin = 7;

4

int value = 0;

void setup() {

pinMode(ledPin, OUTPUT);

pinMode(switchPin, INPUT);

}

void loop() {

value = digitalRead(switchPin);

if (HIGH == value) {

// turn LED off

digitalWrite(ledPin, LOW);

} else {

// turn LED on

digitalWrite(ledPin, HIGH);

}

}

由于采用的是负逻辑电路,开关按下时用digitalRead()函数读取到的值为LOW,此时再用digitalWrite()函数将发光二极管所在的管脚

置为高,点亮发光二极管。同理,当开关抬起时,发光二极管将被熄灭,这样我们就实现了用开关来控制发光二极管的功能。

Arduino教程四: 模拟输出

Arduino, 教程

2 Comments »

5

就像模拟输入一样,在现实的物理世界中我们经常需要输出除了0和1之外的其他数值。例如,除了想用微控制器找开或者关闭电灯

之外,我们还会想控制灯光的亮度,这时就需要用到模拟输出。由于Arduino的微控制器只能产生高电压(5V)或者低电压(0V),

而不能产生变化的电压,因此必须采用脉宽度调制技术(PWM,Pulse Width Modulation)来模仿模拟电压。

PWM是一种开关式稳压电源应用,它是借助微处理器的数字输出来对模拟电路进行控制的一种非常用效的技术,广泛应用在从测量、

通信到功率控制与变换的许多领域中。简而言之,PWM是一种对模拟信号电平进行数字编码的方法,它通过对半导体开关器件的导通

和关断进行控制,使输出端得到一系列幅值相等但宽度不相等的脉冲,而这些脉冲能够被用来代替正弦波或其它所需要的波形。

在Arduino数字I/O管脚9、10和11上,我们可以通过analogWrite()函数来产生模拟输出。该函数有两个参数,其中第一个参数是

要产生模拟信号的引脚(9、10或者11);第二个参数是用于产生模拟信号的脉冲宽度,取值范围是0到255。脉冲宽度的值取0可

以产生0V的模拟电压,取255则可以产生5V的模拟电压。不难看出,脉冲宽度的取值变化1,产生的模拟电压将变化0.0196V(5/255

= 0.0196)。

本实验中我们将用模拟输出来调暗发光二极管(LED),由于正常情况下LED对电压的变化非常敏感,因此当脉冲宽度变化时人眼会

感觉到LED实际上是在不断地熄灭和点亮,而不是逐渐变暗。解决这一问题可以采用滤波电路,它能使有用频率信号通过而同时抑制

(或大大衰减)无用频率信号。实验中我们采用的是低通滤波器,它的原理非常简单,只需要一个电阻和一个电容,能够很好地过滤

掉电路中超过某一频率的信号。

此处给出的电路并不能校平所有脉冲,它之所以被称为“低通滤波”是因为它只允许

频率低于某个限度的脉冲通过,对于高于这个限度的脉冲则被平衡为伪模拟电压,

滤波的频率范围由电阻器和电容器的比值决定。

实验中采用的电路原

理如下:

相应的代码为:

int potPin = 0;

int ledPin =

11;

byte bright_table[] = { 30, 30, 30, 40, 50,

60, 70, 80, 90, 100,110, 120, 130, 140, 150, 160,

170, 180, 190, 200, 210, 220, 230, 240, 250, 250,

240, 230, 220, 210, 200, 190, 180, 170, 160, 150,

140, 130, 120, 110, 100, 90, 80, 70, 60, 50,

40, 30, 30, 30 };

int MAX = 50;

int count = 0;

int val = 0;

void setup() {

pinMode(ledPin, OUTPUT);

}

void loop() {

analogWrite(ledPin, bright_table[count]);

6

count ++;

if (count > MAX) {

count = 0;

}

val = analogRead(potPin);

val = val /4;

delay(val);

}

该工程调用analogWrite()函数在数字I/O端口的11号管脚上模仿模拟输出,每产生一次输出后都设置了相应的延时,而延时的长度

由模拟输入端口0号管脚上的电位器来决定。通过调整电位器的位置,我们可以观察到发光二极管逐渐变亮后再逐渐变暗的效果。

Arduino教程五: 串口输出

Arduino, 教程

No Comments »

在许多实际应用场合中我们会要求在Arduino和其它设备之间实现相互通信,而最常见通常也是最简单的办法就是使用串行通信。在

串行通信中,两个设备之间一个接一个地来回发送数字脉冲,它们之间必须严格遵循相应的协议以保证通信的正确性。

在PC机上上最常见的串行通信协议是RS-232串行协议,而在各种微控制器(单片机)上采用的则是TTL串行协议。由于这两者的电

平有很大的不同,因此在实现PC机和微控制器的通信时,必须进行相应的转换。完成RS-232电平和TTL电平之间的转换一般采用专

用芯片,如MAX232等,但在Arduino上是用相应的电平转换电路来完成的。

根据Arduino的原理图我们不难看出,ATmega的RX和TX引脚一方面直接接到了数字I/O端口的0号和1号管脚, 另一方面又通过

电平转换电路接到了串口的母头上。因此,当我们需要用Arduino与PC机通信时,可以用串口线将两者连接起来;当我们需要用Arduino

与微控制器(如另一块Arduino)通信时,则可以用数字I/O端口的0号和1号管脚。

串行通信的难点在于参数的设置,如波特率、数据位、停止位等,在Arduino语言可以使用()函数来简化这一任务。为了

实现数据的发送,Arduino则提供了()和n()两个函数,它们的区别在于后者会在请求发送的数据后面加上换行

符,以提高输出结果的可读性。

在这一实验中没有用到额外的电路, 我们只需要用串口线将Arduino和PC机连起来就可以了,相应的代码为:

void setup() {

(9600);

}

7

void loop() {

n("Hello World!");

delay(1000);

}

在将工程下载到Arduino模块中之后,在Arduino集成开发环境的工具栏中单击“Serial Monitor”控制,打开串口监视器:

接着将波特率设置为9600,即保持与工程中的设置相一致:

如果一切正常,此时我们就可以在Arduino集成开发环境的Console窗口中看到串口上输出的数据了:

为了检查串口上是否有数据发送,一个比较简单的办法是在数字I/O端口的1号管脚(TX)和5V电源之间接一个发光二极管,如下面

的原理图所示:

这样一旦Arduino在通过串口向PC机发送数据时,相应的发光二极管就会闪烁,实际应用中这是一个非常方便的调试手段;-)

8

Arduino教程六: 串口输入

Arduino, 教程

1 Comment »

串行通信是在实现在PC机与微控制器进行交互的最简单的办法。之前的PC机上一般都配有标准的RS-232或者RS-422接口来实现串

行通信,但现在这种情况已经发生了一些改变,大家更倾向于使用USB这样一种更快速但同时也更加复杂的方式来实现串行通信。尽

管在有些计算机上现在已经找不到RS-232或者RS-422接口了,但我们仍可以通过USB/串口或者PCMCIA/串口这样的转换器,在这些

设备上得到传统的串口。

通过串口连接的Arduino在交互式设计中能够为PC机提供一种全新的交互方式,比如用PC机控制一些之前看来非常复杂的事情,像

声音和视频等。很多场合中都要求Arduino能够通过串口接收来自于PC机的命令,并完成相应的功能,这可以通过Arduino语言中提

供的()函数来实现。

在这一实验中我们同样不需要任何额外的电路,而只需要用串口线将Arduino和PC机连起来就可以了,相应的Arduino工程代码为:

int ledPin = 13;

int val;

void setup() {

pinMode(ledPin, OUTPUT);

(9600);

}

void loop() {

val = ();

if (-1 != val) {

if ('H' == val) {

digitalWrite(ledPin,

HIGH);

delay(500);

digitalWrite(ledPin,

LOW);

}

9

}

}

把工程下载到Arduino模块中之后,在Arduino集成开发环境中打开串口监视器并将波特率设置为9600,然后向Arduino模块发送字

符H,如下图所示:

该工程运行起来之后会不断调用()函数从串口获得数据。Arduino语言提供的这个函数是不阻塞的,也就是说不论串口上是

否真的有数据到达,该函数都会立即返回。()函数每次只读取一个字节的数据,当串口上有数据到达的时候,该函数的返回

值为到达的数据中第一个字符的ASCII码;当串口上没有数据到达的时候,该函数的返回值则为-1。

Arduino语言的参考手册中没有对()函数做过多的说明,我的一个疑问是如果PC机一次发送的数据太多,Arduino是否提

供相应的串口缓存功能来保证数据不会丢失?Arduino语言中提供的另外一个函数ble()或许能够帮助我们用实验来进行

验证:

int ledPin = 13;

int val;

void setup() {

pinMode(ledPin, OUTPUT);

(9600);

}

void loop() {

val = ();

if (-1 != val) {

if ('H' == val) {

digitalWrite(ledPin,

HIGH);

delay(500);

digitalWrite(ledPin,

LOW);

("Available:

");

n(b

le(), DEC);

}

}

}

函数ble()的功能是返回串口缓

冲区中当前剩余的字符个数,按照Arduino

提供的该函数的说明,串口缓冲区中最多能

10

缓冲128个字节。我们可以一次给Arduino模块发送多个字符,来验证这一功能:

在这一实验中,每当Arduino成功收到一个字符H,连接在数字I/O端口管脚13上的发光二极管就会闪烁一次:

Arduino教程七: XBee无线通信

Arduino, 教程

4 Comments »

借助XBee扩展板我们可以很方便地将XBee模块连接到Arduino上,XBee模块的工作原理也非常简单,它与Arduino之间其实就是

通过串行接口(即Tx和Rx引脚)进行通信。对于简单的点对点通信来讲,只需要通过串行接口向XBee模块写数据就可以实现数据

的发送;当XBee模块通过无线通道接收到数据时,通过读串行接口可以很方便地获得这些数据。

原理弄清楚之后,其实我们可以将XBee模块看成是Arduino的串口,通过相应的串口操作函数来实现数据的接收和发送。首先请按照

Arduino XBee模块使用手册中的说明配置好你的两个XBee模块,然后

将相应的跳线连接到XBEE一端:

这里我们使用一个最简单的工程来进行相应的实验:

int ledPin = 13;

int val;

void setup() {

pinMode(ledPin, OUTPUT);

(9600);

}

void loop() {

// send data to another XBee module

('A');

delay(1000);

// receive data from another XBee module

11

val = ();

if (-1 != val) {

if ('A' == val) {

digitalWrite(ledPin, HIGH);

delay(500);

digitalWrite(ledPin, LOW);

delay(500);

}

}

}

该工程首先通过()函数向XBee模块发送一个字母A,该字母会被XBee模块通过无线网络发送出去,并被另外一个XBee

模块接收到。紧接着再通过()函数从XBee模块读取从无线网络接收到的数据,如果是字母A的话,则点亮相应的发光二极

管。

将该工程编译并分别下载到两个Arduino模块中,注意下载的时候不要连接XBee扩展板,这是因为XBee模块会占用串口,从而导致

下载无法正确完成。

下载完成后将XBee扩展板连接到Arduino上,并分别给两者上电。这两个Arduino模块都会向对方发送字母A,然后从对方接收字母

A,并对点亮数字I/O管脚13上连接的发光二极管。你可以试着将两个模块放在房间里的不同位置,来对XBee模块的传输性能进行

测试。

Arduino电机驱动扩展板

Arduino, 基本电路, 教程

11 Comments »

除了使用传感器对各种外部物理量进行感知之外,能够对实际物体的运动进行相应的控制也是互动设计中不可或缺的一部分。在所有

这类动力装置中,电机显然是最常见、最基本、最便宜的解决方案了,常用的电机的种类有很多种,如直流电机,步进电机,伺服电

机,减速电机等,并且每一种电机的控制方法都有所不同。

如果你是一个电子高手,控制普通的直流电机用几个三极管就行了,否则话像L293这样的芯片将是一个更好的选择。L293芯片的核

心是两个H-桥,所有的H-桥芯片都具有如下一些引脚:

逻辑输入

12

逻辑电压

电源电压

电源输出

其中逻辑电压引脚采用与微控制器相同的电压和电流,电源电压采用与运行电机所需要的电压和电流。逻辑输入引脚连接到用来向H-

桥输出控制信号的微控制器上的引脚,而电源输出引脚则连接到电机上。

这么专业的术语翻译到Arduino上可以这样来理解。首先,我们需要两套电源,一套用来给Arduino供电,一套用来给电机供电。其

次,我们需要用到Arduino的数字I/O管脚来控制L293,并把电机接到L293上接受控制。说到这里,正好解释一下Arduino的供电

系统,通常Arduino有三种供电方式:

USB供电

电池供电

变压器供电

后两者在Arduino上统称为外部供电。供电方式的选择是通过Arduino上的电源选择跳线来实现的,当把跳线接到“USB”一端时,采用

的是USB供电方式,这时整个Arduino及其附属电路上的电源都由PC的USB接口提供,此时电流一般比较小,只能驱动功率比较小

的电路,如LED等。当把跳线接到“EXT”一端时,采用的是外部供电方式,这时一般能够驱动比较大的设备,如电机等。Arduino内部

一套电源转换电路,可以用来将外部供电时的电压(6-12V)转换成内部所需要的5V电压,使用L293控制电机正是需要这两套电源。

下面这个就是基于L293D芯片的Arduino专用电机驱动扩展板,它能够用来驱动两个直流电机。

使用该扩展板来驱动直流电机非常简单,只需要将扩展板插到Arduino上,同时将直流电机连接到扩展板上的motors引脚上就可以了。

13

正如上面所提到的,此时应该采用Arduino的外部供电方式,并使用变压器或者电源为Arduino提供电力。这里我选用的是9V变压器

和9V的直流电机:

电机扩展板上motors引脚的上面两针是用来接电机1的,下面两针是用来接电机2的。

14

电路连接好之后,剩下的工作就是如何用程序进行控制了。使用这一扩展板我们能够控制直流电机的转动方向和转动速度,其中对转

动方向的控制是通过Arduino上的数字I/O引脚12和13来实现的,对转速的控制则是通过数字I/O引脚9和10来实现的。

如果要控制直流电机1,我们需要向引脚9输出相应的PWM信号来控制电机的速度,同时设置引脚12和13的高低电压来控制电机的

方向。如果要控制直流电机2,则需要向引脚10输出相应的PWM信号来控制电机的速度,此时也是通过设置引脚12和13 的高低电

压来控制电机的方向的。

电机扩展板上带有S1和S2两个按钮,分别对应于Arduino数字I/O的7号和6号管脚 ,并且在按下时为低电平。因此我们可以像下

面的程序这样利用S1来控制电机1的正反转:

int switchPin = 7; // switch pin

int dir1Pin = 12; // direction 1

int dir2Pin = 13; // direction 2

int speedPin = 9; // spped pin

void setup() {

pinMode(switchPin, INPUT);

pinMode(dir1Pin, OUTPUT);

pinMode(dir2Pin, OUTPUT);

pinMode(speedPin, OUTPUT);

}

void loop() {

// switch is pressed

if (digitalRead(switchPin) == LOW) {

// set spped

analogWrite(speedPin, 250);

// set direction

digitalWrite(dir1Pin, LOW);

15

digitalWrite(dir2Pin, HIGH);

} else {

analogWrite(speedPin, 100);

digitalWrite(dir1Pin, HIGH);

digitalWrite(dir2Pin, LOW);

}

}

在将上述程序下载到Arduino上并运行起来之后,我们就可以通过按S1键,来改变电机的旋转速度和方向了:)

P.S. 在调试这一电机扩展板的奇遇是,在将其插入到Arduino Diecimila的贴片版本上时,发现MC33269异常热,并且电机偶尔才能

工作。进一步设计发现如果把整个扩展板很好地插入到Arduino上时,5V和Gnd之间居然是短路的。一开始并没有发现问题在哪,后

来才发现扩展板上的电容C9与USB接头的外壳短路了!将其锡去掉一下,并抬高扩展板时问题得到解决。实际使用时请检查下图电

容下面的引脚是否与USB接口的外壳短路了,特别是对于贴片版本来讲,最好在通电前用万用表检查一下5V和Gnd之间的电阻值:)

Arduino下载线使用手册

Arduino, DIY, 手册

3 Comments »

Arduino使用的是Atmel公司的AVR单片机,一般为ATmega8和ATmega168,这一系列的单片机都支持ISP(In System

Programmability )编程,无需依赖昂贵的编程器就可以完成程序的下载。Arduino电路在设计上考虑到了ISP功能,也留出了相应的

接口(ICSP),从而允许我们通过ISP下载线来完成bootloader的下载。

新买来的Arduino模块上一般都已经预先下载好了bootloader,因此上电之后就能够直接通过Arduino集成开发环境下载相应的

Arduino程序。正常情况下我们在用Arduino时是不需要ISP下载线的,但在某些情况下可能会出现在Arduino集成开发环境中无法正

常下载程序的现象,这很可能是由于bootloader受损所致。解决的办法就是重新将bootloader烧写到ATmega芯片中,此时你就需

要用到这里介绍的ISP下载线了。

Arduio网站上给出的并口下载线电路我只成功地更新过ATmega8的bootloader,而无法为Diecimila上的ATmega168下载bootloader。

此外,Arduino给出的这一下载线电路过于简单,没有做相应的隔离和保护, 经常使用可能会对Atmega芯片带来一定的损害。AVR

建议使用一片74HC244来隔离并口和ATmega芯片,下面是我所使用的下载线的原理图:

16

以及自制的下载线:

使用并口下载线的时候,我们需要先到计算机的BIOS中将并口设为ECP(

The extended capabilities port

)模式,同时将I/O基

地址设置成378:

17

此时在Windows的设备管理器中,我们会发现并口已经被标记为

“ECP 打印机端口”:

用鼠标右键单击后从弹出的菜单中选择“属性”命令打开属性对话

框,在“资源”页面中我们会看到相应I/O基地址的设置已经生效:

现在就可以用ISP下载线连接计算机并口和Arduino上的ICSP接口

了,请特别留意连接方向:ISP下载线六口插座上标有小三角的一端应该靠近 Arduino的ICSP接口上标为1的一端。虽然计算机并口

能够为下载电路提供一定的电压,但一般我还是建议给Arduino模块加上5V电压(通过USB线和外接电源都可以),以保证下载过程

的稳定。

硬件准备好之后,我们就可以通过相应的软件将bootloader烧到Arduino中。支持AVR下载线的软件比较多,如AVRDUDE和SLISP

等,我们在这里使用的是PonyProg。下载并安装好PonyProg v2.07a BETA版本,启动PonyProg时会提示你进行相应的校准和设置工

作。首先选择“Setup”菜单中的“Calibration”命令进行校准,然后再选择“Setup”菜单中的“Intreface Setup…”命令进行相应的并口设

置:

18

根据你的Arduino模块上的芯片类型,从“Device” 菜单中的“AVR micro”

子菜单中选择“ATmega8”或者“ATmega168”。你也可以从工具栏上的

Device下拉框中进行相应的选择:

首先从“Command”菜单中选择“Read All” 命令,从Arduino模块上读出

ATmega中的当前数据和设置,其中最重要的是之后要设置的熔丝位。

然后选择“File”菜单中的“Open Program (FLASH) File…” 命令,打开“Open

program (FLASH) content file”对话框。从你的Arduino安装目录下找出对

应于的bootloader。对于Arduino 0010版本来讲,我们可以在hardwarebootloaders目录下找到atmega8和atmega168两个目录,

分别对应ATmega8和ATmega168芯片所对应的bootloader(文件扩展名为.hex),在atmega168目录下可以找到

ATmegaBOOT_168_和ATmegaBOOT_168_两个文件,分别对应Diecimila和NG模块。你需要根据你的Arduino

模块的具体情况,加载相应的bootloader文件。

AVR通过熔丝来控制芯片内部的一些功能,比如JTAG,时钟的使用,掉电检测电压,是否允许调试等。熔丝位的配置是为Arduino下

载bootloader过程中最复杂的一步,而且设置出错很有可能导致芯片锁死,所以一定要仔细。选择“Command”菜单中的“Security and

Configuration Bits …”命令,打开相应的熔丝设置对话框。

Arduino的bootloader对熔丝位有一定的要求,主要是同外部时间设置相关的。对于串口模块采用的ATmega8来讲,相应的熔丝字节

要设置成0xCA(Fuse High Byte)和0xFF(Fuse Low Byte),具体每位的含义可以参见Wolf Paulus的文章。在PonyProg中对ATmega8

的熔丝位设置为下图所示:

对于NG和Diecimila采用的ATmega168

来讲,相应的熔丝字节要设置成0xF8

(Extended Fuse Byte), 0xDF(Fuse

High Byte)和0xFF(Fuse Low Byte)。

在PonyProg中对ATmega168的熔丝位

设置为下图所示:

熔丝位设置好之后,选择“Command”菜

单中的“Write All”命令,将bootloader

下载到Arduino中。下载过程中Arduino

上的发光二极管L会不断闪烁。下载完

成之后,我们可以通过Arduino集成开

19

发环境下载一个Arduino工程,来验证新下载的bootloader是否能够正常工作。

DIY Arduino: Hello World

Arduino, DIY

No Comments »

终于要开始写第一个Arduino程序了,就跟之前学习所有语言一样,第一个程序自然是Hello World了。不过这次有点特殊,要让Arduino

显示一个“Hello World”字符串恐怕有点难度,这是因为Arduino模块上没有提供任何可供显示字符的设备。而这对Arduino新手来讲,

也就意味着程序的调试将是一个令人头疼的问题。

最简单的办法是在Arduino提供的数字端口(Digital I/O)上连接发光二极管,然后通过控制发光二极管的亮灭来表明程序的当前运行

状态,这的的确确可以算得上是最原始的调试方法。

我的第一个Arduino程序正是要通过对数字I/O的13号管脚的控制,来实现与其相连的发光二极的亮灭。之所以要选择13号管脚步,

是因为从原理图上可以看出该管脚与ATmega的引脚之间连接了一个1K的电阻,能够起到限流的作用,以保护二极管不被烧坏。

发光二极管是有正负极性的,因此必须连接正确才能够让其正常发光。刚买来的发光二极腿比较长的一端是正极,需要接在Arduino

数字I/O的13号管脚上;腿比较短的一端是负极,需要接在GND管脚上。

运行Arduino的集成开发环境,选择File->New菜单创建一个新的Arduino工程

接着在Arduino集成开发环境的主窗口中输入相应的代码:

int ledPin = 13;

20

void setup()

{

pinMode(ledPin, OUTPUT);

}

void loop()

{

digitalWrite(ledPin, HIGH);

delay(1000);

digitalWrite(ledPin, LOW);

delay(1000);

}

不难看出,一个最简单的Arduino程序至少要实现两个函数:setup()和loop()。其中setup()这个函数主要用来完成相应的初始化工作,

在上面的例子中是将数字I/O的13号管脚设置为数字输出。loop()这个函数则是Arduino程序的主函数,相当于C语言中的main()函

数,一个Arduino程序要完成的主要功能都在该函数中实现,在上面的例子中是通过变换13号管脚的高低电平,并设置一秒的延时,

从而使发光二极管能够间歇性地不断亮灭。

从原理上讲,用Arduino语言编写的程序最后会被翻译成相应的C代码,再用AVR-GCC编译后下载到ATmega单片机中运行。因此设

计Arduino语言的目的就是简化单片机编程,虽然这样效率上会有一些损失,但却能够极大地促进单片机在更广泛领域内的使用,基

本上算是沿袭了PC机上软件设计语言从汇编语言到C语言再到高级语言这一过程,因此很多技术和做法其实可以借鉴。

用Arduino语言编写的代码需要先验证(Verify),以保证语法的正确性,然后再编译生成相应的机器码。对Arduino代码的验证可以

通过Sketch->Verify/Compile菜单命令完成,也可以通过工具栏上的按钮完成:

代码成功通过验证和编译之后,就可以将其下载到Arduino模块中了。由于昨天已经将bootloader成功地烧写到了ATmega中,因此

下载Arduino应用的任务就可以完全交由bootloader来完成了。Arduino的bootloader与集成开发环境的交互是通过串口来完成的,

因此需要用串口线将Arduino与PC机的串中连接起来。我的串口线是自制的,按照Arduino的原理图,只需要接2,3和5三根线,

其中前两根用于数据的收发,最后一根是地线。

串口线连接好之后,在Arduino集成开发环境的Tools->Serial Port菜单下选择与PC相连的串口:

一开始我很奇怪为什么没有设置波特率和其它串行通信参数的地方,后来在Arduino的网站上才知道这些参数都保存在一个名为

的配置文件中,该文件一般保存在类似于C:Documents and SettingsAdministratorApplication DataArduino这样

的目录下。下面是我在该文件中找到的与串口通信相关的一些参数:

21

ts=1

ts=8

ad_rate=19200

=N

不难看出,Arduino模块采用的是19200 8N1方式来进行串口通信的。确定了这些之后,按下Arduino模块的复位按钮,随后立即执行

File->Upload to I/O Board菜单命令将编译好的程序下载到Arduino模块中。Arduino的bootloader被设计成如果在给定的时间(通

常有7到8秒)内没有接收到任何来自集成开发环境的命令,就自动运行之前已经下载的程序,所以我们必须保证在正确的时间段内

给Arduino模块发送程序下载的指令。除了通过菜单命令外,下载程序也可以通过快捷键Ctrl+U,或者直接点击工具栏上的相应按钮

来完成:

将Arduino程序上传到Arduino模块中需要花一些时间,并且取决于工程的大小。当程序上传成功之后,可以在Arduino集成开发环

境的console窗口中看到上传后的程序大小,以及该Arduino模块能够接受的最大程序的大小:

现在再次复位Arduino模块,会看到发光二极管立即闪了一下,表明bootloader正常工作了。接着再过一段时间,大约7到8秒,会

看到发光二极管间歇性地不断亮灭,这就表明第一个Arduino程序已经成功地运行起来了,CONGRATULATIONS!

我在这期间遇到的唯一问题是刚开始的时候无法通过串口线下载程序,最初怀疑是串口通信的问题,后来慢慢排查发现Arduino模块

能够从串口收数据,但却无法从串口发数据。仔细检查了硬件发现原来我在Arduino模块上接的是串口的公头,自然收发的两条线没

有同PC机完全正常地连接上,后来换成一个母头就一切正常了。这一过程中的另一收区是仔细读了Arduino关于串口部分的原理图,

原来这部分还是一个实用的TTL转232的电平转换电路,其中只用到了电阻、二极管和三极管,省去了一个MAX232芯片。

至此,DIY Arduino模块的工作算是暂告一段落,剩下的是如何对各个硬件功能进行详细的验证,这可以结合实际的项目来完成。我计

划下一步做一些简单的Arduino工程,大部分可能都来源于Arduino网站或者是网上收集到的资料,以验证我的Arduino模块,同时

也可以当作入门的教程供大家参考。

AUG

26

DIY Arduino: PCB和焊接

22

Arduino, DIY

7 Comments »

读了一些有关Arduino的介绍性的文章之后,才知道这么一个小东东居然在国外是大红大紫,虽然没有完全想清楚其中的原因,但似

乎并不妨碍自己DIY它的决心。Arduino采用开放源代码的模式,其原理图和电路图都可以从其网站免费得到。在权衡比较了一番之后,

我决定从其采用串口方式的版本开始,这一方面是因为原理相对简单,能够降低组装和调试的难度,另一方面则考虑到USB模拟的串

口并不总是那么稳定。

决定开工之后,花了一上午的时间画好了原理图,基本凑和吧。可轮到电路图时可就不一样了,封装和走线对我这业务选手来讲的确

不是件容易的事情。花了两个晚上的时间,最后还是决定放弃,因为Arduino官方提供的电路图在我看来确实比自己布的要漂亮多了,

看来这一修养只能在随后的日子里慢慢积累了。

去做电路板时遇到一些问题,由于我问到的制造电路板的厂商基本上只认Protel,根本不知道还有Eagle CAD一说,甚至有人还将其

与AutoCAD混为一谈,告诉我这个软件不是用来画电路图的。没有办法,只好回家一顿Google,将其生成Gerber文件后再将送过去。

这一过程也算有点收获,除了知道何为Gerber文件以及如何在Eagle CAD中生成Gerber文件之外,还找到了一个用来查看Gerber

文件的好工具:CAM350。

电路板从送去到拿到一般需要一周多的时间,这期间的主要任务当然是购买元器件了。一开始并没有注意到Arduino串口版本的元件

列表,以为与NG版本一样也采用的是ATmega168,问了好些地方都没得卖,最好只好高价比香港快递过来,估计贵了不止一倍。最

后在组装的时候才发现原来串口版本采用的仍旧是ATmega8,而这在村里还算是很好买到的,这一个郁闷啊!

元件都准备妥当之后,电路板也做出来了,虽然不是与Arduino官方一致的蓝色,但还是挺漂亮的;-)

将元件焊接到PCB板上又是一次对基本功的训练,好在这一版本的Arduino采用的都是分立元件,焊接上没有遇到太大的麻烦。期间

再一次深刻体会到了工具的重要性,不时幻想自己手中那把最便宜的铬铁啥里也能更新换代一下,虽然他的寿命还不到短短的一个月。

焊接完成之后,万里长征估计还只完成了第一步,要让Arduino能够正常的运行起来,肯定还有相当多的调试和排错的工作要做,而

这也正是DIY的乐趣所在;-)

23

Arduino 电子积木 专用传感器扩展板 V4

Arduino, 电子积木

2 Comments »

真没想到,一块传感器扩展板居然被我改到了第四版,而且估计还会继续修改下去。最初的传感器扩展板在设计的时候,只考虑到了

如何将数字传感器和模拟传感器很方便地连接起来。因此在最初定义数字传感器线序的时候,没有更多可以参照的地方,直到后来有

人提出是否可以考虑与伺服电机(舵机)的连线顺序一样,我才很认真地考虑这一问题,并且在最新的V4版本上采用,原因在于:

可以很方便地与舵机相连

不容易出现短路的情况,在接错钱时不会有很严重的后果

可以与模拟传感器接口统一起来,保持通用

用这么多的好处,自然是忍不住在V4上做了这么一个大的修改,好处多多,但升级也会给之前的用户一些不便。最主要的影响在于数

字连接线,由于连线的顺序不一样,因此混用的时候会有一定的麻烦;-) 也就是说,使用V4之前的传感器扩展板的用户,依旧要使用

以前的数字连接线;而使用V4版本的用户,则需要使用另一种数字连接线(我暂时叫它通用传感器连接线)。

V4上其它的改动还包括:

调用了模拟传感器座的位置

POWER区域与最新的Arduino保持一致

数字传感器连接座4个一组,方便连线

添加了一组适合通用连接线的模拟接口

加入了4针的COM/IIC连接座

COM/IIC连接座是为以后的串口模块和IIC模块做准备的,通过设置两个跳线进行相应的选择。

从使用上讲,V4跟之前的版本是一样的,直接连接到标准的Arduino上就可以了:

数字传感器可以借助通用传感器连接线与其相应接:

24

模块传感器则即可以通过模拟传感器连接线,也可以通过通用传感器连接线与传感器扩展板相连:

25

最后,因为数字传感器接口与舵机接口兼容,这样用传感器扩展板就可以直接驱动舵机了:)

小试电子积木

Arduino, 电子积木

No Comments »

某君给我描述了他的一个项目,有8个继电器输出的激光开关,需要把相应的状态读入到Arduino中进行处理。本来电路不算太复杂,

一开始我想是不是可以用万用板搭起来这一外围,后来发现其实用电子积木的思想来构建更加容易和方便:)

首先我用一个Arduino,一个按钮模块和一个继电器模块来模拟他的激光开关,我要实现的效果是按下按钮时,继电器相应地吸合。这

并不困难,实际应用的时候把按钮模块通过数字模块连接线连接到数字I/O管脚2上,再把继电器模块通过数字模块连接线连接到数

字I/O管脚8上:

相应的代码是:

int switchPin = 2;

int relayPin = 8;

int ledPin = 13;

int value = 0;

26

void setup() {

pinMode(switchPin, INPUT);

pinMode(relayPin, OUTPUT);

pinMode(ledPin, OUTPUT);

}

void loop() {

value = digitalRead(switchPin);

if (HIGH == value) {

digitalWrite(relayPin, HIGH);

digitalWrite(ledPin, HIGH);

} else {

digitalWrite(relayPin, LOW);

digitalWrite(ledPin, LOW);

}

}

另外一个Arduino则是项目中会实际用到的,这里我用到了数字按钮模块的电路板,但没有接按钮,而是用两根线直接连接到继电器

的输出,我们不妨把它称为数字输入模块。这样实际的效果就相当于继电器吸合时,从数字输入模块上会读到高电平,当继电器断开

时,从数字模块上则会读出低电平。电路的连接很简单,数字输入模块的一端与继电器连接,另一端通过一根数字模块连接线连接到

Arduino数字I/O管脚的2上:

相应的代码是:

int switchPin = 2;

int ledPin = 13;

int value = 0;

void setup() {

pinMode(switchPin, INPUT);

27

pinMode(ledPin, OUTPUT);

}

void loop() {

value = digitalRead(switchPin);

if (HIGH == value) {

digitalWrite(ledPin, HIGH);

} else {

digitalWrite(ledPin, LOW);

}

}

下面是最后连接好的电路图:

代码并不复杂,最后的效果是当你按下最上面的按钮模块后,中间的继电器吸合,此时从最下面的数字输入模块中读出的值为高,同

时下面那块Arduino上的LED点亮。

使用这些积木部分避免了麻烦的电路连接,但其中比较困难的是如何抽象出所需要的模块,这些模块除了功能性(比如按钮,LED)外,

还可能有部分逻辑功能模块。实践总是检验它们最好的办法,坚持下来慢慢来,也许能发现其中的一些规律吧!

28


本文标签: 模块 相应 数字 串口 下载