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

  } 

Arduino Due 和 Zero

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 和 Zero

Arduino Due板的特性

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

Flash[KB]

USB UART
3.3伏 84 Mhz 12/2 54/12 96 512 2微米 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 Due 和 Zero

Arduino Zero板的特性

工作电压 CPU速度 模拟输入/输出 数字IO/ PWM EEPROM [KB] SRAM [KB] Flash [KB] USB UART
3.3伏 48 Mhz 6/1 14/10 32 256 2微米 2

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

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