Arudino基础教程

基本

Arduino 网络通信

Arduino 无线通信

Arduino 音调库

Arduino 串行外设接口

Arduino 内部集成电路

Arduino 中断

Arduino 通信

Arduino 随机数

Arduino 脉冲宽度调制

Arduino Due 和 Zero

Arduino 三角函数

Arduino 数学库

Arduino 字符函数

Arduino 高级I/O函数

Arduino I/O函数

Arduino 数组

Arduino 时间函数

Arduino 字符串

Arduino 函数

Arduino 循环

Arduino 控制语句

Arduino 运算符

Arduino 变量和常量

Arduino 数据类型

Arduino 程序结构

Arduino 安装

Arduino 板的说明

Arduino 概述

键盘

Arduino 键盘串口

Arduino 鼠标按钮控制

Arduino 键盘消息

Arduino 键盘注销

LED

Arduino LED条形图

Arduino 闪烁LED

电机

Arduino 步进电机

Arduino 伺服电机

Arduino 直流电机

传感器

Arduino 连接开关

Arduino 水位检测器/传感器

Arduino 温度传感器

Arduino 超声波传感器

Arduino PIR传感器

Arduino 湿度传感器

Arduino 网络通信

德州仪器的CC3000 WiFi模块是一个小型银包,最终为你的Arduino项目带来了易用,经济实惠的WiFi功能。
它使用SPI进行通信(而不是UART),因此你可以根据需要尽可能快或尽可能慢地推送数据。它有一个合适的IRQ引脚中断系统,因此你可以有异步连接。它支持802.11b/g,open/WEP/WPA/WPA2安全,TKIP及AES。具有“BSD socket”接口的内置TCP/IP堆栈支持客户端和服务器模式下的TCP和UDP。

Arduino 网络通信

必需的组件

你将需要以下组件:

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

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

程序

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

Arduino 网络通信

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

  • 将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 pin
 

void 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 device var device = new Device("arduino.local");

// Button
$('#on').click(function()
{
   device.
   digitalWrite(8, 1);


  });

$('#off').click(function()
{
   device.
   digitalWrite(8, 0);


  });

该项目的完整代码可以在 GitHub 存储库中找到。进入界面文件夹,只需用你喜欢的浏览器打开HTML文件。你应该会在浏览器中看到类似的内容:

Arduino 网络通信

 

尝试点击Web界面上的按钮;它应该立即改变继电器的状态。
如果你设法让它工作了,恭喜你,你刚刚构建了一个Wi-Fi控制的电灯开关。当然,通过这个项目你可以控制更多的电灯。只需确保你的继电器支持你想要控制的设备所需的电源,你就可以很好的实现了。

Arduino 无线通信

无线发射器和接收器模块工作在315 Mhz。它们可以轻松地装入面包板,并可很好的与微控制器配合使用,创建一个非常简单的无线数据链路。使用一对发射器和接收器,模块将只能单向传输数据,因此,你将需要两对(不同频率)作为发射器/接收器对。
注意 – 这些模块是任意的,并会接收相当大量的噪音。发射器和接收器都在共同的频率下工作,并且没有ID。

Arduino 无线通信

接收器模块规格

产品型号 – 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 无线通信

草图

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

Arduino 无线通信

注意 – 你必须在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熄灭。
 

Arduino 音调库

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

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

必需的组件

你将需要以下组件:

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

程序

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

Arduino 音调库

草图

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

Arduino 音调库

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

Arduino 音调库

然后粘贴以下代码:

/************************************************* * 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文件中的音符。


Arduino 串行外设接口

串行外设接口(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

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

Arduino 串行外设接口

让我们看看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!r" ;

c = *p;

p++)
{
      SPI.transfer (c);

    
  Serial.print(c);

  
  }
    
   digitalWrite(SS, HIGH);

// disable Slave Select
   
  delay(2000);


  }

SPI为从机

例子

#include &lt;SPI.h&gt;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 &lt;sizeof buff)
{
      buff [indx++] = c;

// save data in the next index in the array buff
       if (c == 'r') //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
     
   }
  } 

 

Arduino 内部集成电路

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

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


Arduino 内部集成电路


板的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 library
 

void 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 library
 

void 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++;

  } 

Arduino 中断

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

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

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

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

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。

attachInterrupt语句语法

attachInterrupt(digitalPinToInterrupt(pin),ISR,mode);

//recommended for arduino board attachInterrupt(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.

以下三个常量被预定义为有效值:

  • LOW :在引脚为低电平时触发中断。

  • CHANGE :在引脚更改值时触发中断。

  • FALLING :当引脚从高电平变为低电平时触发中断。 

     

示例

int pin = 2;

//define interrupt pin to 2 volatile
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

  } 

Arduino 通信

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

并行通信

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

Arduino 通信

并行通信的优点和缺点

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

串行通信模块

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

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

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

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

串行通信类型

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

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

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

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

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

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

  • Synchronization bits 

    同步位

  • Data bits 

    数据位

  • Parity bits 

    奇偶校验位

  • Baud rate 

    波特率

同步位

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

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

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


Arduino 通信

数据位

每个分组中的数据量可以设置为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右上角的串口监视器搜索Arduino 通信

在串口监视器的顶部框中键入任意内容,然后按发送键或键盘上的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代码了解更多信息。


Arduino 随机数

要生成随机数,可以使用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 max long 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中的数字相同,但具有不同的值。

Arduino 随机数

字节

一个字节由8位组成。

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

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

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

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

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

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

Arduino 脉冲宽度调制

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

PWM的基本原理

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

Arduino 脉冲宽度调制

有很多术语与PWM相关:

  • On-Time(导通时间) 

    – 时间信号的持续时间较长。

  • Off-Time(关断时间) 

    – 时间信号的持续时间较短。

  • Period(周期) 

    – 表示为PWM信号的导通时间和关断时间的总和。

  • Duty Cycle(占空比) 

    – 它表示为在PWM信号周期内保持导通的时间信号的百分比。

周期

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

Arduino 脉冲宽度调制

占空比

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

Arduino 脉冲宽度调制


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()


Arduino 脉冲宽度调制


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 9 int analogPin = 3;

// potentiometer connected to analog pin 3 int val = 0;

// variable to store the read value  void 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

  }