Arduino是一个基于易用硬件和软件的原型平台(开源)。它由可编程的电路板(称为微控制器)和称为Arduino IDE(集成开发环境)的现成软件组成,用于将计算机代码写入并上传到物理板。


主要特点是:

  • Arduino板卡能够读取来自不同传感器的模拟或数字输入信号,并将其转换为输出,例如激活电机,打开/关闭LED,连接到云端等多种操作。

  • 你可以通过Arduino IDE(简称上传软件)向板上的微控制器发送一组指令来控制板功能。

  • 与大多数以前的可编程电路板不同,Arduino不需要额外的硬件(称为编程器)来将新代码加载到板上。你只需使用USB线即可。

  • 此外,Arduino IDE使用C++的简化版本,使其更容易学习编程。

  • 最后,Arduino提供了一个标准的外形规格,将微控制器的功能打破成更易于使用的软件包。


Arduino板卡

Arduino板的类型

根据使用的不同微控制器,可提供各种Arduino板。然而,所有Arduino板都有一个共同点:它们通过Arduino IDE编程。

差异基于输入和输出的数量(可以在单个板上使用的传感器,LED和按钮的数量),速度,工作电压,外形尺寸等。一些板被设计为嵌入式,并且没有编程接口(硬件),因此你需要单独购买。有些可以直接从3.7V电池运行,其他至少需要5V。

以下是可用的不同Arduino板的列表。

基于ATMEGA328微控制器的Arduino板

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Uno R35V16MHz14661USB通过ATMega16U2
Arduino Uno R3 SMD5V16MHz14661USB通过ATMega16U2
Red Board5V16MHz14661USB通过FTDI
Arduino Pro 3.3v/8 MHz3.3V8MHz14661FTDI兼容头
Arduino Pro 5V/16MHz5V16MHz14661FTDI兼容头
Arduino mini 055V16MHz14861FTDI兼容头
Arduino Pro mini 3.3v/8mhz3.3V8MHz14861FTDI兼容头
Arduino Pro mini 5v/16mhz5V16MHz14861FTDI兼容头
Arduino Ethernet
5V16MHz14661FTDI兼容头
Arduino Fio3.3V8MHz14861FTDI兼容头
LilyPad Arduino 328 main board3.3V8MHz14661FTDI兼容头
LilyPad Arduino simply board3.3V8MHz9450FTDI兼容头

基于ATMEGA32u4微控制器的Arduino板卡

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Leonardo5V16MHz201271本机USB
Pro micro 5V/16MHz5V16MHz14661本机USB
Pro micro 3.3V/8MHz5V16MHz14661本机USB
LilyPad Arduino USB3.3V8MHz14661本机USB

基于ATMEGA2560微控制器的Arduino板卡

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Mega 2560 R35V16MHz5416144USB通过ATMega16U2B
Mega Pro 3.3V3.3V8MHz5416144FTDI兼容头
Mega Pro 5V5V16MHz5416144FTDI兼容头
Mega Pro Mini 3.3V3.3V8MHz5416144FTDI兼容头

基于AT91SAM3X8E微控制器的Arduino板卡

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Mega 2560 R33.3V84MHz5412124本机USB


在本章中,我们将了解 Arduino 板上的不同组件。将学习 Arduino UNO 板,因为它是 Arduino 板系列中最受欢迎的。此外,它是开始使用电子和编码的最佳板。有些板看起来与下面给出的有些不同,但多数 Arduino 中的这些组件大部分是共同的。

以下是 UNO 板的电路:


以下是 UNO 板的详细参数:

名称参数
工作电压5V
输入电压接上 USB 时无须外部供电或外部 7V~12V DC 输入
输出电压5V DC 输出和 3.3V DC 输出 和外部电源输入
微处理器ATmega328
BootloaderArduino Uno
时钟频率16 MHz
输入电压( 推荐)7-12V
输入电压(限制)6-20V
支持 USB 接口协议及供电(不需外接电源)
支持 ISP 下载功能
数字 I/O 端口14(6 个 PWM 输出口)
模拟输入端口6
直流电流  I/O 端口40mA
直流电流 3.3V 端口50mA
Flash 内存32 KB (ATmega328) (0.5 KB用于引导程序)
SRAM2 KB (ATmega328)
EEPROM1 KB (ATmega328)
尺寸75x55x15mm

以下是 UNO 板的详细内容:

Arduino UNO板


Power USB

电源 USB

Arduino 板可以通过使用计算机上的USB线供电。你需要做的是将 USB 线连接到 USB 接口。

Barrel Jack

电源(桶插座)

Arduino 板可以通过将其连接到电源插口直接从交流电源供电。

Voltage Regulator

稳压器

稳压器的功能是控制提供给 Arduino 板的电压,并稳定处理器和其他元件使用的直流电压。

Crystal Oscillator

晶体振荡器

晶振帮助Arduino处理时间问题。Arduino 如何计算时间?答案是,通过使用晶体振荡器。在 Arduino 晶体顶部打印的数字是 16.000H9H。它告诉我们,频率是 16,000,000 赫兹或 16MHz。

Arduino Reset

Arduino 重置

你可以重置你的 Arduino 板,例如从一开始就启动你的程序。可以通过两种方式重置 UNO 板。首先,通过使用板上的复位按钮(17)。其次,你可以将外部复位按钮连接到标有 RESET(5)的 Arduino 引脚。

Pins

引脚(3.3,5,GND,Vin)

  • 3.3V(6) - 提供 3.3 输出电压

  • 5V(7) - 提供 5 输出电压

  • 使用3.3伏和5伏电压,与 Arduino 板一起使用的大多数组件可以正常工作。

  • GND(8)(接地) - Arduino 上有几个 GND 引脚,其中任何一个都可用于将电路接地。

  • VVin(9) - 此引脚也可用于从外部电源(如交流主电源)为 Arduino 板供电。

Analog pins

模拟引脚

Arduino UNO 板有六个模拟输入引脚,A0 到 A5。这些引脚可以从模拟传感器(如湿度传感器或温度传感器)读取信号,并将其转换为可由微处理器读取的数字值。

Main microcontroller

微控制器

每个 Arduino 板都有自己的微控制器(11)。你可以假设它作为板的大脑。Arduino 上的主 IC(集成电路)与板对板略有不同。微控制器通常是 ATMEL 公司的。在从 Arduino IDE 加载新程序之前,你必须知道你的板上有什么 IC。此信息位于 IC 顶部。有关 IC 结构和功能的更多详细信息,请参阅数据表。

ICSP pin

ICSP 引脚

大多数情况下,ICSP(12)是一个 AVR,一个由 MOSI,MISO,SCK,RESET,VCC 和 GND 组成的 Arduino 的微型编程头。它通常被称为 SPI(串行外设接口),可以被认为是输出的“扩展”。实际上,你是将输出设备从属到 SPI 总线的主机。

Power LED indicator

电源 LED 指示灯

当你将 Arduino 插入电源时,此 LED 指示灯应亮起,表明你的电路板已正确通电。如果这个指示灯不亮,那么连接就出现了问题。

TX and RX LEDs

TX 和 RX LED

在你的板上,你会发现两个标签:TX(发送)和RX(接收)。它们出现在 Arduino UNO 板的两个地方。首先,在数字引脚 0 和 1 处,指示引脚负责串行通信。其次,TX 和 RX LED(13)。发送串行数据时,TX LED 以不同的速度闪烁。闪烁速度取决于板所使用的波特率。RX 在接收过程中闪烁。

Digital I/O

数字 I/O

Arduino UNO 板有 14 个数字 I/O 引脚(15)(其中 6 个提供 PWM(脉宽调制)输出),这些引脚可配置为数字输入引脚,用于读取逻辑值(0 或 1) ;或作为数字输出引脚来驱动不同的模块,如 LED,继电器等。标有“〜”的引脚可用于产生 PWM。

AREF

AREF

AREF 代表模拟参考。它有时用于设置外部参考电压(0 至 5 伏之间)作为模拟输入引脚的上限。



在了解Arduino UNO板的主要部分后,我们准备学习如何设置Arduino IDE。一旦我们学到这一点,我们将准备在Arduino板上上传我们的程序。


在本节中,我们将在简单的步骤中学习如何在我们的计算机上设置Arduino IDE,并准备板通过USB线接收程序。


步骤1 - 首先,你必须有Arduino板(你可以选择你喜欢的板)和一根USB线。如果你使用Arduino UNO,Arduino Duemilanove,Nano,Arduino Mega 2560或Diecimila,你将需要一个标准USB线(A插头到B插头)。如下图所示为你将连接到USB打印机的类型。


标准USB电缆


如果使用Arduino Nano,你将需要一条A到Mini-B线,如下图所示。


A到Mini-B电缆


步骤2 - 下载Arduino IDE软件。

你可以从Arduino官方网站的下载页面获得不同版本的Arduino IDE。你必须选择与你的操作系统(Windows,IOS或Linux)兼容的软件。文件下载完成后,解压缩文件。


解压缩文件

步骤3 - 打开板的电源。

Arduino Uno,Mega,Duemilanove和Arduino Nano通过USB连接到计算机或外部电源自动获取电源。如果你使用Arduino Diecimila,则必须确保板的配置为从USB连接获取电源。电源选择使用跳线,一小块塑料安装在USB和电源插孔之间的三个引脚中的两个。检查它是否在最靠近USB端口的两个引脚上。

使用USB线将Arduino板连接到计算机。绿色电源LED等(标有PWR)应该发光。


步骤4 - 启动Arduino IDE。

下载Arduino IDE软件后,需要解压缩该文件夹。在文件夹中,你可以找到带有无穷大标签(application.exe)的应用程序图标。双击该图标以启动IDE。

启动Arduino IDE


步骤5 - 打开你的第一个项目。

一旦软件启动,你有两个选项:

  • 创建一个新项目。
  • 打开一个现有的项目示例。

要创建新项目,请选择Flie→New。


新建项目


要打开现有项目示例,请选择File→Example→Basics→Blink。


打开现有项目示例

在这里,我们只选择一个名为 Blink 的示例。它打开和关闭LED有一些时间延迟。你可以从列表中选择任何其他示例。


步骤6 - 选择你的Arduino主板。

为了避免在将程序上载到板上时出现任何错误,必须选择正确的Arduino板名称,该名称与连接到计算机的电路板相匹配。

转到Tools→Board,然后选择你的板。


选择您的Arduino主板

在这里,根据我们的教程选择了Arduino Uno板,但是你必须选择与你使用的板匹配的名称。


步骤7 - 选择串行端口。

选择Arduino板的串行设备。转到Tools→Serial Port菜单。这可能是COM3或更高(COM1和COM2通常保留为硬件串行端口)。要弄清楚的话,你可以断开你的Arduino板,并重新打开菜单,那么消失的条目应该是Arduino板。重新连接板并选择该串行端口。

选择串行端口。


步骤8 - 将程序上传到你的板。

在解释如何将我们的程序上传到板之前,我们必须演示Arduino IDE工具栏中出现的每个符号的功能。


将程序上传到您的主板

A - 用于检查是否存在任何编译错误。

B - 用于将程序上传到Arduino板。

C - 用于创建新草图的快捷方式。

D - 用于直接打开示例草图之一。

E - 用于保存草图。

F - 用于从板接收串行数据并将串行数据发送到板的串行监视器。


现在,只需点击环境中的“Upload”按钮。等待几秒钟,你将看到板上的RX和TX LED灯闪烁。如果上传成功,则状态栏中将显示“Done uploading”消息。


注意 - 如果你有Arduino Mini,NG或其他电路板,则需要在单击Arduino软件上的上传按钮之前,立即按下电路板上的复位按钮。

在本章中,我们将深入研究Arduino程序结构,并将学习更多Arduino世界中使用的新术语。Arduino软件是开源的。Java环境的源代码在GPL下发布,C/C++微控制器库在LGPL下。


Sketch(草图) - 第一个新的术语是名为“sketch”的Arduino程序。


结构

Arduino程序可以分为三个主要部分:结构,值(变量和常量)和函数在本教程中,我们将逐步了解Arduino软件程序,以及如何编写程序而不会出现任何语法或编译错误。


让我们从结构开始。软件结构包括两个主要函数:

  • Setup()函数
  • Loop()函数
结构
Void setup ( ) {}
  • PURPOSE- 草图启动时会调用 setup()函数。使用它来初始化变量,引脚模式,启用库等。setup函数只能在Arduino板的每次上电或复位后运行一次。

  • INPUT - -

  • OUTPUT - -

  • RETURN- -

Void Loop ( ) {}
  • PURPOSE- 在创建了用于初始化并设置初始值的setup()函数后,loop() 函数,正如它的名称所指,允许你的程序连续循环的更改和响应。可以使用它来主动控制Arduino板。

  • INPUT - -

  • OUTPUT - -

  • RETURN- -

C中的数据类型是指用于声明不同类型的变量或函数的扩展系统。变量的类型确定它在存储器中占用多少空间以及如何解释存储的位模式。

下表提供了你将在Arduino编程期间使用的所有数据类型。

voidBooleancharUnsigned char
byteintUnsigned int
word
longUnsigned long
shortfloatdoublearrayString-char array
String-object


void

void关键字仅用于函数声明。它表示该函数预计不会向调用它的函数返回任何信息。

例子

Void Loop ( ) {   // rest of the code}

Boolean

布尔值保存两个值之一,true或false。每个布尔变量占用一个字节的内存。

例子

boolean val = false ; // declaration of variable with type boolean and initialize it with falseboolean state = true ; // declaration of variable with type boolean and initialize it with true

Char

一种数据类型,占用一个字节的内存,存储一个字符值。字符文字用单引号写成:'A',对于多个字符,字符串使用双引号:"ABC"。

但是,字符是存储为数字。你可以在ASCII图表中查看特定编码。这意味着可以对使用ASCII值的字符进行算术运算。例如,'A'+1的值为66,因为大写字母A的ASCII值为65。

例子

Char chr_a = ‘a’ ;//declaration of variable with type char and initialize it with character aChar chr_c = 97 ;//declaration of variable with type char and initialize it with character 97
ASCII Char Table

unsigned char

unsigned char是一种无符号数据类型,占用一个字节的内存。unsigned char数据类型编码数字为0到255。

例子

Unsigned Char chr_y = 121 ; // declaration of variable with type Unsigned char and initialize it with character y

byte

一个字节存储一个8位无符号数,从0到255。

例子

byte m = 25 ;//declaration of variable with type byte and initialize it with 25

int

整数(int)是数字存储的主要数据类型。int存储16位(2字节)值。这产生-32768至32767的范围(最小值为-2^15,最大值为(2^15)-1)。

int的大小因板而异。例如,在Arduino Due中,int存储32位(4字节)值。这产生-2147483648至2147483647的范围(最小值-2^31和最大值(2^31)-1)。

例子

int counter = 32 ;// declaration of variable with type int and initialize it with 32

Unsigned int

unsigned int(无符号整数)与int相同,存储2字节。然而,它们只存储正值,产生0到65535(2^16)-1的有效范围。Due存储4字节(32位)值,范围从0到4294967295(2^32-1)。

例子

Unsigned int counter = 60 ; // declaration of variable with    type unsigned int and initialize it with 60

Word

在Uno和其他基于ATMEGA的板上,一个word存储一个16位无符号数。在Due和Zero上,它存储一个32位无符号数。

例子

word w = 1000 ;//declaration of variable with type word and initialize it with 1000

Long

Long变量是用于数字存储的扩展大小变量,存储32位(4字节),从-2147483648到2147483647。

例子

Long velocity = 102346 ;//declaration of variable with type Long and initialize it with 102346

unsigned long

unsigned long变量是用于数字存储的扩展大小变量,并存储32位(4字节)。与标准的long不同,unsigned long不会存储负数,它们的范围为0到4294967295(2^32-1)。

例子

Unsigned Long velocity = 101006 ;// declaration of variable with    type Unsigned Long and initialize it with 101006

short

short是16位数据类型。在所有Arduinos(基于ATMega和ARM)上,一个short存储一个16位(2字节)值。这产生-32768至32767的范围(最小值为-2^15,最大值为(2^15)-1)。

例子

short val = 13 ;//declaration of variable with type short and initialize it with 13

float

浮点数的数据类型是具有小数点的数字。浮点数通常用于近似模拟值和连续值,因为它们的分辨率高于整数。

浮点数可以大到3.4028235E+38,也可以低到-3.4028235E+38。它们被存储为32位(4字节)信息。

例子

float num = 1.352;//declaration of variable with type float and initialize it with 1.352

double

在Uno和其他基于ATMEGA的板上,双精度浮点数占用四个字节。也就是说,double实现与float完全相同,精度没有增益。在Arduino Due上,double具有8字节(64位)精度。

例子

double num = 45.352 ;// declaration of variable with type double and initialize it with 45.352


在我们开始解释变量类型之前,我们需要确定一个非常重要的主题,称为变量范围

什么是变量范围?

Arduino使用的C语言中的变量具有名为scope(范围)的属性。scope是程序的一个区域,有三个地方可以声明变量。它们是:

  • 在函数或代码块内部,称为局部变量
  • 在函数参数的定义中,称为形式参数
  • 在所有函数之外,称为全局变量

局部变量

在函数或代码块中声明的变量是局部变量。它们只能由该函数或代码块中的语句使用。局部变量不能在它们自己之外运行。以下是使用局部变量的示例:

Void setup () {}Void loop () {   int x , y ;   int z ; Local variable declaration   x = 0;   y = 0; actual initialization   z = 10;}

全局变量

全局变量在所有函数之外定义,通常位于程序的顶部。全局变量将在程序的整个生命周期中保持其价值。

全局变量可以被任何函数访问。也就是说,一个全局变量可以在整个程序中声明后使用。

以下示例使用全局变量和局部变量:

Int T , S ;float c = 0 ; Global variable declarationVoid setup () {}Void loop () {   int x , y ;   int z ; Local variable declaration   x = 0;   y = 0; actual initialization   z = 10;}


运算符是一个符号,它告诉编译器执行特定的数学或逻辑函数。C语言具有丰富的内置运算符,并提供以下类型的运算符:

  • Arithmetic Operators 算术运算符
  • Comparison Operators 比较运算符
  • Boolean Operators 布尔运算符
  • Bitwise Operators 位运算符
  • Compound Operators 复合运算符

算术运算符

假设变量A为10,变量B为20,则:

示例

运算符名称运算符简写描述例子
赋值运算符
=将等号右侧的值存储在等号左边的变量中。A = B
加号+两个操作数相加A + B将得出30
减号-从第一个操作数中减去第二个操作数A - B将得出-10
乘号*将两个操作数相乘A * B将得出200
除号/用分母除分子B / A将得出2
模数%模数运算符和整数除后的余数B % A将得出0


比较运算符

假设变量A为10,变量B为20,则:

示例

运算符名称运算符简写
描述例子
等于==检查两个操作数的值是否相等,如果相等,则条件为真(true)。(A == B)不为真
不等于!=检查两个操作数的值是否相等,如果值不相等,则条件为真。(A != B)为真
小于<检查左操作数的值是否小于右操作数的值,如果是,则条件为真。(A < B)为真
大于>检查左操作数的值是否大于右操作数的值,如果是,则条件为真。(A > B)不为真
小于或等于<=检查左操作数的值是否小于或等于右操作数的值,如果是,则条件为真。(A <= B)为真
大于或等于>=检查左操作数的值是否大于或等于右操作数的值,如果是,则条件为真。(A >= B)不为真


布尔运算符

假设变量A为10,变量B为20,则:

示例

运算符名称
运算符简写
描述例子
and(与)&&称为逻辑运算符与。如果两个操作数都是非零,那么条件为真。(A && B)为真
or(或)||称为逻辑运算符或。如果两个操作数中的任何一个是非零,则条件为真。(A || B)为真
not(非)!称为逻辑运算符非。用于反转其操作数的逻辑状态。如果条件为真,则逻辑运算符非将为假。!(A && B)为假


位运算符

假设变量A为60,变量B为13,则:

示例

运算符名称
运算符简写
描述例子
and(与)&如果同时存在于两个操作数中,二进制AND运算符复制一位到结果中。(A & B)将得出12,即0000 1100
or(或)|如果存在于任一操作数中,二进制OR运算符复制一位到结果中。(A | B)将得出61,即0011 1101
xor(异或)^如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制XOR运算符复制一位到结果中。(A ^ B)将得出49,即0011 0001
not(非)~二进制NOT运算符是一元运算符,具有"翻转"位效果。(〜A)将得出-60,即1100 0011
shift left(左移)
<<二进制左移运算符。左操作数的值向左移动右操作数指定的位数A<< 2将得出240,即1111 0000
shift right(右移)
>>二进制右移运算符。左操作数的值向右移动右操作数指定的位数A>> 2将得出15,即0000 1111


复合运算符

假设变量A为10,变量B为20,则:

示例

运算符名称
运算符简写
描述例子
自增++自增运算符,将整数值增加1A++ 将得出11
自减--自减运算符,将整数值减1A-- 将得出9
复合加
+=加且赋值运算符。把右边操作数加上左边操作数的结果赋值给左边操作数。B += A 等效于 B = B + A
复合减
-=减且赋值运算符。把左边操作数减去右边操作数的结果赋值给左边操作数。B -= A等效于B = B - A
复合乘
*=乘且赋值运算符。把右边操作数乘以左边操作数的结果赋值给左边操作数。B *= A等价于B = B * A
复合除
/=除且赋值运算符。把左边操作数除以右边操作数的结果赋值给左边操作数。B /= A等效于B = B / A
复合模数
%=求模且赋值运算符。 求两个操作数的模赋值给左边操作数B %= A等效于B = B % A
复合按位或|=按位或且赋值运算符A |= 2与A = A | 2相同
复合按位与
&=按位与且赋值运算符A &= 2与A = A & 2相同

判断结构要求程序员指定要由程序评估或测试的一个或多个条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。

以下是大多数编程语言中典型的判断结构的一般形式:


流程图


控制语句是源代码中控制程序执行流程的元素。它们是:

序号控制语句和描述
1

If 语句

它采用括号中的表达式,后面跟随语句或语句块。如果表达式为真,则执行语句或语句块,否则跳过这些语句。

2

If … else 语句

一个 if 语句后面可以跟随一个可选的else语句,当表达式为false时执行。

3

If … else if … else 语句

if 语句后面可以跟随一个可选的 else if ... else 语句,其对于测试各种条件非常有用。

4

switch case 语句

类似于if语句, switch ... case 通过允许程序员指定应在各种条件下执行的不同代码来控制程序的流程。

5

条件运算符 ? :

条件运算符? :是C语言中唯一的三元运算符。


编程语言提供了各种控制结构,允许更复杂的执行路径。

循环语句允许我们多次执行一个语句或一组语句,以下是大多数编程语言中循环语句的一般形式:

流程图


C语言提供以下类型的循环来处理循环需求。

序号循环及描述
1

while循环

while循环将会连续、无限循环,直到括号()内的表达式变为false。必须用一些东西改变被测试的变量,否则while循环永远不会退出。

2

do…while循环

do ... while循环类似于while循环。在while循环中,循环连续条件在循环开始时测试,然后再执行循环体。

3

for循环

 for循环执行语句预定的次数。循环的控制表达式在for循环括号内完全的初始化,测试和操作。

4

嵌套循环

C语言允许你在另一个循环内使用一个循环。下面的例子说明了这个概念。

5

无限循环

它是没有终止条件的循环,因此循环变为无限。


函数允许在代码段中构造程序来执行单独的任务。创建函数的典型情况是在程序需要多次执行相同的动作时。

将代码片段标准化为函数具有几个优点:

  • 函数帮助程序员保持组织性。通常有助于概念化程序。

  • 函数将一个动作编码在一个地方,以便函数只需要考虑一次和调试一次。

  • 如果代码需要更改,这也减少了修改错误的几率。

  • 由于代码段被多次重复使用,函数使整个草图更小更紧凑。

  • 通过将代码模块化以令其在其他程序中重复使用变得更容易,通过使用函数使得代码更具可读性。

在Arduino草图或程序中有两个必需的函数,即setup()和loop()。其他函数必须在这两个函数的括号之外创建。

定义函数的最常用的语法是:


定义函数

函数声明

函数在循环函数之上或之下的任何其他函数之外声明。

我们可以用两种不同的方式声明函数:

第一种方法是在循环函数上面写入被称为函数原型的函数的一部分,它包括:

  • 函数返回类型
  • 函数名称
  • 函数参数类型,不需要写参数名称

函数原型后面必须加上分号(;)。


以下示例为使用第一种方法的函数声明的示范。

例子

int sum_func (int x, int y) // function declaration {   int z = 0;   z = x+y ;   return z; // return the value}void setup () {   Statements // group of statements}Void loop () {   int result = 0 ;   result = Sum_func (5,6) ; // function call}


第二种方法,称为函数定义或声明,必须在循环函数的下面声明,它包括:

  • 函数返回类型
  • 函数名称
  • 函数参数类型,这里必须添加参数名称
  • 函数体(调用函数时执行的函数内部的语句)

以下示例演示了使用第二种方法的函数声明。

例子

int sum_func (int , int ) ; // function prototypevoid setup () {   Statements // group of statements}Void loop () {   int result = 0 ;   result = Sum_func (5,6) ; // function call}int sum_func (int x, int y) // function declaration {   int z = 0;   z = x+y ;   return z; // return the value}

第二种方法只是在循环函数下面声明函数。


字符串用于存储文本。它们可用在LCD或Arduino IDE串口监视器窗口中显示文本。字符串也可用于存储用户输入。例如,用户在连接到Arduino的键盘上键入的字符。

在Arduino编程中有两种类型的字符串:

  • 字符数组,与C编程中使用的字符串相同。
  • Arduino字符串,它允许我们在草图中使用字符串对象。

在本章中,我们将学习Arduino草图中的字符串,对象和字符串的使用。在本章末尾,你将学习在草图中使用哪种类型的字符串。

字符串字符数组

我们要学习的第一种类型的字符串是 char 类型的一系列字符。在前面的章节中,我们学习了一个数组是什么:存储器中存储的相同类型的变量的连续序列。一个字符串是一个char变量的数组。

字符串是一个特殊的数组,在字符串的末尾有一个额外的元素,其值总是为0(零)。这被称为“空终止字符串”。

字符串字符数组示例

此示例将显示如何创建字符串并将其打印到串口监视器窗口。

void setup() {   char my_str[6]; // an array big enough for a 5 character string   Serial.begin(9600);   my_str[0] = 'H'; // the string consists of 5 characters   my_str[1] = 'e';   my_str[2] = 'l';   my_str[3] = 'l';   my_str[4] = 'o';   my_str[5] = 0; // 6th array element is a null terminator   Serial.println(my_str);}void loop() { }

以下示例显示了字符串由什么组成。一个具有可打印字符的字符数组和0作为数组的最后一个元素,表示这是字符串结束的位置。通过使用 Serial.println()并传递字符串的名称,可以将字符串打印到Arduino IDE串口监视器窗口。

同样的例子可以用更方便的方式编写,如下所示:

示例

void setup() {   char my_str[] = "Hello";   Serial.begin(9600);   Serial.println(my_str);}void loop() {}

在这个草图中,编译器计算字符串数组的大小,并自动使用空值0终止字符串。一个长度为六个元素长,由五个字符后跟一个零组成的数组,其创建方式与上一个草图完全相同。

操作字符串数组

我们可以在草图中更改字符串数组,如下图所示。

例子

void setup() {   char like[] = "I like coffee and cake"; // create a string   Serial.begin(9600);   // (1) print the string   Serial.println(like);   // (2) delete part of the string   like[13] = 0;   Serial.println(like);   // (3) substitute a word into the string   like[13] = ' '; // replace the null terminator with a space   like[18] = 't'; // insert the new word   like[19] = 'e';   like[20] = 'a';   like[21] = 0; // terminate the string   Serial.println(like);}void loop() {}

结果

I like coffee and cakeI like coffeeI like coffee and tea

以上草图按以下方式工作。

(1)创建和打印字符串

在上面给出的草图中,创建了一个新的字符串,然后打印出来显示在串口监视器窗口中。

(2)缩短字符串

通过用空终止0替换字符串中的第14个字符来缩短字符串。这是从0开始计算的字符串数组中的13号元素。

打印字符串时,所有字符都打印到新的空终止0。其他字符不消失;它们仍然存在于内存中,并且字符串数组仍然是相同的大小。唯一的区别是任何使用字符串的函数只能看到第一个空终止符前的字符串。

(3)更改字符串中的单词

最后,草图用“tea”代替“cake”一词。它首先必须用空格替换空终止符,如[13],以便将字符串恢复为原来的格式。

新字符用单词“tea”覆盖单词“cake”的“cak”。这是通过覆盖单个字符来完成的。“cake”的“e”被替换为新的空终止字符。结果是字符串实际上终止于两个空字符,即字符串末尾的原始字符,以及替换“cake”中的“e”的新字符。这在打印新字符串时没有区别,因为打印字符串的函数在遇到第一个空终止字符时将停止打印字符串字符。

操作字符串数组的函数

上一个草图通过访问字符串中的单个字符,以手动方式操作字符串。为了更方便操作字符串数组,你可以编写自己的函数来执行,也可以使用 C 语言库中的一些字符串函数。

下面显示了操作字符串数组的列表函数。

下一个草图使用了一些C字符串函数。

例子

void setup() {   char str[] = "This is my string"; // create a string   char out_str[40]; // output from string functions placed here   int num; // general purpose integer   Serial.begin(9600);   // (1) print the string   Serial.println(str);   // (2) get the length of the string (excludes null terminator)   num = strlen(str);   Serial.print("String length is: ");   Serial.println(num);   // (3) get the length of the array (includes null terminator)   num = sizeof(str); // sizeof() is not a C string function   Serial.print("Size of the array: ");   Serial.println(num);   // (4) copy a string   strcpy(out_str, str);   Serial.println(out_str);   // (5) add a string to the end of a string (append)   strcat(out_str, " sketch.");   Serial.println(out_str);   num = strlen(out_str);   Serial.print("String length is: ");   Serial.println(num);   num = sizeof(out_str);   Serial.print("Size of the array out_str[]: ");   Serial.println(num);}void loop() {}

结果

This is my stringString length is: 17Size of the array: 18This is my stringThis is my string sketch.String length is: 25Size of the array out_str[]: 40

以上草图按以下方式工作。

(1)打印字符串

最新创建的字符串将打印到串口监视器窗口,如之前的草图所完成的。

(2)获取字符串的长度

strlen()函数用于获取字符串的长度。字符串的长度仅对于可打印字符,不包括空终止符。

该字符串包含17个字符,因此我们在串口监视器窗口中看到17个字符。

(3)获取数组的长度

运算符sizeof()用于获取包含字符串的数组的长度。长度包括空终止符,因此长度比字符串的长度多1。

sizeof()看起来像一个函数,但技术上是一个运算符。它不是C字符串库的一部分,但在草图中用于显示数组大小和字符串大小(或字符串长度)之间的差异。

(4)复制字符串

strcpy()函数用于将str[]字符串复制到out_num[]数组。strcpy()函数将传递给它的第二个字符串复制到第一个字符串中。现在,字符串的副本存在于out_num[]数组中,但只占用了数组的18个元素,因此在数组中仍然有22个空闲的char元素。这些空闲元素在内存中的字符串的后面可以找到。

将字符串复制到数组中,以便我们在数组中有一些额外的空间用于草图的下一部分,即在字符串的末尾添加一个字符串。

(5)将字符串附加到字符串(连接)

草图将一个字符串加到另一个字符串,这称为串联。这是使用strcat()函数完成的。strcat()函数将传递给它的第二个字符串放到传递给它的第一个字符串的末尾。

串联后,打印字符串的长度以显示新的字符串长度。然后打印数组的长度,以显示在40个元素长的数组中有一个25个字符长度的字符串。

请记住,25个字符长度的字符串实际上占用了数组的26个字符,因为还有空终止0。

数组边界

使用字符串和数组时,在字符串或数组的边界内工作是非常重要的。在示例草图中,创建了一个长度为40个字符的数组,以分配可用于操作字符串的内存。

如果数组太小,而我们尝试复制比数组大的字符串,那么字符串将复制到超出数组的末尾。超出数组末尾的内存可能包含草图中使用的其他重要数据,然而它们将被字符串覆盖。如果超出字符串末尾的内存超出范围,则可能会导致草图崩溃或导致意外行为。

在Arduino编程中使用的第二种类型的字符串是字符串对象。

什么是对象?

对象是一个包含数据和函数的构造。字符串对象可以像变量一样被创建并分配一个值或字符串。字符串对象包含函数(在面向对象编程(OOP)中称为“方法”),它们对字符串对象中包含的字符串数据进行操作。

下面的草图和解释将清楚说明对象是什么,以及如何使用字符串对象。

例子

void setup() {    String my_str = "This is my string.";   Serial.begin(9600);   // (1) print the string   Serial.println(my_str);   // (2) change the string to upper-case   my_str.toUpperCase();   Serial.println(my_str);   // (3) overwrite the string   my_str = "My new string.";   Serial.println(my_str);   // (4) replace a word in the string   my_str.replace("string", "Arduino sketch");   Serial.println(my_str);   // (5) get the length of the string   Serial.print("String length is: ");   Serial.println(my_str.length());}void loop() { }

结果

This is my string.THIS IS MY STRING.My new string.My new Arduino sketch.String length is: 22

创建字符串对象,并在草图顶部分配一个值(或字符串)。

String my_str = "This is my string." ;

这将创建一个名为 my_str 的String对象,并为其赋值“This is my string.”。

这可以与创建变量并为其分配一个值(如整数)相比较:

int my_var = 102;

以上草图以下列方式工作。

(1)打印字符串

字符串可以像字符数组字符串一样打印到串口监视器窗口。

(2)将字符串转换为大写

创建的字符串对象my_str,有多个可以在其上操作的函数或方法。这些方法通过使用对象名称后跟点运算符(.),然后使用函数的名称来调用的。

my_str.toUpperCase();

toUpperCase()函数对包含在类型为String的 my_str 对象中的字符串进行操作,并将对象包含的字符串数据(或文本)转换为大写字符。String类包含的函数列表可以在Arduino字符串参考中找到。从技术上讲,String被称为一个类,用于创建String对象。

(3)覆盖字符串

赋值运算符用于将新字符串分配给 my_str 对象以替换旧字符串。

my_str = "My new string." ;

赋值运算符不能用于字符数组字符串,仅适用于String对象。

(4)替换字符串中的单词

replace()函数用于将传递给它的第二个字符串替换传递给它的第一个字符串。replace()是构建在String类中的另一个函数,因此可以在String对象my_str上使用。

(5)获取字符串的长度

通过使用length()可以很容易地获取字符串的长度。在示例草图中,由length()返回的结果直接传递到Serial.println(),而不使用中间变量。

何时使用字符串对象

字符串对象比字符串字符数组更容易使用。该对象具有内置函数,可以对字符串执行多个操作。

使用String对象的主要缺点是,它使用了大量的内存,可能会很快耗尽Arduino的RAM内存,这可能会导致Arduino挂起,崩溃或行为意外。如果Arduino上的草图很小并限制了对象的使用,那么应该没有问题。

字符数组字符串更难使用,你可能需要编写自己的函数来操作这些类型的字符串。其优点是,你可以控制字符串数组的大小,因此你可以保持数组很小来节省内存。

你需要确保不要超出字符串数组边界的范围,而String对象没有这个问题,只要有足够的内存供它操作,就会照顾到你的字符串边界。在内存不足时,String对象可以尝试在不存在的内存中写入,但绝不会在超出其操作的字符串末尾的地方写入。

在哪里使用字符串

在本章中,我们学习了字符串,它们在内存中的行为及其操作。

字符串的用法将在课程的下一部分进行介绍,届时我们将学习如何从串口监视器窗口获取用户输入并将输入保存为字符串。

Arduino提供四种不同的时间操作函数。它们是:

序号函数和描述
1

delay() 函数

delay()函数的工作方式非常简单。它接受单个整数(或数字)参数。此数字表示时间(以毫秒为单位)。

2

delayMicroseconds() 函数

delayMicroseconds()函数接受单个整数(或数字)参数。一毫秒内有一千微秒,一秒内有一百万微秒。

3

millis() 函数

此函数用于返回Arduino板开始运行当前程序时的毫秒数。

4

micros() 函数

micros()函数返回Arduino板开始运行当前程序时的微秒数。该数字在大约70分钟后溢出,即回到零。


数组是连续的一组相同类型的内存位置。要引用数组中的特定位置或元素,我们指定数组的名称和数组中特定元素的位置编号。

下图给出了一个名为C的整数数组,它包含11个元素。通过给出数组名称,后面跟特定元素的位置编号:方括号([]),你可以引用这些元素中的任何一个。位置编号更正式地称为下标或索引(该数字指定从数组开始的元素数)。第一个元素具有下标0(零),有时称为零元素。

因此,数组C的元素是C[0],C[1],C[2]等等。数组C中的最高下标是10,其比数组中的元素数少1。数组名遵循与其他变量名相同的约定。


Elements of Array


下标必须是整数或整数表达式(使用任何整数类型)。如果程序使用表达式作为下标,则程序评估表达式以确定下标。例如,如果我们假设变量a等于5,变量b等于6,那么语句将数组元素C[11]加2。

下标数组名是一个左值,它可以在赋值的左侧使用,就像非数组变量名一样。

让我们更仔细地检查给定图中的数组C。整个数组的名称是C。它的11个元素被称为C[0]到C[10]。C[0]的值为-45,C[1]的值为6,C[2]的值为0,C[7]的值为62,C[10]的值为78。

要打印数组C的前三个元素中包含的值的总和,我们将写:

Serial.print (C[ 0 ] + C[ 1 ] + C[ 2 ] );

要将C[6]的值除以2并将结果赋值给变量x,我们将写:

x = C[ 6 ] / 2;

声明数组

数组占用内存中的空间。要指定元素的类型和数组所需的元素数量,请使用以下形式的声明:

type arrayName [ arraySize ] ;

编译器保留适当的内存量(回想一下,保留内存的声明更恰当地被称为定义)。arraySize必须是大于零的整数常量。例如,要告诉编译器为整数数组C保留11个元素,请使用声明:

int C[ 12 ]; // C is an array of 12 integers

数组可以声明为包含任何非引用数据类型的值。例如,可以使用字符串类型的数组来存储字符串。

使用数组的示例

本节提供了许多示例来演示如何声明,初始化以及操作数组。

示例1:声明数组并使用循环来初始化数组的元素

程序声明一个10元素的整数数组 n 。行a-b使用 For 语句将数组元素初始化为零。与其他自动变量一样,自动数组不会隐式初始化为零。第一个输出语句(行c)显示在后续for语句(行d-e)中打印的列的列标题,以表格格式打印数组。

示例

int n[ 10 ] ; // n is an array of 10 integersvoid setup () {    Serial.begin(9600); //串口初始化 }void loop () {   for ( int i = 0; i < 10; ++i ){  // initialize elements of array n to 0      n[ i ] = 0; // set element at location i to 0      Serial.print (i) ;      Serial.print (‘
’) ;   }   for ( int j = 0; j < 10; ++j ){  // output each array element's value      Serial.print (n[j]) ;      Serial.print (‘
’) ;   } }

结果 - 它会产生以下结果:

元件

0

1

2

3

4

5

6

7

8

9

0

0

0

0

0

0

0

0

0

0


示例2:使用初始化器列表在声明中初始化数组

数组元素也可以在数组声明中初始化,通过在数组名后面跟随等号和一个用大括号及逗号分隔的初始化器列表。程序使用初始化器列表来初始化一个具有10个值的整数数组(行a),并以表格格式(行b-c)打印数组。

示例

// n is an array of 10 integersint n[ 10 ] = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37 } ;

void setup () {

    Serial.begin(9600); //串口初始化 

}

void loop () { for ( int i = 0; i < 10; ++i ){ // initialize elements of array n to 0 Serial.print (i) ; Serial.print (‘ ’) ; } for ( int j = 0; j < 10; ++j ){ // output each array element's value Serial.print (n[j]) ; Serial.print (‘ ’) ; } }

结果 - 它会产生以下结果:

元件

0

1

2

3

4

5

6

7

8

9

32

27

64

18

95

14

90

70

60

37


示例3:对数组的元素求和

通常,数组的元素表示要在计算中使用的一系列值。例如,如果数组的元素表示考试成绩,教授可能希望将数组的元素进行加总,并使用该总和来计算班级考试的平均成绩。程序将包含在10元素整数数组 a 中的值进行求和。

示例

const int arraySize = 10; // constant variable indicating size of arrayint a[ arraySize ] = { 87, 68, 94, 100, 83, 78, 85, 91, 76, 87 };int total = 0;

void setup () {

    Serial.begin(9600); //串口初始化 

}

void loop () { // sum contents of array a for ( int i = 0; i < arraySize; ++i ) total += a[ i ]; Serial.print (“Total of array elements : ") ; Serial.print(total) ;}

结果 - 它会产生以下结果:

Total of array elements: 849

数组对Arduino很重要,应该需要更多的关注。以下是学习Arduino应该清楚的与数组相关的重要概念:

序号概念和描述
1将数组传递给函数

要将数组参数传递给函数,请指定没有任何括号的数组的名称。

2多维数组

具有两个维度(即,下标)的数组通常表示由排列在行和列中的信息组成的值的表格。



Arduino板上的引脚可以配置为输入或输出。我们将在这些模式下解释引脚的功能。重要的是要注意,大多数Arduino模拟引脚可以按照与数字引脚完全相同的方式进行配置和使用。

引脚配置为INPUT

Arduino引脚默认配置为输入,因此在使用它们作为输入时,不需要使用 pinMode()显式声明为输入。以这种方式配置的引脚被称为处于高阻抗状态。输入引脚对采样电路的要求非常小,相当于引脚前面的100兆欧的串联电阻。

这意味着将输入引脚从一个状态切换到另一个状态所需的电流非常小。这使得引脚可用于诸如实现电容式触摸传感器或读取LED作为光电二极管的任务。

被配置为pinMode(pin,INPUT)的引脚(没有任何东西连接到它们,或者有连接到它们而未连接到其他电路的导线),报告引脚状态看似随机的变化,从环境中拾取电子噪音或电容耦合附近引脚的状态。

上拉电阻

如果没有输入,上拉电阻通常用于将输入引脚引导到已知状态。这可以通过在输入端添加上拉电阻(到5V)或下拉电阻(接地电阻)来实现。10K电阻对于上拉或下拉电阻来说是一个很好的值。

使用内置上拉电阻,引脚配置为输入

Atmega芯片内置了2万个上拉电阻,可通过软件访问。通过将pinMode()设置为INPUT_PULLUP可访问这些内置上拉电阻。这有效地反转了INPUT模式的行为,其中HIGH表示传感器关闭,LOW表示传感器开启。此上拉的值取决于所使用的微控制器。在大多数基于AVR的板上,该值保证在20kΩ和50kΩ之间。在Arduino Due上,它介于50kΩ和150kΩ之间。有关确切的值,请参考板上微控制器的数据表。

当将传感器连接到配置为INPUT_PULLUP的引脚时,另一端应接地。在简单开关的情况下,这会导致当开关打开时引脚变为高电平,当按下开关时引脚为低电平。上拉电阻提供足够的电流来点亮连接到被配置为输入的引脚的LED。如果项目中的LED似乎在工作,但很昏暗,这可能是发生了什么。

控制引脚是高电平还是低电平的相同寄存器(内部芯片存储器单元)控制上拉电阻。因此,当引脚处于INPUT模式时,配置为有上拉电阻导通的引脚将被开启;如果引脚通过pinMode()切换到OUTPUT模式,引脚将配置为高电平。这也适用于另一个方向,如果通过pinMode()切换到输入,则处于高电平状态的输出引脚将设置上拉电阻。

示例

pinMode(3,INPUT) ; // set pin to input without using built in pull up resistorpinMode(5,INPUT_PULLUP) ; // set pin to input using built in pull up resistor

引脚配置为OUTPUT

通过pinMode()配置为OUTPUT的引脚被认为处于低阻抗状态。这意味着它们可以向其他电路提供大量的电流。Atmega引脚可以向其他器件/电路提供(提供正电流)或吸收(提供负电流)高达40mA(毫安)的电流。这是足以点亮LED或者运行许多传感器的电流(不要忘记串联电阻),但不足以运行继电器,螺线管或电机。

试图从输出引脚运行高电流器件,可能损坏或破坏引脚中的输出晶体管,或损坏整个Atmega芯片。通常,这会导致微控制器中出现“死”引脚,但是剩余的芯片仍然可以正常工作。因此,最好通过470Ω或1k电阻将OUTPUT引脚连接到其他器件,除非特定应用需要从引脚吸取最大电流。

pinMode()函数

pinMode()函数用于将特定引脚配置为输入或输出。可以使用INPUT_PULLUP模式启用内部上拉电阻。此外,INPUT模式显式禁止内部上拉。

pinMode()函数语法

Void setup () {   pinMode (pin , mode);}
  • pin - 你希望设置模式的引脚的编号

  • mode - INPUT,OUTPUT或INPUT_PULLUP。

示例

int button = 5 ; // button connected to pin 5int LED = 6; // LED connected to pin 6void setup () {   pinMode(button , INPUT_PULLUP);    // set the digital pin as input with pull-up resistor   pinMode(button , OUTPUT); // set the digital pin as output}void setup () {   If (digitalRead(button ) == LOW) // if button pressed {      digitalWrite(LED,HIGH); // turn on led      delay(500); // delay for 500 ms      digitalWrite(LED,LOW); // turn off led      delay(500); // delay for 500 ms   }}

digitalWrite()函数

digitalWrite()函数用于向数字引脚写入HIGH或LOW值。如果该引脚已通过pinMode()配置为OUTPUT,则其电压将被设置为相应的值:HIGH为5V(或3.3V在3.3V板上),LOW为0V(接地)。如果引脚配置为INPUT,则digitalWrite()将启用(HIGH)或禁止(LOW)输入引脚的内部上拉。建议将pinMode()设置为INPUT_PULLUP,以启用 内部上拉电阻。

如果不将pinMode()设置为OUTPUT,而将LED连接到引脚,则在调用digitalWrite(HIGH)时,LED可能会变暗。在没有明确设置pinMode()时,digitalWrite()将启用内部上拉电阻,这就像一个大的限流电阻。

digitalWrite()函数语法

Void loop() {   digitalWrite (pin ,value);}
  • pin - 你希望设置模式的引脚的编号

  • value - HIGH或LOW。

示例

int LED = 6; // LED connected to pin 6void setup () {   pinMode(LED, OUTPUT); // set the digital pin as output}void setup() {    digitalWrite(LED,HIGH); // turn on led   delay(500); // delay for 500 ms   digitalWrite(LED,LOW); // turn off led   delay(500); // delay for 500 ms}

analogRead()函数

Arduino能够检测是否有一个电压施加到其引脚,并通过digitalRead()函数报告。开/关传感器(检测物体的存在)和模拟传感器之间存在一个差异,模拟传感器的值连续变化。为了读取这种类型的传感器,我们需要一个不同类型的引脚。

在Arduino板的右下角,你会看到6个标记为“Analog In”的引脚。这些特殊引脚不仅可以告知是否有电压施加给它们,还可以告知它们的值。通过使用analogRead()函数,我们可以读取施加到其中一个引脚的电压。

此函数返回0到1023之间的数字,表示0到5伏特之间的电压。例如,如果施加到编号0的引脚的电压为2.5V,则analogRead(0)返回512。

analogRead()函数语法

analogRead(pin);
  • pin - 要读取的模拟输入引脚的编号(大多数电路板上为0至5,Mini和Nano上为0至7,Mega上为0至15)

示例

int analogPin = 3;//potentiometer wiper (middle terminal)    // connected to analog pin 3 int val = 0; // variable to store the value readvoid setup() {   Serial.begin(9600); // setup serial} void loop() {   val = analogRead(analogPin); // read the input pin   Serial.println(val); // debug value}


在本章中,我们将学习一些高级的输入和输出函数。

analogReference()函数

配置用于模拟输入的参考电压(即用作输入范围顶部的值)。选项是:

  • DEFAULT - 5伏(5V Arduino板)或3.3伏(3.3V Arduino板)的默认模拟参考值

  • INTERNAL - 内置参考,在ATmega168或ATmega328上等于1.1伏特,在ATmega8上等于2.56伏特(不适用于Arduino Mega)

  • INTERNAL1V1 - 内置1.1V参考(仅限Arduino Mega)

  • INTERNAL2V56 - 内置2.56V参考(仅限Arduino Mega)

  • EXTERNAL - 施加到AREF引脚的电压(仅限0到5V)用作参考

analogReference()函数语法

analogReference (type);

type - 可以使用以下任何类型(DEFAULT,INTERNAL,INTERNAL1V1,INTERNAL2V56,EXTERNAL)

对AREF引脚的外部参考电压,请勿使用小于0V或大于5V的任何值。如果在AREF引脚上使用外部参考,则必须在调用 analogRead()函数之前将模拟参考设置为EXTERNAL。否则,将短路有效参考电压(内部产生的)和AREF引脚,可能会损坏Arduino板上的微控制器。


analogReference()函数


或者,你可以通过5K电阻将外部参考电压连接到AREF引脚,从而允许在外部和内部参考电压之间切换。

注意,电阻将改变用作参考的电压,因为AREF引脚上有一个内部32K电阻。两者用作分压器。例如,通过电阻器施加的2.5V将在AREF引脚处产生2.5*32/(32+5)=〜2.2V电压。

示例

int analogPin = 3;// potentiometer wiper (middle terminal) connected to analog pin 3 int val = 0; // variable to store the read valuevoid setup() {   Serial.begin(9600); // setup serial   analogReference(EXTERNAL); // the voltage applied to the AREF pin (0 to 5V only)       // is used as the reference.}void loop() {   val = analogRead(analogPin); // read the input pin   Serial.println(val); // debug value}


所有数据都以字符形式输入计算机,包括字母,数字和各种特殊符号。在本章节中,我们讨论C++检查和操作单个字符的功能。

字符处理库包括几个函数,执行有用的测试和字符数据的操作。每个函数接收一个字符,表示为int或EOF作为参数。字符通常作为整数操作。

记住,EOF通常具有值-1,而一些硬件架构不允许负值存储在char变量中。因此,字符处理函数将字符作为整数来操作。

下表总结了字符处理库的函数。使用字符处理库中的函数时,请包含<cctype>标题。

序号原型和描述
1

int isdigit(int c)

如果c是数字,则返回1,否则返回0。

2

int isalpha(int c)

如果c是字母,则返回1,否则返回0。

3

int isalnum(int c)

如果c是数字或字母,则返回1,否则返回0。

4

int isxdigit(int c)

如果c是十六进制数字字符,则返回1,否则返回0。

5

int islower(int c)

如果c是小写字母,则返回1,否则返回0。

6

int isupper(int c)

如果c是大写字母,则返回1;否则返回0。

7

int isspace(int c)

如果c是空白字符:换行符(' ')、空格符(' ')、换页符('f')、回车符(' ')、水平制表符(' ')或垂直制表符('v'),则返回1,否则返回0。

8

int iscntrl(int c)

如果c是控制字符,如换行符(' ')、换页符('f')、回车符(' ')、水平制表符 (v')、垂直制表符('v')、alert('a')或退格(''),则返回1,否则返回0。

9

int ispunct(int c)

如果c是除空格,数字或字母以外的打印字符,则返回1,否则返回0。

10

int isprint(int c)

如果c是包含空格(' ')的打印字符,则返回1,否则返回0。

11

int isgraph(int c)

如果c是除空格(' ')之外的打印字符,则返回1,否则返回0。

例子

以下示例演示如何使用函数 isdigit,isalpha,isalnum isxdigit 函数 isdigit 确定其参数是否为数字(0-9)。函数 isalpha 确定其参数是大写字母(A-Z)还是小写字母(a-z)。函数 isalnum 确定其参数是大写,小写字母还是数字。函数 isxdigit 确定其参数是否为十六进制数字(A-F,a-f,0-9)。

例1

void setup () {   Serial.begin (9600);   Serial.print ("According to isdigit:
");   Serial.print (isdigit( '8' ) ? "8 is a": "8 is not a");   Serial.print (" digit
" );   Serial.print (isdigit( '8' ) ?"# is a": "# is not a") ;   Serial.print (" digit
");   Serial.print ("
According to isalpha:
" );   Serial.print (isalpha('A' ) ?"A is a": "A is not a");   Serial.print (" letter
");   Serial.print (isalpha('A' ) ?"b is a": "b is not a");   Serial.print (" letter
");   Serial.print (isalpha('A') ?"& is a": "& is not a");   Serial.print (" letter
");   Serial.print (isalpha( 'A' ) ?"4 is a":"4 is not a");   Serial.print (" letter
");   Serial.print ("
According to isalnum:
");   Serial.print (isalnum( 'A' ) ?"A is a" : "A is not a" );   Serial.print (" digit or a letter
" );   Serial.print (isalnum( '8' ) ?"8 is a" : "8 is not a" ) ;   Serial.print (" digit or a letter
");   Serial.print (isalnum( '#' ) ?"# is a" : "# is not a" );   Serial.print (" digit or a letter
");   Serial.print ("
According to isxdigit:
");   Serial.print (isxdigit( 'F' ) ?"F is a" : "F is not a" );   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( 'J' ) ?"J is a" : "J is not a" ) ;   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( '7' ) ?"7 is a" : "7 is not a" ) ;   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( '$' ) ? "$ is a" : "$ is not a" );   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( 'f' ) ? “f is a" : "f is not a");   }void loop () {}

结果

According to isdigit:8 is a digit# is not a digitAccording to isalpha:A is a letterb is a letter& is not a letter4 is not a letterAccording to isalnum:A is a digit or a letter8 is a digit or a letter# is not a digit or a letterAccording to isxdigit:F is a hexadecimal digitJ is not a hexadecimal digit7 is a hexadecimal digit$ is not a hexadecimal digitf is a hexadecimal digit

我们对每个函数使用条件运算符(?:)来确定字符串“is a”或字符串“is not a”是否应该打印在每个测试字符的输出中。例如,行a表示如果“8”是数字,即如果isdigit返回真(非零)值,则打印字符串“8 is a”。如果“8”不是数字(即,如果isdigit返回0),则打印字符串“8 is not a”。

例2

以下示例演示了函数 islower isupper 的使用。函数 islower 确定其参数是否为小写字母(a-z)。函数 isupper 确定其参数是否为大写字母(A-Z)。

int thisChar = 0xA0;void setup () {   Serial.begin (9600);   Serial.print ("According to islower:
") ;   Serial.print (islower( 'p' ) ? "p is a" : "p is not a" );   Serial.print ( " lowercase letter
" );   Serial.print ( islower( 'P') ? "P is a" : "P is not a") ;   Serial.print ("lowercase letter
");   Serial.print (islower( '5' ) ? "5 is a" : "5 is not a" );   Serial.print ( " lowercase letter
" );   Serial.print ( islower( '!' )? "! is a" : "! is not a") ;   Serial.print ("lowercase letter
");   Serial.print ("
According to isupper:
") ;   Serial.print (isupper ( 'D' ) ? "D is a" : "D is not an" );   Serial.print ( " uppercase letter
" );   Serial.print ( isupper ( 'd' )? "d is a" : "d is not an") ;   Serial.print ( " uppercase letter
" );   Serial.print (isupper ( '8' ) ? "8 is a" : "8 is not an" );   Serial.print ( " uppercase letter
" );   Serial.print ( islower( '$' )? "$ is a" : "$ is not an") ;   Serial.print ("uppercase letter
 ");}void setup () {}

结果

According to islower:p is a lowercase letterP is not a lowercase letter5 is not a lowercase letter! is not a lowercase letterAccording to isupper:D is an uppercase letterd is not an uppercase letter8 is not an uppercase letter$ is not an uppercase letter

例3

以下示例演示如何使用函数 isspace,iscntrl,ispunct,isprint isgraph

  • 函数 isspace 确定其参数是否为空白字符,例如空格(' '),换页符('f'),换行符(' '),回车符(' '),水平制表符(' ')或垂直制表符('v')。

  • 函数 iscntrl 确定其参数是否为控制字符,如水平制表符(' '),垂直制表符('v'),换页符('f'),alert('a'),退格符(''),回车符(' ')或换行符(' ')。

  • 函数 ispunct 确定其参数是否是除空格,数字或字母以外的打印字符(例如$,#,(,),[,],{,},;,:或%)。

  • 函数 isprint 确定其参数是否为可以在屏幕上显示的字符(包括空格字符)。

  • 函数 isgraph 测试与isprint相同的字符,但不包括空格字符。

void setup () {   Serial.begin (9600);   Serial.print ( " According to isspace:
Newline ") ;   Serial.print (isspace( '
' )? " is a" : " is not a" );   Serial.print ( " whitespace character
Horizontal tab") ;   Serial.print (isspace( '	' )? " is a" : " is not a" );   Serial.print ( " whitespace character
") ;   Serial.print (isspace('%')? " % is a" : " % is not a" );      Serial.print ( " 
According to iscntrl:
Newline") ;   Serial.print ( iscntrl( '
' )?"is a" : " is not a" ) ;   Serial.print (" control character
");   Serial.print (iscntrl( '$' ) ? " $ is a" : " $ is not a" );   Serial.print (" control character
");   Serial.print ("
According to ispunct:
");   Serial.print (ispunct(';' ) ?"; is a" : "; is not a" ) ;   Serial.print (" punctuation character
");   Serial.print (ispunct('Y' ) ?"Y is a" : "Y is not a" ) ;   Serial.print ("punctuation character
");   Serial.print (ispunct('#' ) ?"# is a" : "# is not a" ) ;   Serial.print ("punctuation character
");   Serial.print ( "
 According to isprint:
");   Serial.print (isprint('$' ) ?"$ is a" : "$ is not a" );   Serial.print (" printing character
Alert ");   Serial.print (isprint('a' ) ?" is a" : " is not a" );   Serial.print (" printing character
Space ");   Serial.print (isprint(' ' ) ?" is a" : " is not a" );   Serial.print (" printing character
");      Serial.print ("
 According to isgraph:
");   Serial.print (isgraph ('Q' ) ?"Q is a" : "Q is not a" );   Serial.print ("printing character other than a space
Space ");   Serial.print (isgraph (' ') ?" is a" : " is not a" );   Serial.print ("printing character other than a space ");}void loop () {}

结果

According to isspace:Newline is a whitespace characterHorizontal tab is a whitespace character% is not a whitespace characterAccording to iscntrl:Newline is a control character$ is not a control characterAccording to ispunct:; is a punctuation characterY is not a punctuation character# is a punctuation characterAccording to isprint:$ is a printing characterAlert is not a printing characterSpace is a printing characterAccording to isgraph:Q is a printing character other than a spaceSpace is not a printing character other than a space


Arduino数学库(math.h)包含了许多用于操作浮点数的有用的数学函数。

库中的宏

以下是在标题math.h中定义的宏:

描述
M_E2.7182818284590452354常数e。
M_LOG2E

1.4426950408889634074

/* log_2 e */

e以2为底的对数。
M_1_PI

0.31830988618379067154

/* 1/pi */

常数1/pi。
M_2_PI

0.63661977236758134308

/* 2/pi */

常数2/pi。
M_2_SQRTPI

1.12837916709551257390

/* 2/sqrt(pi) */

常数2/sqrt(pi)。
M_LN10

2.30258509299404568402

/* log_e 10 */

10的自然对数。
M_LN2

0.69314718055994530942

/* log_e 2 */

2的自然对数。
M_LOG10E

0.43429448190325182765

/* log_10 e */

e以10为底的对数。
M_PI

3.14159265358979323846

/* pi */

常数pi。
M_PI_2

3.3V1.57079632679489661923

/* pi/2 */

常数pi/2。
M_PI_4

0.78539816339744830962

/* pi/4 */

常数pi/4。
M_SQRT1_2

0.70710678118654752440

/* 1/sqrt(2) */

常数1/sqrt(2)。
M_SQRT2

1.41421356237309504880

/* sqrt(2) */

2的平方根。
acosf-acos()函数的别名。
asinf-asin()函数的别名。
atan2f-atan2()函数的别名。
cbrtf-cbrt()函数的别名。
ceilf-ceil()函数的别名。
copysignf-copysign()函数的别名。
coshf-cosh()函数的别名。
expf-exp()函数的别名。
fabsf-fabs()函数的别名。
fdimf-fdim()函数的别名。
floorf-floor()函数的别名。
fmaxf-fmax()函数的别名。
fminf-fmin()函数的别名。
fmodf-fmod()函数的别名。
frexpf-frexp()函数的别名。
hypotf-hypot()函数的别名。
INFINITY-无穷大常量。
isfinitef-isfinite()函数的别名。
isinff-isinf()函数的别名。
isnanf-isnan()函数的别名。
ldexpf-ldexp()函数的别名。
log10f-log10()函数的别名。
logf-log()函数的别名。
lrintf-lrint()函数的别名。
lroundf-lround()函数的别名。

库函数

以下函数在标题 math.h 中定义:

序号库函数和描述
1

double acos (double __x)

acos()函数计算x的反余弦的主值。返回值在[0, pi]弧度的范围内。不在[-1, +1]范围内的参数会发生域错误。

2

double asin (double __x)

asin()函数计算x的反正弦的主值。返回值在[-pi/2, pi/2]弧度的范围内。不在[-1, +1]范围内的参数会发生域错误。

3

double atan (double __x)

atan()函数计算x的反正切的主值。返回值在[-pi/2, pi/2]弧度的范围内。

4

double atan2 (double __y, double __x)

atan2()函数计算y/x的反正切的主值,使用两个参数的符号来确定返回值的象限。返回值在[-pi, +pi]弧度的范围内。

5

double cbrt (double __x)

cbrt()函数返回x的立方根值。

6

double ceil (double __x)

ceil()函数返回大于或等于x的最小整数值,以浮点数表示。

7

static double copysign (double __x, double __y)

copysign()函数返回x,但带有y的符号。即使x或y是NaN或零,他们也可以工作。

8

double cos(double __x)

cos()函数返回x的余弦,以弧度为单位。

9

double cosh (double __x)

cosh()函数返回x的双曲余弦。

10

double exp (double __x)

exp()返回e的x次幂的值。

11

double fabs (double __x)

fabs()函数计算浮点数x的绝对值。

12

double fdim (double __x, double __y)

fdim()函数返回max(x - y, 0)。如果x或y或者两者都是NaN,则返回NaN。

13

double floor (double __x)

floor()函数返回小于或等于x的最大整数值,以浮点数表示。

14

double fma (double __x, double __y, double __z)

fma()函数执行浮点乘加,即运算(x * y) + z,但是中间结果不会四舍五入到目标类型。这有时可以提高计算的精度。

15

double fmax (double __x, double __y)

fmax()函数返回两个值x和y中较大的一个。如果一个参数是NaN,则返回另一个参数。如果两个参数都是NaN,则返回NaN。

16

double fmin (double __x, double __y)

fmin()函数返回两个值x和y中较小的一个。如果一个参数是NaN,则返回另一个参数。如果两个参数都是NaN,则返回NaN。

17

double fmod (double __x, double__y)

fmod()函数返回x / y的余数。

18

double frexp (double __x, int * __pexp)

frexp()函数将浮点数分解为规格化分数和2的整次幂。它将整数存储在pexp指向的int对象中。如果x是一个正常的浮点数,则frexp()函数返回值v,使得v具有区间[1/2, 1)或零的量值,而x等于v乘以2的pexp次幂。如果x是零,那么结果的两个部分都是零。如果x不是有限数字,frexp()将按原样返回x,并通过pexp存储0。

注意 − 这个实现允许一个零指针作为指令来跳过存储指数。

19

double hypot (double __x, double__y)

hypot()函数返回sqrt(x*x + y*y)。这是一个边长为x和y的直角三角形的斜边的长度,或点(x, y)距离原点的距离。使用这个函数而不是直接使用公式是比较明智的,因为误差要小得多。x和y没有下溢。如果结果在范围内,则不会溢出。

20

static int isfinite (double __x)

如果x是有限的,isfinite()函数返回一个非零值:不是正或负无穷,也不是NaN

21

int isinf (double __x)

如果参数x是正无穷大,则函数isinf()返回1;如果x是负无穷大,则返回-1,否则返回0。

注意 − GCC 4.3可以用内联代码替换这个函数,这个代码对两个无穷大返回1值(gcc bug #35509)。

22

int isnan (double __x)

如果参数x表示“非数字”(NaN)对象,则函数isnan()返回1,否则返回0。

23

double ldexp (double __x, int __exp )

ldexp()函数将浮点数乘以2的整数次幂。它返回x乘以2的exp次幂的值。

24

double log (double __x)

log()函数返回参数x的自然对数。

25

double log10(double __x)

log10()函数返回参数x的对数,以10为基数。

26

long lrint (double __x)

lrint()函数将x四舍五入到最近的整数,将中间情况舍入到偶数整数方向(例如,1.5和2.5的值都舍入到2)。这个函数类似于rint()函数,但是它的返回值类型不同,并且有可能溢出。

返回

四舍五入的长整数值。如果x不是有限数字或者溢出,则此实现返回LONG_MIN值(0x80000000)。

27

long lround (double __x)

lround()将函数将x四舍五入到最近的整数,但中间情况不舍入到0(不是到最近的偶数整数)。这个函数类似于round()函数,但是它的返回值的类型是不同的,并且有可能溢出。

返回

四舍五入的长整数值。如果x不是有限数字或者溢出,则此实现返回LONG_MIN值(0x80000000)。

28

double modf (double __x, double * __iptr )

modf()函数将参数x分解为整数部分和小数部分,每个部分都与参数具有相同的符号。它在iptr指向的对象中将整数部分存储为double。

modf()函数返回x的有符号小数部分。

注意 − 这个实现跳过零指针的写入。但是,GCC 4.3可以用内联代码替换这个函数,不允许使用NULL地址来避免存储。

29

float modff (float __x, float * __iptr)

modf()函数的别名。

30

double pow (double __x, double __y)

pow()函数返回x的y次幂。

31

double round (double __x)

round()函数将x四舍五入到最近的整数,但中间情况不舍入到0(不是到最近的偶数整数)。不可能会溢出。

返回

四舍五入的值。如果x是整数或无穷大,则返回x本身。如果x是NaN,则返回NaN

32

int signbit (double __x)

如果x的值设置了符号位,signbit()函数将返回一个非零值。这与“x < 0.0”不同,因为IEEE 754浮点允许零署名。比较“-0.0 < 0.0”是错的,但“signbit (-0.0)”会返回一个非零值。

33

double sin (double __x)

sin()函数返回x的正弦值,以弧度为单位。

34

double sinh (double __x)

sinh()函数返回x的双曲正弦。

35

double sqrt (double __x)

sqrt()函数返回x的非负平方根。

36

double square (double __x)

square()函数返回x * x。

注意 − 此函数不属于C标准定义。

37

double tan (double __x)

tan()函数返回x的正切值,以弧度为单位。

38

double tanh ( double __x)

tanh()函数返回x的双曲正切。

39

double trunc (double __x)

trunc()函数将x四舍五入为最近的整数,不大于绝对值。


例子

以下示例显示如何使用最常用的math.h库函数:

double double__x = 45.45 ;double double__y = 30.20 ;void setup() {   Serial.begin(9600);   Serial.print("cos num = ");   Serial.println (cos (double__x) ); // returns cosine of x   Serial.print("absolute value of num = ");   Serial.println (fabs (double__x) ); // absolute value of a float   Serial.print("floating point modulo = ");   Serial.println (fmod (double__x, double__y)); // floating point modulo   Serial.print("sine of num = ");   Serial.println (sin (double__x) ) ;// returns sine of x   Serial.print("square root of num : ");   Serial.println ( sqrt (double__x) );// returns square root of x   Serial.print("tangent of num : ");   Serial.println ( tan (double__x) ); // returns tangent of x   Serial.print("exponential value of num : ");   Serial.println ( exp (double__x) ); // function returns the exponential value of x.   Serial.print("cos num : ");   Serial.println (atan (double__x) ); // arc tangent of x   Serial.print("tangent of num : ");   Serial.println (atan2 (double__y, double__x) );// arc tangent of y/x   Serial.print("arc tangent of num : ");   Serial.println (log (double__x) ) ; // natural logarithm of x   Serial.print("cos num : ");   Serial.println ( log10 (double__x)); // logarithm of x to base 10.   Serial.print("logarithm of num to base 10 : ");   Serial.println (pow (double__x, double__y) );// x to power of y   Serial.print("power of num : ");   Serial.println (square (double__x)); // square of x}void loop() {}

结果

cos num = 0.10absolute value of num = 45.45floating point modulo =15.25sine of num = 0.99square root of num : 6.74tangent of num : 9.67exponential value of num : ovfcos num : 1.55tangent of num : 0.59arc tangent of num : 3.82cos num : 1.66logarithm of num to base 10 : infpower of num : 2065.70


你需要使用三角几何来计算移动物体的距离或角速度。Arduino提供了传统的三角函数(sin,cos,tan,asin,acos,atan),可以通过编写它们的原型来概括。Math.h包含三角函数的原型。

三角函数的精确语法

double sin(double x); //返回x的正弦值double cos(double y); //返回y的余弦值double tan(double x); //返回x的正切值double acos(double x); //返回x的反余弦数double asin(double x); //返回x的反正弦数double atan(double x); //返回x的反正切数

例子

double sine = sin(2); // 大约 0.90929737091
double cosine = cos(2); // 大约 -0.41614685058
double tangent = tan(2); // 大约 -2.18503975868


Arduino Due是基于Atmel SAM3X8E ARM Cortex-M3 CPU的微控制器板。它是第一款基于32位ARM内核微控制器的Arduino板。

主要功能:

  • 它有54个数字输入/输出引脚(其中12个可用作PWM输出)
  • 12个模拟输入
  • 4个UART(硬件串行端口)
  • 84 MHz时钟,一个USB OTG连接
  • 2个DAC(数字到模拟),2个TWI,1个电源插孔,1个SPI头,1个JTAG头
  • 重置按钮和一个清除按钮

Arduino Due

Arduino Due板的特性

工作电压CPU速度模拟输入/输出数字IO/PWMEEPROM [KB]SRAM [KB]

Flash[KB]

USBUART
3.3伏84 Mhz12/254/12-965122微米4

通讯

  • 4个硬件UART
  • 2个I2C
  • 1个CAN接口(汽车通信协议)
  • 1个SPI
  • 1接口JTAG(10引脚)
  • 1个USB主机(像Leonardo一样)
  • 1编程端口

与大多数Arduino板不同,Arduino Due板运行在3.3V电压下。I/O引脚可以承受的最大电压为3.3V。对任何I/O引脚施加高于3.3V的电压都可能会损坏电路板。

该板包含了支持微控制器所需的一切。你可以使用micro-USB电缆将其连接到计算机,或者使用AC-to-DC适配器或电池为其供电以启用。Due与所有工作在3.3V电压的Arduino盾板兼容。

Arduino Zero

Zero是由UNO建立的平台的简单而强大的32位扩展。Zero板通过提供更高的性能扩展其系列,为设备提供各种项目机会,并成为学习32位应用程序开发的绝佳教育工具。

主要特点是:

  • Zero应用程序涵盖从智能物联网设备,可穿戴技术,高科技自动化,到疯狂的机器人技术。

  • 该板采用Atmel的SAMD21 MCU供电,该MCU配有32位ARMCortex®M0 +内核。

  • 其最重要的特性之一是Atmel的嵌入式调试器(EDBG),它提供了一个完整的调试接口,无需额外的硬件,显着提高了软件调试的易用性。

  • EDBG还支持可用于器件和引导加载程序编程的虚拟COM端口。


Arduino Zero

Arduino Zero板的特性

工作电压CPU速度模拟输入/输出数字IO/ PWMEEPROM [KB]SRAM [KB]Flash [KB]USBUART
3.3伏48 Mhz6/114/10-322562微米2

与大多数Arduino和Genuino板不同,Zero运行在3.3V电压下。I/O引脚可以承受的最大电压为3.3V。对任何I/O引脚施加高于3.3V的电压都可能会损坏电路板。

该板包含支持微控制器所需的一切。你可以使用micro-USB电缆将其连接到计算机,或者使用AC-to-DC适配器或电池为其供电以启用。Zero与所有工作在3.3V电压的盾板兼容。


脉冲宽度调制或PWM是用于改变脉冲串中的脉冲宽度的常用技术。PWM有许多应用,如控制伺服和速度控制器,限制电机和LED的有效功率。

PWM的基本原理

脉冲宽度调制基本上是一个随时间变化而变化的方波。基本的PWM信号如下图所示。

基本PWM信号

有很多术语与PWM相关:

  • On-Time(导通时间) - 时间信号的持续时间较长。

  • Off-Time(关断时间) - 时间信号的持续时间较短。

  • Period(周期) - 表示为PWM信号的导通时间和关断时间的总和。

  • Duty Cycle(占空比) - 它表示为在PWM信号周期内保持导通的时间信号的百分比。

周期

如图所示,Ton表示导通时间,Toff表示信号的关断时间。周期是导通和关断时间的总和,并按照以下公式计算:

周期

占空比

占空比用于计算为一段时间的导通时间。使用上面计算的周期,占空比计算为:

占空比

analogWrite()函数

analogWrite()函数将模拟值(PWM波)写入引脚。它可用于以不同的亮度点亮LED或以各种速度驱动电机。在调用analogWrite()函数之后,引脚将产生指定占空比的稳定方波,直到下一次调用analogWrite()或在相同引脚上调用digitalRead()或digitalWrite()。大多数引脚上的PWM信号频率约为490 Hz。在Uno和类似的板上,引脚5和6的频率约为980Hz。Leonardo上的引脚3和11也以980Hz运行。

在大多数Arduino板上(ATmega168或ATmega328),此功能在引脚3,5,6,9,10和11上工作。在Arduino Mega上,它在引脚2-13和44-46上工作。旧的Arduino ATmega8板仅支持引脚9,10和11上的 analogWrite()


analogWrite()函数


Arduino Due支持引脚2至13以及引脚DAC0和DAC1上的 analogWrite()与PWM引脚不同,DAC0和DAC1是数模转换器,用作真正的模拟输出。

在调用analogWrite()之前,不需要调用pinMode()将引脚设置为输出。

analogWrite()函数语法

analogWrite ( pin , value ) ;value − the duty cycle: between 0 (always off) and 255 (always on).

value - 占空比:0(始终导通)到255(始终关断)之间。

示例

int ledPin = 9; // LED connected to digital pin 9int analogPin = 3; // potentiometer connected to analog pin 3int val = 0; // variable to store the read valuevoid setup() {   pinMode(ledPin, OUTPUT); // sets the pin as output}void loop() {   val = analogRead(analogPin); // read the input pin   analogWrite(ledPin, (val / 4)); // analogRead values go from 0 to 1023,       // analogWrite values from 0 to 255}

要生成随机数,可以使用Arduino随机数函数。我们有两个函数:

  • randomSeed(seed)
  • random()

randomSeed(seed)

randomSeed(seed)函数重置Arduino的伪随机数生成器。虽然random()返回的数字的分布本质上是随机的,但是顺序是可预测的。你应该将发生器重置为某个随机值。如果你有一个未连接的模拟引脚,它可能会从周围环境中拾取随机噪音。这些可能是无线电波,宇宙射线,手机的电磁干扰,荧光灯等。

例子

randomSeed(analogRead(5)); // randomize using noise from analog pin 5

random()

random函数生成伪随机数。以下是语法。

random()语法

long random(max) // it generate random numbers from 0 to maxlong random(min, max) // it generate random numbers from min to max

例子

long randNumber;void setup() {   Serial.begin(9600);   // if analog input pin 0 is unconnected, random analog   // noise will cause the call to randomSeed() to generate   // different seed numbers each time the sketch runs.   // randomSeed() will then shuffle the random function.   randomSeed(analogRead(0));}void loop() {   // print a random number from 0 to 299   Serial.print("random1=");   randNumber = random(300);   Serial.println(randNumber); // print a random number from 0to 299   Serial.print("random2=");   randNumber = random(10, 20);// print a random number from 10 to 19   Serial.println (randNumber);   delay(50);}

让我们现在重温我们对一些基本概念的知识,例如位和字节。

Bit(位)

位只是一个二进制数字。

  • 二进制系统使用两个数字,0和1。

  • 与十进制数字系统类似,数字的位数不具有相同的值,位的“意义"取决于其在二进制数中的位置。例如,十进制数666中的数字相同,但具有不同的值。

Bits

字节

一个字节由8位组成。

  • 如果一个位是一个数字,逻辑上字节表示数字。

  • 可以对它们执行所有数学运算。

  • 一个字节中的数字也不具有相同的意义。

  • 最左边的位具有被称为最高有效位(MSB)的最大值。

  • 最右边的位具有最小值,因此称为最低有效位(LSB)。

  • 由于可以以256种不同的方式组合一个字节的八个0和1,所以可以由一个字节表示的最大十进制数是255(一个组合表示零)。


中断(interrupt)停止Arduino的当前工作,以便可以完成一些其他工作。

假设你坐在家里和别人聊天。突然电话响了。停止聊天,拿起电话与来电者通话。当你完成电话交谈后,你回去和电话响之前的那个人聊天。

同样,你可以把主程序想象成是与某人聊天,电话铃声使你停止聊天。中断服务程序是在电话上通话的过程。当通话结束后,你回到你聊天的主程序。这个例子准确地解释了中断如何使处理器执行操作。

主程序在电路中运行并执行一些功能。但是,当发生中断时,主程序在另一个程序执行时停止。当这个程序结束时,处理器再次返回主程序。

中断

重要特征

这里有一些关于中断的重要特征:

  • 中断可以来自各种来源。在这种情况下,我们使用的是由数字引脚上的状态改变触发的硬件中断。

  • 大多数Arduino设计有两个硬件中断(称为“interrupt0”和“interrupt1”)分别硬连接到数字I/O引脚2和3。

  • Arduino Mega有六个硬件中断,包括引脚21,20,19和18上的附加中断(“interrupt2”到“interrupt5”)。

  • 你可以使用称为“中断服务程序”(Interrupt Service Routine,通常称为ISR)的特殊函数来定义程序。

  • 你可以定义该程序并指定上升沿,下降沿或两者的条件。在这些特定条件下,将处理中断。

  • 每次在输入引脚上发生事件时,都可以自动执行该函数。

中断类型

有两种类型的中断:

  • 硬件中断 - 它们响应外部事件而发生,例如外部中断引脚变为高电平或低电平。

  • 软件中断 - 它们响应于在软件中发送的指令而发生。“Arduino语言”支持的唯一类型的中断是attachInterrupt()函数。

在Arduino中使用中断

中断在 Arduino 程序中非常有用,因为它有助于解决时序问题。中断的良好应用是读取旋转编码器或观察用户输入。一般情况下,ISR 应尽可能短且快。如果你的草图使用多个 ISR,则一次只能运行一个。其他中断将在当前完成之后执行,其顺序取决于它们的优先级。

通常,全局变量用于在 ISR 和主程序之间传递数据。为了确保在 ISR 和主程序之间共享的变量正确更新,请将它们声明为 volatile。

Arduino 中主要有时钟中断和外部中断,本文所说的中断指的是外部中断。Arduino 中的外部中断通常是由Pin 口(数字 Pin 口,不是模拟口)电平改变触发的。每种型号的 Arduino 版都有数个 Pin 口可以用来注册中断,具体如下:

开发板可以用来注册中断的Pin口
Uno, Nano, Mini, other 328-based2, 3
Uno WiFi Rev.2所有数字口
Mega, Mega2560, MegaADK2, 3, 18, 19, 20, 21
Micro, Leonardo, other 32u4-based0, 1, 2, 3, 7
Zero除了4号口外的所有数字口
MKR Family boards0, 1, 4, 5, 6, 7, 8, 9, A1, A2
Due所有数字口
101所有数字口 (只有 2, 5, 7, 8, 10, 11, 12, 13数字口可以使用 CHANGE​ 类型中断,中断类型在下文有介绍)

注册中断主要是通过​ attachInterrupt() ​函数实现的,其原型为:

void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode);
  1. 第一个参数为中断号,Arduino上每个可以注册中断的Pin口都会被分配一个中断号,这里需要传入的是中断号而不是Pin口号。但是不同的Arduino开发板上面的中断号分配并不完全一样。各个开发板的Pin口号和中断号对应关系如下:
     开发板 中断号0 中断号1 中断号2 中断号3 中断号4 中断号5
     Uno, Ethernet PIN 2 PIN 3    
     Mega2560 PIN 2 PIN 3 PIN 21 PIN 20 PIN 19 PIN 18
     基于32u4的开发板 如 Leonardo, Micro PIN 3 PIN 2 PIN 0 PIN 1 PIN 7 
    从上表中可以看出同一个 Pin 口在不同的开发板上可能会有不同的中断号,这势必会影响程序的可移植性。幸运的是,Arduino 还提供了另一个函数 digitalPinToInterrupt(int)。从名字就能看出,这个函数能输入 Pin 口号并输出对应的中断号。需要注意的是,输入的 Pin 口号需要在上述的支持列表当中。所以,Arduino 官方推荐我们使用 
    attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); 
    这种方式来注册中断号。
  2. 第二个参数是中断服务例程(ISR)的函数指针,在 C/C++ 中直接写该函数的函数名即可。在触发时,该函数将会被调用。该函数必须没有任何的参数也没有任何的返回值。
  3. 第三个参数是中断触发条件,由几个可选的值:
    LOW 当中断所在 Pin 口处于低电平时触发
    CHANGE 当中断所在 Pin口电平改变时触发
    RISING 当中断所在Pin口从低电平变为高电平(上升沿)时触发
    FALLING 当中断所在Pin口从高电平变为低电平(下降沿)时触发
    对于 Due,Zero 和 MKR1000开发板,还有一个 HIGH 表示当中断所在 Pin 口处于高电平时触发

示例

int pin = 2; //define interrupt pin to 2volatile int state = LOW; // To make sure variables shared between an ISR//the main program are updated correctly,declare them as volatile.void setup() {   pinMode(13, OUTPUT); //set pin 13 as output   attachInterrupt(digitalPinToInterrupt(pin), blink, CHANGE);   //interrupt at pin 2 blink ISR when pin to change the value} void loop() {    digitalWrite(13, state); //pin 13 equal the state value} void blink() {    //ISR function   state = !state; //toggle the state when the interrupt occurs}

attachInterrupt语句语法

attachInterrupt(digitalPinToInterrupt(pin),ISR,mode);//recommended for arduino boardattachInterrupt(pin, ISR, mode) ; //recommended Arduino Due, Zero only//argument pin: the pin number//argument ISR: the ISR to call when the interrupt occurs;    //this function must take no parameters and return nothing.    //This function is sometimes referred to as an interrupt service routine.//argument mode: defines when the interrupt should be triggered.

在 Arduino 中使用中断需要注意的问题

  1. 由于中断会打断正常代码的运行,因此 ISR 的应该尽可能快地执行完毕。
  2. 在 ISR 中修改的全局变量要用 volatile 修饰符修饰以防止编译器优化
  3. 在 ISR 中不能使用其他用中断实现的函数,如 millis() delay() 等。延时可以使用  delayMicroseconds(),它不是用中断实现的。





已经定义了数百个通信协议来实现这种数据交换。每个协议可以分为两类:并行或串行。

并行通信

通过输入/输出端口在Arduino和外设之间进行并行连接是短距离(最多几米)的理想解决方案。然而,在其他情况下,当需要在两个设备之间建立较长距离的通信时,不可能使用并行连接。并行接口同时传输多个位。它们通常需要数据总线 - 通过八条,十六条或更多的线路进行传输。数据以1和0的巨大波形传输。

并行通信

并行通信的优点和缺点

并行通信肯定有其优势。它比串行更快,更直接,相对容易实施。然而,它需要许多的输入/输出(I / O)端口和线路。如果你曾经把一个项目从一个基本的Arduino Uno移动到一个Mega,你就知道微处理器上的I/O线是很宝贵的,而且很少。因此,我们更喜欢串行通信,牺牲针脚空间的潜在速度。

串行通信模块

今天,大多数Arduino板都是用几种不同的串行通信系统作为标准设备。

使用哪个系统取决于以下因素:

  • 微控制器有多少个器件与数据交换?
  • 数据交换的速度有多快?
  • 这些设备之间的距离是多少?
  • 是否需要同时发送和接收数据?

有关串行通信的最重要的事情之一是协议,应该严格遵守。它是一套规则,必须应用这些规则才能使设备正确地解释它们相互交换的数据。幸运的是,Arduino会自动处理这个问题,这样程序员/用户的工作就可以简化为简单的写(发送的数据)和读(接收的数据)。

串行通信类型

串行通信可以进一步分类为:

  • 同步 - 同步的设备使用相同的时钟,它们的时序彼此同步。

  • 异步 - 异步的设备具有各自的时钟,并由前一状态的输出触发。

很容易找出设备是否同步。如果给所有连接的设备提供相同的时钟,则它们是同步的。如果没有时钟线,它是异步的。

例如,UART(通用异步收发器)模块是异步的。

异步串行协议有一些内置的规则。这些规则只是有助于确保可靠且无误的数据传输的机制。这些避免外部时钟信号的机制是:

  • Synchronization bits 同步位
  • Data bits 数据位
  • Parity bits 奇偶校验位
  • Baud rate 波特率

同步位

同步位是与每个数据包传输的两个或三个特殊位。它们是起始位和停止位。正如它们的名称,这些位分别标记数据包的开始和结束。

起始位始终只有一个,但停止位的数量可以配置为一个或两个(尽管通常保持为1)。

起始位始终由从1到0的空闲数据线指示,而停止位将通过将线保持在1处而转换回空闲状态。


同步位

数据位

每个分组中的数据量可以设置为5到9位的任意大小。当然,标准数据大小是基本8位字节,但其他大小有它们的用途。7位数据包的效率可能比8位高,特别是如果你只是传输7位ASCII字符。

奇偶校验位

用户可以选择是否应该有奇偶校验位,如果是,则奇偶校验应该是奇数还是偶数。如果数据位中的1的数目是偶数,则奇偶校验位为0。奇数的奇偶校验正好相反。

波特率

术语波特率用于表示每秒传输的位数[bps]。注意,它指的是位,而不是字节。协议通常要求每个字节与几个控制位一起传输。这意味着串行数据流中的一个字节可以包括11位。例如,如果波特率为300bps,则每秒可以传输最大37字节和最小27字节。

Arduino UART

以下代码将使Arduino在启动时发送hello world。

void setup() {   Serial.begin(9600); //set up serial library baud rate to 9600   Serial.println("hello world"); //print hello world}void loop() {}

将Arduino草图上传到Arduino后,打开Arduino IDE右上角的串口监视器搜索Search

在串口监视器的顶部框中键入任意内容,然后按发送键或键盘上的enter键。这将发送一系列字节到Arduino。

以下代码返回它接收到的任何东西作为输入。

以下代码将使Arduino根据提供的输入传送输出。

void setup() {   Serial.begin(9600); //set up serial library baud rate to 9600}void loop() {   if(Serial.available()) //if number of bytes (characters) available for reading from {       serial port      Serial.print("I received:"); //print I received      Serial.write(Serial.read()); //send what you read   }}

请注意,Serial.print Serial.println 将发回实际的ASCII代码,而 Serial.write 将返回实际的文本。请参阅ASCII代码了解更多信息。


内部集成电路(I2C)是用于微控制器和新一代专用集成电路之间的串行数据交换系统。当它们之间的距离很短(接收器和发射器通常在同一个印刷电路板上)时使用。通过两根导线建立连接。一个用于数据传输,另一个用于同步(时钟信号)。

如下图所示,一个设备始终是主设备。它在通信开始之前执行一个从芯片的寻址。这样,一个微控制器可以与112个不同的设备进行通信。波特率通常为100 Kb/sec(标准模式)或10 Kb/sec(慢波特率模式)。最近出现了波特率为3.4 Mb/s的系统。通过I2C总线通信的设备之间的距离限制在几米之内。


内部集成电路


板的I2C引脚

I2C总线由两个信号组成 - SCL和SDA。SCL是时钟信号,SDA是数据信号。当前总线主机总是产生时钟信号。一些从设备可能迫使时钟低电平以延迟主设备发送更多数据(或者在主设备尝试将数据写出之前请求更多的时间来准备数据)。这被称为“时钟伸展”。

以下是不同Arduino板的引脚:

  • Uno, Pro Mini A4 (SDA), A5 (SCL)
  • Mega, Due 20 (SDA), 21 (SCL)
  • Leonardo, Yun 2 (SDA), 3 (SCL)

Arduino I2C

我们有两种模式 - 主代码和从代码 - 使用I2C连接两个Arduino板。它们是:

  • Master Transmitter / Slave Receiver 主发射器/从接收器
  • Master Receiver / Slave Transmitter 主接收器/从发射器

主发射器/从接收器

让我们现在看看什么是主发送器和从接收器。

主发射器

以下函数用于初始化Wire库,并将I2C总线作为主器件或从器件加入。这通常只被调用一次。

  • Wire.begin(地址) - 在我们的例子中,地址是7位从地址,因为未指定主机,它将作为主机加入总线。

  • Wire.beginTransmission(地址) - 开始向给定地址的I2C从设备发送数据。

  • Wire.write() - 用于从主设备传输到从设备的队列字节(在beginTransmission()和endTransmission()之间的调用)。

  • Wire.endTransmission() - 结束由beginTransmission()开始的对从设备的传输,并传输由wire.write()排队的字节。

示例

#include <Wire.h> //include wire libraryvoid setup() //this will run only once {    Wire.begin(); // join i2c bus as master} short age = 0; void loop() {      Wire.beginTransmission(2);    // transmit to device #2   Wire.write("age is = ");   Wire.write(age); // sends one byte   Wire.endTransmission(); // stop transmitting   delay(1000); }

从接收器

使用以下函数:

  • Wire.begin(地址) - 地址是7位从地址。

  • Wire.onReceive(收到的数据处理程序) - 当从设备从主设备接收数据时调用的函数。

  • Wire.available() - 返回Wire.read()可用于检索的字节数,应在Wire.onReceive()处理程序中调用。

示例

#include <Wire.h> //include wire libraryvoid setup() {  //this will run only once   Wire.begin(2); // join i2c bus with address #2   Wire.onReceive(receiveEvent); // call receiveEvent when the master send any thing    Serial.begin(9600); // start serial for output to print what we receive }void loop() {      delay(250); }//-----this function will execute whenever data is received from master-----//void receiveEvent(int howMany) {    while (Wire.available()>1) // loop through all but the last {      char c = Wire.read(); // receive byte as a character      Serial.print(c); // print the character   }}

主接收器/从发射器

让我们现在看看什么是主接收器和从发射器。

主接收器

主机被编程为请求,然后读取从唯一寻址的从机Arduino发送的数据字节。

使用以下函数:

Wire.requestFrom(地址,字节数) - 主设备用于请求从设备的字节。然后可以使用函数wire.available()和wire.read()检索字节。

示例

#include <Wire.h> //include wire library void setup() {    Wire.begin(); // join i2c bus (address optional for master)    Serial.begin(9600); // start serial for output} void loop() {    Wire.requestFrom(2, 1); // request 1 bytes from slave device #2   while (Wire.available()) // slave may send less than requested {      char c = Wire.read(); // receive a byte as character      Serial.print(c); // print the character   }    delay(500); }

从发射器

使用以下函数:

Wire.onRequest(处理程序) - 当主设备从此从设备请求数据时调用该函数。

示例

#include <Wire.h> void setup() {    Wire.begin(2); // join i2c bus with address #2   Wire.onRequest(requestEvent); // register event} Byte x = 0;void loop() {    delay(100); } // function that executes whenever data is requested by master// this function is registered as an event, see setup()void requestEvent() {    Wire.write(x); // respond with message of 1 bytes as expected by master   x++; }


串行外设接口(SPI)总线是用于串行通信的系统,最多可使用四个导体,通常为三个。一个导体用于数据接收,一个导体用于数据发送,一个导体用于同步,另一个导体用于选择与之通信的设备。它是一个全双工连接,这意味着数据是同时发送和接收的。最大波特率高于I2C通信系统中的波特率。

板的SPI引脚

SPI使用以下四条线:

  • SCK - 这是由主机驱动的串行时钟。

  • MOSI - 这是由主机驱动的主输出/从输入。

  • MISO - 这是由主机驱动的主输入/从输出。

  • SS - 这是从机选择线。

使用以下函数,必须包括SPI.h.

  • SPI.begin() - 通过将SCK,MOSI和SS设置为输出来初始化SPI总线,将SCK和MOSI拉低,将SS拉高。

  • SPI.setClockDivider(分频器) - 相对于系统时钟设置SPI时钟分频器。在基于AVR的板上,可用的分频器为2,4,8,16,32,64或128。默认设置为SPI_CLOCK_DIV4,它将SPI时钟设置为系统时钟的四分之一(对于20 MHz的电路板为5 Mhz)。

  • Divider - 它可以是(SPI_CLOCK_DIV2,SPI_CLOCK_DIV4,SPI_CLOCK_DIV8,SPI_CLOCK_DIV16,SPI_CLOCK_DIV32,SPI_CLOCK_DIV64,SPI_CLOCK_DIV128)。

  • SPI.transfer(val) - SPI传输基于同时发送和接收:接收的数据在receivedVal中返回。

  • SPI.beginTransaction(SPISettings(speedMaximum,dataOrder,dataMode)) - speedMaximum是时钟,dataOrder(MSBFIRST或LSBFIRST),dataMode(SPI_MODE0,SPI_MODE1,SPI_MODE2或SPI_MODE3)。

SPI中有四种操作模式,如下所示:

  • 模式0(默认值) - 时钟通常为低电平(CPOL = 0),数据在从低电平到高电平(前沿)(CPHA = 0)的转换时采样。

  • 模式1 - 时钟通常为低电平(CPOL = 0),数据在从高电平到低电平(后沿)(CPHA = 1)的转换时采样。

  • 模式2 - 时钟通常为高电平(CPOL = 1),数据在从高电平到低电平(前沿)(CPHA = 0)的转换时采样。

  • 模式3 - 时钟通常为高电平(CPOL = 1),数据在从低电平到高电平(后沿)(CPHA = 1)的转换时采样。

  • SPI.attachInterrupt(handler) - 当从设备从主设备接收数据时调用的函数。

现在,我们将两个Arduino UNO板连接在一起;一个作为主机,另一个作为从机。

  • (SS):引脚10
  • (MOSI):引脚11
  • (MISO):引脚12
  • (SCK):引脚13

接地是常见的。以下是两个电路板之间的连接的图示:


两个电路板之间的连接

让我们看看SPI作为主机和SPI作为从机的例子。

SPI为主机

例子

#include <SPI.h>void setup (void) {   Serial.begin(115200); //set baud rate to 115200 for usart   digitalWrite(SS, HIGH); // disable Slave Select   SPI.begin ();   SPI.setClockDivider(SPI_CLOCK_DIV8);//divide the clock by 8}void loop (void) {   char c;   digitalWrite(SS, LOW); // enable Slave Select   // send test string   for (const char * p = "Hello, world!
" ; c = *p; p++) {      SPI.transfer (c);      Serial.print(c);   }   digitalWrite(SS, HIGH); // disable Slave Select   delay(2000);}

SPI为从机

例子

#include <SPI.h>char buff [50];volatile byte indx;volatile boolean process;void setup (void) {   Serial.begin (115200);   pinMode(MISO, OUTPUT); // have to send on master in so it set as output   SPCR |= _BV(SPE); // turn on SPI in slave mode   indx = 0; // buffer empty   process = false;   SPI.attachInterrupt(); // turn on interrupt}ISR (SPI_STC_vect) // SPI interrupt routine {    byte c = SPDR; // read byte from SPI Data Register   if (indx < sizeof buff) {      buff [indx++] = c; // save data in the next index in the array buff      if (c == '
') //check for the end of the word      process = true;   }}void loop (void) {   if (process) {      process = false; //reset the process      Serial.println (buff); //print the array on serial monitor      indx= 0; //reset button to zero   }}


LED是用于许多不同应用的小型强光灯。首先,我们将学习闪烁LED,即微控制器的Hello World。它就像打开和关闭灯一样简单。建立这个重要的基线将为你提供坚实的基础,以实现更复杂的实验。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × LED
  • 1 × 330Ω 电阻
  • 2 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

连接面包板

注意 - 要了解LED的极性,请仔细查看。两个腿中较短的,朝向灯泡的平坦边缘表示负极端子。


LED

像电阻器这样的组件需要将其端子弯曲成90°角,以便恰当的适配面包板插座。你也可以将端子切短。


电阻器

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开新的草图文件。

打开Arduino IDE软件

Arduino代码

/*   Blink   Turns on an LED on for one second, then off for one second, repeatedly.*/// the setup function runs once when you press reset or power the boardvoid setup() {  // initialize digital pin 13 as an output.   pinMode(2, OUTPUT);}// the loop function runs over and over again forevervoid loop() {   digitalWrite(2, HIGH); // turn the LED on (HIGH is the voltage level)   delay(1000); // wait for a second   digitalWrite(2, LOW); // turn the LED off by making the voltage LOW   delay(1000); // wait for a second}

代码说明

pinMode(2,OUTPUT) - 在使用Arduino的引脚之前,你需要告诉Arduino Uno R3它是INPUT还是OUTPUT。我们使用一个内置的“函数”pinMode()来做到这一点。

digitalWrite(2,HIGH) - 当使用引脚作为OUTPUT时,可以将其命令为HIGH(输出5伏)或LOW(输出0伏)。

结果

你应该看到你的LED打开和关闭。如果没有看到所需的输出,请确保你已正确组装电路,并已验证和将代码上传到电路板。


这个例子演示了使用analogWrite()函数来渐变LED的功能。AnalogWrite使用脉冲宽度调制(PWM),以开和关之间的不同比率非常快速地打开和关闭数字引脚,以产生渐变效应。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × LED
  • 1 × 330Ω 电阻
  • 2 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

电路图

注意 − 要了解LED的极性,请仔细查看。两个腿中较短的,朝向灯泡的平坦边缘表示负极端子。


LED

像电阻器这样的组件需要将其端子弯曲成90°角,以便恰当的适配面包板插座。你也可以将端子切短。


电阻

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开新的草图文件。

Sketch

Arduino代码

/*   Fade   This example shows how to fade an LED on pin 9 using the analogWrite() function.   The analogWrite() function uses PWM, so if you want to change the pin you're using, be   sure to use another PWM capable pin. On most Arduino, the PWM pins are identified with   a "~" sign, like ~3, ~5, ~6, ~9, ~10 and ~11.*/int led = 9; // the PWM pin the LED is attached toint brightness = 0; // how bright the LED isint fadeAmount = 5; // how many points to fade the LED by// the setup routine runs once when you press reset:void setup() {   // declare pin 9 to be an output:   pinMode(led, OUTPUT);}// the loop routine runs over and over again forever:void loop() {   // set the brightness of pin 9:   analogWrite(led, brightness);   // change the brightness for next time through the loop:   brightness = brightness + fadeAmount;   // reverse the direction of the fading at the ends of the fade:   if (brightness == 0 || brightness == 255) {      fadeAmount = -fadeAmount ;   }   // wait for 30 milliseconds to see the dimming effect   delay(300);}

代码说明

将引脚9声明为LED引脚之后,在代码的setup()函数中没有任何操作。你将在代码的主循环中使用的analogWrite()函数会需要两个参数:一个告诉函数要写入哪个引脚,另一个表示要写入的PWM值。

为了使LED渐变熄灭和亮起,将PWM值从0(一直关闭)逐渐增加到255(一直开启),然后回到0,以完成循环。在上面给出的草图中,PWM值使用称为brightness的变量设置。每次通过循环时,它增加变量fadeAmount的值。

如果brightness处于其值的任一极值(0或255),则fadeAmount变为负值。换句话说,如果fadeAmount是5,那么它被设置为-5。如果它是-5,那么它被设置为5。下一次通过循环,这个改变也将导致brightness改变方向。

analogWrite()可以非常快速地改变PWM值,因此草图结束时的delay控制了渐变的速度。尝试改变delay的值,看看它如何改变渐变效果。

结果

你应该看到你的LED亮度逐渐变化。

此示例将向你展示如何读取模拟引脚0上的模拟输入。输入从analogRead()转换为电压,并打印输出到Arduino软件(IDE)的串口监视器。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 5K可变电阻(电位器)
  • 2 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

123456

电位器

电位器是一种简单的机电传感器。它将来自输入操作器的旋转或线性运动转换为电阻的变化。这种变化是(或可以)用于控制任何东西,从高保真音响系统到巨大的集装箱船的方向。

我们知道电位器最初被称为变阻器(本质上是一个可变的绕线电阻)。现在可用的电阻器的种类现在相当惊人的,而初学者(特别是)可能很难确定哪种类型适合于给定的任务。一些不同的电阻器类型,都可以用于相同的任务,使得确定工作更难。

pIYBAF1eBUOAXXTOAAB-0b8xr5030427a975e4ae143e9f

左边的图像显示电阻器的标准原理图符号。右边的图像是电位器。

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

void setup() {   // 初始化串行通信速率为9600bit/s:   Serial.begin(9600);}void loop() {   // 读取模拟引脚A0的输入数据   int sensorValue = analogRead(A0);   // 将模拟信号转换成电压   float voltage = sensorValue * (5.0 / 1023.0);   // 打印到串口监视器   Serial.println(voltage);}

代码说明

在下面给出的程序或草图中,你在设置功能中做的第一件事是在你的电路板和你的电脑之间以9600比特每秒开始串行通信,使用以下代码:

Serial.begin(9600);

在代码的主循环中,你需要建立一个变量来存储来自电位器的电阻值(其范围在0到1023之间,非常适合int数据类型):

int sensorValue = analogRead(A0);

要将值从0-1023更改为与引脚正在读取的电压相对应的范围,你需要创建另一个变量,一个浮点数并进行一些计算。要缩小0.0和5.0之间的数字,将5.0除以1023.0,再乘以sensorValue:

float voltage= sensorValue * (5.0 / 1023.0);

最后,你需要将此信息打印到串行窗口。你可以用最后一行代码中的Serial.println()命令:

Serial.println(voltage)

现在,通过单击顶部绿色栏右侧的图标或按Ctrl+Shift+M打开Arduino IDE中的串口监视器。

串行监视器

结果

你会看到一个从0.0到5.0的稳定的数字流。当你转动电位器时,这些值会改变,对应于引脚A0上的电压。


此示例展示如何读取模拟引脚0处的模拟输入,将analogRead()中的值转换为电压,并将其输出到Arduino软件(IDE)的串口监视器。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 5k欧姆可变电阻(电位器)
  • 2 × 跳线
  • 8 × LED(LED条形图显示如下图所示)

程序

按照电路图连接面包板上的组件,如下图所示。

连接面包板

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

10段LED条形图

LED条形图

这10段条形图LED有许多用途。紧凑的占用空间,简单的连接,它们易用于原型或成品。实质上,它们是10个独立的蓝色LED,每个都有独立的阳极和阴极连接。

它们也有黄色,红色和绿色。

注意 - 这些条形图上的引脚可能与数据表中列出的内容不同。将设备旋转180度将纠正变化,使得引脚11成为第一引脚。

Arduino代码

/*   LED bar graph   Turns on a series of LEDs based on the value of an analog sensor.    This is a simple way to make a bar graph display.    Though this graph uses 8LEDs, you can use any number by      changing the LED count and the pins in the array.   This method can be used to control any series of digital      outputs that depends on an analog input.*/// these constants won't change:const int analogPin = A0; // the pin that the potentiometer is attached toconst int ledCount = 8; // the number of LEDs in the bar graphint ledPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; // an array of pin numbers to which LEDs are attachedvoid setup() {   // loop over the pin array and set them all to output:   for (int thisLed = 0; thisLed < ledCount; thisLed++) {      pinMode(ledPins[thisLed], OUTPUT);   }}void loop() {   // read the potentiometer:   int sensorReading = analogRead(analogPin);   // map the result to a range from 0 to the number of LEDs:   int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);   // loop over the LED array:   for (int thisLed = 0; thisLed < ledCount; thisLed++) {      // if the array element's index is less than ledLevel,      // turn the pin for this element on:      if (thisLed < ledLevel) {         digitalWrite(ledPins[thisLed], HIGH);      }else { // turn off all pins higher than the ledLevel:         digitalWrite(ledPins[thisLed], LOW);      }   }} 

代码说明

草图的工作方式是这样的:首先,你阅读输入。将输入值映射到输出范围,在这种情况下为十个LED。然后,你设置一个 for-loop 以迭代输出。如果系列中的输出数量低于映射的输入范围,则将其打开。如果没有,则将其关闭。

结果

当模拟读数的值增加时,你将看到LED逐个打开,而当读数减少时,LED逐个关闭。


本示例使用键盘库将你在计算机上的用户会话注销,此时ARDUINO UNO上的引脚2被拉至接地。草图同时按两个或三个按键的顺序模拟按键,并在短暂的延迟之后释放它们。

警告 - 当你使用 Keyboard.print()命令时,Arduino接管你的计算机键盘。为确保在使用此功能运行草图时不会失去对计算机的控制,请在调用Keyboard.print()之前设置可靠的控制系统。此草图旨在在引脚被拉至接地后才发送键盘命令。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Leonardo, Micro, 或Due板
  • 1 × 按钮
  • 1 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

面包板

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

对于本例,你需要使用Arduino IDE 1.6.7

Sketch

注意 - 你必须在Arduino库文件中包含键盘库。将键盘库文件复制并粘贴到名为libraries的文件(下图高亮显示)中,如以下屏幕截图所示。

在Arduino库文件中包含键盘库

Arduino代码

/*   Keyboard logout   This sketch demonstrates the Keyboard library.   When you connect pin 2 to ground, it performs a logout.   It uses keyboard combinations to do this, as follows:   On Windows, CTRL-ALT-DEL followed by ALT-l   On Ubuntu, CTRL-ALT-DEL, and ENTER   On OSX, CMD-SHIFT-q   To wake: Spacebar.   Circuit:   * Arduino Leonardo or Micro   * wire to connect D2 to ground.*/#define OSX 0#define WINDOWS 1#define UBUNTU 2#include "Keyboard.h"// change this to match your platform:int platform = WINDOWS;void setup() {   // make pin 2 an input and turn on the   // pullup resistor so it goes high unless   // connected to ground:      pinMode(2, INPUT_PULLUP);   Keyboard.begin();}void loop() {   while (digitalRead(2) == HIGH) {      // do nothing until pin 2 goes low      delay(500);   }      delay(1000);      switch (platform) {      case OSX:      Keyboard.press(KEY_LEFT_GUI);	        // Shift-Q logs out:      Keyboard.press(KEY_LEFT_SHIFT);      Keyboard.press('Q');      delay(100);	        // enter:      Keyboard.write(KEY_RETURN);      break;	        case WINDOWS:      // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);      delay(100);      Keyboard.releaseAll();	        //ALT-l:      delay(2000);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press('l');      Keyboard.releaseAll();      break;	        case UBUNTU:      // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);	        delay(1000);      Keyboard.releaseAll();	        // Enter to confirm logout:      Keyboard.write(KEY_RETURN);      break;   }      // do nothing:   while (true);}Keyboard.releaseAll();   // enter:      Keyboard.write(KEY_RETURN);      break;      case WINDOWS:	     // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);      delay(100);      Keyboard.releaseAll();	     //ALT-l:      delay(2000);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press('l');      Keyboard.releaseAll();      break;	     case UBUNTU:      // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);      delay(1000);      Keyboard.releaseAll();	        // Enter to confirm logout:      Keyboard.write(KEY_RETURN);      break;   }   // do nothing:   while (true);}

代码说明

在将程序上传到你的板之前,请确保将正在使用的正确操作系统分配给平台变量。

在草图运行时,按下按钮将引脚2接地,而板将发送注销序列发送到USB连接的PC。

结果

当将引脚2接地时,它将执行注销操作。

它使用以下键盘组合注销:

  • Windows 上,按CTRL-ALT-DEL,然后按ALT-l

  • Ubuntu ,CTRL-ALT-DEL和ENTER

  • OSX 上,CMD-SHIFT-q


在此示例中,当按下按钮时,文本字符串作为键盘输入发送到计算机。字符串报告按钮被按下的次数。一旦你完成了Leonardo版的程序化和接线,打开你最喜欢的文本编辑器来查看结果。

警告 - 当你使用 Keyboard.print()命令时,Arduino将接管你的计算机键盘。为确保在使用此功能运行草图时不会失去对计算机的控制,请在调用 Keyboard.print()之前设置可靠的控制系统。这个草图包括一个按钮来切换键盘,以便它只在按下按钮后运行。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Leonardo, Micro, 或Due板
  • 1 × 瞬时按钮
  • 1 × 10k欧姆电阻

程序

按照电路图连接面包板上的组件,如下图所示。

面包板

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

/*   Keyboard Message test For the Arduino Leonardo and Micro,      Sends a text string when a button is pressed.   The circuit:   * pushbutton attached from pin 4 to +5V   * 10-kilohm resistor attached from pin 4 to ground*/#include "Keyboard.h"const int buttonPin = 4; // input pin for pushbuttonint previousButtonState = HIGH; // for checking the state of a pushButtonint counter = 0; // button push countervoid setup() {   pinMode(buttonPin, INPUT); // make the pushButton pin an input:   Keyboard.begin(); // initialize control over the keyboard:}void loop() {   int buttonState = digitalRead(buttonPin); // read the pushbutton:   if ((buttonState != previousButtonState)&& (buttonState == HIGH)) // and it's currently pressed: {      // increment the button counter      counter++;      // type out a message      Keyboard.print("You pressed the button ");      Keyboard.print(counter);      Keyboard.println(" times.");   }   // save the current button state for comparison next time:   previousButtonState = buttonState;}

代码说明

将按钮的一个端子连接到Arduino上的引脚4。将另一个引脚连接到5V。使用电阻作为下拉电阻,通过将其从引脚4接地来提供接地参考。

一旦你程序化了电路板,拔下USB电缆,打开一个文本编辑器并将文本光标放在打字区域。再次通过USB将电路板连接到计算机,然后按按钮在文档中写入。

结果

通过使用任意文本编辑器,将显示通过Arduino发送的文本。


使用鼠标库,你可以使用Arduino Leonardo,Micro或Due来控制计算机的屏幕光标。

这个特殊的例子使用五个按钮来移动屏幕上的光标。四个按钮是方向性的(上,下,左,右),一个是用于鼠标左键单击。来自Arduino的光标移动总是相对的。每次读取输入时,光标的位置都会相对于当前位置进行更新。

只要有一个方向按钮被按下,Arduino就会移动鼠标,在合适的方向上将HIGH输入映射到5的范围。

第五个按钮用于控制来自鼠标的左键单击。当按钮被释放时,计算机将识别事件。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Leonardo, Micro 或 Due板
  • 5 × 10k欧姆电阻
  • 5 × 瞬时按钮

程序

按照电路图连接面包板上的组件,如下图所示。

面包板上的组件

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

对于本例,你需要使用Arduino IDE 1.6.7

Sketch

Arduino代码

/*   Button Mouse Control   For Leonardo and Due boards only .Controls the mouse from    five pushbuttons on an Arduino Leonardo, Micro or Due.   Hardware:   * 5 pushbuttons attached to D2, D3, D4, D5, D6   The mouse movement is always relative. This sketch reads   four pushbuttons, and uses them to set the movement of the mouse.   WARNING: When you use the Mouse.move() command, the Arduino takes   over your mouse! Make sure you have control before you use the mouse commands.*/#include "Mouse.h"// set pin numbers for the five buttons:const int upButton = 2;const int downButton = 3;const int leftButton = 4;const int rightButton = 5;const int mouseButton = 6;int range = 5; // output range of X or Y movement; affects movement speedint responseDelay = 10; // response delay of the mouse, in msvoid setup() {   // initialize the buttons' inputs:   pinMode(upButton, INPUT);   pinMode(downButton, INPUT);   pinMode(leftButton, INPUT);   pinMode(rightButton, INPUT);   pinMode(mouseButton, INPUT);   // initialize mouse control:   Mouse.begin();}void loop() {   // read the buttons:   int upState = digitalRead(upButton);   int downState = digitalRead(downButton);   int rightState = digitalRead(rightButton);   int leftState = digitalRead(leftButton);   int clickState = digitalRead(mouseButton);   // calculate the movement distance based on the button states:   int xDistance = (leftState - rightState) * range;   int yDistance = (upState - downState) * range;   // if X or Y is non-zero, move:   if ((xDistance != 0) || (yDistance != 0)) {      Mouse.move(xDistance, yDistance, 0);   }   // if the mouse button is pressed:   if (clickState == HIGH) {      // if the mouse is not pressed, press it:      if (!Mouse.isPressed(MOUSE_LEFT)) {         Mouse.press(MOUSE_LEFT);      }   } else {                           // else the mouse button is not pressed:      // if the mouse is pressed, release it:      if (Mouse.isPressed(MOUSE_LEFT)) {         Mouse.release(MOUSE_LEFT);      }   }   // a delay so the mouse does not move too fast:   delay(responseDelay);}

代码说明

使用micro-USB线将电路板连接到计算机。按钮连接到引脚2至6的数字输入。确保使用10k下拉电阻。


此示例监听来自串口的一个字节。当接收到时,电路板发送一个击键回到计算机。发送的击键比接收的击键高一个,因此如果从串口监视器发送“a”,你将从连接到计算机的电路板接收到“b”。“1”将返回“2”等。

警告 - 当你使用 Keyboard.print()命令时,Leonardo,Micro或Due板会接管你计算机的键盘。为确保在使用此功能运行草图时不会失去对计算机的控制,请在调用Keyboard.print()之前设置可靠的控制系统。这个草图被设计为只在板通过串口接收到一个字节后才发送一个键盘命令。

必需的组件

你将需要以下组件:

  • 1 × Arduino Leonardo, Micro, 或 Due板

程序

只需使用USB线将电路板连接到计算机。

用USB电缆将电路板连接到计算机

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch


注意 - 你必须在Arduino库文件中包含键盘库。将键盘库文件复制并粘贴到以下标黄色的名为“libraries”的文件中。

在Arduino库文件中包含键盘库

Arduino代码

/*   Keyboard test   For the Arduino Leonardo, Micro or Due Reads      a byte from the serial port, sends a keystroke back.    The sent keystroke is one higher than what's received, e.g. if you send a, you get b, send      A you get B, and so forth.   The circuit:   * none*/#include "Keyboard.h"void setup() {   // open the serial port:   Serial.begin(9600);   // initialize control over the keyboard:   Keyboard.begin();}void loop() {   // check for incoming serial data:   if (Serial.available() > 0) {      // read incoming serial data:      char inChar = Serial.read();      // Type the next ASCII value from what you received:      Keyboard.write(inChar + 1);   }}

代码说明

一旦开始编程,则打开你的串口监视器并发送一个字节。电路板将回复一个击键,这是一个更高的数字。

结果

当你发送一个字节时,电路板将会在Arduino IDE串口监视器上回复一个更高数字的击键。


在本节中,我们将学习如何使用不同的传感器连接我们的Arduino板。我们将讨论以下传感器:

  • 湿度传感器(DHT22)
  • 温度传感器(LM35)
  • 水位检测传感器(简单水触发器)
  • PIR传感器
  • 超声波传感器
  • GPS

湿度传感器(DHT22)

DHT-22(也称为AM2302)是一个数字输出,相对湿度和温度传感器。它使用电容式湿度传感器和热敏电阻来测量周围空气,并在数据引脚上发送数字信号。

在本例中,你将学习如何将此传感器与Arduino UNO一起使用。室温和湿度将打印到串口监视器上。

DHT-22传感器

DHT-22传感器

连接很简单。左边的第一个引脚为3-5V电源,第二个引脚连接到数据输入引脚,最右边的引脚接地。

技术细节

  • 电源 - 3-5V

  • 最大电流 - 2.5mA

  • 湿度 - 0-100%,精确度为2-5%

  • 温度 - 40至80°C,精确度为±0.5°C

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × DHT22
  • 1 × 10K欧姆电阻

程序

按照电路图连接面包板上的组件,如下图所示。

电路图

挂接面包板上的组件

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

// Example testing sketch for various DHT humidity/temperature sensors#include "DHT.h"#define DHTPIN 2 // what digital pin we're connected to// Uncomment whatever type you're using!//#define DHTTYPE DHT11 // DHT 11#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321//#define DHTTYPE DHT21 // DHT 21 (AM2301)// Connect pin 1 (on the left) of the sensor to +5V// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1// to 3.3V instead of 5V!// Connect pin 2 of the sensor to whatever your DHTPIN is// Connect pin 4 (on the right) of the sensor to GROUND// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor// Initialize DHT sensor.// Note that older versions of this library took an optional third parameter to// tweak the timings for faster processors. This parameter is no longer needed// as the current DHT reading algorithm adjusts itself to work on faster procs.DHT dht(DHTPIN, DHTTYPE);void setup() {   Serial.begin(9600);   Serial.println("DHTxx test!");   dht.begin();}void loop() {   delay(2000); // Wait a few seconds between measurements   float h = dht.readHumidity();   // Reading temperature or humidity takes about 250 milliseconds!   float t = dht.readTemperature();   // Read temperature as Celsius (the default)   float f = dht.readTemperature(true);   // Read temperature as Fahrenheit (isFahrenheit = true)   // Check if any reads failed and exit early (to try again).   if (isnan(h) || isnan(t) || isnan(f)) {      Serial.println("Failed to read from DHT sensor!");      return;   }      // Compute heat index in Fahrenheit (the default)   float hif = dht.computeHeatIndex(f, h);   // Compute heat index in Celsius (isFahreheit = false)   float hic = dht.computeHeatIndex(t, h, false);   Serial.print ("Humidity: ");   Serial.print (h);   Serial.print (" %	");   Serial.print ("Temperature: ");   Serial.print (t);   Serial.print (" *C ");   Serial.print (f);   Serial.print (" *F	");   Serial.print ("Heat index: ");   Serial.print (hic);   Serial.print (" *C ");   Serial.print (hif);   Serial.println (" *F");}

代码说明

DHT22传感器具有四个端子连接到电路板的端子(Vcc,DATA,NC,GND),如下:

  • DATA引脚连接到Arduino的2号引脚号
  • Vcc引脚连接到Arduino板的5伏电压
  • GND引脚连接到Arduino板的接地
  • 我们需要在DATA和Vcc引脚之间连接10k欧姆电阻(上拉电阻)

一旦硬件连接完成,你需要添加DHT22库到你的Arduino库文件,如前所述。

结果

你将看到串口监视器上的温度和湿度显示,每2秒更新一次。


温度传感器LM35系列是精密集成电路温度器件,输出电压与摄氏温度成线性比例。

LM35器件优于以开尔文校准的线性温度传感器,因为用户不需要从输出中减去大的恒定电压以获得便利的摄氏缩放。LM35器件不需要任何外部校准或调整,即可在室温下提供±1/4°C的典型精度,在-55°C至150°C的温度范围内提供±3°C的典型精度。

温度传感器

技术规格

  • 直接以摄氏度校准
  • 线性 + 10-mV/°C比例因子
  • 0.5°C确保准确度(在25°C)
  • 额定温度范围为-55°C至150°C
  • 适用于远程应用

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × LM35 传感器

程序

按照电路图连接面包板上的组件,如下图所示。

面包板

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

float temp;int tempPin = 0;void setup() {   Serial.begin(9600);}void loop() {   temp = analogRead(tempPin);   // read analog volt from sensor and save to variable temp   temp = temp * 0.48828125;   // convert the analog volt to its temperature equivalent   Serial.print("TEMPERATURE = ");   Serial.print(temp); // display temperature value   Serial.print("*C");   Serial.println();   delay(1000); // update sensor reading each one second}

代码说明

LM35传感器有三个端子:Vs,Vout和GND。我们将按如下方式连接传感器:

  • 将+Vs连接到Arduino板上的+5v电压。
  • 将Vout连接到Arduino板上的模拟0或A0。
  • 将GND连接到Arduino上的GND。

模数转换器(ADC)基于公式ADC值将模拟值转换为数字近似值=样本*1024/参考电压(+5v)。将模拟值转换为数字逼近。 那么用+5v做参考,数字近似值将等于输入电压*205。

结果

你将看到串口监视器上的温度显示,每秒更新一次。


水位传感器砖设计用于水位检测,可广泛应用于检测降雨,水位,甚至液体泄漏。

Water Detector / Sensor

将水位传感器连接到Arduino是检测泄漏,溢出,洪水,雨水等的好方法。它可用于检测水的存在,水位,体积以及是否缺水。当这个用来提醒你给植物浇水时,有一个比较好的Grove传感器。传感器具有一系列暴露的迹线,当检测到水时读取LOW。

在本章中,我们将把水位传感器连接到Arduino上的数字引脚8,并将使用非常方便的LED来帮助识别水位传感器何时与水源接触。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 水位传感器
  • 1 × led
  • 1 × 330欧姆电阻

程序

按照电路图连接面包板上的组件,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

#define Grove_Water_Sensor 8 // Attach Water sensor to Arduino Digital Pin 8#define LED 9 // Attach an LED to Digital Pin 9 (or use onboard LED)void setup() {   pinMode(Grove_Water_Sensor, INPUT); // The Water Sensor is an Input   pinMode(LED, OUTPUT); // The LED is an Output}void loop() {   /* The water sensor will switch LOW when water is detected.   Get the Arduino to illuminate the LED and activate the buzzer   when water is detected, and switch both off when no water is present */   if( digitalRead(Grove_Water_Sensor) == LOW) {      digitalWrite(LED,HIGH);   }else {      digitalWrite(LED,LOW);   }}

代码说明

水位传感器具有三个端子:S,Vout(+)和GND(-)。按如下所示连接传感器:

  • 将+Vs连接到Arduino板上的+5v。
  • 将S连接到Arduino板上的数字引脚8。
  • 将GND连接到Arduino上的GND。
  • 将LED连接到Arduino板上的数字引脚9。

当传感器检测到水时,Arduino上的引脚8变为LOW,然后Arduino上的LED亮起。

结果

当传感器检测到水时,你会看到指示LED灯亮起。


PIR传感器可以让你感知运动。它们用于检测人是否进入或离开传感器的范围。通常出现在家庭或企业使用的电器和小工具中。它们通常被称为PIR,“被动红外”,“热电”或“IR运动”传感器。

以下是PIR传感器的优点:

  • 体积小
  • 镜头范围广
  • 易于界面
  • 廉价
  • 低电量
  • 使用方便
  • 不会磨损

PIR传感器


PIR由热电传感器制成,圆形金属罐中央有一个矩形晶体,可以检测红外辐射的水平。所有东西都发射出低水平的辐射,而东西越热发射的辐射就越多。运动检测器中的传感器分成两半。这是为了检测运动(变化)而不是平均IR水平。两个半部分相互连接,以便彼此抵消。如果一半看到比另一半更多或更少的红外辐射,则输出将摆动高或低。

PIR


PIR具有可调设置,并在3引脚ground/out/power板上安装了一个接头。

可调设置

对于许多需要在人们离开或进入该区域进行检测的基础项目或产品,PIR传感器是非常有用的。请注意,PIR不会告诉你周围的人数或与传感器的距离。镜头通常固定在有一定距离的扫描范围内,有时候它们会被房子里的宠物带走

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × PIR传感器(MQ3)

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

#define pirPin 2int calibrationTime = 30;long unsigned int lowIn;long unsigned int pause = 5000;boolean lockLow = true;boolean takeLowTime;int PIRValue = 0;void setup() {   Serial.begin(9600);   pinMode(pirPin, INPUT);}void loop() {   PIRSensor();}void PIRSensor() {   if(digitalRead(pirPin) == HIGH) {      if(lockLow) {         PIRValue = 1;         lockLow = false;         Serial.println("Motion detected.");         delay(50);      }      takeLowTime = true;   }   if(digitalRead(pirPin) == LOW) {      if(takeLowTime){         lowIn = millis();takeLowTime = false;      }      if(!lockLow && millis() - lowIn > pause) {         PIRValue = 0;         lockLow = true;         Serial.println("Motion ended.");         delay(50);      }   }}

代码说明

PIR传感器有三个端子:Vcc,OUT和GND。按如下所示连接传感器: 

  • 将+Vcc连接到Arduino板上的+5v。
  • 将OUT连接到Arduino板上的数字引脚2。
  • 将GND连接到Arduino上的GND。

您可以通过位于传感器板底部的两个可变电阻器来调节传感器灵敏度和延迟时间。

可变电阻器

一旦传感器检测到任何运动,Arduino将通过串口发送一条消息,表示检测到运动。PIR感测运动将延迟一定时间以检查是否存有新的运动。如果没有检测到运动,Arduino将发送一条新消息,说明运动已经结束。

结果

如果检测到运动,你将在串口上看到一条消息,并在运动停止时看到另一条消息。


HC-SR04超声波传感器使用声纳来确定物体的距离,就像蝙蝠一样。它提供了非常好的非接触范围检测,准确度高,读数稳定,易于使用,尺寸从2厘米到400厘米或1英寸到13英尺不等。

其操作不受阳光或黑色材料的影响,尽管在声学上,柔软的材料(如布料等)可能难以检测到。它配有超声波发射器和接收器模块。

超声波传感器

超声波

技术规格

电源 - + 5V DC
静态电流 - <2mA
工作电流 - 15mA
有效角度 - <15°
测距距离 - 2厘米-400厘米/1英寸-13英尺
分辨率 - 0.3厘米
测量角度 - 30度

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 超声波传感器(HC-SR04)

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

const int pingPin = 7; // Trigger Pin of Ultrasonic Sensorconst int echoPin = 6; // Echo Pin of Ultrasonic Sensorvoid setup() {   Serial.begin(9600); // Starting Serial Terminal}void loop() {   long duration, inches, cm;   pinMode(pingPin, OUTPUT);   digitalWrite(pingPin, LOW);   delayMicroseconds(2);   digitalWrite(pingPin, HIGH);   delayMicroseconds(10);   digitalWrite(pingPin, LOW);   pinMode(echoPin, INPUT);   duration = pulseIn(echoPin, HIGH);   inches = microsecondsToInches(duration);   cm = microsecondsToCentimeters(duration);   Serial.print(inches);   Serial.print("in, ");   Serial.print(cm);   Serial.print("cm");   Serial.println();   delay(100);}long microsecondsToInches(long microseconds) {   return microseconds / 74 / 2;}long microsecondsToCentimeters(long microseconds) {   return microseconds / 29 / 2;}

代码说明

超声波传感器有四个端子:+5V,Trigger,Echo和GND,连接如下:

  • 将+5V引脚连接到Arduino板上的+5v。
  • 将Trigger连接到Arduino板上的数字引脚7。
  • 将Echo连接到Arduino板上的数字引脚6。
  • 将GND连接到Arduino上的GND。

在我们的程序中,我们通过串口显示了传感器测量的距离,单位为英寸和厘米。

结果

你将在Arduino串口监视器上看到传感器测量的距离,单位为英寸和厘米。


按钮或开关连接电路中的两个开路端子。当按下连接到引脚8的按钮开关时,此示例打开引脚2上的LED。

按钮

下拉电阻

在电子逻辑电路中使用下拉电阻,以确保在外部器件断开连接或处于高阻抗状态时,Arduino的输入信号达到预期的逻辑电平。虽然没有任何东西连接到输入引脚,但这并不意味着它是一个逻辑0。下拉电阻连接在地面和器件上相应的引脚之间。

下图显示了数字电路中下拉电阻的示例。在电源电压和微控制器引脚之间连接了一个按钮开关。在这样的电路中,当开关闭合时,微控制器输入处于逻辑高值;但是当开关打开时,下拉电阻将输入电压下拉到接地(逻辑零值),防止输入处于未定义状态。

下拉电阻的电阻必须大于逻辑电路的阻抗,否则可能会使电压下降太多,而无论开关的位置如何,引脚处的输入电压将保持在恒定的逻辑低值。

下拉电阻

必需的组件

你将需要以下组件:

  • 1 × Arduino UNO 板
  • 1 × 330欧姆电阻
  • 1 × 4.7K欧姆电阻(下拉)
  • 1 × LED

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

// constants won't change. They're used here to// set pin numbers:const int buttonPin = 8; // the number of the pushbutton pinconst int ledPin = 2; // the number of the LED pin// variables will change:int buttonState = 0; // variable for reading the pushbutton statusvoid setup() {   // initialize the LED pin as an output:   pinMode(ledPin, OUTPUT);   // initialize the pushbutton pin as an input:   pinMode(buttonPin, INPUT);}void loop() {   // read the state of the pushbutton value:   buttonState = digitalRead(buttonPin);   // check if the pushbutton is pressed.   // if it is, the buttonState is HIGH:   if (buttonState == HIGH) {      // turn LED on:      digitalWrite(ledPin, HIGH);   } else {      // turn LED off:      digitalWrite(ledPin, LOW);   }}

代码说明

当开关打开时(按钮未被按下),按钮的两个端子之间没有连接,因此引脚接地(通过下拉电阻),我们读取低电平。当开关闭合时(按钮被按下),它在其两个端子之间建立连接,将引脚连接到5伏,这样我们读出高电平。

结果

按下按钮时LED亮灯,松开按钮时LED熄灯。


在本章中,我们将使用Arduino板(UNO)连接不同类型的电机,并向你展示如何连接电机并从电路板上驱动它。

有三种不同类型的电机:

  • DC motor 直流电机
  • Servo motor 伺服电机
  • Stepper motor 步进电机

直流电机(DC—Direct Current motor)是最常见的电机类型。直流电动机通常只有两个引线,一个正极和一个负极。如果将这两根引线直接连接到电池,电机将旋转。如果切换引线,电机将以相反的方向旋转。

直流电机

警告 - 不要直接从Arduino板引脚驱动电机。这可能会损坏电路板。使用驱动电路或IC。

我们将本章分为三个部分:

  • 只让你的电机旋转
  • 控制电机速度
  • 控制直流电机的旋转方向

必需的组件

你将需要以下组件:

  • 1x Arduino UNO 板
  • 1x PN2222 晶体管
  • 1x 小型6V直流电机
  • 1x 1N4001二极管
  • 1x 270Ω电阻

程序

按照电路图进行连接,如下图所示。

电路图

预防措施

进行连接时,请采取以下预防措施:

  • 首先,确保晶体管以正确的方式连接。如图所示,晶体管的扁平面应该面向Arduino板。

  • 其次,根据图像中所示的排列,二极管的条纹端应朝向+5V电源线。

Arduino旋转控制代码

int motorPin = 3;void setup() {}void loop() {   digitalWrite(motorPin, HIGH);}

代码说明

晶体管就像一个开关,控制电机的功率。Arduino引脚3用于打开和关闭晶体管,并在草图中命名为“motorPin”。

结果

当Arduino引脚3变为高电平时,电机将全速旋转。

电机速度控制

以下是连接到Arduino板的直流电机的原理图。

直流电机的原理图

Arduino代码

int motorPin = 9;void setup() {   pinMode(motorPin, OUTPUT);   Serial.begin(9600);   while (! Serial);   Serial.println("Speed 0 to 255");}void loop() {   if (Serial.available()) {      int speed = Serial.parseInt();      if (speed >= 0 && speed <= 255) {         analogWrite(motorPin, speed);      }   }}

代码说明

晶体管就像一个开关,控制电机的功率。Arduino引脚3用于打开和关闭晶体管,并在草图中命名为“motorPin”。

当程序启动时,它会提示你提供值以控制电机的速度。你需要在串口监视器中输入介于0和255之间的值。

Command Window

在“loop”函数中,命令“Serial.parseInt”用于读取在串口监视器中作为文本输入的数字,并将其转换为“int”。你可以在此处输入任何数字。如果数字在0到255之间,下一行中的“if”语句只使用此数字进行模拟写入。

结果

直流电机将根据通过串口接收的值(0到250)以不同的速度旋转。

旋转方向控制

为了控制直流电机的旋转方向,无需互换引线,可以使用称为H桥的电路。H桥是可以双向驱动电机的电子电路。H桥用于许多不同的应用中。最常见的应用之一是控制机器人中的电机。它被称为H桥,是因为它使用四个晶体管连接,使示意图看起来像一个“H”。

我们将在这里使用L298 H桥 IC。L298可以控制直流电机和步进电机的速度和方向,并可以同时控制两个电机。每个电机的额定电流为2A。然而,在这些电流下,你将需要使用散热片。

旋转方向控制

必需的组件

你将需要以下组件:

  • 1 × L298桥式IC
  • 1 × 直流电机
  • 1 × Arduino UNO
  • 1 × 面包板
  • 10 × 跳线

程序

以下是Arduino Uno板的直流电机接口示意图。

直流电机接口

上图显示了如何连接L298 IC控制两个电机。每个电机有三个输入引脚,Motor1的Input1(IN1),Input2(IN2)和Enable1(EN1);Motor2的Input3,Input4和Enable2。

由于在这个例子中我们只控制一个电机,因此我们将把Arduino连接到L298 IC的IN1(引脚5),IN2(引脚7)和Enable1(引脚6)。引脚5和7是数字的,即ON或OFF输入,而引脚6需要脉冲宽度调制(PWM)信号来控制电机速度。

下表显示了电机根据IN1和IN2的数字值转动的方向。

IN1IN2电机行为
  制动
1 向前
 1向后
11制动

IC L298的引脚IN1连接到Arduino的引脚8,而IN2连接到引脚9。Arduino的这两个数字引脚控制电机的方向。IC的EN A引脚连接到Arduino的PWM引脚2。这将控制电机的速度。

为了设置Arduino引脚8和9的值,我们使用了digitalWrite()函数,而设置引脚2的值,我们必须使用analogWrite()函数。

连接步骤

  • 将IC的5V和接地分别连接到Arduino的5V和接地。
  • 将电机连接到IC的引脚2和3。
  • 将IC的IN1连接到Arduino的引脚8。
  • 将IC的IN2连接到Arduino的引脚9。
  • 将IC的EN1连接到Arduino的引脚2。
  • 将ICD的SENS A引脚接地。
  • 使用Arduino USB线连接Arduino,并使用Arduino IDE软件将程序上传到Arduino。
  • 使用电源,电池或USB线为Arduino板供电。

Arduino代码

const int pwm = 2 ; //initializing pin 2 as pwmconst int in_1 = 8 ;const int in_2 = 9 ;//For providing logic to L298 IC to choose the direction of the DC motorvoid setup() {   pinMode(pwm,OUTPUT) ; //we have to set PWM pin as output   pinMode(in_1,OUTPUT) ; //Logic pins are also set as output   pinMode(in_2,OUTPUT) ;}void loop() {   //For Clock wise motion , in_1 = High , in_2 = Low   digitalWrite(in_1,HIGH) ;   digitalWrite(in_2,LOW) ;   analogWrite(pwm,255) ;   /* setting pwm of the motor to 255 we can change the speed of rotation   by changing pwm input but we are only using arduino so we are using highest   value to driver the motor */   //Clockwise for 3 secs   delay(3000) ;   //For brake   digitalWrite(in_1,HIGH) ;   digitalWrite(in_2,HIGH) ;   delay(1000) ;   //For Anti Clock-wise motion - IN_1 = LOW , IN_2 = HIGH   digitalWrite(in_1,LOW) ;   digitalWrite(in_2,HIGH) ;   delay(3000) ;   //For brake   digitalWrite(in_1,HIGH) ;   digitalWrite(in_2,HIGH) ;   delay(1000) ;}

结果

电机首先在顺时针(CW)方向运行3秒,然后逆时针(CCW)运行3秒。


伺服电机是一种有输出轴的小型设备。通过向伺服发送编码信号,可以将该轴定位到特定的角度位置。只要编码信号存在于输入线上,伺服将保持轴的角位置。如果编码信号改变,则轴的角位置改变。实际上,伺服用于无线电控制的飞机中来定位控制面,如升降舵和方向舵。它们还用于无线电控制的汽车,木偶,当然还有机器人。


伺服电机

伺服在机器人中非常有用。电机体积小,内置控制电路,相对于它们尺寸来说非常强大。标准伺服如Futaba S-148具有42盎司/英寸的扭矩,这对于其尺寸来说是坚固的。它还吸取与机械负载成比例的功率。因此,轻负载伺服不会消耗太多能量。

伺服电机的内胆如下图所示。你可以看到控制电路,电机,一组齿轮和外壳。还可以看到连接到外部的3根电线。一个是接电源(+5伏),一个接地,而白线是控制线。

伺服电机的内胆

伺服电机的工作

伺服电机有一些控制电路和一个连接到输出轴上的电位器(一个可变电阻,也称为电位器)。在上图中,电位器可以在电路板的右侧看到。该电位器允许控制电路监视伺服电机的当前角度。

如果轴处于正确的角度,则电机关闭。如果电路发现角度不正确,则会转动电机直到处于所需的角度。伺服的输出轴能够在180度左右的地方移动。通常情况下,它是在210度范围内的某个地方,然而,这取决于制造商。正常伺服用于控制0至180度的角运动。由于主输出齿轮上的机械止动装置,机械上它无法转动更远。

施加到电机上的功率与其需要行进的距离成比例。因此,如果轴需要转动较大的距离,电机将以全速运转。如果只需要少量转动,电机将以较低的速度运转。这称为比例控制

如何沟通伺服应该转动的角度?

控制线用于传达角度。该角度由施加到控制线的脉冲持续时间确定。这称为脉冲编码调制伺服期望每20毫秒(0.02秒)看到一个脉冲。脉冲的长度将决定电机转动的距离。例如,1.5毫秒脉冲将使电机转到90度位置(通常称为中性位置)。如果脉冲短于1.5毫秒,则电机将轴转到更接近0度。如果脉冲长于1.5毫秒,则轴转接近180度。

转动角度

必需的组件

你将需要以下组件:

  • 1 × Arduino UNO板
  • 1 × 伺服电机
  • 1 × ULN2003驱动IC
  • 1 × 10KΩ电阻

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

/* Controlling a servo position using a potentiometer (variable resistor) */#include <Servo.h>   Servo myservo; // create servo object to control a servo   int potpin = 0; // analog pin used to connect the potentiometer   int val; // variable to read the value from the analog pinvoid setup() {   myservo.attach(9); // attaches the servo on pin 9 to the servo object}void loop() {   val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)   val = map(val, 0, 1023, 0, 180);   // scale it to use it with the servo (value between 0 and 180)   myservo.write(val); // sets the servo position according to the scaled value   delay(15);}

代码说明

伺服电机有三个端子:电源,接地和信号。电源线通常为红色,应连接到Arduino上的5V引脚。接地线通常为黑色或棕色,应连接到ULN2003 IC(10-16)的一个端子。为了保护你的Arduino板免受损坏,你将需要一些驱动IC来处理这些。这里我们使用ULN2003 IC来驱动伺服电机。信号引脚通常为黄色或橙色,应连接到Arduino引脚9。

连接电位器

分压器是串联电路中的电阻器,其将输出电压缩放到施加的输入电压的特定比例。下面是电路图:

连接电位计


公式

Vout是输出电位,取决于施加的输入电压(Vin)和电阻(R1R2这意味着流过R1的电流也将流过R2而不被分流。在上述等式中,随着R的值改变,Vout相对于输入电压Vin而缩放。

通常,电位器是一个分压器,它可以根据可变电阻的值而使用旋钮来缩放电路的输出电压。它有三个引脚:GND,Signal和+5V,如下图所示:

分压器

结果

通过更改电位器的NOP位置,伺服电机将改变其角度。


步进电机是无刷同步电机,它将完整的旋转分成多个步骤。与无刷直流电机不同,当向其施加固定的直流电压时,它将连续旋转,步进电机以不连续的步进角旋转。

因此,步进电机被制造成具有每转12,24,72,144,180和200的步长,从而产生每步30°,15°,5°,2.5°,2°和1.8°的步进角。步进电机可以有或没有反馈控制。

想象一下在RC飞机上的电机。电机在一个方向或另一个方向上转速非常快。你可以通过给予电机的功率量来改变速度,但是你不能让螺旋桨停在特定位置。

现在想象一个打印机。打印机内有很多移动部件,包括电机。一个电机用作进纸,当墨水开始印在纸上时旋转滚轴移动纸张。此电机需要能够将纸张移动一个精确的距离,以便能够打印下一行文本或图像的下一行。

还有另一个电机连接到一个螺杆上来回移动打印头。同样,该螺杆需要移动一个精确的量,以便一个字母接一个地打印。这就是步进电机派上用场的地方。

进步机电

步进电机如何工作?

常规的直流电动机只在方向上旋转,而步进电动机可以以精确的增量旋转。

步进电机可以根据需要转动精确的度数(或步长)。这使你可以完全控制电机,允许你将其移动到精确的位置并保持在该位置。它通过为电机内部的线圈非常短时间的供电来实现。缺点是你必须给电机一直供电,以将它保持在你想要的位置。

你现在需要知道的是,要移动步进电机,你要告诉它在一个方向或另一个方向上移动一定数量的步进,并告诉它沿那个方向步进的速度。步进电机的种类繁多。这里描述的方法可以用于推断如何使用本教程中未提到的其他电机和驱动程序。但是,始终建议你查阅针对具体型号的电机和驱动器的数据表和指南。

增量旋转

必需的组件

你将需要以下组件:

  • 1 × Arduino UNO板
  • 1 ×小型双极步进电机,如下图所示
  • 1 ×LM298驱动IC
小型双极步进电机

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

/* Stepper Motor Control */#include <Stepper.h>const int stepsPerRevolution = 90;// change this to fit the number of steps per revolution// for your motor// initialize the stepper library on pins 8 through 11:Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);void setup() {   // set the speed at 60 rpm:   myStepper.setSpeed(5);   // initialize the serial port:   Serial.begin(9600);}void loop() {   // step one revolution in one direction:   Serial.println("clockwise");   myStepper.step(stepsPerRevolution);   delay(500);   // step one revolution in the other direction:   Serial.println("counterclockwise");   myStepper.step(-stepsPerRevolution);   delay(500);}

代码说明

该程序驱动单极或双极步进电机。电机连接到Arduino的数字引脚8-11。

结果

电机将在一个方向上旋转一圈,然后在另一个方向上旋转一圈。


在本章中,我们将使用Arduino音调库。它只是一个Arduino库,可以在任意Arduino引脚上产生指定频率(50%占空比)的方波。持续时间可以有选择的指定,否则方波会一直持续到stop()函数被调用。该引脚可以连接到压电蜂鸣器或扬声器播放音调。

警告 - 不要将引脚直接连接到任何音频输入。电压远远高于标准线路电压,并可能损坏声卡输入等。你可以使用分压器来降低电压。

必需的组件

你将需要以下组件:

  • 1 × 8欧姆扬声器
  • 1 × 1k电阻
  • 1 × Arduino UNO 板

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

要制作pitches.h文件,请单击串口监视器图标正下方的按钮,然后选择“New Tab”,或使用Ctrl+Shift+N。

制作pitches.h文件

然后粘贴以下代码:

/************************************************** Public Constants*************************************************/#define NOTE_B0 31#define NOTE_C1 33#define NOTE_CS1 35#define NOTE_D1 37#define NOTE_DS1 39#define NOTE_E1 41#define NOTE_F1 44#define NOTE_FS1 46#define NOTE_G1 49#define NOTE_GS1 52#define NOTE_A1 55#define NOTE_AS1 58#define NOTE_B1 62#define NOTE_C2 65#define NOTE_CS2 69#define NOTE_D2 73#define NOTE_DS2 78#define NOTE_E2 82#define NOTE_F2 87#define NOTE_FS2 93#define NOTE_G2 98#define NOTE_GS2 104#define NOTE_A2 110#define NOTE_AS2 117#define NOTE_B2 123#define NOTE_C3 131#define NOTE_CS3 139#define NOTE_D3 147#define NOTE_DS3 156#define NOTE_E3 165#define NOTE_F3 175#define NOTE_FS3 185#define NOTE_G3 196#define NOTE_GS3 208#define NOTE_A3 220#define NOTE_AS3 233#define NOTE_B3 247#define NOTE_C4 262#define NOTE_CS4 277#define NOTE_D4 294#define NOTE_DS4 311#define NOTE_E4 330#define NOTE_F4 349#define NOTE_FS4 370#define NOTE_G4 392#define NOTE_GS4 415#define NOTE_A4 440#define NOTE_AS4 466#define NOTE_B4 494#define NOTE_C5 523#define NOTE_CS5 554#define NOTE_D5 587#define NOTE_DS5 622#define NOTE_E5 659#define NOTE_F5 698#define NOTE_FS5 740#define NOTE_G5 784#define NOTE_GS5 831#define NOTE_A5 880#define NOTE_AS5 932#define NOTE_B5 988#define NOTE_C6 1047#define NOTE_CS6 1109#define NOTE_D6 1175#define NOTE_DS6 1245#define NOTE_E6 1319#define NOTE_F6 1397#define NOTE_FS6 1480#define NOTE_G6 1568#define NOTE_GS6 1661#define NOTE_A6 1760#define NOTE_AS6 1865#define NOTE_B6 1976#define NOTE_C7 2093#define NOTE_CS7 2217#define NOTE_D7 2349#define NOTE_DS7 2489#define NOTE_E7 2637#define NOTE_F7 2794#define NOTE_FS7 2960#define NOTE_G7 3136#define NOTE_GS7 3322#define NOTE_A7 3520#define NOTE_AS7 3729#define NOTE_B7 3951#define NOTE_C8 4186#define NOTE_CS8 4435#define NOTE_D8 4699#define NOTE_DS8 4978

将上面给出的代码保存为 pitches.h

Arduino代码

#include "pitches.h"// notes in the melody:int melody[] = {NOTE_C4, NOTE_G3,NOTE_G3, NOTE_GS3, NOTE_G3,0, NOTE_B3, NOTE_C4};// note durations: 4 = quarter note, 8 = eighth note, etc.:int noteDurations[] = {   4, 8, 8, 4,4,4,4,4 };void setup() {   // iterate over the notes of the melody:   for (int thisNote = 0; thisNote < 8; thisNote++) {      // to calculate the note duration, take one second      // divided by the note type.      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.      int noteDuration = 1000/noteDurations[thisNote];      tone(8, melody[thisNote],noteDuration);      //pause for the note's duration plus 30 ms:      delay(noteDuration +30);   }}void loop() {   // no need to repeat the melody.}

代码说明

代码使用一个额外的文件,pitches.h。此文件包含典型音符的所有音高值。例如,NOTE_C4是中央C。NOTE_FS4是F#,等等。这个注释表最初是由Brett Hagman编写的,tone()命令是基于它工作的。当你想制作音符时会发现它很有用。

结果

你会听到保存在pitches.h文件中的音符。


无线发射器和接收器模块工作在315 Mhz。它们可以轻松地装入面包板,并可很好的与微控制器配合使用,创建一个非常简单的无线数据链路。使用一对发射器和接收器,模块将只能单向传输数据,因此,你将需要两对(不同频率)作为发射器/接收器对。

注意 - 这些模块是任意的,并会接收相当大量的噪音。发射器和接收器都在共同的频率下工作,并且没有ID。

无线发射器

接收器模块规格

产品型号 - MX-05V
工作电压 - DC5V
静态电流 - 4mA
接收频率 - 315Mhz
接收灵敏度 - -105DB
尺寸 - 30*14*7mm

发射器模块规格

产品型号 - MX-FS-03V
发射距离 - 20-200米(不同电压,不同结果)
工作电压 - 3.5-12V
尺寸 - 19*19mm
操作模式 - AM
传输速率 - 4KB/S
发射功率 - 10mW
发射频率 - 315Mhz
外置天线 - 25cm普通多芯或单芯线
从左到右的引脚分布 - DATA;VCC;GND

必需的组件

你将需要以下组件:

  • 2 × Arduino UNO板
  • 1 × Rf链路发射器
  • 1 × Rf链路接收器

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

注意 - 你必须在Arduino库文件中包含键盘库。将VirtualWire.lib文件复制并粘贴到库文件夹中,如下面屏幕截图的高亮部分所示。

在Arduino库文件中包含键盘库

发射器的Arduino代码

//simple Tx on pin D12#include <VirtualWire.h>char *controller;void setup() {   pinMode(13,OUTPUT);   vw_set_ptt_inverted(true);   vw_set_tx_pin(12);   vw_setup(4000);// speed of data transfer Kbps}void loop() {   controller="1" ;   vw_send((uint8_t *)controller, strlen(controller));   vw_wait_tx(); // Wait until the whole message is gone   digitalWrite(13,1);   delay(2000);   controller="0" ;   vw_send((uint8_t *)controller, strlen(controller));   vw_wait_tx(); // Wait until the whole message is gone   digitalWrite(13,0);   delay(2000);}

代码说明

这是一个简单的代码。首先发送字符“1”,两秒后发送字符“0”,以此类推。

接收器的Arduino代码

//simple Rx on pin D12#include <VirtualWire.h>void setup() {   vw_set_ptt_inverted(true); // Required for DR3100   vw_set_rx_pin(12);   vw_setup(4000); // Bits per sec   pinMode(5, OUTPUT);   vw_rx_start(); // Start the receiver PLL running}void loop() {   uint8_t buf[VW_MAX_MESSAGE_LEN];   uint8_t buflen = VW_MAX_MESSAGE_LEN;   if (vw_get_message(buf, &buflen)) // Non-blocking {      if(buf[0]=='1') {         digitalWrite(5,1);      }      if(buf[0]=='0') {         digitalWrite(5,0);      }   }}

代码说明

当接收到字符“1”时,连接到Arduino板上引脚5的LED亮起,当接收到字符“0”时,LED熄灭。


德州仪器的CC3000 WiFi模块是一个小型银包,最终为你的Arduino项目带来了易用,经济实惠的WiFi功能。

它使用SPI进行通信(而不是UART),因此你可以根据需要尽可能快或尽可能慢地推送数据。它有一个合适的IRQ引脚中断系统,因此你可以有异步连接。它支持802.11b/g,open/WEP/WPA/WPA2安全,TKIP及AES。具有“BSD socket”接口的内置TCP/IP堆栈支持客户端和服务器模式下的TCP和UDP。


CC3000

必需的组件

你将需要以下组件:

  • 1 × Arduino Uno
  • 1 × Adafruit CC3000分线板
  • 1 × 5V继电器
  • 1 × 整流二极管
  • 1 × LED
  • 1 × 220欧姆电阻
  • 1 × 面包板和一些跳线

对于这个项目,你只需要通常的Arduino IDE,Adafruit的CC3000库以及CC3000 MDNS库。我们也将使用aREST库通过WiFi向中继发送命令。

程序

按照电路图进行连接,如下图所示。

电路图

这个项目的硬件配置非常简单。

  • 将CC3000板的IRQ引脚连接到Arduino板的引脚3。
  • VBAT连接到引脚5,CS连接到引脚10。
  • 将SPI引脚连接到Arduino板:MOSI,MISO和CLK分别连接到引脚11,12和13。
  • Vin连接到Arduino 5V,GND连接到GND。

现在,让我们连接继电器。

将继电器放在面包板上后,你可以开始识别继电器上的两个重要部分:指示继电器的线圈部分和连接LED的开关部分。

  • 首先,将Arduino板的8号引脚连接到线圈的一个引脚。
  • 将另一个引脚连接到Arduino板的接地。

您还必须将整流二极管(阳极连接到接地引脚)放置在线圈的引脚上,以在继电器切换时保护电路。

  • 将Arduino板的+5V连接到继电器开关的公共引脚。

  • 最后,将开关的另一个引脚(通常是继电器断开时未连接的引脚)连接到与220欧姆电阻串联的LED,并将LED的另一端连接到Arduino的接地。

测试单个组件

你可以使用以下草图测试继电器:

const int relay_pin = 8; // Relay pinvoid setup() {   Serial.begin(9600);   pinMode(relay_pin,OUTPUT);}void loop() {   // Activate relay   digitalWrite(relay_pin, HIGH);   // Wait for 1 second   delay(1000);   // Deactivate relay   digitalWrite(relay_pin, LOW);   // Wait for 1 second   delay(1000);}

代码说明

代码是不言自明的。你只需将其上传到电路板,继电器将每秒切换状态,LED将相应地亮起和熄灭。

添加WiFi连接

现在让我们使用CC3000 WiFi芯片无线控制继电器。该项目的软件基于TCP协议。但是,对于这个项目,Arduino板将运行一个小的Web服务器,以便我们可以“监听”来自计算机的命令。我们先来看看Arduino草图,然后我们将看到如何编写服务器端代码并创建一个漂亮的界面。

首先,Arduino草图。这里的目标是连接到你的WiFi网络,创建Web服务器,检查是否有传入的TCP连接,然后相应地更改继电器的状态。

代码的重要部分

#include <Adafruit_CC3000.h>#include <SPI.h>#include <CC3000_MDNS.h>#include <Ethernet.h>#include <aREST.h>

你需要在代码中定义特定于你的配置的内容,即Wi-Fi名称和密码,以及TCP通信端口(我们在此使用了80)。

// WiFi network (change with your settings!)   #define WLAN_SSID "yourNetwork" // cannot be longer than 32 characters!   #define WLAN_PASS "yourPassword"   #define WLAN_SECURITY WLAN_SEC_WPA2 // This can be WLAN_SEC_UNSEC, WLAN_SEC_WEP,    // WLAN_SEC_WPA or WLAN_SEC_WPA2// The port to listen for incoming TCP connections   #define LISTEN_PORT 80

然后我们可以创建CC3000实例,服务器和aREST实例:

// Server instance   Adafruit_CC3000_Server restServer(LISTEN_PORT); // DNS responder instance   MDNSResponder mdns; // Create aREST instance   aREST rest = aREST();

在草图的setup()部分,我们现在可以将CC3000芯片连接到网络:

cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);

计算机将如何知道在哪里发送数据?一种方法是运行草图一次,然后获取CC3000板的IP地址,并再次修改服务器代码。但是,我们可以做得更好,这就是CC3000 MDNS库发挥作用的地方。我们将使用此库为我们的CC3000板分配一个固定名称,以便我们可以将此名称直接写入服务器代码。

这可以用下面的代码片段完成:

if (!mdns.begin("arduino", cc3000)) {   while(1);}

我们还需要监听传入的连接。

restServer.begin();

接下来,我们要对将被连续执行的草图的loop()函数进行编码。我们首先要更新mDNS服务器。

mdns.update();

在Arduino板上运行的服务器将等待传入连接并处理请求。

Adafruit_CC3000_ClientRef client = restServer.available();rest.handle(client);

现在通过WiFi测试项目非常容易。确保你使用自己的WiFi名称和密码更新草图,并将草图上传到Arduino板。打开你的Arduino IDE串口监视器,并查找电路板的IP地址。

我们假设其余的是192.168.1.103。

然后,只需进入你喜欢的网络浏览器,然后键入:

192.168.1.103/digital/8/1

你应该看到继电器自动打开。

构建继电器界面

我们现在将编写项目的界面。这里将有两个部分:包含界面的HTML文件和用于处理界面上点击的客户端Javascript文件。这里的界面基于aREST.js项目,这是为了方便从你的计算机控制WiFi设备。
让我们先看一下名为interface.html的HTML文件。第一部分包括导入所有界面需要的库:

<head>   <meta charset = utf-8 />   <title> Relay Control </title>   <link rel = "stylesheet" type = "text/css"       href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">   <link rel="stylesheet" type = "text/css" href = "style.css">   <script type = "text/javascript"       src = "https://code.jquery.com/jquery-2.1.4.min.js"></script>   <script type = "text/javascript"       src = "https://cdn.rawgit.com/Foliotek/AjaxQ/master/ajaxq.js"></script>   <script type = "text/javascript"       src = "https://cdn.rawgit.com/marcoschwartz/aREST.js/master/aREST.js"></script>   <script type = "text/javascript"       src = "script.js"></script></head>

然后,我们在界面中定义两个按钮,一个用于打开继电器,另一个用于再次关闭继电器。

<div class = 'container'>   <h1>Relay Control</h1>   <div class = 'row'>      <div class = "col-md-1">Relay</div>      <div class = "col-md-2">         <button id = 'on' class = 'btn btn-block btn-success'>On</button>      </div>      <div class = "col-md-2">         <button id = 'off' class = 'btn btn-block btn-danger'>On</button>      </div>   </div></div>

现在,我们还需要一个客户端Javascript文件来处理按钮上的点击。我们还将创建一个设备,我们将链接到Arduino设备的mDNS名称。如果你在Arduino代码中改变了这个,你也需要在这里修改它。

// Create devicevar device = new Device("arduino.local");// Button$('#on').click(function() {   device.digitalWrite(8, 1);});$('#off').click(function() {   device.digitalWrite(8, 0);});

该项目的完整代码可以在 GitHub 存储库中找到。进入界面文件夹,只需用你喜欢的浏览器打开HTML文件。应该会在浏览器中看到类似的内容:

Relay Control


尝试点击Web界面上的按钮;它应该立即改变继电器的状态。

如果你设法让它工作了,恭喜你,你刚刚构建了一个Wi-Fi控制的电灯开关。当然,通过这个项目你可以控制更多的电灯。只需确保你的继电器支持你想要控制的设备所需的电源,你就可以很好的实现了。


Arduino是一个基于易用硬件和软件的原型平台(开源)。它由可编程的电路板(称为微控制器)和称为Arduino IDE(集成开发环境)的现成软件组成,用于将计算机代码写入并上传到物理板。


主要特点是:

  • Arduino板卡能够读取来自不同传感器的模拟或数字输入信号,并将其转换为输出,例如激活电机,打开/关闭LED,连接到云端等多种操作。

  • 你可以通过Arduino IDE(简称上传软件)向板上的微控制器发送一组指令来控制板功能。

  • 与大多数以前的可编程电路板不同,Arduino不需要额外的硬件(称为编程器)来将新代码加载到板上。你只需使用USB线即可。

  • 此外,Arduino IDE使用C++的简化版本,使其更容易学习编程。

  • 最后,Arduino提供了一个标准的外形规格,将微控制器的功能打破成更易于使用的软件包。


Arduino板卡

Arduino板的类型

根据使用的不同微控制器,可提供各种Arduino板。然而,所有Arduino板都有一个共同点:它们通过Arduino IDE编程。

差异基于输入和输出的数量(可以在单个板上使用的传感器,LED和按钮的数量),速度,工作电压,外形尺寸等。一些板被设计为嵌入式,并且没有编程接口(硬件),因此你需要单独购买。有些可以直接从3.7V电池运行,其他至少需要5V。

以下是可用的不同Arduino板的列表。

基于ATMEGA328微控制器的Arduino板

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Uno R35V16MHz14661USB通过ATMega16U2
Arduino Uno R3 SMD5V16MHz14661USB通过ATMega16U2
Red Board5V16MHz14661USB通过FTDI
Arduino Pro 3.3v/8 MHz3.3V8MHz14661FTDI兼容头
Arduino Pro 5V/16MHz5V16MHz14661FTDI兼容头
Arduino mini 055V16MHz14861FTDI兼容头
Arduino Pro mini 3.3v/8mhz3.3V8MHz14861FTDI兼容头
Arduino Pro mini 5v/16mhz5V16MHz14861FTDI兼容头
Arduino Ethernet
5V16MHz14661FTDI兼容头
Arduino Fio3.3V8MHz14861FTDI兼容头
LilyPad Arduino 328 main board3.3V8MHz14661FTDI兼容头
LilyPad Arduino simply board3.3V8MHz9450FTDI兼容头

基于ATMEGA32u4微控制器的Arduino板卡

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Leonardo5V16MHz201271本机USB
Pro micro 5V/16MHz5V16MHz14661本机USB
Pro micro 3.3V/8MHz5V16MHz14661本机USB
LilyPad Arduino USB3.3V8MHz14661本机USB

基于ATMEGA2560微控制器的Arduino板卡

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Mega 2560 R35V16MHz5416144USB通过ATMega16U2B
Mega Pro 3.3V3.3V8MHz5416144FTDI兼容头
Mega Pro 5V5V16MHz5416144FTDI兼容头
Mega Pro Mini 3.3V3.3V8MHz5416144FTDI兼容头

基于AT91SAM3X8E微控制器的Arduino板卡

板名称工作电压时钟速度数字i/o模拟输入PWMUART编程接口
Arduino Mega 2560 R33.3V84MHz5412124本机USB


在本章中,我们将了解 Arduino 板上的不同组件。将学习 Arduino UNO 板,因为它是 Arduino 板系列中最受欢迎的。此外,它是开始使用电子和编码的最佳板。有些板看起来与下面给出的有些不同,但多数 Arduino 中的这些组件大部分是共同的。

以下是 UNO 板的电路:


以下是 UNO 板的详细参数:

名称参数
工作电压5V
输入电压接上 USB 时无须外部供电或外部 7V~12V DC 输入
输出电压5V DC 输出和 3.3V DC 输出 和外部电源输入
微处理器ATmega328
BootloaderArduino Uno
时钟频率16 MHz
输入电压( 推荐)7-12V
输入电压(限制)6-20V
支持 USB 接口协议及供电(不需外接电源)
支持 ISP 下载功能
数字 I/O 端口14(6 个 PWM 输出口)
模拟输入端口6
直流电流  I/O 端口40mA
直流电流 3.3V 端口50mA
Flash 内存32 KB (ATmega328) (0.5 KB用于引导程序)
SRAM2 KB (ATmega328)
EEPROM1 KB (ATmega328)
尺寸75x55x15mm

以下是 UNO 板的详细内容:

Arduino UNO板


Power USB

电源 USB

Arduino 板可以通过使用计算机上的USB线供电。你需要做的是将 USB 线连接到 USB 接口。

Barrel Jack

电源(桶插座)

Arduino 板可以通过将其连接到电源插口直接从交流电源供电。

Voltage Regulator

稳压器

稳压器的功能是控制提供给 Arduino 板的电压,并稳定处理器和其他元件使用的直流电压。

Crystal Oscillator

晶体振荡器

晶振帮助Arduino处理时间问题。Arduino 如何计算时间?答案是,通过使用晶体振荡器。在 Arduino 晶体顶部打印的数字是 16.000H9H。它告诉我们,频率是 16,000,000 赫兹或 16MHz。

Arduino Reset

Arduino 重置

你可以重置你的 Arduino 板,例如从一开始就启动你的程序。可以通过两种方式重置 UNO 板。首先,通过使用板上的复位按钮(17)。其次,你可以将外部复位按钮连接到标有 RESET(5)的 Arduino 引脚。

Pins

引脚(3.3,5,GND,Vin)

  • 3.3V(6) - 提供 3.3 输出电压

  • 5V(7) - 提供 5 输出电压

  • 使用3.3伏和5伏电压,与 Arduino 板一起使用的大多数组件可以正常工作。

  • GND(8)(接地) - Arduino 上有几个 GND 引脚,其中任何一个都可用于将电路接地。

  • VVin(9) - 此引脚也可用于从外部电源(如交流主电源)为 Arduino 板供电。

Analog pins

模拟引脚

Arduino UNO 板有六个模拟输入引脚,A0 到 A5。这些引脚可以从模拟传感器(如湿度传感器或温度传感器)读取信号,并将其转换为可由微处理器读取的数字值。

Main microcontroller

微控制器

每个 Arduino 板都有自己的微控制器(11)。你可以假设它作为板的大脑。Arduino 上的主 IC(集成电路)与板对板略有不同。微控制器通常是 ATMEL 公司的。在从 Arduino IDE 加载新程序之前,你必须知道你的板上有什么 IC。此信息位于 IC 顶部。有关 IC 结构和功能的更多详细信息,请参阅数据表。

ICSP pin

ICSP 引脚

大多数情况下,ICSP(12)是一个 AVR,一个由 MOSI,MISO,SCK,RESET,VCC 和 GND 组成的 Arduino 的微型编程头。它通常被称为 SPI(串行外设接口),可以被认为是输出的“扩展”。实际上,你是将输出设备从属到 SPI 总线的主机。

Power LED indicator

电源 LED 指示灯

当你将 Arduino 插入电源时,此 LED 指示灯应亮起,表明你的电路板已正确通电。如果这个指示灯不亮,那么连接就出现了问题。

TX and RX LEDs

TX 和 RX LED

在你的板上,你会发现两个标签:TX(发送)和RX(接收)。它们出现在 Arduino UNO 板的两个地方。首先,在数字引脚 0 和 1 处,指示引脚负责串行通信。其次,TX 和 RX LED(13)。发送串行数据时,TX LED 以不同的速度闪烁。闪烁速度取决于板所使用的波特率。RX 在接收过程中闪烁。

Digital I/O

数字 I/O

Arduino UNO 板有 14 个数字 I/O 引脚(15)(其中 6 个提供 PWM(脉宽调制)输出),这些引脚可配置为数字输入引脚,用于读取逻辑值(0 或 1) ;或作为数字输出引脚来驱动不同的模块,如 LED,继电器等。标有“〜”的引脚可用于产生 PWM。

AREF

AREF

AREF 代表模拟参考。它有时用于设置外部参考电压(0 至 5 伏之间)作为模拟输入引脚的上限。



在了解Arduino UNO板的主要部分后,我们准备学习如何设置Arduino IDE。一旦我们学到这一点,我们将准备在Arduino板上上传我们的程序。


在本节中,我们将在简单的步骤中学习如何在我们的计算机上设置Arduino IDE,并准备板通过USB线接收程序。


步骤1 - 首先,你必须有Arduino板(你可以选择你喜欢的板)和一根USB线。如果你使用Arduino UNO,Arduino Duemilanove,Nano,Arduino Mega 2560或Diecimila,你将需要一个标准USB线(A插头到B插头)。如下图所示为你将连接到USB打印机的类型。


标准USB电缆


如果使用Arduino Nano,你将需要一条A到Mini-B线,如下图所示。


A到Mini-B电缆


步骤2 - 下载Arduino IDE软件。

你可以从Arduino官方网站的下载页面获得不同版本的Arduino IDE。你必须选择与你的操作系统(Windows,IOS或Linux)兼容的软件。文件下载完成后,解压缩文件。


解压缩文件

步骤3 - 打开板的电源。

Arduino Uno,Mega,Duemilanove和Arduino Nano通过USB连接到计算机或外部电源自动获取电源。如果你使用Arduino Diecimila,则必须确保板的配置为从USB连接获取电源。电源选择使用跳线,一小块塑料安装在USB和电源插孔之间的三个引脚中的两个。检查它是否在最靠近USB端口的两个引脚上。

使用USB线将Arduino板连接到计算机。绿色电源LED等(标有PWR)应该发光。


步骤4 - 启动Arduino IDE。

下载Arduino IDE软件后,需要解压缩该文件夹。在文件夹中,你可以找到带有无穷大标签(application.exe)的应用程序图标。双击该图标以启动IDE。

启动Arduino IDE


步骤5 - 打开你的第一个项目。

一旦软件启动,你有两个选项:

  • 创建一个新项目。
  • 打开一个现有的项目示例。

要创建新项目,请选择Flie→New。


新建项目


要打开现有项目示例,请选择File→Example→Basics→Blink。


打开现有项目示例

在这里,我们只选择一个名为 Blink 的示例。它打开和关闭LED有一些时间延迟。你可以从列表中选择任何其他示例。


步骤6 - 选择你的Arduino主板。

为了避免在将程序上载到板上时出现任何错误,必须选择正确的Arduino板名称,该名称与连接到计算机的电路板相匹配。

转到Tools→Board,然后选择你的板。


选择您的Arduino主板

在这里,根据我们的教程选择了Arduino Uno板,但是你必须选择与你使用的板匹配的名称。


步骤7 - 选择串行端口。

选择Arduino板的串行设备。转到Tools→Serial Port菜单。这可能是COM3或更高(COM1和COM2通常保留为硬件串行端口)。要弄清楚的话,你可以断开你的Arduino板,并重新打开菜单,那么消失的条目应该是Arduino板。重新连接板并选择该串行端口。

选择串行端口。


步骤8 - 将程序上传到你的板。

在解释如何将我们的程序上传到板之前,我们必须演示Arduino IDE工具栏中出现的每个符号的功能。


将程序上传到您的主板

A - 用于检查是否存在任何编译错误。

B - 用于将程序上传到Arduino板。

C - 用于创建新草图的快捷方式。

D - 用于直接打开示例草图之一。

E - 用于保存草图。

F - 用于从板接收串行数据并将串行数据发送到板的串行监视器。


现在,只需点击环境中的“Upload”按钮。等待几秒钟,你将看到板上的RX和TX LED灯闪烁。如果上传成功,则状态栏中将显示“Done uploading”消息。


注意 - 如果你有Arduino Mini,NG或其他电路板,则需要在单击Arduino软件上的上传按钮之前,立即按下电路板上的复位按钮。

在本章中,我们将深入研究Arduino程序结构,并将学习更多Arduino世界中使用的新术语。Arduino软件是开源的。Java环境的源代码在GPL下发布,C/C++微控制器库在LGPL下。


Sketch(草图) - 第一个新的术语是名为“sketch”的Arduino程序。


结构

Arduino程序可以分为三个主要部分:结构,值(变量和常量)和函数在本教程中,我们将逐步了解Arduino软件程序,以及如何编写程序而不会出现任何语法或编译错误。


让我们从结构开始。软件结构包括两个主要函数:

  • Setup()函数
  • Loop()函数
结构
Void setup ( ) {}
  • PURPOSE- 草图启动时会调用 setup()函数。使用它来初始化变量,引脚模式,启用库等。setup函数只能在Arduino板的每次上电或复位后运行一次。

  • INPUT - -

  • OUTPUT - -

  • RETURN- -

Void Loop ( ) {}
  • PURPOSE- 在创建了用于初始化并设置初始值的setup()函数后,loop() 函数,正如它的名称所指,允许你的程序连续循环的更改和响应。可以使用它来主动控制Arduino板。

  • INPUT - -

  • OUTPUT - -

  • RETURN- -

C中的数据类型是指用于声明不同类型的变量或函数的扩展系统。变量的类型确定它在存储器中占用多少空间以及如何解释存储的位模式。

下表提供了你将在Arduino编程期间使用的所有数据类型。

voidBooleancharUnsigned char
byteintUnsigned int
word
longUnsigned long
shortfloatdoublearrayString-char array
String-object


void

void关键字仅用于函数声明。它表示该函数预计不会向调用它的函数返回任何信息。

例子

Void Loop ( ) {   // rest of the code}

Boolean

布尔值保存两个值之一,true或false。每个布尔变量占用一个字节的内存。

例子

boolean val = false ; // declaration of variable with type boolean and initialize it with falseboolean state = true ; // declaration of variable with type boolean and initialize it with true

Char

一种数据类型,占用一个字节的内存,存储一个字符值。字符文字用单引号写成:'A',对于多个字符,字符串使用双引号:"ABC"。

但是,字符是存储为数字。你可以在ASCII图表中查看特定编码。这意味着可以对使用ASCII值的字符进行算术运算。例如,'A'+1的值为66,因为大写字母A的ASCII值为65。

例子

Char chr_a = ‘a’ ;//declaration of variable with type char and initialize it with character aChar chr_c = 97 ;//declaration of variable with type char and initialize it with character 97
ASCII Char Table

unsigned char

unsigned char是一种无符号数据类型,占用一个字节的内存。unsigned char数据类型编码数字为0到255。

例子

Unsigned Char chr_y = 121 ; // declaration of variable with type Unsigned char and initialize it with character y

byte

一个字节存储一个8位无符号数,从0到255。

例子

byte m = 25 ;//declaration of variable with type byte and initialize it with 25

int

整数(int)是数字存储的主要数据类型。int存储16位(2字节)值。这产生-32768至32767的范围(最小值为-2^15,最大值为(2^15)-1)。

int的大小因板而异。例如,在Arduino Due中,int存储32位(4字节)值。这产生-2147483648至2147483647的范围(最小值-2^31和最大值(2^31)-1)。

例子

int counter = 32 ;// declaration of variable with type int and initialize it with 32

Unsigned int

unsigned int(无符号整数)与int相同,存储2字节。然而,它们只存储正值,产生0到65535(2^16)-1的有效范围。Due存储4字节(32位)值,范围从0到4294967295(2^32-1)。

例子

Unsigned int counter = 60 ; // declaration of variable with    type unsigned int and initialize it with 60

Word

在Uno和其他基于ATMEGA的板上,一个word存储一个16位无符号数。在Due和Zero上,它存储一个32位无符号数。

例子

word w = 1000 ;//declaration of variable with type word and initialize it with 1000

Long

Long变量是用于数字存储的扩展大小变量,存储32位(4字节),从-2147483648到2147483647。

例子

Long velocity = 102346 ;//declaration of variable with type Long and initialize it with 102346

unsigned long

unsigned long变量是用于数字存储的扩展大小变量,并存储32位(4字节)。与标准的long不同,unsigned long不会存储负数,它们的范围为0到4294967295(2^32-1)。

例子

Unsigned Long velocity = 101006 ;// declaration of variable with    type Unsigned Long and initialize it with 101006

short

short是16位数据类型。在所有Arduinos(基于ATMega和ARM)上,一个short存储一个16位(2字节)值。这产生-32768至32767的范围(最小值为-2^15,最大值为(2^15)-1)。

例子

short val = 13 ;//declaration of variable with type short and initialize it with 13

float

浮点数的数据类型是具有小数点的数字。浮点数通常用于近似模拟值和连续值,因为它们的分辨率高于整数。

浮点数可以大到3.4028235E+38,也可以低到-3.4028235E+38。它们被存储为32位(4字节)信息。

例子

float num = 1.352;//declaration of variable with type float and initialize it with 1.352

double

在Uno和其他基于ATMEGA的板上,双精度浮点数占用四个字节。也就是说,double实现与float完全相同,精度没有增益。在Arduino Due上,double具有8字节(64位)精度。

例子

double num = 45.352 ;// declaration of variable with type double and initialize it with 45.352


在我们开始解释变量类型之前,我们需要确定一个非常重要的主题,称为变量范围

什么是变量范围?

Arduino使用的C语言中的变量具有名为scope(范围)的属性。scope是程序的一个区域,有三个地方可以声明变量。它们是:

  • 在函数或代码块内部,称为局部变量
  • 在函数参数的定义中,称为形式参数
  • 在所有函数之外,称为全局变量

局部变量

在函数或代码块中声明的变量是局部变量。它们只能由该函数或代码块中的语句使用。局部变量不能在它们自己之外运行。以下是使用局部变量的示例:

Void setup () {}Void loop () {   int x , y ;   int z ; Local variable declaration   x = 0;   y = 0; actual initialization   z = 10;}

全局变量

全局变量在所有函数之外定义,通常位于程序的顶部。全局变量将在程序的整个生命周期中保持其价值。

全局变量可以被任何函数访问。也就是说,一个全局变量可以在整个程序中声明后使用。

以下示例使用全局变量和局部变量:

Int T , S ;float c = 0 ; Global variable declarationVoid setup () {}Void loop () {   int x , y ;   int z ; Local variable declaration   x = 0;   y = 0; actual initialization   z = 10;}


运算符是一个符号,它告诉编译器执行特定的数学或逻辑函数。C语言具有丰富的内置运算符,并提供以下类型的运算符:

  • Arithmetic Operators 算术运算符
  • Comparison Operators 比较运算符
  • Boolean Operators 布尔运算符
  • Bitwise Operators 位运算符
  • Compound Operators 复合运算符

算术运算符

假设变量A为10,变量B为20,则:

示例

运算符名称运算符简写描述例子
赋值运算符
=将等号右侧的值存储在等号左边的变量中。A = B
加号+两个操作数相加A + B将得出30
减号-从第一个操作数中减去第二个操作数A - B将得出-10
乘号*将两个操作数相乘A * B将得出200
除号/用分母除分子B / A将得出2
模数%模数运算符和整数除后的余数B % A将得出0


比较运算符

假设变量A为10,变量B为20,则:

示例

运算符名称运算符简写
描述例子
等于==检查两个操作数的值是否相等,如果相等,则条件为真(true)。(A == B)不为真
不等于!=检查两个操作数的值是否相等,如果值不相等,则条件为真。(A != B)为真
小于<检查左操作数的值是否小于右操作数的值,如果是,则条件为真。(A < B)为真
大于>检查左操作数的值是否大于右操作数的值,如果是,则条件为真。(A > B)不为真
小于或等于<=检查左操作数的值是否小于或等于右操作数的值,如果是,则条件为真。(A <= B)为真
大于或等于>=检查左操作数的值是否大于或等于右操作数的值,如果是,则条件为真。(A >= B)不为真


布尔运算符

假设变量A为10,变量B为20,则:

示例

运算符名称
运算符简写
描述例子
and(与)&&称为逻辑运算符与。如果两个操作数都是非零,那么条件为真。(A && B)为真
or(或)||称为逻辑运算符或。如果两个操作数中的任何一个是非零,则条件为真。(A || B)为真
not(非)!称为逻辑运算符非。用于反转其操作数的逻辑状态。如果条件为真,则逻辑运算符非将为假。!(A && B)为假


位运算符

假设变量A为60,变量B为13,则:

示例

运算符名称
运算符简写
描述例子
and(与)&如果同时存在于两个操作数中,二进制AND运算符复制一位到结果中。(A & B)将得出12,即0000 1100
or(或)|如果存在于任一操作数中,二进制OR运算符复制一位到结果中。(A | B)将得出61,即0011 1101
xor(异或)^如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制XOR运算符复制一位到结果中。(A ^ B)将得出49,即0011 0001
not(非)~二进制NOT运算符是一元运算符,具有"翻转"位效果。(〜A)将得出-60,即1100 0011
shift left(左移)
<<二进制左移运算符。左操作数的值向左移动右操作数指定的位数A<< 2将得出240,即1111 0000
shift right(右移)
>>二进制右移运算符。左操作数的值向右移动右操作数指定的位数A>> 2将得出15,即0000 1111


复合运算符

假设变量A为10,变量B为20,则:

示例

运算符名称
运算符简写
描述例子
自增++自增运算符,将整数值增加1A++ 将得出11
自减--自减运算符,将整数值减1A-- 将得出9
复合加
+=加且赋值运算符。把右边操作数加上左边操作数的结果赋值给左边操作数。B += A 等效于 B = B + A
复合减
-=减且赋值运算符。把左边操作数减去右边操作数的结果赋值给左边操作数。B -= A等效于B = B - A
复合乘
*=乘且赋值运算符。把右边操作数乘以左边操作数的结果赋值给左边操作数。B *= A等价于B = B * A
复合除
/=除且赋值运算符。把左边操作数除以右边操作数的结果赋值给左边操作数。B /= A等效于B = B / A
复合模数
%=求模且赋值运算符。 求两个操作数的模赋值给左边操作数B %= A等效于B = B % A
复合按位或|=按位或且赋值运算符A |= 2与A = A | 2相同
复合按位与
&=按位与且赋值运算符A &= 2与A = A & 2相同

判断结构要求程序员指定要由程序评估或测试的一个或多个条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。

以下是大多数编程语言中典型的判断结构的一般形式:


流程图


控制语句是源代码中控制程序执行流程的元素。它们是:

序号控制语句和描述
1

If 语句

它采用括号中的表达式,后面跟随语句或语句块。如果表达式为真,则执行语句或语句块,否则跳过这些语句。

2

If … else 语句

一个 if 语句后面可以跟随一个可选的else语句,当表达式为false时执行。

3

If … else if … else 语句

if 语句后面可以跟随一个可选的 else if ... else 语句,其对于测试各种条件非常有用。

4

switch case 语句

类似于if语句, switch ... case 通过允许程序员指定应在各种条件下执行的不同代码来控制程序的流程。

5

条件运算符 ? :

条件运算符? :是C语言中唯一的三元运算符。


编程语言提供了各种控制结构,允许更复杂的执行路径。

循环语句允许我们多次执行一个语句或一组语句,以下是大多数编程语言中循环语句的一般形式:

流程图


C语言提供以下类型的循环来处理循环需求。

序号循环及描述
1

while循环

while循环将会连续、无限循环,直到括号()内的表达式变为false。必须用一些东西改变被测试的变量,否则while循环永远不会退出。

2

do…while循环

do ... while循环类似于while循环。在while循环中,循环连续条件在循环开始时测试,然后再执行循环体。

3

for循环

 for循环执行语句预定的次数。循环的控制表达式在for循环括号内完全的初始化,测试和操作。

4

嵌套循环

C语言允许你在另一个循环内使用一个循环。下面的例子说明了这个概念。

5

无限循环

它是没有终止条件的循环,因此循环变为无限。


函数允许在代码段中构造程序来执行单独的任务。创建函数的典型情况是在程序需要多次执行相同的动作时。

将代码片段标准化为函数具有几个优点:

  • 函数帮助程序员保持组织性。通常有助于概念化程序。

  • 函数将一个动作编码在一个地方,以便函数只需要考虑一次和调试一次。

  • 如果代码需要更改,这也减少了修改错误的几率。

  • 由于代码段被多次重复使用,函数使整个草图更小更紧凑。

  • 通过将代码模块化以令其在其他程序中重复使用变得更容易,通过使用函数使得代码更具可读性。

在Arduino草图或程序中有两个必需的函数,即setup()和loop()。其他函数必须在这两个函数的括号之外创建。

定义函数的最常用的语法是:


定义函数

函数声明

函数在循环函数之上或之下的任何其他函数之外声明。

我们可以用两种不同的方式声明函数:

第一种方法是在循环函数上面写入被称为函数原型的函数的一部分,它包括:

  • 函数返回类型
  • 函数名称
  • 函数参数类型,不需要写参数名称

函数原型后面必须加上分号(;)。


以下示例为使用第一种方法的函数声明的示范。

例子

int sum_func (int x, int y) // function declaration {   int z = 0;   z = x+y ;   return z; // return the value}void setup () {   Statements // group of statements}Void loop () {   int result = 0 ;   result = Sum_func (5,6) ; // function call}


第二种方法,称为函数定义或声明,必须在循环函数的下面声明,它包括:

  • 函数返回类型
  • 函数名称
  • 函数参数类型,这里必须添加参数名称
  • 函数体(调用函数时执行的函数内部的语句)

以下示例演示了使用第二种方法的函数声明。

例子

int sum_func (int , int ) ; // function prototypevoid setup () {   Statements // group of statements}Void loop () {   int result = 0 ;   result = Sum_func (5,6) ; // function call}int sum_func (int x, int y) // function declaration {   int z = 0;   z = x+y ;   return z; // return the value}

第二种方法只是在循环函数下面声明函数。


字符串用于存储文本。它们可用在LCD或Arduino IDE串口监视器窗口中显示文本。字符串也可用于存储用户输入。例如,用户在连接到Arduino的键盘上键入的字符。

在Arduino编程中有两种类型的字符串:

  • 字符数组,与C编程中使用的字符串相同。
  • Arduino字符串,它允许我们在草图中使用字符串对象。

在本章中,我们将学习Arduino草图中的字符串,对象和字符串的使用。在本章末尾,你将学习在草图中使用哪种类型的字符串。

字符串字符数组

我们要学习的第一种类型的字符串是 char 类型的一系列字符。在前面的章节中,我们学习了一个数组是什么:存储器中存储的相同类型的变量的连续序列。一个字符串是一个char变量的数组。

字符串是一个特殊的数组,在字符串的末尾有一个额外的元素,其值总是为0(零)。这被称为“空终止字符串”。

字符串字符数组示例

此示例将显示如何创建字符串并将其打印到串口监视器窗口。

void setup() {   char my_str[6]; // an array big enough for a 5 character string   Serial.begin(9600);   my_str[0] = 'H'; // the string consists of 5 characters   my_str[1] = 'e';   my_str[2] = 'l';   my_str[3] = 'l';   my_str[4] = 'o';   my_str[5] = 0; // 6th array element is a null terminator   Serial.println(my_str);}void loop() { }

以下示例显示了字符串由什么组成。一个具有可打印字符的字符数组和0作为数组的最后一个元素,表示这是字符串结束的位置。通过使用 Serial.println()并传递字符串的名称,可以将字符串打印到Arduino IDE串口监视器窗口。

同样的例子可以用更方便的方式编写,如下所示:

示例

void setup() {   char my_str[] = "Hello";   Serial.begin(9600);   Serial.println(my_str);}void loop() {}

在这个草图中,编译器计算字符串数组的大小,并自动使用空值0终止字符串。一个长度为六个元素长,由五个字符后跟一个零组成的数组,其创建方式与上一个草图完全相同。

操作字符串数组

我们可以在草图中更改字符串数组,如下图所示。

例子

void setup() {   char like[] = "I like coffee and cake"; // create a string   Serial.begin(9600);   // (1) print the string   Serial.println(like);   // (2) delete part of the string   like[13] = 0;   Serial.println(like);   // (3) substitute a word into the string   like[13] = ' '; // replace the null terminator with a space   like[18] = 't'; // insert the new word   like[19] = 'e';   like[20] = 'a';   like[21] = 0; // terminate the string   Serial.println(like);}void loop() {}

结果

I like coffee and cakeI like coffeeI like coffee and tea

以上草图按以下方式工作。

(1)创建和打印字符串

在上面给出的草图中,创建了一个新的字符串,然后打印出来显示在串口监视器窗口中。

(2)缩短字符串

通过用空终止0替换字符串中的第14个字符来缩短字符串。这是从0开始计算的字符串数组中的13号元素。

打印字符串时,所有字符都打印到新的空终止0。其他字符不消失;它们仍然存在于内存中,并且字符串数组仍然是相同的大小。唯一的区别是任何使用字符串的函数只能看到第一个空终止符前的字符串。

(3)更改字符串中的单词

最后,草图用“tea”代替“cake”一词。它首先必须用空格替换空终止符,如[13],以便将字符串恢复为原来的格式。

新字符用单词“tea”覆盖单词“cake”的“cak”。这是通过覆盖单个字符来完成的。“cake”的“e”被替换为新的空终止字符。结果是字符串实际上终止于两个空字符,即字符串末尾的原始字符,以及替换“cake”中的“e”的新字符。这在打印新字符串时没有区别,因为打印字符串的函数在遇到第一个空终止字符时将停止打印字符串字符。

操作字符串数组的函数

上一个草图通过访问字符串中的单个字符,以手动方式操作字符串。为了更方便操作字符串数组,你可以编写自己的函数来执行,也可以使用 C 语言库中的一些字符串函数。

下面显示了操作字符串数组的列表函数。

下一个草图使用了一些C字符串函数。

例子

void setup() {   char str[] = "This is my string"; // create a string   char out_str[40]; // output from string functions placed here   int num; // general purpose integer   Serial.begin(9600);   // (1) print the string   Serial.println(str);   // (2) get the length of the string (excludes null terminator)   num = strlen(str);   Serial.print("String length is: ");   Serial.println(num);   // (3) get the length of the array (includes null terminator)   num = sizeof(str); // sizeof() is not a C string function   Serial.print("Size of the array: ");   Serial.println(num);   // (4) copy a string   strcpy(out_str, str);   Serial.println(out_str);   // (5) add a string to the end of a string (append)   strcat(out_str, " sketch.");   Serial.println(out_str);   num = strlen(out_str);   Serial.print("String length is: ");   Serial.println(num);   num = sizeof(out_str);   Serial.print("Size of the array out_str[]: ");   Serial.println(num);}void loop() {}

结果

This is my stringString length is: 17Size of the array: 18This is my stringThis is my string sketch.String length is: 25Size of the array out_str[]: 40

以上草图按以下方式工作。

(1)打印字符串

最新创建的字符串将打印到串口监视器窗口,如之前的草图所完成的。

(2)获取字符串的长度

strlen()函数用于获取字符串的长度。字符串的长度仅对于可打印字符,不包括空终止符。

该字符串包含17个字符,因此我们在串口监视器窗口中看到17个字符。

(3)获取数组的长度

运算符sizeof()用于获取包含字符串的数组的长度。长度包括空终止符,因此长度比字符串的长度多1。

sizeof()看起来像一个函数,但技术上是一个运算符。它不是C字符串库的一部分,但在草图中用于显示数组大小和字符串大小(或字符串长度)之间的差异。

(4)复制字符串

strcpy()函数用于将str[]字符串复制到out_num[]数组。strcpy()函数将传递给它的第二个字符串复制到第一个字符串中。现在,字符串的副本存在于out_num[]数组中,但只占用了数组的18个元素,因此在数组中仍然有22个空闲的char元素。这些空闲元素在内存中的字符串的后面可以找到。

将字符串复制到数组中,以便我们在数组中有一些额外的空间用于草图的下一部分,即在字符串的末尾添加一个字符串。

(5)将字符串附加到字符串(连接)

草图将一个字符串加到另一个字符串,这称为串联。这是使用strcat()函数完成的。strcat()函数将传递给它的第二个字符串放到传递给它的第一个字符串的末尾。

串联后,打印字符串的长度以显示新的字符串长度。然后打印数组的长度,以显示在40个元素长的数组中有一个25个字符长度的字符串。

请记住,25个字符长度的字符串实际上占用了数组的26个字符,因为还有空终止0。

数组边界

使用字符串和数组时,在字符串或数组的边界内工作是非常重要的。在示例草图中,创建了一个长度为40个字符的数组,以分配可用于操作字符串的内存。

如果数组太小,而我们尝试复制比数组大的字符串,那么字符串将复制到超出数组的末尾。超出数组末尾的内存可能包含草图中使用的其他重要数据,然而它们将被字符串覆盖。如果超出字符串末尾的内存超出范围,则可能会导致草图崩溃或导致意外行为。

在Arduino编程中使用的第二种类型的字符串是字符串对象。

什么是对象?

对象是一个包含数据和函数的构造。字符串对象可以像变量一样被创建并分配一个值或字符串。字符串对象包含函数(在面向对象编程(OOP)中称为“方法”),它们对字符串对象中包含的字符串数据进行操作。

下面的草图和解释将清楚说明对象是什么,以及如何使用字符串对象。

例子

void setup() {    String my_str = "This is my string.";   Serial.begin(9600);   // (1) print the string   Serial.println(my_str);   // (2) change the string to upper-case   my_str.toUpperCase();   Serial.println(my_str);   // (3) overwrite the string   my_str = "My new string.";   Serial.println(my_str);   // (4) replace a word in the string   my_str.replace("string", "Arduino sketch");   Serial.println(my_str);   // (5) get the length of the string   Serial.print("String length is: ");   Serial.println(my_str.length());}void loop() { }

结果

This is my string.THIS IS MY STRING.My new string.My new Arduino sketch.String length is: 22

创建字符串对象,并在草图顶部分配一个值(或字符串)。

String my_str = "This is my string." ;

这将创建一个名为 my_str 的String对象,并为其赋值“This is my string.”。

这可以与创建变量并为其分配一个值(如整数)相比较:

int my_var = 102;

以上草图以下列方式工作。

(1)打印字符串

字符串可以像字符数组字符串一样打印到串口监视器窗口。

(2)将字符串转换为大写

创建的字符串对象my_str,有多个可以在其上操作的函数或方法。这些方法通过使用对象名称后跟点运算符(.),然后使用函数的名称来调用的。

my_str.toUpperCase();

toUpperCase()函数对包含在类型为String的 my_str 对象中的字符串进行操作,并将对象包含的字符串数据(或文本)转换为大写字符。String类包含的函数列表可以在Arduino字符串参考中找到。从技术上讲,String被称为一个类,用于创建String对象。

(3)覆盖字符串

赋值运算符用于将新字符串分配给 my_str 对象以替换旧字符串。

my_str = "My new string." ;

赋值运算符不能用于字符数组字符串,仅适用于String对象。

(4)替换字符串中的单词

replace()函数用于将传递给它的第二个字符串替换传递给它的第一个字符串。replace()是构建在String类中的另一个函数,因此可以在String对象my_str上使用。

(5)获取字符串的长度

通过使用length()可以很容易地获取字符串的长度。在示例草图中,由length()返回的结果直接传递到Serial.println(),而不使用中间变量。

何时使用字符串对象

字符串对象比字符串字符数组更容易使用。该对象具有内置函数,可以对字符串执行多个操作。

使用String对象的主要缺点是,它使用了大量的内存,可能会很快耗尽Arduino的RAM内存,这可能会导致Arduino挂起,崩溃或行为意外。如果Arduino上的草图很小并限制了对象的使用,那么应该没有问题。

字符数组字符串更难使用,你可能需要编写自己的函数来操作这些类型的字符串。其优点是,你可以控制字符串数组的大小,因此你可以保持数组很小来节省内存。

你需要确保不要超出字符串数组边界的范围,而String对象没有这个问题,只要有足够的内存供它操作,就会照顾到你的字符串边界。在内存不足时,String对象可以尝试在不存在的内存中写入,但绝不会在超出其操作的字符串末尾的地方写入。

在哪里使用字符串

在本章中,我们学习了字符串,它们在内存中的行为及其操作。

字符串的用法将在课程的下一部分进行介绍,届时我们将学习如何从串口监视器窗口获取用户输入并将输入保存为字符串。

Arduino提供四种不同的时间操作函数。它们是:

序号函数和描述
1

delay() 函数

delay()函数的工作方式非常简单。它接受单个整数(或数字)参数。此数字表示时间(以毫秒为单位)。

2

delayMicroseconds() 函数

delayMicroseconds()函数接受单个整数(或数字)参数。一毫秒内有一千微秒,一秒内有一百万微秒。

3

millis() 函数

此函数用于返回Arduino板开始运行当前程序时的毫秒数。

4

micros() 函数

micros()函数返回Arduino板开始运行当前程序时的微秒数。该数字在大约70分钟后溢出,即回到零。


数组是连续的一组相同类型的内存位置。要引用数组中的特定位置或元素,我们指定数组的名称和数组中特定元素的位置编号。

下图给出了一个名为C的整数数组,它包含11个元素。通过给出数组名称,后面跟特定元素的位置编号:方括号([]),你可以引用这些元素中的任何一个。位置编号更正式地称为下标或索引(该数字指定从数组开始的元素数)。第一个元素具有下标0(零),有时称为零元素。

因此,数组C的元素是C[0],C[1],C[2]等等。数组C中的最高下标是10,其比数组中的元素数少1。数组名遵循与其他变量名相同的约定。


Elements of Array


下标必须是整数或整数表达式(使用任何整数类型)。如果程序使用表达式作为下标,则程序评估表达式以确定下标。例如,如果我们假设变量a等于5,变量b等于6,那么语句将数组元素C[11]加2。

下标数组名是一个左值,它可以在赋值的左侧使用,就像非数组变量名一样。

让我们更仔细地检查给定图中的数组C。整个数组的名称是C。它的11个元素被称为C[0]到C[10]。C[0]的值为-45,C[1]的值为6,C[2]的值为0,C[7]的值为62,C[10]的值为78。

要打印数组C的前三个元素中包含的值的总和,我们将写:

Serial.print (C[ 0 ] + C[ 1 ] + C[ 2 ] );

要将C[6]的值除以2并将结果赋值给变量x,我们将写:

x = C[ 6 ] / 2;

声明数组

数组占用内存中的空间。要指定元素的类型和数组所需的元素数量,请使用以下形式的声明:

type arrayName [ arraySize ] ;

编译器保留适当的内存量(回想一下,保留内存的声明更恰当地被称为定义)。arraySize必须是大于零的整数常量。例如,要告诉编译器为整数数组C保留11个元素,请使用声明:

int C[ 12 ]; // C is an array of 12 integers

数组可以声明为包含任何非引用数据类型的值。例如,可以使用字符串类型的数组来存储字符串。

使用数组的示例

本节提供了许多示例来演示如何声明,初始化以及操作数组。

示例1:声明数组并使用循环来初始化数组的元素

程序声明一个10元素的整数数组 n 。行a-b使用 For 语句将数组元素初始化为零。与其他自动变量一样,自动数组不会隐式初始化为零。第一个输出语句(行c)显示在后续for语句(行d-e)中打印的列的列标题,以表格格式打印数组。

示例

int n[ 10 ] ; // n is an array of 10 integersvoid setup () {    Serial.begin(9600); //串口初始化 }void loop () {   for ( int i = 0; i < 10; ++i ){  // initialize elements of array n to 0      n[ i ] = 0; // set element at location i to 0      Serial.print (i) ;      Serial.print (‘
’) ;   }   for ( int j = 0; j < 10; ++j ){  // output each array element's value      Serial.print (n[j]) ;      Serial.print (‘
’) ;   } }

结果 - 它会产生以下结果:

元件

0

1

2

3

4

5

6

7

8

9

0

0

0

0

0

0

0

0

0

0


示例2:使用初始化器列表在声明中初始化数组

数组元素也可以在数组声明中初始化,通过在数组名后面跟随等号和一个用大括号及逗号分隔的初始化器列表。程序使用初始化器列表来初始化一个具有10个值的整数数组(行a),并以表格格式(行b-c)打印数组。

示例

// n is an array of 10 integersint n[ 10 ] = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37 } ;

void setup () {

    Serial.begin(9600); //串口初始化 

}

void loop () { for ( int i = 0; i < 10; ++i ){ // initialize elements of array n to 0 Serial.print (i) ; Serial.print (‘ ’) ; } for ( int j = 0; j < 10; ++j ){ // output each array element's value Serial.print (n[j]) ; Serial.print (‘ ’) ; } }

结果 - 它会产生以下结果:

元件

0

1

2

3

4

5

6

7

8

9

32

27

64

18

95

14

90

70

60

37


示例3:对数组的元素求和

通常,数组的元素表示要在计算中使用的一系列值。例如,如果数组的元素表示考试成绩,教授可能希望将数组的元素进行加总,并使用该总和来计算班级考试的平均成绩。程序将包含在10元素整数数组 a 中的值进行求和。

示例

const int arraySize = 10; // constant variable indicating size of arrayint a[ arraySize ] = { 87, 68, 94, 100, 83, 78, 85, 91, 76, 87 };int total = 0;

void setup () {

    Serial.begin(9600); //串口初始化 

}

void loop () { // sum contents of array a for ( int i = 0; i < arraySize; ++i ) total += a[ i ]; Serial.print (“Total of array elements : ") ; Serial.print(total) ;}

结果 - 它会产生以下结果:

Total of array elements: 849

数组对Arduino很重要,应该需要更多的关注。以下是学习Arduino应该清楚的与数组相关的重要概念:

序号概念和描述
1将数组传递给函数

要将数组参数传递给函数,请指定没有任何括号的数组的名称。

2多维数组

具有两个维度(即,下标)的数组通常表示由排列在行和列中的信息组成的值的表格。



Arduino板上的引脚可以配置为输入或输出。我们将在这些模式下解释引脚的功能。重要的是要注意,大多数Arduino模拟引脚可以按照与数字引脚完全相同的方式进行配置和使用。

引脚配置为INPUT

Arduino引脚默认配置为输入,因此在使用它们作为输入时,不需要使用 pinMode()显式声明为输入。以这种方式配置的引脚被称为处于高阻抗状态。输入引脚对采样电路的要求非常小,相当于引脚前面的100兆欧的串联电阻。

这意味着将输入引脚从一个状态切换到另一个状态所需的电流非常小。这使得引脚可用于诸如实现电容式触摸传感器或读取LED作为光电二极管的任务。

被配置为pinMode(pin,INPUT)的引脚(没有任何东西连接到它们,或者有连接到它们而未连接到其他电路的导线),报告引脚状态看似随机的变化,从环境中拾取电子噪音或电容耦合附近引脚的状态。

上拉电阻

如果没有输入,上拉电阻通常用于将输入引脚引导到已知状态。这可以通过在输入端添加上拉电阻(到5V)或下拉电阻(接地电阻)来实现。10K电阻对于上拉或下拉电阻来说是一个很好的值。

使用内置上拉电阻,引脚配置为输入

Atmega芯片内置了2万个上拉电阻,可通过软件访问。通过将pinMode()设置为INPUT_PULLUP可访问这些内置上拉电阻。这有效地反转了INPUT模式的行为,其中HIGH表示传感器关闭,LOW表示传感器开启。此上拉的值取决于所使用的微控制器。在大多数基于AVR的板上,该值保证在20kΩ和50kΩ之间。在Arduino Due上,它介于50kΩ和150kΩ之间。有关确切的值,请参考板上微控制器的数据表。

当将传感器连接到配置为INPUT_PULLUP的引脚时,另一端应接地。在简单开关的情况下,这会导致当开关打开时引脚变为高电平,当按下开关时引脚为低电平。上拉电阻提供足够的电流来点亮连接到被配置为输入的引脚的LED。如果项目中的LED似乎在工作,但很昏暗,这可能是发生了什么。

控制引脚是高电平还是低电平的相同寄存器(内部芯片存储器单元)控制上拉电阻。因此,当引脚处于INPUT模式时,配置为有上拉电阻导通的引脚将被开启;如果引脚通过pinMode()切换到OUTPUT模式,引脚将配置为高电平。这也适用于另一个方向,如果通过pinMode()切换到输入,则处于高电平状态的输出引脚将设置上拉电阻。

示例

pinMode(3,INPUT) ; // set pin to input without using built in pull up resistorpinMode(5,INPUT_PULLUP) ; // set pin to input using built in pull up resistor

引脚配置为OUTPUT

通过pinMode()配置为OUTPUT的引脚被认为处于低阻抗状态。这意味着它们可以向其他电路提供大量的电流。Atmega引脚可以向其他器件/电路提供(提供正电流)或吸收(提供负电流)高达40mA(毫安)的电流。这是足以点亮LED或者运行许多传感器的电流(不要忘记串联电阻),但不足以运行继电器,螺线管或电机。

试图从输出引脚运行高电流器件,可能损坏或破坏引脚中的输出晶体管,或损坏整个Atmega芯片。通常,这会导致微控制器中出现“死”引脚,但是剩余的芯片仍然可以正常工作。因此,最好通过470Ω或1k电阻将OUTPUT引脚连接到其他器件,除非特定应用需要从引脚吸取最大电流。

pinMode()函数

pinMode()函数用于将特定引脚配置为输入或输出。可以使用INPUT_PULLUP模式启用内部上拉电阻。此外,INPUT模式显式禁止内部上拉。

pinMode()函数语法

Void setup () {   pinMode (pin , mode);}
  • pin - 你希望设置模式的引脚的编号

  • mode - INPUT,OUTPUT或INPUT_PULLUP。

示例

int button = 5 ; // button connected to pin 5int LED = 6; // LED connected to pin 6void setup () {   pinMode(button , INPUT_PULLUP);    // set the digital pin as input with pull-up resistor   pinMode(button , OUTPUT); // set the digital pin as output}void setup () {   If (digitalRead(button ) == LOW) // if button pressed {      digitalWrite(LED,HIGH); // turn on led      delay(500); // delay for 500 ms      digitalWrite(LED,LOW); // turn off led      delay(500); // delay for 500 ms   }}

digitalWrite()函数

digitalWrite()函数用于向数字引脚写入HIGH或LOW值。如果该引脚已通过pinMode()配置为OUTPUT,则其电压将被设置为相应的值:HIGH为5V(或3.3V在3.3V板上),LOW为0V(接地)。如果引脚配置为INPUT,则digitalWrite()将启用(HIGH)或禁止(LOW)输入引脚的内部上拉。建议将pinMode()设置为INPUT_PULLUP,以启用 内部上拉电阻。

如果不将pinMode()设置为OUTPUT,而将LED连接到引脚,则在调用digitalWrite(HIGH)时,LED可能会变暗。在没有明确设置pinMode()时,digitalWrite()将启用内部上拉电阻,这就像一个大的限流电阻。

digitalWrite()函数语法

Void loop() {   digitalWrite (pin ,value);}
  • pin - 你希望设置模式的引脚的编号

  • value - HIGH或LOW。

示例

int LED = 6; // LED connected to pin 6void setup () {   pinMode(LED, OUTPUT); // set the digital pin as output}void setup() {    digitalWrite(LED,HIGH); // turn on led   delay(500); // delay for 500 ms   digitalWrite(LED,LOW); // turn off led   delay(500); // delay for 500 ms}

analogRead()函数

Arduino能够检测是否有一个电压施加到其引脚,并通过digitalRead()函数报告。开/关传感器(检测物体的存在)和模拟传感器之间存在一个差异,模拟传感器的值连续变化。为了读取这种类型的传感器,我们需要一个不同类型的引脚。

在Arduino板的右下角,你会看到6个标记为“Analog In”的引脚。这些特殊引脚不仅可以告知是否有电压施加给它们,还可以告知它们的值。通过使用analogRead()函数,我们可以读取施加到其中一个引脚的电压。

此函数返回0到1023之间的数字,表示0到5伏特之间的电压。例如,如果施加到编号0的引脚的电压为2.5V,则analogRead(0)返回512。

analogRead()函数语法

analogRead(pin);
  • pin - 要读取的模拟输入引脚的编号(大多数电路板上为0至5,Mini和Nano上为0至7,Mega上为0至15)

示例

int analogPin = 3;//potentiometer wiper (middle terminal)    // connected to analog pin 3 int val = 0; // variable to store the value readvoid setup() {   Serial.begin(9600); // setup serial} void loop() {   val = analogRead(analogPin); // read the input pin   Serial.println(val); // debug value}


在本章中,我们将学习一些高级的输入和输出函数。

analogReference()函数

配置用于模拟输入的参考电压(即用作输入范围顶部的值)。选项是:

  • DEFAULT - 5伏(5V Arduino板)或3.3伏(3.3V Arduino板)的默认模拟参考值

  • INTERNAL - 内置参考,在ATmega168或ATmega328上等于1.1伏特,在ATmega8上等于2.56伏特(不适用于Arduino Mega)

  • INTERNAL1V1 - 内置1.1V参考(仅限Arduino Mega)

  • INTERNAL2V56 - 内置2.56V参考(仅限Arduino Mega)

  • EXTERNAL - 施加到AREF引脚的电压(仅限0到5V)用作参考

analogReference()函数语法

analogReference (type);

type - 可以使用以下任何类型(DEFAULT,INTERNAL,INTERNAL1V1,INTERNAL2V56,EXTERNAL)

对AREF引脚的外部参考电压,请勿使用小于0V或大于5V的任何值。如果在AREF引脚上使用外部参考,则必须在调用 analogRead()函数之前将模拟参考设置为EXTERNAL。否则,将短路有效参考电压(内部产生的)和AREF引脚,可能会损坏Arduino板上的微控制器。


analogReference()函数


或者,你可以通过5K电阻将外部参考电压连接到AREF引脚,从而允许在外部和内部参考电压之间切换。

注意,电阻将改变用作参考的电压,因为AREF引脚上有一个内部32K电阻。两者用作分压器。例如,通过电阻器施加的2.5V将在AREF引脚处产生2.5*32/(32+5)=〜2.2V电压。

示例

int analogPin = 3;// potentiometer wiper (middle terminal) connected to analog pin 3 int val = 0; // variable to store the read valuevoid setup() {   Serial.begin(9600); // setup serial   analogReference(EXTERNAL); // the voltage applied to the AREF pin (0 to 5V only)       // is used as the reference.}void loop() {   val = analogRead(analogPin); // read the input pin   Serial.println(val); // debug value}


所有数据都以字符形式输入计算机,包括字母,数字和各种特殊符号。在本章节中,我们讨论C++检查和操作单个字符的功能。

字符处理库包括几个函数,执行有用的测试和字符数据的操作。每个函数接收一个字符,表示为int或EOF作为参数。字符通常作为整数操作。

记住,EOF通常具有值-1,而一些硬件架构不允许负值存储在char变量中。因此,字符处理函数将字符作为整数来操作。

下表总结了字符处理库的函数。使用字符处理库中的函数时,请包含<cctype>标题。

序号原型和描述
1

int isdigit(int c)

如果c是数字,则返回1,否则返回0。

2

int isalpha(int c)

如果c是字母,则返回1,否则返回0。

3

int isalnum(int c)

如果c是数字或字母,则返回1,否则返回0。

4

int isxdigit(int c)

如果c是十六进制数字字符,则返回1,否则返回0。

5

int islower(int c)

如果c是小写字母,则返回1,否则返回0。

6

int isupper(int c)

如果c是大写字母,则返回1;否则返回0。

7

int isspace(int c)

如果c是空白字符:换行符(' ')、空格符(' ')、换页符('f')、回车符(' ')、水平制表符(' ')或垂直制表符('v'),则返回1,否则返回0。

8

int iscntrl(int c)

如果c是控制字符,如换行符(' ')、换页符('f')、回车符(' ')、水平制表符 (v')、垂直制表符('v')、alert('a')或退格(''),则返回1,否则返回0。

9

int ispunct(int c)

如果c是除空格,数字或字母以外的打印字符,则返回1,否则返回0。

10

int isprint(int c)

如果c是包含空格(' ')的打印字符,则返回1,否则返回0。

11

int isgraph(int c)

如果c是除空格(' ')之外的打印字符,则返回1,否则返回0。

例子

以下示例演示如何使用函数 isdigit,isalpha,isalnum isxdigit 函数 isdigit 确定其参数是否为数字(0-9)。函数 isalpha 确定其参数是大写字母(A-Z)还是小写字母(a-z)。函数 isalnum 确定其参数是大写,小写字母还是数字。函数 isxdigit 确定其参数是否为十六进制数字(A-F,a-f,0-9)。

例1

void setup () {   Serial.begin (9600);   Serial.print ("According to isdigit:
");   Serial.print (isdigit( '8' ) ? "8 is a": "8 is not a");   Serial.print (" digit
" );   Serial.print (isdigit( '8' ) ?"# is a": "# is not a") ;   Serial.print (" digit
");   Serial.print ("
According to isalpha:
" );   Serial.print (isalpha('A' ) ?"A is a": "A is not a");   Serial.print (" letter
");   Serial.print (isalpha('A' ) ?"b is a": "b is not a");   Serial.print (" letter
");   Serial.print (isalpha('A') ?"& is a": "& is not a");   Serial.print (" letter
");   Serial.print (isalpha( 'A' ) ?"4 is a":"4 is not a");   Serial.print (" letter
");   Serial.print ("
According to isalnum:
");   Serial.print (isalnum( 'A' ) ?"A is a" : "A is not a" );   Serial.print (" digit or a letter
" );   Serial.print (isalnum( '8' ) ?"8 is a" : "8 is not a" ) ;   Serial.print (" digit or a letter
");   Serial.print (isalnum( '#' ) ?"# is a" : "# is not a" );   Serial.print (" digit or a letter
");   Serial.print ("
According to isxdigit:
");   Serial.print (isxdigit( 'F' ) ?"F is a" : "F is not a" );   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( 'J' ) ?"J is a" : "J is not a" ) ;   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( '7' ) ?"7 is a" : "7 is not a" ) ;   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( '$' ) ? "$ is a" : "$ is not a" );   Serial.print (" hexadecimal digit
" );   Serial.print (isxdigit( 'f' ) ? “f is a" : "f is not a");   }void loop () {}

结果

According to isdigit:8 is a digit# is not a digitAccording to isalpha:A is a letterb is a letter& is not a letter4 is not a letterAccording to isalnum:A is a digit or a letter8 is a digit or a letter# is not a digit or a letterAccording to isxdigit:F is a hexadecimal digitJ is not a hexadecimal digit7 is a hexadecimal digit$ is not a hexadecimal digitf is a hexadecimal digit

我们对每个函数使用条件运算符(?:)来确定字符串“is a”或字符串“is not a”是否应该打印在每个测试字符的输出中。例如,行a表示如果“8”是数字,即如果isdigit返回真(非零)值,则打印字符串“8 is a”。如果“8”不是数字(即,如果isdigit返回0),则打印字符串“8 is not a”。

例2

以下示例演示了函数 islower isupper 的使用。函数 islower 确定其参数是否为小写字母(a-z)。函数 isupper 确定其参数是否为大写字母(A-Z)。

int thisChar = 0xA0;void setup () {   Serial.begin (9600);   Serial.print ("According to islower:
") ;   Serial.print (islower( 'p' ) ? "p is a" : "p is not a" );   Serial.print ( " lowercase letter
" );   Serial.print ( islower( 'P') ? "P is a" : "P is not a") ;   Serial.print ("lowercase letter
");   Serial.print (islower( '5' ) ? "5 is a" : "5 is not a" );   Serial.print ( " lowercase letter
" );   Serial.print ( islower( '!' )? "! is a" : "! is not a") ;   Serial.print ("lowercase letter
");   Serial.print ("
According to isupper:
") ;   Serial.print (isupper ( 'D' ) ? "D is a" : "D is not an" );   Serial.print ( " uppercase letter
" );   Serial.print ( isupper ( 'd' )? "d is a" : "d is not an") ;   Serial.print ( " uppercase letter
" );   Serial.print (isupper ( '8' ) ? "8 is a" : "8 is not an" );   Serial.print ( " uppercase letter
" );   Serial.print ( islower( '$' )? "$ is a" : "$ is not an") ;   Serial.print ("uppercase letter
 ");}void setup () {}

结果

According to islower:p is a lowercase letterP is not a lowercase letter5 is not a lowercase letter! is not a lowercase letterAccording to isupper:D is an uppercase letterd is not an uppercase letter8 is not an uppercase letter$ is not an uppercase letter

例3

以下示例演示如何使用函数 isspace,iscntrl,ispunct,isprint isgraph

  • 函数 isspace 确定其参数是否为空白字符,例如空格(' '),换页符('f'),换行符(' '),回车符(' '),水平制表符(' ')或垂直制表符('v')。

  • 函数 iscntrl 确定其参数是否为控制字符,如水平制表符(' '),垂直制表符('v'),换页符('f'),alert('a'),退格符(''),回车符(' ')或换行符(' ')。

  • 函数 ispunct 确定其参数是否是除空格,数字或字母以外的打印字符(例如$,#,(,),[,],{,},;,:或%)。

  • 函数 isprint 确定其参数是否为可以在屏幕上显示的字符(包括空格字符)。

  • 函数 isgraph 测试与isprint相同的字符,但不包括空格字符。

void setup () {   Serial.begin (9600);   Serial.print ( " According to isspace:
Newline ") ;   Serial.print (isspace( '
' )? " is a" : " is not a" );   Serial.print ( " whitespace character
Horizontal tab") ;   Serial.print (isspace( '	' )? " is a" : " is not a" );   Serial.print ( " whitespace character
") ;   Serial.print (isspace('%')? " % is a" : " % is not a" );      Serial.print ( " 
According to iscntrl:
Newline") ;   Serial.print ( iscntrl( '
' )?"is a" : " is not a" ) ;   Serial.print (" control character
");   Serial.print (iscntrl( '$' ) ? " $ is a" : " $ is not a" );   Serial.print (" control character
");   Serial.print ("
According to ispunct:
");   Serial.print (ispunct(';' ) ?"; is a" : "; is not a" ) ;   Serial.print (" punctuation character
");   Serial.print (ispunct('Y' ) ?"Y is a" : "Y is not a" ) ;   Serial.print ("punctuation character
");   Serial.print (ispunct('#' ) ?"# is a" : "# is not a" ) ;   Serial.print ("punctuation character
");   Serial.print ( "
 According to isprint:
");   Serial.print (isprint('$' ) ?"$ is a" : "$ is not a" );   Serial.print (" printing character
Alert ");   Serial.print (isprint('a' ) ?" is a" : " is not a" );   Serial.print (" printing character
Space ");   Serial.print (isprint(' ' ) ?" is a" : " is not a" );   Serial.print (" printing character
");      Serial.print ("
 According to isgraph:
");   Serial.print (isgraph ('Q' ) ?"Q is a" : "Q is not a" );   Serial.print ("printing character other than a space
Space ");   Serial.print (isgraph (' ') ?" is a" : " is not a" );   Serial.print ("printing character other than a space ");}void loop () {}

结果

According to isspace:Newline is a whitespace characterHorizontal tab is a whitespace character% is not a whitespace characterAccording to iscntrl:Newline is a control character$ is not a control characterAccording to ispunct:; is a punctuation characterY is not a punctuation character# is a punctuation characterAccording to isprint:$ is a printing characterAlert is not a printing characterSpace is a printing characterAccording to isgraph:Q is a printing character other than a spaceSpace is not a printing character other than a space


Arduino数学库(math.h)包含了许多用于操作浮点数的有用的数学函数。

库中的宏

以下是在标题math.h中定义的宏:

描述
M_E2.7182818284590452354常数e。
M_LOG2E

1.4426950408889634074

/* log_2 e */

e以2为底的对数。
M_1_PI

0.31830988618379067154

/* 1/pi */

常数1/pi。
M_2_PI

0.63661977236758134308

/* 2/pi */

常数2/pi。
M_2_SQRTPI

1.12837916709551257390

/* 2/sqrt(pi) */

常数2/sqrt(pi)。
M_LN10

2.30258509299404568402

/* log_e 10 */

10的自然对数。
M_LN2

0.69314718055994530942

/* log_e 2 */

2的自然对数。
M_LOG10E

0.43429448190325182765

/* log_10 e */

e以10为底的对数。
M_PI

3.14159265358979323846

/* pi */

常数pi。
M_PI_2

3.3V1.57079632679489661923

/* pi/2 */

常数pi/2。
M_PI_4

0.78539816339744830962

/* pi/4 */

常数pi/4。
M_SQRT1_2

0.70710678118654752440

/* 1/sqrt(2) */

常数1/sqrt(2)。
M_SQRT2

1.41421356237309504880

/* sqrt(2) */

2的平方根。
acosf-acos()函数的别名。
asinf-asin()函数的别名。
atan2f-atan2()函数的别名。
cbrtf-cbrt()函数的别名。
ceilf-ceil()函数的别名。
copysignf-copysign()函数的别名。
coshf-cosh()函数的别名。
expf-exp()函数的别名。
fabsf-fabs()函数的别名。
fdimf-fdim()函数的别名。
floorf-floor()函数的别名。
fmaxf-fmax()函数的别名。
fminf-fmin()函数的别名。
fmodf-fmod()函数的别名。
frexpf-frexp()函数的别名。
hypotf-hypot()函数的别名。
INFINITY-无穷大常量。
isfinitef-isfinite()函数的别名。
isinff-isinf()函数的别名。
isnanf-isnan()函数的别名。
ldexpf-ldexp()函数的别名。
log10f-log10()函数的别名。
logf-log()函数的别名。
lrintf-lrint()函数的别名。
lroundf-lround()函数的别名。

库函数

以下函数在标题 math.h 中定义:

序号库函数和描述
1

double acos (double __x)

acos()函数计算x的反余弦的主值。返回值在[0, pi]弧度的范围内。不在[-1, +1]范围内的参数会发生域错误。

2

double asin (double __x)

asin()函数计算x的反正弦的主值。返回值在[-pi/2, pi/2]弧度的范围内。不在[-1, +1]范围内的参数会发生域错误。

3

double atan (double __x)

atan()函数计算x的反正切的主值。返回值在[-pi/2, pi/2]弧度的范围内。

4

double atan2 (double __y, double __x)

atan2()函数计算y/x的反正切的主值,使用两个参数的符号来确定返回值的象限。返回值在[-pi, +pi]弧度的范围内。

5

double cbrt (double __x)

cbrt()函数返回x的立方根值。

6

double ceil (double __x)

ceil()函数返回大于或等于x的最小整数值,以浮点数表示。

7

static double copysign (double __x, double __y)

copysign()函数返回x,但带有y的符号。即使x或y是NaN或零,他们也可以工作。

8

double cos(double __x)

cos()函数返回x的余弦,以弧度为单位。

9

double cosh (double __x)

cosh()函数返回x的双曲余弦。

10

double exp (double __x)

exp()返回e的x次幂的值。

11

double fabs (double __x)

fabs()函数计算浮点数x的绝对值。

12

double fdim (double __x, double __y)

fdim()函数返回max(x - y, 0)。如果x或y或者两者都是NaN,则返回NaN。

13

double floor (double __x)

floor()函数返回小于或等于x的最大整数值,以浮点数表示。

14

double fma (double __x, double __y, double __z)

fma()函数执行浮点乘加,即运算(x * y) + z,但是中间结果不会四舍五入到目标类型。这有时可以提高计算的精度。

15

double fmax (double __x, double __y)

fmax()函数返回两个值x和y中较大的一个。如果一个参数是NaN,则返回另一个参数。如果两个参数都是NaN,则返回NaN。

16

double fmin (double __x, double __y)

fmin()函数返回两个值x和y中较小的一个。如果一个参数是NaN,则返回另一个参数。如果两个参数都是NaN,则返回NaN。

17

double fmod (double __x, double__y)

fmod()函数返回x / y的余数。

18

double frexp (double __x, int * __pexp)

frexp()函数将浮点数分解为规格化分数和2的整次幂。它将整数存储在pexp指向的int对象中。如果x是一个正常的浮点数,则frexp()函数返回值v,使得v具有区间[1/2, 1)或零的量值,而x等于v乘以2的pexp次幂。如果x是零,那么结果的两个部分都是零。如果x不是有限数字,frexp()将按原样返回x,并通过pexp存储0。

注意 − 这个实现允许一个零指针作为指令来跳过存储指数。

19

double hypot (double __x, double__y)

hypot()函数返回sqrt(x*x + y*y)。这是一个边长为x和y的直角三角形的斜边的长度,或点(x, y)距离原点的距离。使用这个函数而不是直接使用公式是比较明智的,因为误差要小得多。x和y没有下溢。如果结果在范围内,则不会溢出。

20

static int isfinite (double __x)

如果x是有限的,isfinite()函数返回一个非零值:不是正或负无穷,也不是NaN

21

int isinf (double __x)

如果参数x是正无穷大,则函数isinf()返回1;如果x是负无穷大,则返回-1,否则返回0。

注意 − GCC 4.3可以用内联代码替换这个函数,这个代码对两个无穷大返回1值(gcc bug #35509)。

22

int isnan (double __x)

如果参数x表示“非数字”(NaN)对象,则函数isnan()返回1,否则返回0。

23

double ldexp (double __x, int __exp )

ldexp()函数将浮点数乘以2的整数次幂。它返回x乘以2的exp次幂的值。

24

double log (double __x)

log()函数返回参数x的自然对数。

25

double log10(double __x)

log10()函数返回参数x的对数,以10为基数。

26

long lrint (double __x)

lrint()函数将x四舍五入到最近的整数,将中间情况舍入到偶数整数方向(例如,1.5和2.5的值都舍入到2)。这个函数类似于rint()函数,但是它的返回值类型不同,并且有可能溢出。

返回

四舍五入的长整数值。如果x不是有限数字或者溢出,则此实现返回LONG_MIN值(0x80000000)。

27

long lround (double __x)

lround()将函数将x四舍五入到最近的整数,但中间情况不舍入到0(不是到最近的偶数整数)。这个函数类似于round()函数,但是它的返回值的类型是不同的,并且有可能溢出。

返回

四舍五入的长整数值。如果x不是有限数字或者溢出,则此实现返回LONG_MIN值(0x80000000)。

28

double modf (double __x, double * __iptr )

modf()函数将参数x分解为整数部分和小数部分,每个部分都与参数具有相同的符号。它在iptr指向的对象中将整数部分存储为double。

modf()函数返回x的有符号小数部分。

注意 − 这个实现跳过零指针的写入。但是,GCC 4.3可以用内联代码替换这个函数,不允许使用NULL地址来避免存储。

29

float modff (float __x, float * __iptr)

modf()函数的别名。

30

double pow (double __x, double __y)

pow()函数返回x的y次幂。

31

double round (double __x)

round()函数将x四舍五入到最近的整数,但中间情况不舍入到0(不是到最近的偶数整数)。不可能会溢出。

返回

四舍五入的值。如果x是整数或无穷大,则返回x本身。如果x是NaN,则返回NaN

32

int signbit (double __x)

如果x的值设置了符号位,signbit()函数将返回一个非零值。这与“x < 0.0”不同,因为IEEE 754浮点允许零署名。比较“-0.0 < 0.0”是错的,但“signbit (-0.0)”会返回一个非零值。

33

double sin (double __x)

sin()函数返回x的正弦值,以弧度为单位。

34

double sinh (double __x)

sinh()函数返回x的双曲正弦。

35

double sqrt (double __x)

sqrt()函数返回x的非负平方根。

36

double square (double __x)

square()函数返回x * x。

注意 − 此函数不属于C标准定义。

37

double tan (double __x)

tan()函数返回x的正切值,以弧度为单位。

38

double tanh ( double __x)

tanh()函数返回x的双曲正切。

39

double trunc (double __x)

trunc()函数将x四舍五入为最近的整数,不大于绝对值。


例子

以下示例显示如何使用最常用的math.h库函数:

double double__x = 45.45 ;double double__y = 30.20 ;void setup() {   Serial.begin(9600);   Serial.print("cos num = ");   Serial.println (cos (double__x) ); // returns cosine of x   Serial.print("absolute value of num = ");   Serial.println (fabs (double__x) ); // absolute value of a float   Serial.print("floating point modulo = ");   Serial.println (fmod (double__x, double__y)); // floating point modulo   Serial.print("sine of num = ");   Serial.println (sin (double__x) ) ;// returns sine of x   Serial.print("square root of num : ");   Serial.println ( sqrt (double__x) );// returns square root of x   Serial.print("tangent of num : ");   Serial.println ( tan (double__x) ); // returns tangent of x   Serial.print("exponential value of num : ");   Serial.println ( exp (double__x) ); // function returns the exponential value of x.   Serial.print("cos num : ");   Serial.println (atan (double__x) ); // arc tangent of x   Serial.print("tangent of num : ");   Serial.println (atan2 (double__y, double__x) );// arc tangent of y/x   Serial.print("arc tangent of num : ");   Serial.println (log (double__x) ) ; // natural logarithm of x   Serial.print("cos num : ");   Serial.println ( log10 (double__x)); // logarithm of x to base 10.   Serial.print("logarithm of num to base 10 : ");   Serial.println (pow (double__x, double__y) );// x to power of y   Serial.print("power of num : ");   Serial.println (square (double__x)); // square of x}void loop() {}

结果

cos num = 0.10absolute value of num = 45.45floating point modulo =15.25sine of num = 0.99square root of num : 6.74tangent of num : 9.67exponential value of num : ovfcos num : 1.55tangent of num : 0.59arc tangent of num : 3.82cos num : 1.66logarithm of num to base 10 : infpower of num : 2065.70


你需要使用三角几何来计算移动物体的距离或角速度。Arduino提供了传统的三角函数(sin,cos,tan,asin,acos,atan),可以通过编写它们的原型来概括。Math.h包含三角函数的原型。

三角函数的精确语法

double sin(double x); //返回x的正弦值double cos(double y); //返回y的余弦值double tan(double x); //返回x的正切值double acos(double x); //返回x的反余弦数double asin(double x); //返回x的反正弦数double atan(double x); //返回x的反正切数

例子

double sine = sin(2); // 大约 0.90929737091
double cosine = cos(2); // 大约 -0.41614685058
double tangent = tan(2); // 大约 -2.18503975868


Arduino Due是基于Atmel SAM3X8E ARM Cortex-M3 CPU的微控制器板。它是第一款基于32位ARM内核微控制器的Arduino板。

主要功能:

  • 它有54个数字输入/输出引脚(其中12个可用作PWM输出)
  • 12个模拟输入
  • 4个UART(硬件串行端口)
  • 84 MHz时钟,一个USB OTG连接
  • 2个DAC(数字到模拟),2个TWI,1个电源插孔,1个SPI头,1个JTAG头
  • 重置按钮和一个清除按钮

Arduino Due

Arduino Due板的特性

工作电压CPU速度模拟输入/输出数字IO/PWMEEPROM [KB]SRAM [KB]

Flash[KB]

USBUART
3.3伏84 Mhz12/254/12-965122微米4

通讯

  • 4个硬件UART
  • 2个I2C
  • 1个CAN接口(汽车通信协议)
  • 1个SPI
  • 1接口JTAG(10引脚)
  • 1个USB主机(像Leonardo一样)
  • 1编程端口

与大多数Arduino板不同,Arduino Due板运行在3.3V电压下。I/O引脚可以承受的最大电压为3.3V。对任何I/O引脚施加高于3.3V的电压都可能会损坏电路板。

该板包含了支持微控制器所需的一切。你可以使用micro-USB电缆将其连接到计算机,或者使用AC-to-DC适配器或电池为其供电以启用。Due与所有工作在3.3V电压的Arduino盾板兼容。

Arduino Zero

Zero是由UNO建立的平台的简单而强大的32位扩展。Zero板通过提供更高的性能扩展其系列,为设备提供各种项目机会,并成为学习32位应用程序开发的绝佳教育工具。

主要特点是:

  • Zero应用程序涵盖从智能物联网设备,可穿戴技术,高科技自动化,到疯狂的机器人技术。

  • 该板采用Atmel的SAMD21 MCU供电,该MCU配有32位ARMCortex®M0 +内核。

  • 其最重要的特性之一是Atmel的嵌入式调试器(EDBG),它提供了一个完整的调试接口,无需额外的硬件,显着提高了软件调试的易用性。

  • EDBG还支持可用于器件和引导加载程序编程的虚拟COM端口。


Arduino Zero

Arduino Zero板的特性

工作电压CPU速度模拟输入/输出数字IO/ PWMEEPROM [KB]SRAM [KB]Flash [KB]USBUART
3.3伏48 Mhz6/114/10-322562微米2

与大多数Arduino和Genuino板不同,Zero运行在3.3V电压下。I/O引脚可以承受的最大电压为3.3V。对任何I/O引脚施加高于3.3V的电压都可能会损坏电路板。

该板包含支持微控制器所需的一切。你可以使用micro-USB电缆将其连接到计算机,或者使用AC-to-DC适配器或电池为其供电以启用。Zero与所有工作在3.3V电压的盾板兼容。


脉冲宽度调制或PWM是用于改变脉冲串中的脉冲宽度的常用技术。PWM有许多应用,如控制伺服和速度控制器,限制电机和LED的有效功率。

PWM的基本原理

脉冲宽度调制基本上是一个随时间变化而变化的方波。基本的PWM信号如下图所示。

基本PWM信号

有很多术语与PWM相关:

  • On-Time(导通时间) - 时间信号的持续时间较长。

  • Off-Time(关断时间) - 时间信号的持续时间较短。

  • Period(周期) - 表示为PWM信号的导通时间和关断时间的总和。

  • Duty Cycle(占空比) - 它表示为在PWM信号周期内保持导通的时间信号的百分比。

周期

如图所示,Ton表示导通时间,Toff表示信号的关断时间。周期是导通和关断时间的总和,并按照以下公式计算:

周期

占空比

占空比用于计算为一段时间的导通时间。使用上面计算的周期,占空比计算为:

占空比

analogWrite()函数

analogWrite()函数将模拟值(PWM波)写入引脚。它可用于以不同的亮度点亮LED或以各种速度驱动电机。在调用analogWrite()函数之后,引脚将产生指定占空比的稳定方波,直到下一次调用analogWrite()或在相同引脚上调用digitalRead()或digitalWrite()。大多数引脚上的PWM信号频率约为490 Hz。在Uno和类似的板上,引脚5和6的频率约为980Hz。Leonardo上的引脚3和11也以980Hz运行。

在大多数Arduino板上(ATmega168或ATmega328),此功能在引脚3,5,6,9,10和11上工作。在Arduino Mega上,它在引脚2-13和44-46上工作。旧的Arduino ATmega8板仅支持引脚9,10和11上的 analogWrite()


analogWrite()函数


Arduino Due支持引脚2至13以及引脚DAC0和DAC1上的 analogWrite()与PWM引脚不同,DAC0和DAC1是数模转换器,用作真正的模拟输出。

在调用analogWrite()之前,不需要调用pinMode()将引脚设置为输出。

analogWrite()函数语法

analogWrite ( pin , value ) ;value − the duty cycle: between 0 (always off) and 255 (always on).

value - 占空比:0(始终导通)到255(始终关断)之间。

示例

int ledPin = 9; // LED connected to digital pin 9int analogPin = 3; // potentiometer connected to analog pin 3int val = 0; // variable to store the read valuevoid setup() {   pinMode(ledPin, OUTPUT); // sets the pin as output}void loop() {   val = analogRead(analogPin); // read the input pin   analogWrite(ledPin, (val / 4)); // analogRead values go from 0 to 1023,       // analogWrite values from 0 to 255}

要生成随机数,可以使用Arduino随机数函数。我们有两个函数:

  • randomSeed(seed)
  • random()

randomSeed(seed)

randomSeed(seed)函数重置Arduino的伪随机数生成器。虽然random()返回的数字的分布本质上是随机的,但是顺序是可预测的。你应该将发生器重置为某个随机值。如果你有一个未连接的模拟引脚,它可能会从周围环境中拾取随机噪音。这些可能是无线电波,宇宙射线,手机的电磁干扰,荧光灯等。

例子

randomSeed(analogRead(5)); // randomize using noise from analog pin 5

random()

random函数生成伪随机数。以下是语法。

random()语法

long random(max) // it generate random numbers from 0 to maxlong random(min, max) // it generate random numbers from min to max

例子

long randNumber;void setup() {   Serial.begin(9600);   // if analog input pin 0 is unconnected, random analog   // noise will cause the call to randomSeed() to generate   // different seed numbers each time the sketch runs.   // randomSeed() will then shuffle the random function.   randomSeed(analogRead(0));}void loop() {   // print a random number from 0 to 299   Serial.print("random1=");   randNumber = random(300);   Serial.println(randNumber); // print a random number from 0to 299   Serial.print("random2=");   randNumber = random(10, 20);// print a random number from 10 to 19   Serial.println (randNumber);   delay(50);}

让我们现在重温我们对一些基本概念的知识,例如位和字节。

Bit(位)

位只是一个二进制数字。

  • 二进制系统使用两个数字,0和1。

  • 与十进制数字系统类似,数字的位数不具有相同的值,位的“意义"取决于其在二进制数中的位置。例如,十进制数666中的数字相同,但具有不同的值。

Bits

字节

一个字节由8位组成。

  • 如果一个位是一个数字,逻辑上字节表示数字。

  • 可以对它们执行所有数学运算。

  • 一个字节中的数字也不具有相同的意义。

  • 最左边的位具有被称为最高有效位(MSB)的最大值。

  • 最右边的位具有最小值,因此称为最低有效位(LSB)。

  • 由于可以以256种不同的方式组合一个字节的八个0和1,所以可以由一个字节表示的最大十进制数是255(一个组合表示零)。


中断(interrupt)停止Arduino的当前工作,以便可以完成一些其他工作。

假设你坐在家里和别人聊天。突然电话响了。停止聊天,拿起电话与来电者通话。当你完成电话交谈后,你回去和电话响之前的那个人聊天。

同样,你可以把主程序想象成是与某人聊天,电话铃声使你停止聊天。中断服务程序是在电话上通话的过程。当通话结束后,你回到你聊天的主程序。这个例子准确地解释了中断如何使处理器执行操作。

主程序在电路中运行并执行一些功能。但是,当发生中断时,主程序在另一个程序执行时停止。当这个程序结束时,处理器再次返回主程序。

中断

重要特征

这里有一些关于中断的重要特征:

  • 中断可以来自各种来源。在这种情况下,我们使用的是由数字引脚上的状态改变触发的硬件中断。

  • 大多数Arduino设计有两个硬件中断(称为“interrupt0”和“interrupt1”)分别硬连接到数字I/O引脚2和3。

  • Arduino Mega有六个硬件中断,包括引脚21,20,19和18上的附加中断(“interrupt2”到“interrupt5”)。

  • 你可以使用称为“中断服务程序”(Interrupt Service Routine,通常称为ISR)的特殊函数来定义程序。

  • 你可以定义该程序并指定上升沿,下降沿或两者的条件。在这些特定条件下,将处理中断。

  • 每次在输入引脚上发生事件时,都可以自动执行该函数。

中断类型

有两种类型的中断:

  • 硬件中断 - 它们响应外部事件而发生,例如外部中断引脚变为高电平或低电平。

  • 软件中断 - 它们响应于在软件中发送的指令而发生。“Arduino语言”支持的唯一类型的中断是attachInterrupt()函数。

在Arduino中使用中断

中断在 Arduino 程序中非常有用,因为它有助于解决时序问题。中断的良好应用是读取旋转编码器或观察用户输入。一般情况下,ISR 应尽可能短且快。如果你的草图使用多个 ISR,则一次只能运行一个。其他中断将在当前完成之后执行,其顺序取决于它们的优先级。

通常,全局变量用于在 ISR 和主程序之间传递数据。为了确保在 ISR 和主程序之间共享的变量正确更新,请将它们声明为 volatile。

Arduino 中主要有时钟中断和外部中断,本文所说的中断指的是外部中断。Arduino 中的外部中断通常是由Pin 口(数字 Pin 口,不是模拟口)电平改变触发的。每种型号的 Arduino 版都有数个 Pin 口可以用来注册中断,具体如下:

开发板可以用来注册中断的Pin口
Uno, Nano, Mini, other 328-based2, 3
Uno WiFi Rev.2所有数字口
Mega, Mega2560, MegaADK2, 3, 18, 19, 20, 21
Micro, Leonardo, other 32u4-based0, 1, 2, 3, 7
Zero除了4号口外的所有数字口
MKR Family boards0, 1, 4, 5, 6, 7, 8, 9, A1, A2
Due所有数字口
101所有数字口 (只有 2, 5, 7, 8, 10, 11, 12, 13数字口可以使用 CHANGE​ 类型中断,中断类型在下文有介绍)

注册中断主要是通过​ attachInterrupt() ​函数实现的,其原型为:

void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode);
  1. 第一个参数为中断号,Arduino上每个可以注册中断的Pin口都会被分配一个中断号,这里需要传入的是中断号而不是Pin口号。但是不同的Arduino开发板上面的中断号分配并不完全一样。各个开发板的Pin口号和中断号对应关系如下:
     开发板 中断号0 中断号1 中断号2 中断号3 中断号4 中断号5
     Uno, Ethernet PIN 2 PIN 3    
     Mega2560 PIN 2 PIN 3 PIN 21 PIN 20 PIN 19 PIN 18
     基于32u4的开发板 如 Leonardo, Micro PIN 3 PIN 2 PIN 0 PIN 1 PIN 7 
    从上表中可以看出同一个 Pin 口在不同的开发板上可能会有不同的中断号,这势必会影响程序的可移植性。幸运的是,Arduino 还提供了另一个函数 digitalPinToInterrupt(int)。从名字就能看出,这个函数能输入 Pin 口号并输出对应的中断号。需要注意的是,输入的 Pin 口号需要在上述的支持列表当中。所以,Arduino 官方推荐我们使用 
    attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); 
    这种方式来注册中断号。
  2. 第二个参数是中断服务例程(ISR)的函数指针,在 C/C++ 中直接写该函数的函数名即可。在触发时,该函数将会被调用。该函数必须没有任何的参数也没有任何的返回值。
  3. 第三个参数是中断触发条件,由几个可选的值:
    LOW 当中断所在 Pin 口处于低电平时触发
    CHANGE 当中断所在 Pin口电平改变时触发
    RISING 当中断所在Pin口从低电平变为高电平(上升沿)时触发
    FALLING 当中断所在Pin口从高电平变为低电平(下降沿)时触发
    对于 Due,Zero 和 MKR1000开发板,还有一个 HIGH 表示当中断所在 Pin 口处于高电平时触发

示例

int pin = 2; //define interrupt pin to 2volatile int state = LOW; // To make sure variables shared between an ISR//the main program are updated correctly,declare them as volatile.void setup() {   pinMode(13, OUTPUT); //set pin 13 as output   attachInterrupt(digitalPinToInterrupt(pin), blink, CHANGE);   //interrupt at pin 2 blink ISR when pin to change the value} void loop() {    digitalWrite(13, state); //pin 13 equal the state value} void blink() {    //ISR function   state = !state; //toggle the state when the interrupt occurs}

attachInterrupt语句语法

attachInterrupt(digitalPinToInterrupt(pin),ISR,mode);//recommended for arduino boardattachInterrupt(pin, ISR, mode) ; //recommended Arduino Due, Zero only//argument pin: the pin number//argument ISR: the ISR to call when the interrupt occurs;    //this function must take no parameters and return nothing.    //This function is sometimes referred to as an interrupt service routine.//argument mode: defines when the interrupt should be triggered.

在 Arduino 中使用中断需要注意的问题

  1. 由于中断会打断正常代码的运行,因此 ISR 的应该尽可能快地执行完毕。
  2. 在 ISR 中修改的全局变量要用 volatile 修饰符修饰以防止编译器优化
  3. 在 ISR 中不能使用其他用中断实现的函数,如 millis() delay() 等。延时可以使用  delayMicroseconds(),它不是用中断实现的。





已经定义了数百个通信协议来实现这种数据交换。每个协议可以分为两类:并行或串行。

并行通信

通过输入/输出端口在Arduino和外设之间进行并行连接是短距离(最多几米)的理想解决方案。然而,在其他情况下,当需要在两个设备之间建立较长距离的通信时,不可能使用并行连接。并行接口同时传输多个位。它们通常需要数据总线 - 通过八条,十六条或更多的线路进行传输。数据以1和0的巨大波形传输。

并行通信

并行通信的优点和缺点

并行通信肯定有其优势。它比串行更快,更直接,相对容易实施。然而,它需要许多的输入/输出(I / O)端口和线路。如果你曾经把一个项目从一个基本的Arduino Uno移动到一个Mega,你就知道微处理器上的I/O线是很宝贵的,而且很少。因此,我们更喜欢串行通信,牺牲针脚空间的潜在速度。

串行通信模块

今天,大多数Arduino板都是用几种不同的串行通信系统作为标准设备。

使用哪个系统取决于以下因素:

  • 微控制器有多少个器件与数据交换?
  • 数据交换的速度有多快?
  • 这些设备之间的距离是多少?
  • 是否需要同时发送和接收数据?

有关串行通信的最重要的事情之一是协议,应该严格遵守。它是一套规则,必须应用这些规则才能使设备正确地解释它们相互交换的数据。幸运的是,Arduino会自动处理这个问题,这样程序员/用户的工作就可以简化为简单的写(发送的数据)和读(接收的数据)。

串行通信类型

串行通信可以进一步分类为:

  • 同步 - 同步的设备使用相同的时钟,它们的时序彼此同步。

  • 异步 - 异步的设备具有各自的时钟,并由前一状态的输出触发。

很容易找出设备是否同步。如果给所有连接的设备提供相同的时钟,则它们是同步的。如果没有时钟线,它是异步的。

例如,UART(通用异步收发器)模块是异步的。

异步串行协议有一些内置的规则。这些规则只是有助于确保可靠且无误的数据传输的机制。这些避免外部时钟信号的机制是:

  • Synchronization bits 同步位
  • Data bits 数据位
  • Parity bits 奇偶校验位
  • Baud rate 波特率

同步位

同步位是与每个数据包传输的两个或三个特殊位。它们是起始位和停止位。正如它们的名称,这些位分别标记数据包的开始和结束。

起始位始终只有一个,但停止位的数量可以配置为一个或两个(尽管通常保持为1)。

起始位始终由从1到0的空闲数据线指示,而停止位将通过将线保持在1处而转换回空闲状态。


同步位

数据位

每个分组中的数据量可以设置为5到9位的任意大小。当然,标准数据大小是基本8位字节,但其他大小有它们的用途。7位数据包的效率可能比8位高,特别是如果你只是传输7位ASCII字符。

奇偶校验位

用户可以选择是否应该有奇偶校验位,如果是,则奇偶校验应该是奇数还是偶数。如果数据位中的1的数目是偶数,则奇偶校验位为0。奇数的奇偶校验正好相反。

波特率

术语波特率用于表示每秒传输的位数[bps]。注意,它指的是位,而不是字节。协议通常要求每个字节与几个控制位一起传输。这意味着串行数据流中的一个字节可以包括11位。例如,如果波特率为300bps,则每秒可以传输最大37字节和最小27字节。

Arduino UART

以下代码将使Arduino在启动时发送hello world。

void setup() {   Serial.begin(9600); //set up serial library baud rate to 9600   Serial.println("hello world"); //print hello world}void loop() {}

将Arduino草图上传到Arduino后,打开Arduino IDE右上角的串口监视器搜索Search

在串口监视器的顶部框中键入任意内容,然后按发送键或键盘上的enter键。这将发送一系列字节到Arduino。

以下代码返回它接收到的任何东西作为输入。

以下代码将使Arduino根据提供的输入传送输出。

void setup() {   Serial.begin(9600); //set up serial library baud rate to 9600}void loop() {   if(Serial.available()) //if number of bytes (characters) available for reading from {       serial port      Serial.print("I received:"); //print I received      Serial.write(Serial.read()); //send what you read   }}

请注意,Serial.print Serial.println 将发回实际的ASCII代码,而 Serial.write 将返回实际的文本。请参阅ASCII代码了解更多信息。


内部集成电路(I2C)是用于微控制器和新一代专用集成电路之间的串行数据交换系统。当它们之间的距离很短(接收器和发射器通常在同一个印刷电路板上)时使用。通过两根导线建立连接。一个用于数据传输,另一个用于同步(时钟信号)。

如下图所示,一个设备始终是主设备。它在通信开始之前执行一个从芯片的寻址。这样,一个微控制器可以与112个不同的设备进行通信。波特率通常为100 Kb/sec(标准模式)或10 Kb/sec(慢波特率模式)。最近出现了波特率为3.4 Mb/s的系统。通过I2C总线通信的设备之间的距离限制在几米之内。


内部集成电路


板的I2C引脚

I2C总线由两个信号组成 - SCL和SDA。SCL是时钟信号,SDA是数据信号。当前总线主机总是产生时钟信号。一些从设备可能迫使时钟低电平以延迟主设备发送更多数据(或者在主设备尝试将数据写出之前请求更多的时间来准备数据)。这被称为“时钟伸展”。

以下是不同Arduino板的引脚:

  • Uno, Pro Mini A4 (SDA), A5 (SCL)
  • Mega, Due 20 (SDA), 21 (SCL)
  • Leonardo, Yun 2 (SDA), 3 (SCL)

Arduino I2C

我们有两种模式 - 主代码和从代码 - 使用I2C连接两个Arduino板。它们是:

  • Master Transmitter / Slave Receiver 主发射器/从接收器
  • Master Receiver / Slave Transmitter 主接收器/从发射器

主发射器/从接收器

让我们现在看看什么是主发送器和从接收器。

主发射器

以下函数用于初始化Wire库,并将I2C总线作为主器件或从器件加入。这通常只被调用一次。

  • Wire.begin(地址) - 在我们的例子中,地址是7位从地址,因为未指定主机,它将作为主机加入总线。

  • Wire.beginTransmission(地址) - 开始向给定地址的I2C从设备发送数据。

  • Wire.write() - 用于从主设备传输到从设备的队列字节(在beginTransmission()和endTransmission()之间的调用)。

  • Wire.endTransmission() - 结束由beginTransmission()开始的对从设备的传输,并传输由wire.write()排队的字节。

示例

#include <Wire.h> //include wire libraryvoid setup() //this will run only once {    Wire.begin(); // join i2c bus as master} short age = 0; void loop() {      Wire.beginTransmission(2);    // transmit to device #2   Wire.write("age is = ");   Wire.write(age); // sends one byte   Wire.endTransmission(); // stop transmitting   delay(1000); }

从接收器

使用以下函数:

  • Wire.begin(地址) - 地址是7位从地址。

  • Wire.onReceive(收到的数据处理程序) - 当从设备从主设备接收数据时调用的函数。

  • Wire.available() - 返回Wire.read()可用于检索的字节数,应在Wire.onReceive()处理程序中调用。

示例

#include <Wire.h> //include wire libraryvoid setup() {  //this will run only once   Wire.begin(2); // join i2c bus with address #2   Wire.onReceive(receiveEvent); // call receiveEvent when the master send any thing    Serial.begin(9600); // start serial for output to print what we receive }void loop() {      delay(250); }//-----this function will execute whenever data is received from master-----//void receiveEvent(int howMany) {    while (Wire.available()>1) // loop through all but the last {      char c = Wire.read(); // receive byte as a character      Serial.print(c); // print the character   }}

主接收器/从发射器

让我们现在看看什么是主接收器和从发射器。

主接收器

主机被编程为请求,然后读取从唯一寻址的从机Arduino发送的数据字节。

使用以下函数:

Wire.requestFrom(地址,字节数) - 主设备用于请求从设备的字节。然后可以使用函数wire.available()和wire.read()检索字节。

示例

#include <Wire.h> //include wire library void setup() {    Wire.begin(); // join i2c bus (address optional for master)    Serial.begin(9600); // start serial for output} void loop() {    Wire.requestFrom(2, 1); // request 1 bytes from slave device #2   while (Wire.available()) // slave may send less than requested {      char c = Wire.read(); // receive a byte as character      Serial.print(c); // print the character   }    delay(500); }

从发射器

使用以下函数:

Wire.onRequest(处理程序) - 当主设备从此从设备请求数据时调用该函数。

示例

#include <Wire.h> void setup() {    Wire.begin(2); // join i2c bus with address #2   Wire.onRequest(requestEvent); // register event} Byte x = 0;void loop() {    delay(100); } // function that executes whenever data is requested by master// this function is registered as an event, see setup()void requestEvent() {    Wire.write(x); // respond with message of 1 bytes as expected by master   x++; }


串行外设接口(SPI)总线是用于串行通信的系统,最多可使用四个导体,通常为三个。一个导体用于数据接收,一个导体用于数据发送,一个导体用于同步,另一个导体用于选择与之通信的设备。它是一个全双工连接,这意味着数据是同时发送和接收的。最大波特率高于I2C通信系统中的波特率。

板的SPI引脚

SPI使用以下四条线:

  • SCK - 这是由主机驱动的串行时钟。

  • MOSI - 这是由主机驱动的主输出/从输入。

  • MISO - 这是由主机驱动的主输入/从输出。

  • SS - 这是从机选择线。

使用以下函数,必须包括SPI.h.

  • SPI.begin() - 通过将SCK,MOSI和SS设置为输出来初始化SPI总线,将SCK和MOSI拉低,将SS拉高。

  • SPI.setClockDivider(分频器) - 相对于系统时钟设置SPI时钟分频器。在基于AVR的板上,可用的分频器为2,4,8,16,32,64或128。默认设置为SPI_CLOCK_DIV4,它将SPI时钟设置为系统时钟的四分之一(对于20 MHz的电路板为5 Mhz)。

  • Divider - 它可以是(SPI_CLOCK_DIV2,SPI_CLOCK_DIV4,SPI_CLOCK_DIV8,SPI_CLOCK_DIV16,SPI_CLOCK_DIV32,SPI_CLOCK_DIV64,SPI_CLOCK_DIV128)。

  • SPI.transfer(val) - SPI传输基于同时发送和接收:接收的数据在receivedVal中返回。

  • SPI.beginTransaction(SPISettings(speedMaximum,dataOrder,dataMode)) - speedMaximum是时钟,dataOrder(MSBFIRST或LSBFIRST),dataMode(SPI_MODE0,SPI_MODE1,SPI_MODE2或SPI_MODE3)。

SPI中有四种操作模式,如下所示:

  • 模式0(默认值) - 时钟通常为低电平(CPOL = 0),数据在从低电平到高电平(前沿)(CPHA = 0)的转换时采样。

  • 模式1 - 时钟通常为低电平(CPOL = 0),数据在从高电平到低电平(后沿)(CPHA = 1)的转换时采样。

  • 模式2 - 时钟通常为高电平(CPOL = 1),数据在从高电平到低电平(前沿)(CPHA = 0)的转换时采样。

  • 模式3 - 时钟通常为高电平(CPOL = 1),数据在从低电平到高电平(后沿)(CPHA = 1)的转换时采样。

  • SPI.attachInterrupt(handler) - 当从设备从主设备接收数据时调用的函数。

现在,我们将两个Arduino UNO板连接在一起;一个作为主机,另一个作为从机。

  • (SS):引脚10
  • (MOSI):引脚11
  • (MISO):引脚12
  • (SCK):引脚13

接地是常见的。以下是两个电路板之间的连接的图示:


两个电路板之间的连接

让我们看看SPI作为主机和SPI作为从机的例子。

SPI为主机

例子

#include <SPI.h>void setup (void) {   Serial.begin(115200); //set baud rate to 115200 for usart   digitalWrite(SS, HIGH); // disable Slave Select   SPI.begin ();   SPI.setClockDivider(SPI_CLOCK_DIV8);//divide the clock by 8}void loop (void) {   char c;   digitalWrite(SS, LOW); // enable Slave Select   // send test string   for (const char * p = "Hello, world!
" ; c = *p; p++) {      SPI.transfer (c);      Serial.print(c);   }   digitalWrite(SS, HIGH); // disable Slave Select   delay(2000);}

SPI为从机

例子

#include <SPI.h>char buff [50];volatile byte indx;volatile boolean process;void setup (void) {   Serial.begin (115200);   pinMode(MISO, OUTPUT); // have to send on master in so it set as output   SPCR |= _BV(SPE); // turn on SPI in slave mode   indx = 0; // buffer empty   process = false;   SPI.attachInterrupt(); // turn on interrupt}ISR (SPI_STC_vect) // SPI interrupt routine {    byte c = SPDR; // read byte from SPI Data Register   if (indx < sizeof buff) {      buff [indx++] = c; // save data in the next index in the array buff      if (c == '
') //check for the end of the word      process = true;   }}void loop (void) {   if (process) {      process = false; //reset the process      Serial.println (buff); //print the array on serial monitor      indx= 0; //reset button to zero   }}


LED是用于许多不同应用的小型强光灯。首先,我们将学习闪烁LED,即微控制器的Hello World。它就像打开和关闭灯一样简单。建立这个重要的基线将为你提供坚实的基础,以实现更复杂的实验。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × LED
  • 1 × 330Ω 电阻
  • 2 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

连接面包板

注意 - 要了解LED的极性,请仔细查看。两个腿中较短的,朝向灯泡的平坦边缘表示负极端子。


LED

像电阻器这样的组件需要将其端子弯曲成90°角,以便恰当的适配面包板插座。你也可以将端子切短。


电阻器

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开新的草图文件。

打开Arduino IDE软件

Arduino代码

/*   Blink   Turns on an LED on for one second, then off for one second, repeatedly.*/// the setup function runs once when you press reset or power the boardvoid setup() {  // initialize digital pin 13 as an output.   pinMode(2, OUTPUT);}// the loop function runs over and over again forevervoid loop() {   digitalWrite(2, HIGH); // turn the LED on (HIGH is the voltage level)   delay(1000); // wait for a second   digitalWrite(2, LOW); // turn the LED off by making the voltage LOW   delay(1000); // wait for a second}

代码说明

pinMode(2,OUTPUT) - 在使用Arduino的引脚之前,你需要告诉Arduino Uno R3它是INPUT还是OUTPUT。我们使用一个内置的“函数”pinMode()来做到这一点。

digitalWrite(2,HIGH) - 当使用引脚作为OUTPUT时,可以将其命令为HIGH(输出5伏)或LOW(输出0伏)。

结果

你应该看到你的LED打开和关闭。如果没有看到所需的输出,请确保你已正确组装电路,并已验证和将代码上传到电路板。


这个例子演示了使用analogWrite()函数来渐变LED的功能。AnalogWrite使用脉冲宽度调制(PWM),以开和关之间的不同比率非常快速地打开和关闭数字引脚,以产生渐变效应。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × LED
  • 1 × 330Ω 电阻
  • 2 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

电路图

注意 − 要了解LED的极性,请仔细查看。两个腿中较短的,朝向灯泡的平坦边缘表示负极端子。


LED

像电阻器这样的组件需要将其端子弯曲成90°角,以便恰当的适配面包板插座。你也可以将端子切短。


电阻

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开新的草图文件。

Sketch

Arduino代码

/*   Fade   This example shows how to fade an LED on pin 9 using the analogWrite() function.   The analogWrite() function uses PWM, so if you want to change the pin you're using, be   sure to use another PWM capable pin. On most Arduino, the PWM pins are identified with   a "~" sign, like ~3, ~5, ~6, ~9, ~10 and ~11.*/int led = 9; // the PWM pin the LED is attached toint brightness = 0; // how bright the LED isint fadeAmount = 5; // how many points to fade the LED by// the setup routine runs once when you press reset:void setup() {   // declare pin 9 to be an output:   pinMode(led, OUTPUT);}// the loop routine runs over and over again forever:void loop() {   // set the brightness of pin 9:   analogWrite(led, brightness);   // change the brightness for next time through the loop:   brightness = brightness + fadeAmount;   // reverse the direction of the fading at the ends of the fade:   if (brightness == 0 || brightness == 255) {      fadeAmount = -fadeAmount ;   }   // wait for 30 milliseconds to see the dimming effect   delay(300);}

代码说明

将引脚9声明为LED引脚之后,在代码的setup()函数中没有任何操作。你将在代码的主循环中使用的analogWrite()函数会需要两个参数:一个告诉函数要写入哪个引脚,另一个表示要写入的PWM值。

为了使LED渐变熄灭和亮起,将PWM值从0(一直关闭)逐渐增加到255(一直开启),然后回到0,以完成循环。在上面给出的草图中,PWM值使用称为brightness的变量设置。每次通过循环时,它增加变量fadeAmount的值。

如果brightness处于其值的任一极值(0或255),则fadeAmount变为负值。换句话说,如果fadeAmount是5,那么它被设置为-5。如果它是-5,那么它被设置为5。下一次通过循环,这个改变也将导致brightness改变方向。

analogWrite()可以非常快速地改变PWM值,因此草图结束时的delay控制了渐变的速度。尝试改变delay的值,看看它如何改变渐变效果。

结果

你应该看到你的LED亮度逐渐变化。

此示例将向你展示如何读取模拟引脚0上的模拟输入。输入从analogRead()转换为电压,并打印输出到Arduino软件(IDE)的串口监视器。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 5K可变电阻(电位器)
  • 2 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

123456

电位器

电位器是一种简单的机电传感器。它将来自输入操作器的旋转或线性运动转换为电阻的变化。这种变化是(或可以)用于控制任何东西,从高保真音响系统到巨大的集装箱船的方向。

我们知道电位器最初被称为变阻器(本质上是一个可变的绕线电阻)。现在可用的电阻器的种类现在相当惊人的,而初学者(特别是)可能很难确定哪种类型适合于给定的任务。一些不同的电阻器类型,都可以用于相同的任务,使得确定工作更难。

pIYBAF1eBUOAXXTOAAB-0b8xr5030427a975e4ae143e9f

左边的图像显示电阻器的标准原理图符号。右边的图像是电位器。

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

void setup() {   // 初始化串行通信速率为9600bit/s:   Serial.begin(9600);}void loop() {   // 读取模拟引脚A0的输入数据   int sensorValue = analogRead(A0);   // 将模拟信号转换成电压   float voltage = sensorValue * (5.0 / 1023.0);   // 打印到串口监视器   Serial.println(voltage);}

代码说明

在下面给出的程序或草图中,你在设置功能中做的第一件事是在你的电路板和你的电脑之间以9600比特每秒开始串行通信,使用以下代码:

Serial.begin(9600);

在代码的主循环中,你需要建立一个变量来存储来自电位器的电阻值(其范围在0到1023之间,非常适合int数据类型):

int sensorValue = analogRead(A0);

要将值从0-1023更改为与引脚正在读取的电压相对应的范围,你需要创建另一个变量,一个浮点数并进行一些计算。要缩小0.0和5.0之间的数字,将5.0除以1023.0,再乘以sensorValue:

float voltage= sensorValue * (5.0 / 1023.0);

最后,你需要将此信息打印到串行窗口。你可以用最后一行代码中的Serial.println()命令:

Serial.println(voltage)

现在,通过单击顶部绿色栏右侧的图标或按Ctrl+Shift+M打开Arduino IDE中的串口监视器。

串行监视器

结果

你会看到一个从0.0到5.0的稳定的数字流。当你转动电位器时,这些值会改变,对应于引脚A0上的电压。


此示例展示如何读取模拟引脚0处的模拟输入,将analogRead()中的值转换为电压,并将其输出到Arduino软件(IDE)的串口监视器。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 5k欧姆可变电阻(电位器)
  • 2 × 跳线
  • 8 × LED(LED条形图显示如下图所示)

程序

按照电路图连接面包板上的组件,如下图所示。

连接面包板

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

10段LED条形图

LED条形图

这10段条形图LED有许多用途。紧凑的占用空间,简单的连接,它们易用于原型或成品。实质上,它们是10个独立的蓝色LED,每个都有独立的阳极和阴极连接。

它们也有黄色,红色和绿色。

注意 - 这些条形图上的引脚可能与数据表中列出的内容不同。将设备旋转180度将纠正变化,使得引脚11成为第一引脚。

Arduino代码

/*   LED bar graph   Turns on a series of LEDs based on the value of an analog sensor.    This is a simple way to make a bar graph display.    Though this graph uses 8LEDs, you can use any number by      changing the LED count and the pins in the array.   This method can be used to control any series of digital      outputs that depends on an analog input.*/// these constants won't change:const int analogPin = A0; // the pin that the potentiometer is attached toconst int ledCount = 8; // the number of LEDs in the bar graphint ledPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; // an array of pin numbers to which LEDs are attachedvoid setup() {   // loop over the pin array and set them all to output:   for (int thisLed = 0; thisLed < ledCount; thisLed++) {      pinMode(ledPins[thisLed], OUTPUT);   }}void loop() {   // read the potentiometer:   int sensorReading = analogRead(analogPin);   // map the result to a range from 0 to the number of LEDs:   int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);   // loop over the LED array:   for (int thisLed = 0; thisLed < ledCount; thisLed++) {      // if the array element's index is less than ledLevel,      // turn the pin for this element on:      if (thisLed < ledLevel) {         digitalWrite(ledPins[thisLed], HIGH);      }else { // turn off all pins higher than the ledLevel:         digitalWrite(ledPins[thisLed], LOW);      }   }} 

代码说明

草图的工作方式是这样的:首先,你阅读输入。将输入值映射到输出范围,在这种情况下为十个LED。然后,你设置一个 for-loop 以迭代输出。如果系列中的输出数量低于映射的输入范围,则将其打开。如果没有,则将其关闭。

结果

当模拟读数的值增加时,你将看到LED逐个打开,而当读数减少时,LED逐个关闭。


本示例使用键盘库将你在计算机上的用户会话注销,此时ARDUINO UNO上的引脚2被拉至接地。草图同时按两个或三个按键的顺序模拟按键,并在短暂的延迟之后释放它们。

警告 - 当你使用 Keyboard.print()命令时,Arduino接管你的计算机键盘。为确保在使用此功能运行草图时不会失去对计算机的控制,请在调用Keyboard.print()之前设置可靠的控制系统。此草图旨在在引脚被拉至接地后才发送键盘命令。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Leonardo, Micro, 或Due板
  • 1 × 按钮
  • 1 × 跳线

程序

按照电路图连接面包板上的组件,如下图所示。

面包板

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

对于本例,你需要使用Arduino IDE 1.6.7

Sketch

注意 - 你必须在Arduino库文件中包含键盘库。将键盘库文件复制并粘贴到名为libraries的文件(下图高亮显示)中,如以下屏幕截图所示。

在Arduino库文件中包含键盘库

Arduino代码

/*   Keyboard logout   This sketch demonstrates the Keyboard library.   When you connect pin 2 to ground, it performs a logout.   It uses keyboard combinations to do this, as follows:   On Windows, CTRL-ALT-DEL followed by ALT-l   On Ubuntu, CTRL-ALT-DEL, and ENTER   On OSX, CMD-SHIFT-q   To wake: Spacebar.   Circuit:   * Arduino Leonardo or Micro   * wire to connect D2 to ground.*/#define OSX 0#define WINDOWS 1#define UBUNTU 2#include "Keyboard.h"// change this to match your platform:int platform = WINDOWS;void setup() {   // make pin 2 an input and turn on the   // pullup resistor so it goes high unless   // connected to ground:      pinMode(2, INPUT_PULLUP);   Keyboard.begin();}void loop() {   while (digitalRead(2) == HIGH) {      // do nothing until pin 2 goes low      delay(500);   }      delay(1000);      switch (platform) {      case OSX:      Keyboard.press(KEY_LEFT_GUI);	        // Shift-Q logs out:      Keyboard.press(KEY_LEFT_SHIFT);      Keyboard.press('Q');      delay(100);	        // enter:      Keyboard.write(KEY_RETURN);      break;	        case WINDOWS:      // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);      delay(100);      Keyboard.releaseAll();	        //ALT-l:      delay(2000);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press('l');      Keyboard.releaseAll();      break;	        case UBUNTU:      // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);	        delay(1000);      Keyboard.releaseAll();	        // Enter to confirm logout:      Keyboard.write(KEY_RETURN);      break;   }      // do nothing:   while (true);}Keyboard.releaseAll();   // enter:      Keyboard.write(KEY_RETURN);      break;      case WINDOWS:	     // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);      delay(100);      Keyboard.releaseAll();	     //ALT-l:      delay(2000);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press('l');      Keyboard.releaseAll();      break;	     case UBUNTU:      // CTRL-ALT-DEL:      Keyboard.press(KEY_LEFT_CTRL);      Keyboard.press(KEY_LEFT_ALT);      Keyboard.press(KEY_DELETE);      delay(1000);      Keyboard.releaseAll();	        // Enter to confirm logout:      Keyboard.write(KEY_RETURN);      break;   }   // do nothing:   while (true);}

代码说明

在将程序上传到你的板之前,请确保将正在使用的正确操作系统分配给平台变量。

在草图运行时,按下按钮将引脚2接地,而板将发送注销序列发送到USB连接的PC。

结果

当将引脚2接地时,它将执行注销操作。

它使用以下键盘组合注销:

  • Windows 上,按CTRL-ALT-DEL,然后按ALT-l

  • Ubuntu ,CTRL-ALT-DEL和ENTER

  • OSX 上,CMD-SHIFT-q


在此示例中,当按下按钮时,文本字符串作为键盘输入发送到计算机。字符串报告按钮被按下的次数。一旦你完成了Leonardo版的程序化和接线,打开你最喜欢的文本编辑器来查看结果。

警告 - 当你使用 Keyboard.print()命令时,Arduino将接管你的计算机键盘。为确保在使用此功能运行草图时不会失去对计算机的控制,请在调用 Keyboard.print()之前设置可靠的控制系统。这个草图包括一个按钮来切换键盘,以便它只在按下按钮后运行。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Leonardo, Micro, 或Due板
  • 1 × 瞬时按钮
  • 1 × 10k欧姆电阻

程序

按照电路图连接面包板上的组件,如下图所示。

面包板

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

/*   Keyboard Message test For the Arduino Leonardo and Micro,      Sends a text string when a button is pressed.   The circuit:   * pushbutton attached from pin 4 to +5V   * 10-kilohm resistor attached from pin 4 to ground*/#include "Keyboard.h"const int buttonPin = 4; // input pin for pushbuttonint previousButtonState = HIGH; // for checking the state of a pushButtonint counter = 0; // button push countervoid setup() {   pinMode(buttonPin, INPUT); // make the pushButton pin an input:   Keyboard.begin(); // initialize control over the keyboard:}void loop() {   int buttonState = digitalRead(buttonPin); // read the pushbutton:   if ((buttonState != previousButtonState)&& (buttonState == HIGH)) // and it's currently pressed: {      // increment the button counter      counter++;      // type out a message      Keyboard.print("You pressed the button ");      Keyboard.print(counter);      Keyboard.println(" times.");   }   // save the current button state for comparison next time:   previousButtonState = buttonState;}

代码说明

将按钮的一个端子连接到Arduino上的引脚4。将另一个引脚连接到5V。使用电阻作为下拉电阻,通过将其从引脚4接地来提供接地参考。

一旦你程序化了电路板,拔下USB电缆,打开一个文本编辑器并将文本光标放在打字区域。再次通过USB将电路板连接到计算机,然后按按钮在文档中写入。

结果

通过使用任意文本编辑器,将显示通过Arduino发送的文本。


使用鼠标库,你可以使用Arduino Leonardo,Micro或Due来控制计算机的屏幕光标。

这个特殊的例子使用五个按钮来移动屏幕上的光标。四个按钮是方向性的(上,下,左,右),一个是用于鼠标左键单击。来自Arduino的光标移动总是相对的。每次读取输入时,光标的位置都会相对于当前位置进行更新。

只要有一个方向按钮被按下,Arduino就会移动鼠标,在合适的方向上将HIGH输入映射到5的范围。

第五个按钮用于控制来自鼠标的左键单击。当按钮被释放时,计算机将识别事件。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Leonardo, Micro 或 Due板
  • 5 × 10k欧姆电阻
  • 5 × 瞬时按钮

程序

按照电路图连接面包板上的组件,如下图所示。

面包板上的组件

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

对于本例,你需要使用Arduino IDE 1.6.7

Sketch

Arduino代码

/*   Button Mouse Control   For Leonardo and Due boards only .Controls the mouse from    five pushbuttons on an Arduino Leonardo, Micro or Due.   Hardware:   * 5 pushbuttons attached to D2, D3, D4, D5, D6   The mouse movement is always relative. This sketch reads   four pushbuttons, and uses them to set the movement of the mouse.   WARNING: When you use the Mouse.move() command, the Arduino takes   over your mouse! Make sure you have control before you use the mouse commands.*/#include "Mouse.h"// set pin numbers for the five buttons:const int upButton = 2;const int downButton = 3;const int leftButton = 4;const int rightButton = 5;const int mouseButton = 6;int range = 5; // output range of X or Y movement; affects movement speedint responseDelay = 10; // response delay of the mouse, in msvoid setup() {   // initialize the buttons' inputs:   pinMode(upButton, INPUT);   pinMode(downButton, INPUT);   pinMode(leftButton, INPUT);   pinMode(rightButton, INPUT);   pinMode(mouseButton, INPUT);   // initialize mouse control:   Mouse.begin();}void loop() {   // read the buttons:   int upState = digitalRead(upButton);   int downState = digitalRead(downButton);   int rightState = digitalRead(rightButton);   int leftState = digitalRead(leftButton);   int clickState = digitalRead(mouseButton);   // calculate the movement distance based on the button states:   int xDistance = (leftState - rightState) * range;   int yDistance = (upState - downState) * range;   // if X or Y is non-zero, move:   if ((xDistance != 0) || (yDistance != 0)) {      Mouse.move(xDistance, yDistance, 0);   }   // if the mouse button is pressed:   if (clickState == HIGH) {      // if the mouse is not pressed, press it:      if (!Mouse.isPressed(MOUSE_LEFT)) {         Mouse.press(MOUSE_LEFT);      }   } else {                           // else the mouse button is not pressed:      // if the mouse is pressed, release it:      if (Mouse.isPressed(MOUSE_LEFT)) {         Mouse.release(MOUSE_LEFT);      }   }   // a delay so the mouse does not move too fast:   delay(responseDelay);}

代码说明

使用micro-USB线将电路板连接到计算机。按钮连接到引脚2至6的数字输入。确保使用10k下拉电阻。


此示例监听来自串口的一个字节。当接收到时,电路板发送一个击键回到计算机。发送的击键比接收的击键高一个,因此如果从串口监视器发送“a”,你将从连接到计算机的电路板接收到“b”。“1”将返回“2”等。

警告 - 当你使用 Keyboard.print()命令时,Leonardo,Micro或Due板会接管你计算机的键盘。为确保在使用此功能运行草图时不会失去对计算机的控制,请在调用Keyboard.print()之前设置可靠的控制系统。这个草图被设计为只在板通过串口接收到一个字节后才发送一个键盘命令。

必需的组件

你将需要以下组件:

  • 1 × Arduino Leonardo, Micro, 或 Due板

程序

只需使用USB线将电路板连接到计算机。

用USB电缆将电路板连接到计算机

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch


注意 - 你必须在Arduino库文件中包含键盘库。将键盘库文件复制并粘贴到以下标黄色的名为“libraries”的文件中。

在Arduino库文件中包含键盘库

Arduino代码

/*   Keyboard test   For the Arduino Leonardo, Micro or Due Reads      a byte from the serial port, sends a keystroke back.    The sent keystroke is one higher than what's received, e.g. if you send a, you get b, send      A you get B, and so forth.   The circuit:   * none*/#include "Keyboard.h"void setup() {   // open the serial port:   Serial.begin(9600);   // initialize control over the keyboard:   Keyboard.begin();}void loop() {   // check for incoming serial data:   if (Serial.available() > 0) {      // read incoming serial data:      char inChar = Serial.read();      // Type the next ASCII value from what you received:      Keyboard.write(inChar + 1);   }}

代码说明

一旦开始编程,则打开你的串口监视器并发送一个字节。电路板将回复一个击键,这是一个更高的数字。

结果

当你发送一个字节时,电路板将会在Arduino IDE串口监视器上回复一个更高数字的击键。


在本节中,我们将学习如何使用不同的传感器连接我们的Arduino板。我们将讨论以下传感器:

  • 湿度传感器(DHT22)
  • 温度传感器(LM35)
  • 水位检测传感器(简单水触发器)
  • PIR传感器
  • 超声波传感器
  • GPS

湿度传感器(DHT22)

DHT-22(也称为AM2302)是一个数字输出,相对湿度和温度传感器。它使用电容式湿度传感器和热敏电阻来测量周围空气,并在数据引脚上发送数字信号。

在本例中,你将学习如何将此传感器与Arduino UNO一起使用。室温和湿度将打印到串口监视器上。

DHT-22传感器

DHT-22传感器

连接很简单。左边的第一个引脚为3-5V电源,第二个引脚连接到数据输入引脚,最右边的引脚接地。

技术细节

  • 电源 - 3-5V

  • 最大电流 - 2.5mA

  • 湿度 - 0-100%,精确度为2-5%

  • 温度 - 40至80°C,精确度为±0.5°C

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × DHT22
  • 1 × 10K欧姆电阻

程序

按照电路图连接面包板上的组件,如下图所示。

电路图

挂接面包板上的组件

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

// Example testing sketch for various DHT humidity/temperature sensors#include "DHT.h"#define DHTPIN 2 // what digital pin we're connected to// Uncomment whatever type you're using!//#define DHTTYPE DHT11 // DHT 11#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321//#define DHTTYPE DHT21 // DHT 21 (AM2301)// Connect pin 1 (on the left) of the sensor to +5V// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1// to 3.3V instead of 5V!// Connect pin 2 of the sensor to whatever your DHTPIN is// Connect pin 4 (on the right) of the sensor to GROUND// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor// Initialize DHT sensor.// Note that older versions of this library took an optional third parameter to// tweak the timings for faster processors. This parameter is no longer needed// as the current DHT reading algorithm adjusts itself to work on faster procs.DHT dht(DHTPIN, DHTTYPE);void setup() {   Serial.begin(9600);   Serial.println("DHTxx test!");   dht.begin();}void loop() {   delay(2000); // Wait a few seconds between measurements   float h = dht.readHumidity();   // Reading temperature or humidity takes about 250 milliseconds!   float t = dht.readTemperature();   // Read temperature as Celsius (the default)   float f = dht.readTemperature(true);   // Read temperature as Fahrenheit (isFahrenheit = true)   // Check if any reads failed and exit early (to try again).   if (isnan(h) || isnan(t) || isnan(f)) {      Serial.println("Failed to read from DHT sensor!");      return;   }      // Compute heat index in Fahrenheit (the default)   float hif = dht.computeHeatIndex(f, h);   // Compute heat index in Celsius (isFahreheit = false)   float hic = dht.computeHeatIndex(t, h, false);   Serial.print ("Humidity: ");   Serial.print (h);   Serial.print (" %	");   Serial.print ("Temperature: ");   Serial.print (t);   Serial.print (" *C ");   Serial.print (f);   Serial.print (" *F	");   Serial.print ("Heat index: ");   Serial.print (hic);   Serial.print (" *C ");   Serial.print (hif);   Serial.println (" *F");}

代码说明

DHT22传感器具有四个端子连接到电路板的端子(Vcc,DATA,NC,GND),如下:

  • DATA引脚连接到Arduino的2号引脚号
  • Vcc引脚连接到Arduino板的5伏电压
  • GND引脚连接到Arduino板的接地
  • 我们需要在DATA和Vcc引脚之间连接10k欧姆电阻(上拉电阻)

一旦硬件连接完成,你需要添加DHT22库到你的Arduino库文件,如前所述。

结果

你将看到串口监视器上的温度和湿度显示,每2秒更新一次。


温度传感器LM35系列是精密集成电路温度器件,输出电压与摄氏温度成线性比例。

LM35器件优于以开尔文校准的线性温度传感器,因为用户不需要从输出中减去大的恒定电压以获得便利的摄氏缩放。LM35器件不需要任何外部校准或调整,即可在室温下提供±1/4°C的典型精度,在-55°C至150°C的温度范围内提供±3°C的典型精度。

温度传感器

技术规格

  • 直接以摄氏度校准
  • 线性 + 10-mV/°C比例因子
  • 0.5°C确保准确度(在25°C)
  • 额定温度范围为-55°C至150°C
  • 适用于远程应用

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × LM35 传感器

程序

按照电路图连接面包板上的组件,如下图所示。

面包板

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

float temp;int tempPin = 0;void setup() {   Serial.begin(9600);}void loop() {   temp = analogRead(tempPin);   // read analog volt from sensor and save to variable temp   temp = temp * 0.48828125;   // convert the analog volt to its temperature equivalent   Serial.print("TEMPERATURE = ");   Serial.print(temp); // display temperature value   Serial.print("*C");   Serial.println();   delay(1000); // update sensor reading each one second}

代码说明

LM35传感器有三个端子:Vs,Vout和GND。我们将按如下方式连接传感器:

  • 将+Vs连接到Arduino板上的+5v电压。
  • 将Vout连接到Arduino板上的模拟0或A0。
  • 将GND连接到Arduino上的GND。

模数转换器(ADC)基于公式ADC值将模拟值转换为数字近似值=样本*1024/参考电压(+5v)。将模拟值转换为数字逼近。 那么用+5v做参考,数字近似值将等于输入电压*205。

结果

你将看到串口监视器上的温度显示,每秒更新一次。


水位传感器砖设计用于水位检测,可广泛应用于检测降雨,水位,甚至液体泄漏。

Water Detector / Sensor

将水位传感器连接到Arduino是检测泄漏,溢出,洪水,雨水等的好方法。它可用于检测水的存在,水位,体积以及是否缺水。当这个用来提醒你给植物浇水时,有一个比较好的Grove传感器。传感器具有一系列暴露的迹线,当检测到水时读取LOW。

在本章中,我们将把水位传感器连接到Arduino上的数字引脚8,并将使用非常方便的LED来帮助识别水位传感器何时与水源接触。

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 水位传感器
  • 1 × led
  • 1 × 330欧姆电阻

程序

按照电路图连接面包板上的组件,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

#define Grove_Water_Sensor 8 // Attach Water sensor to Arduino Digital Pin 8#define LED 9 // Attach an LED to Digital Pin 9 (or use onboard LED)void setup() {   pinMode(Grove_Water_Sensor, INPUT); // The Water Sensor is an Input   pinMode(LED, OUTPUT); // The LED is an Output}void loop() {   /* The water sensor will switch LOW when water is detected.   Get the Arduino to illuminate the LED and activate the buzzer   when water is detected, and switch both off when no water is present */   if( digitalRead(Grove_Water_Sensor) == LOW) {      digitalWrite(LED,HIGH);   }else {      digitalWrite(LED,LOW);   }}

代码说明

水位传感器具有三个端子:S,Vout(+)和GND(-)。按如下所示连接传感器:

  • 将+Vs连接到Arduino板上的+5v。
  • 将S连接到Arduino板上的数字引脚8。
  • 将GND连接到Arduino上的GND。
  • 将LED连接到Arduino板上的数字引脚9。

当传感器检测到水时,Arduino上的引脚8变为LOW,然后Arduino上的LED亮起。

结果

当传感器检测到水时,你会看到指示LED灯亮起。


PIR传感器可以让你感知运动。它们用于检测人是否进入或离开传感器的范围。通常出现在家庭或企业使用的电器和小工具中。它们通常被称为PIR,“被动红外”,“热电”或“IR运动”传感器。

以下是PIR传感器的优点:

  • 体积小
  • 镜头范围广
  • 易于界面
  • 廉价
  • 低电量
  • 使用方便
  • 不会磨损

PIR传感器


PIR由热电传感器制成,圆形金属罐中央有一个矩形晶体,可以检测红外辐射的水平。所有东西都发射出低水平的辐射,而东西越热发射的辐射就越多。运动检测器中的传感器分成两半。这是为了检测运动(变化)而不是平均IR水平。两个半部分相互连接,以便彼此抵消。如果一半看到比另一半更多或更少的红外辐射,则输出将摆动高或低。

PIR


PIR具有可调设置,并在3引脚ground/out/power板上安装了一个接头。

可调设置

对于许多需要在人们离开或进入该区域进行检测的基础项目或产品,PIR传感器是非常有用的。请注意,PIR不会告诉你周围的人数或与传感器的距离。镜头通常固定在有一定距离的扫描范围内,有时候它们会被房子里的宠物带走

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × PIR传感器(MQ3)

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

#define pirPin 2int calibrationTime = 30;long unsigned int lowIn;long unsigned int pause = 5000;boolean lockLow = true;boolean takeLowTime;int PIRValue = 0;void setup() {   Serial.begin(9600);   pinMode(pirPin, INPUT);}void loop() {   PIRSensor();}void PIRSensor() {   if(digitalRead(pirPin) == HIGH) {      if(lockLow) {         PIRValue = 1;         lockLow = false;         Serial.println("Motion detected.");         delay(50);      }      takeLowTime = true;   }   if(digitalRead(pirPin) == LOW) {      if(takeLowTime){         lowIn = millis();takeLowTime = false;      }      if(!lockLow && millis() - lowIn > pause) {         PIRValue = 0;         lockLow = true;         Serial.println("Motion ended.");         delay(50);      }   }}

代码说明

PIR传感器有三个端子:Vcc,OUT和GND。按如下所示连接传感器: 

  • 将+Vcc连接到Arduino板上的+5v。
  • 将OUT连接到Arduino板上的数字引脚2。
  • 将GND连接到Arduino上的GND。

您可以通过位于传感器板底部的两个可变电阻器来调节传感器灵敏度和延迟时间。

可变电阻器

一旦传感器检测到任何运动,Arduino将通过串口发送一条消息,表示检测到运动。PIR感测运动将延迟一定时间以检查是否存有新的运动。如果没有检测到运动,Arduino将发送一条新消息,说明运动已经结束。

结果

如果检测到运动,你将在串口上看到一条消息,并在运动停止时看到另一条消息。


HC-SR04超声波传感器使用声纳来确定物体的距离,就像蝙蝠一样。它提供了非常好的非接触范围检测,准确度高,读数稳定,易于使用,尺寸从2厘米到400厘米或1英寸到13英尺不等。

其操作不受阳光或黑色材料的影响,尽管在声学上,柔软的材料(如布料等)可能难以检测到。它配有超声波发射器和接收器模块。

超声波传感器

超声波

技术规格

电源 - + 5V DC
静态电流 - <2mA
工作电流 - 15mA
有效角度 - <15°
测距距离 - 2厘米-400厘米/1英寸-13英尺
分辨率 - 0.3厘米
测量角度 - 30度

必需的组件

你将需要以下组件:

  • 1 × Breadboard 面包板
  • 1 × Arduino Uno R3
  • 1 × 超声波传感器(HC-SR04)

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

const int pingPin = 7; // Trigger Pin of Ultrasonic Sensorconst int echoPin = 6; // Echo Pin of Ultrasonic Sensorvoid setup() {   Serial.begin(9600); // Starting Serial Terminal}void loop() {   long duration, inches, cm;   pinMode(pingPin, OUTPUT);   digitalWrite(pingPin, LOW);   delayMicroseconds(2);   digitalWrite(pingPin, HIGH);   delayMicroseconds(10);   digitalWrite(pingPin, LOW);   pinMode(echoPin, INPUT);   duration = pulseIn(echoPin, HIGH);   inches = microsecondsToInches(duration);   cm = microsecondsToCentimeters(duration);   Serial.print(inches);   Serial.print("in, ");   Serial.print(cm);   Serial.print("cm");   Serial.println();   delay(100);}long microsecondsToInches(long microseconds) {   return microseconds / 74 / 2;}long microsecondsToCentimeters(long microseconds) {   return microseconds / 29 / 2;}

代码说明

超声波传感器有四个端子:+5V,Trigger,Echo和GND,连接如下:

  • 将+5V引脚连接到Arduino板上的+5v。
  • 将Trigger连接到Arduino板上的数字引脚7。
  • 将Echo连接到Arduino板上的数字引脚6。
  • 将GND连接到Arduino上的GND。

在我们的程序中,我们通过串口显示了传感器测量的距离,单位为英寸和厘米。

结果

你将在Arduino串口监视器上看到传感器测量的距离,单位为英寸和厘米。


按钮或开关连接电路中的两个开路端子。当按下连接到引脚8的按钮开关时,此示例打开引脚2上的LED。

按钮

下拉电阻

在电子逻辑电路中使用下拉电阻,以确保在外部器件断开连接或处于高阻抗状态时,Arduino的输入信号达到预期的逻辑电平。虽然没有任何东西连接到输入引脚,但这并不意味着它是一个逻辑0。下拉电阻连接在地面和器件上相应的引脚之间。

下图显示了数字电路中下拉电阻的示例。在电源电压和微控制器引脚之间连接了一个按钮开关。在这样的电路中,当开关闭合时,微控制器输入处于逻辑高值;但是当开关打开时,下拉电阻将输入电压下拉到接地(逻辑零值),防止输入处于未定义状态。

下拉电阻的电阻必须大于逻辑电路的阻抗,否则可能会使电压下降太多,而无论开关的位置如何,引脚处的输入电压将保持在恒定的逻辑低值。

下拉电阻

必需的组件

你将需要以下组件:

  • 1 × Arduino UNO 板
  • 1 × 330欧姆电阻
  • 1 × 4.7K欧姆电阻(下拉)
  • 1 × LED

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

// constants won't change. They're used here to// set pin numbers:const int buttonPin = 8; // the number of the pushbutton pinconst int ledPin = 2; // the number of the LED pin// variables will change:int buttonState = 0; // variable for reading the pushbutton statusvoid setup() {   // initialize the LED pin as an output:   pinMode(ledPin, OUTPUT);   // initialize the pushbutton pin as an input:   pinMode(buttonPin, INPUT);}void loop() {   // read the state of the pushbutton value:   buttonState = digitalRead(buttonPin);   // check if the pushbutton is pressed.   // if it is, the buttonState is HIGH:   if (buttonState == HIGH) {      // turn LED on:      digitalWrite(ledPin, HIGH);   } else {      // turn LED off:      digitalWrite(ledPin, LOW);   }}

代码说明

当开关打开时(按钮未被按下),按钮的两个端子之间没有连接,因此引脚接地(通过下拉电阻),我们读取低电平。当开关闭合时(按钮被按下),它在其两个端子之间建立连接,将引脚连接到5伏,这样我们读出高电平。

结果

按下按钮时LED亮灯,松开按钮时LED熄灯。


在本章中,我们将使用Arduino板(UNO)连接不同类型的电机,并向你展示如何连接电机并从电路板上驱动它。

有三种不同类型的电机:

  • DC motor 直流电机
  • Servo motor 伺服电机
  • Stepper motor 步进电机

直流电机(DC—Direct Current motor)是最常见的电机类型。直流电动机通常只有两个引线,一个正极和一个负极。如果将这两根引线直接连接到电池,电机将旋转。如果切换引线,电机将以相反的方向旋转。

直流电机

警告 - 不要直接从Arduino板引脚驱动电机。这可能会损坏电路板。使用驱动电路或IC。

我们将本章分为三个部分:

  • 只让你的电机旋转
  • 控制电机速度
  • 控制直流电机的旋转方向

必需的组件

你将需要以下组件:

  • 1x Arduino UNO 板
  • 1x PN2222 晶体管
  • 1x 小型6V直流电机
  • 1x 1N4001二极管
  • 1x 270Ω电阻

程序

按照电路图进行连接,如下图所示。

电路图

预防措施

进行连接时,请采取以下预防措施:

  • 首先,确保晶体管以正确的方式连接。如图所示,晶体管的扁平面应该面向Arduino板。

  • 其次,根据图像中所示的排列,二极管的条纹端应朝向+5V电源线。

Arduino旋转控制代码

int motorPin = 3;void setup() {}void loop() {   digitalWrite(motorPin, HIGH);}

代码说明

晶体管就像一个开关,控制电机的功率。Arduino引脚3用于打开和关闭晶体管,并在草图中命名为“motorPin”。

结果

当Arduino引脚3变为高电平时,电机将全速旋转。

电机速度控制

以下是连接到Arduino板的直流电机的原理图。

直流电机的原理图

Arduino代码

int motorPin = 9;void setup() {   pinMode(motorPin, OUTPUT);   Serial.begin(9600);   while (! Serial);   Serial.println("Speed 0 to 255");}void loop() {   if (Serial.available()) {      int speed = Serial.parseInt();      if (speed >= 0 && speed <= 255) {         analogWrite(motorPin, speed);      }   }}

代码说明

晶体管就像一个开关,控制电机的功率。Arduino引脚3用于打开和关闭晶体管,并在草图中命名为“motorPin”。

当程序启动时,它会提示你提供值以控制电机的速度。你需要在串口监视器中输入介于0和255之间的值。

Command Window

在“loop”函数中,命令“Serial.parseInt”用于读取在串口监视器中作为文本输入的数字,并将其转换为“int”。你可以在此处输入任何数字。如果数字在0到255之间,下一行中的“if”语句只使用此数字进行模拟写入。

结果

直流电机将根据通过串口接收的值(0到250)以不同的速度旋转。

旋转方向控制

为了控制直流电机的旋转方向,无需互换引线,可以使用称为H桥的电路。H桥是可以双向驱动电机的电子电路。H桥用于许多不同的应用中。最常见的应用之一是控制机器人中的电机。它被称为H桥,是因为它使用四个晶体管连接,使示意图看起来像一个“H”。

我们将在这里使用L298 H桥 IC。L298可以控制直流电机和步进电机的速度和方向,并可以同时控制两个电机。每个电机的额定电流为2A。然而,在这些电流下,你将需要使用散热片。

旋转方向控制

必需的组件

你将需要以下组件:

  • 1 × L298桥式IC
  • 1 × 直流电机
  • 1 × Arduino UNO
  • 1 × 面包板
  • 10 × 跳线

程序

以下是Arduino Uno板的直流电机接口示意图。

直流电机接口

上图显示了如何连接L298 IC控制两个电机。每个电机有三个输入引脚,Motor1的Input1(IN1),Input2(IN2)和Enable1(EN1);Motor2的Input3,Input4和Enable2。

由于在这个例子中我们只控制一个电机,因此我们将把Arduino连接到L298 IC的IN1(引脚5),IN2(引脚7)和Enable1(引脚6)。引脚5和7是数字的,即ON或OFF输入,而引脚6需要脉冲宽度调制(PWM)信号来控制电机速度。

下表显示了电机根据IN1和IN2的数字值转动的方向。

IN1IN2电机行为
  制动
1 向前
 1向后
11制动

IC L298的引脚IN1连接到Arduino的引脚8,而IN2连接到引脚9。Arduino的这两个数字引脚控制电机的方向。IC的EN A引脚连接到Arduino的PWM引脚2。这将控制电机的速度。

为了设置Arduino引脚8和9的值,我们使用了digitalWrite()函数,而设置引脚2的值,我们必须使用analogWrite()函数。

连接步骤

  • 将IC的5V和接地分别连接到Arduino的5V和接地。
  • 将电机连接到IC的引脚2和3。
  • 将IC的IN1连接到Arduino的引脚8。
  • 将IC的IN2连接到Arduino的引脚9。
  • 将IC的EN1连接到Arduino的引脚2。
  • 将ICD的SENS A引脚接地。
  • 使用Arduino USB线连接Arduino,并使用Arduino IDE软件将程序上传到Arduino。
  • 使用电源,电池或USB线为Arduino板供电。

Arduino代码

const int pwm = 2 ; //initializing pin 2 as pwmconst int in_1 = 8 ;const int in_2 = 9 ;//For providing logic to L298 IC to choose the direction of the DC motorvoid setup() {   pinMode(pwm,OUTPUT) ; //we have to set PWM pin as output   pinMode(in_1,OUTPUT) ; //Logic pins are also set as output   pinMode(in_2,OUTPUT) ;}void loop() {   //For Clock wise motion , in_1 = High , in_2 = Low   digitalWrite(in_1,HIGH) ;   digitalWrite(in_2,LOW) ;   analogWrite(pwm,255) ;   /* setting pwm of the motor to 255 we can change the speed of rotation   by changing pwm input but we are only using arduino so we are using highest   value to driver the motor */   //Clockwise for 3 secs   delay(3000) ;   //For brake   digitalWrite(in_1,HIGH) ;   digitalWrite(in_2,HIGH) ;   delay(1000) ;   //For Anti Clock-wise motion - IN_1 = LOW , IN_2 = HIGH   digitalWrite(in_1,LOW) ;   digitalWrite(in_2,HIGH) ;   delay(3000) ;   //For brake   digitalWrite(in_1,HIGH) ;   digitalWrite(in_2,HIGH) ;   delay(1000) ;}

结果

电机首先在顺时针(CW)方向运行3秒,然后逆时针(CCW)运行3秒。


伺服电机是一种有输出轴的小型设备。通过向伺服发送编码信号,可以将该轴定位到特定的角度位置。只要编码信号存在于输入线上,伺服将保持轴的角位置。如果编码信号改变,则轴的角位置改变。实际上,伺服用于无线电控制的飞机中来定位控制面,如升降舵和方向舵。它们还用于无线电控制的汽车,木偶,当然还有机器人。


伺服电机

伺服在机器人中非常有用。电机体积小,内置控制电路,相对于它们尺寸来说非常强大。标准伺服如Futaba S-148具有42盎司/英寸的扭矩,这对于其尺寸来说是坚固的。它还吸取与机械负载成比例的功率。因此,轻负载伺服不会消耗太多能量。

伺服电机的内胆如下图所示。你可以看到控制电路,电机,一组齿轮和外壳。还可以看到连接到外部的3根电线。一个是接电源(+5伏),一个接地,而白线是控制线。

伺服电机的内胆

伺服电机的工作

伺服电机有一些控制电路和一个连接到输出轴上的电位器(一个可变电阻,也称为电位器)。在上图中,电位器可以在电路板的右侧看到。该电位器允许控制电路监视伺服电机的当前角度。

如果轴处于正确的角度,则电机关闭。如果电路发现角度不正确,则会转动电机直到处于所需的角度。伺服的输出轴能够在180度左右的地方移动。通常情况下,它是在210度范围内的某个地方,然而,这取决于制造商。正常伺服用于控制0至180度的角运动。由于主输出齿轮上的机械止动装置,机械上它无法转动更远。

施加到电机上的功率与其需要行进的距离成比例。因此,如果轴需要转动较大的距离,电机将以全速运转。如果只需要少量转动,电机将以较低的速度运转。这称为比例控制

如何沟通伺服应该转动的角度?

控制线用于传达角度。该角度由施加到控制线的脉冲持续时间确定。这称为脉冲编码调制伺服期望每20毫秒(0.02秒)看到一个脉冲。脉冲的长度将决定电机转动的距离。例如,1.5毫秒脉冲将使电机转到90度位置(通常称为中性位置)。如果脉冲短于1.5毫秒,则电机将轴转到更接近0度。如果脉冲长于1.5毫秒,则轴转接近180度。

转动角度

必需的组件

你将需要以下组件:

  • 1 × Arduino UNO板
  • 1 × 伺服电机
  • 1 × ULN2003驱动IC
  • 1 × 10KΩ电阻

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

/* Controlling a servo position using a potentiometer (variable resistor) */#include <Servo.h>   Servo myservo; // create servo object to control a servo   int potpin = 0; // analog pin used to connect the potentiometer   int val; // variable to read the value from the analog pinvoid setup() {   myservo.attach(9); // attaches the servo on pin 9 to the servo object}void loop() {   val = analogRead(potpin);   // reads the value of the potentiometer (value between 0 and 1023)   val = map(val, 0, 1023, 0, 180);   // scale it to use it with the servo (value between 0 and 180)   myservo.write(val); // sets the servo position according to the scaled value   delay(15);}

代码说明

伺服电机有三个端子:电源,接地和信号。电源线通常为红色,应连接到Arduino上的5V引脚。接地线通常为黑色或棕色,应连接到ULN2003 IC(10-16)的一个端子。为了保护你的Arduino板免受损坏,你将需要一些驱动IC来处理这些。这里我们使用ULN2003 IC来驱动伺服电机。信号引脚通常为黄色或橙色,应连接到Arduino引脚9。

连接电位器

分压器是串联电路中的电阻器,其将输出电压缩放到施加的输入电压的特定比例。下面是电路图:

连接电位计


公式

Vout是输出电位,取决于施加的输入电压(Vin)和电阻(R1R2这意味着流过R1的电流也将流过R2而不被分流。在上述等式中,随着R的值改变,Vout相对于输入电压Vin而缩放。

通常,电位器是一个分压器,它可以根据可变电阻的值而使用旋钮来缩放电路的输出电压。它有三个引脚:GND,Signal和+5V,如下图所示:

分压器

结果

通过更改电位器的NOP位置,伺服电机将改变其角度。


步进电机是无刷同步电机,它将完整的旋转分成多个步骤。与无刷直流电机不同,当向其施加固定的直流电压时,它将连续旋转,步进电机以不连续的步进角旋转。

因此,步进电机被制造成具有每转12,24,72,144,180和200的步长,从而产生每步30°,15°,5°,2.5°,2°和1.8°的步进角。步进电机可以有或没有反馈控制。

想象一下在RC飞机上的电机。电机在一个方向或另一个方向上转速非常快。你可以通过给予电机的功率量来改变速度,但是你不能让螺旋桨停在特定位置。

现在想象一个打印机。打印机内有很多移动部件,包括电机。一个电机用作进纸,当墨水开始印在纸上时旋转滚轴移动纸张。此电机需要能够将纸张移动一个精确的距离,以便能够打印下一行文本或图像的下一行。

还有另一个电机连接到一个螺杆上来回移动打印头。同样,该螺杆需要移动一个精确的量,以便一个字母接一个地打印。这就是步进电机派上用场的地方。

进步机电

步进电机如何工作?

常规的直流电动机只在方向上旋转,而步进电动机可以以精确的增量旋转。

步进电机可以根据需要转动精确的度数(或步长)。这使你可以完全控制电机,允许你将其移动到精确的位置并保持在该位置。它通过为电机内部的线圈非常短时间的供电来实现。缺点是你必须给电机一直供电,以将它保持在你想要的位置。

你现在需要知道的是,要移动步进电机,你要告诉它在一个方向或另一个方向上移动一定数量的步进,并告诉它沿那个方向步进的速度。步进电机的种类繁多。这里描述的方法可以用于推断如何使用本教程中未提到的其他电机和驱动程序。但是,始终建议你查阅针对具体型号的电机和驱动器的数据表和指南。

增量旋转

必需的组件

你将需要以下组件:

  • 1 × Arduino UNO板
  • 1 ×小型双极步进电机,如下图所示
  • 1 ×LM298驱动IC
小型双极步进电机

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

Arduino代码

/* Stepper Motor Control */#include <Stepper.h>const int stepsPerRevolution = 90;// change this to fit the number of steps per revolution// for your motor// initialize the stepper library on pins 8 through 11:Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);void setup() {   // set the speed at 60 rpm:   myStepper.setSpeed(5);   // initialize the serial port:   Serial.begin(9600);}void loop() {   // step one revolution in one direction:   Serial.println("clockwise");   myStepper.step(stepsPerRevolution);   delay(500);   // step one revolution in the other direction:   Serial.println("counterclockwise");   myStepper.step(-stepsPerRevolution);   delay(500);}

代码说明

该程序驱动单极或双极步进电机。电机连接到Arduino的数字引脚8-11。

结果

电机将在一个方向上旋转一圈,然后在另一个方向上旋转一圈。


在本章中,我们将使用Arduino音调库。它只是一个Arduino库,可以在任意Arduino引脚上产生指定频率(50%占空比)的方波。持续时间可以有选择的指定,否则方波会一直持续到stop()函数被调用。该引脚可以连接到压电蜂鸣器或扬声器播放音调。

警告 - 不要将引脚直接连接到任何音频输入。电压远远高于标准线路电压,并可能损坏声卡输入等。你可以使用分压器来降低电压。

必需的组件

你将需要以下组件:

  • 1 × 8欧姆扬声器
  • 1 × 1k电阻
  • 1 × Arduino UNO 板

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

要制作pitches.h文件,请单击串口监视器图标正下方的按钮,然后选择“New Tab”,或使用Ctrl+Shift+N。

制作pitches.h文件

然后粘贴以下代码:

/************************************************** Public Constants*************************************************/#define NOTE_B0 31#define NOTE_C1 33#define NOTE_CS1 35#define NOTE_D1 37#define NOTE_DS1 39#define NOTE_E1 41#define NOTE_F1 44#define NOTE_FS1 46#define NOTE_G1 49#define NOTE_GS1 52#define NOTE_A1 55#define NOTE_AS1 58#define NOTE_B1 62#define NOTE_C2 65#define NOTE_CS2 69#define NOTE_D2 73#define NOTE_DS2 78#define NOTE_E2 82#define NOTE_F2 87#define NOTE_FS2 93#define NOTE_G2 98#define NOTE_GS2 104#define NOTE_A2 110#define NOTE_AS2 117#define NOTE_B2 123#define NOTE_C3 131#define NOTE_CS3 139#define NOTE_D3 147#define NOTE_DS3 156#define NOTE_E3 165#define NOTE_F3 175#define NOTE_FS3 185#define NOTE_G3 196#define NOTE_GS3 208#define NOTE_A3 220#define NOTE_AS3 233#define NOTE_B3 247#define NOTE_C4 262#define NOTE_CS4 277#define NOTE_D4 294#define NOTE_DS4 311#define NOTE_E4 330#define NOTE_F4 349#define NOTE_FS4 370#define NOTE_G4 392#define NOTE_GS4 415#define NOTE_A4 440#define NOTE_AS4 466#define NOTE_B4 494#define NOTE_C5 523#define NOTE_CS5 554#define NOTE_D5 587#define NOTE_DS5 622#define NOTE_E5 659#define NOTE_F5 698#define NOTE_FS5 740#define NOTE_G5 784#define NOTE_GS5 831#define NOTE_A5 880#define NOTE_AS5 932#define NOTE_B5 988#define NOTE_C6 1047#define NOTE_CS6 1109#define NOTE_D6 1175#define NOTE_DS6 1245#define NOTE_E6 1319#define NOTE_F6 1397#define NOTE_FS6 1480#define NOTE_G6 1568#define NOTE_GS6 1661#define NOTE_A6 1760#define NOTE_AS6 1865#define NOTE_B6 1976#define NOTE_C7 2093#define NOTE_CS7 2217#define NOTE_D7 2349#define NOTE_DS7 2489#define NOTE_E7 2637#define NOTE_F7 2794#define NOTE_FS7 2960#define NOTE_G7 3136#define NOTE_GS7 3322#define NOTE_A7 3520#define NOTE_AS7 3729#define NOTE_B7 3951#define NOTE_C8 4186#define NOTE_CS8 4435#define NOTE_D8 4699#define NOTE_DS8 4978

将上面给出的代码保存为 pitches.h

Arduino代码

#include "pitches.h"// notes in the melody:int melody[] = {NOTE_C4, NOTE_G3,NOTE_G3, NOTE_GS3, NOTE_G3,0, NOTE_B3, NOTE_C4};// note durations: 4 = quarter note, 8 = eighth note, etc.:int noteDurations[] = {   4, 8, 8, 4,4,4,4,4 };void setup() {   // iterate over the notes of the melody:   for (int thisNote = 0; thisNote < 8; thisNote++) {      // to calculate the note duration, take one second      // divided by the note type.      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.      int noteDuration = 1000/noteDurations[thisNote];      tone(8, melody[thisNote],noteDuration);      //pause for the note's duration plus 30 ms:      delay(noteDuration +30);   }}void loop() {   // no need to repeat the melody.}

代码说明

代码使用一个额外的文件,pitches.h。此文件包含典型音符的所有音高值。例如,NOTE_C4是中央C。NOTE_FS4是F#,等等。这个注释表最初是由Brett Hagman编写的,tone()命令是基于它工作的。当你想制作音符时会发现它很有用。

结果

你会听到保存在pitches.h文件中的音符。


无线发射器和接收器模块工作在315 Mhz。它们可以轻松地装入面包板,并可很好的与微控制器配合使用,创建一个非常简单的无线数据链路。使用一对发射器和接收器,模块将只能单向传输数据,因此,你将需要两对(不同频率)作为发射器/接收器对。

注意 - 这些模块是任意的,并会接收相当大量的噪音。发射器和接收器都在共同的频率下工作,并且没有ID。

无线发射器

接收器模块规格

产品型号 - MX-05V
工作电压 - DC5V
静态电流 - 4mA
接收频率 - 315Mhz
接收灵敏度 - -105DB
尺寸 - 30*14*7mm

发射器模块规格

产品型号 - MX-FS-03V
发射距离 - 20-200米(不同电压,不同结果)
工作电压 - 3.5-12V
尺寸 - 19*19mm
操作模式 - AM
传输速率 - 4KB/S
发射功率 - 10mW
发射频率 - 315Mhz
外置天线 - 25cm普通多芯或单芯线
从左到右的引脚分布 - DATA;VCC;GND

必需的组件

你将需要以下组件:

  • 2 × Arduino UNO板
  • 1 × Rf链路发射器
  • 1 × Rf链路接收器

程序

按照电路图进行连接,如下图所示。

电路图

草图

在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。

Sketch

注意 - 你必须在Arduino库文件中包含键盘库。将VirtualWire.lib文件复制并粘贴到库文件夹中,如下面屏幕截图的高亮部分所示。

在Arduino库文件中包含键盘库

发射器的Arduino代码

//simple Tx on pin D12#include <VirtualWire.h>char *controller;void setup() {   pinMode(13,OUTPUT);   vw_set_ptt_inverted(true);   vw_set_tx_pin(12);   vw_setup(4000);// speed of data transfer Kbps}void loop() {   controller="1" ;   vw_send((uint8_t *)controller, strlen(controller));   vw_wait_tx(); // Wait until the whole message is gone   digitalWrite(13,1);   delay(2000);   controller="0" ;   vw_send((uint8_t *)controller, strlen(controller));   vw_wait_tx(); // Wait until the whole message is gone   digitalWrite(13,0);   delay(2000);}

代码说明

这是一个简单的代码。首先发送字符“1”,两秒后发送字符“0”,以此类推。

接收器的Arduino代码

//simple Rx on pin D12#include <VirtualWire.h>void setup() {   vw_set_ptt_inverted(true); // Required for DR3100   vw_set_rx_pin(12);   vw_setup(4000); // Bits per sec   pinMode(5, OUTPUT);   vw_rx_start(); // Start the receiver PLL running}void loop() {   uint8_t buf[VW_MAX_MESSAGE_LEN];   uint8_t buflen = VW_MAX_MESSAGE_LEN;   if (vw_get_message(buf, &buflen)) // Non-blocking {      if(buf[0]=='1') {         digitalWrite(5,1);      }      if(buf[0]=='0') {         digitalWrite(5,0);      }   }}

代码说明

当接收到字符“1”时,连接到Arduino板上引脚5的LED亮起,当接收到字符“0”时,LED熄灭。


德州仪器的CC3000 WiFi模块是一个小型银包,最终为你的Arduino项目带来了易用,经济实惠的WiFi功能。

它使用SPI进行通信(而不是UART),因此你可以根据需要尽可能快或尽可能慢地推送数据。它有一个合适的IRQ引脚中断系统,因此你可以有异步连接。它支持802.11b/g,open/WEP/WPA/WPA2安全,TKIP及AES。具有“BSD socket”接口的内置TCP/IP堆栈支持客户端和服务器模式下的TCP和UDP。


CC3000

必需的组件

你将需要以下组件:

  • 1 × Arduino Uno
  • 1 × Adafruit CC3000分线板
  • 1 × 5V继电器
  • 1 × 整流二极管
  • 1 × LED
  • 1 × 220欧姆电阻
  • 1 × 面包板和一些跳线

对于这个项目,你只需要通常的Arduino IDE,Adafruit的CC3000库以及CC3000 MDNS库。我们也将使用aREST库通过WiFi向中继发送命令。

程序

按照电路图进行连接,如下图所示。

电路图

这个项目的硬件配置非常简单。

  • 将CC3000板的IRQ引脚连接到Arduino板的引脚3。
  • VBAT连接到引脚5,CS连接到引脚10。
  • 将SPI引脚连接到Arduino板:MOSI,MISO和CLK分别连接到引脚11,12和13。
  • Vin连接到Arduino 5V,GND连接到GND。

现在,让我们连接继电器。

将继电器放在面包板上后,你可以开始识别继电器上的两个重要部分:指示继电器的线圈部分和连接LED的开关部分。

  • 首先,将Arduino板的8号引脚连接到线圈的一个引脚。
  • 将另一个引脚连接到Arduino板的接地。

您还必须将整流二极管(阳极连接到接地引脚)放置在线圈的引脚上,以在继电器切换时保护电路。

  • 将Arduino板的+5V连接到继电器开关的公共引脚。

  • 最后,将开关的另一个引脚(通常是继电器断开时未连接的引脚)连接到与220欧姆电阻串联的LED,并将LED的另一端连接到Arduino的接地。

测试单个组件

你可以使用以下草图测试继电器:

const int relay_pin = 8; // Relay pinvoid setup() {   Serial.begin(9600);   pinMode(relay_pin,OUTPUT);}void loop() {   // Activate relay   digitalWrite(relay_pin, HIGH);   // Wait for 1 second   delay(1000);   // Deactivate relay   digitalWrite(relay_pin, LOW);   // Wait for 1 second   delay(1000);}

代码说明

代码是不言自明的。你只需将其上传到电路板,继电器将每秒切换状态,LED将相应地亮起和熄灭。

添加WiFi连接

现在让我们使用CC3000 WiFi芯片无线控制继电器。该项目的软件基于TCP协议。但是,对于这个项目,Arduino板将运行一个小的Web服务器,以便我们可以“监听”来自计算机的命令。我们先来看看Arduino草图,然后我们将看到如何编写服务器端代码并创建一个漂亮的界面。

首先,Arduino草图。这里的目标是连接到你的WiFi网络,创建Web服务器,检查是否有传入的TCP连接,然后相应地更改继电器的状态。

代码的重要部分

#include <Adafruit_CC3000.h>#include <SPI.h>#include <CC3000_MDNS.h>#include <Ethernet.h>#include <aREST.h>

你需要在代码中定义特定于你的配置的内容,即Wi-Fi名称和密码,以及TCP通信端口(我们在此使用了80)。

// WiFi network (change with your settings!)   #define WLAN_SSID "yourNetwork" // cannot be longer than 32 characters!   #define WLAN_PASS "yourPassword"   #define WLAN_SECURITY WLAN_SEC_WPA2 // This can be WLAN_SEC_UNSEC, WLAN_SEC_WEP,    // WLAN_SEC_WPA or WLAN_SEC_WPA2// The port to listen for incoming TCP connections   #define LISTEN_PORT 80

然后我们可以创建CC3000实例,服务器和aREST实例:

// Server instance   Adafruit_CC3000_Server restServer(LISTEN_PORT); // DNS responder instance   MDNSResponder mdns; // Create aREST instance   aREST rest = aREST();

在草图的setup()部分,我们现在可以将CC3000芯片连接到网络:

cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);

计算机将如何知道在哪里发送数据?一种方法是运行草图一次,然后获取CC3000板的IP地址,并再次修改服务器代码。但是,我们可以做得更好,这就是CC3000 MDNS库发挥作用的地方。我们将使用此库为我们的CC3000板分配一个固定名称,以便我们可以将此名称直接写入服务器代码。

这可以用下面的代码片段完成:

if (!mdns.begin("arduino", cc3000)) {   while(1);}

我们还需要监听传入的连接。

restServer.begin();

接下来,我们要对将被连续执行的草图的loop()函数进行编码。我们首先要更新mDNS服务器。

mdns.update();

在Arduino板上运行的服务器将等待传入连接并处理请求。

Adafruit_CC3000_ClientRef client = restServer.available();rest.handle(client);

现在通过WiFi测试项目非常容易。确保你使用自己的WiFi名称和密码更新草图,并将草图上传到Arduino板。打开你的Arduino IDE串口监视器,并查找电路板的IP地址。

我们假设其余的是192.168.1.103。

然后,只需进入你喜欢的网络浏览器,然后键入:

192.168.1.103/digital/8/1

你应该看到继电器自动打开。

构建继电器界面

我们现在将编写项目的界面。这里将有两个部分:包含界面的HTML文件和用于处理界面上点击的客户端Javascript文件。这里的界面基于aREST.js项目,这是为了方便从你的计算机控制WiFi设备。
让我们先看一下名为interface.html的HTML文件。第一部分包括导入所有界面需要的库:

<head>   <meta charset = utf-8 />   <title> Relay Control </title>   <link rel = "stylesheet" type = "text/css"       href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">   <link rel="stylesheet" type = "text/css" href = "style.css">   <script type = "text/javascript"       src = "https://code.jquery.com/jquery-2.1.4.min.js"></script>   <script type = "text/javascript"       src = "https://cdn.rawgit.com/Foliotek/AjaxQ/master/ajaxq.js"></script>   <script type = "text/javascript"       src = "https://cdn.rawgit.com/marcoschwartz/aREST.js/master/aREST.js"></script>   <script type = "text/javascript"       src = "script.js"></script></head>

然后,我们在界面中定义两个按钮,一个用于打开继电器,另一个用于再次关闭继电器。

<div class = 'container'>   <h1>Relay Control</h1>   <div class = 'row'>      <div class = "col-md-1">Relay</div>      <div class = "col-md-2">         <button id = 'on' class = 'btn btn-block btn-success'>On</button>      </div>      <div class = "col-md-2">         <button id = 'off' class = 'btn btn-block btn-danger'>On</button>      </div>   </div></div>

现在,我们还需要一个客户端Javascript文件来处理按钮上的点击。我们还将创建一个设备,我们将链接到Arduino设备的mDNS名称。如果你在Arduino代码中改变了这个,你也需要在这里修改它。

// Create devicevar device = new Device("arduino.local");// Button$('#on').click(function() {   device.digitalWrite(8, 1);});$('#off').click(function() {   device.digitalWrite(8, 0);});

该项目的完整代码可以在 GitHub 存储库中找到。进入界面文件夹,只需用你喜欢的浏览器打开HTML文件。应该会在浏览器中看到类似的内容:

Relay Control


尝试点击Web界面上的按钮;它应该立即改变继电器的状态。

如果你设法让它工作了,恭喜你,你刚刚构建了一个Wi-Fi控制的电灯开关。当然,通过这个项目你可以控制更多的电灯。只需确保你的继电器支持你想要控制的设备所需的电源,你就可以很好的实现了。