基本
键盘
LED
电机
传感器
Arduino 超声波传感器
一个聚焦STEAM教育的站点
Arduino 超声波传感器
你将需要以下组件:
对于这个项目,你只需要通常的Arduino IDE,Adafruit的CC3000库以及CC3000 MDNS库。我们也将使用aREST库通过WiFi向中继发送命令。
按照电路图进行连接,如下图所示。
这个项目的硬件配置非常简单。
现在,让我们连接继电器。
将继电器放在面包板上后,你可以开始识别继电器上的两个重要部分:指示继电器的线圈部分和连接LED的开关部分。
您还必须将整流二极管(阳极连接到接地引脚)放置在线圈的引脚上,以在继电器切换时保护电路。
你可以使用以下草图测试继电器:
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将相应地亮起和熄灭。
现在让我们使用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文件。你应该会在浏览器中看到类似的内容:
尝试点击Web界面上的按钮;它应该立即改变继电器的状态。
如果你设法让它工作了,恭喜你,你刚刚构建了一个Wi-Fi控制的电灯开关。当然,通过这个项目你可以控制更多的电灯。只需确保你的继电器支持你想要控制的设备所需的电源,你就可以很好的实现了。
你将需要以下组件:
按照电路图进行连接,如下图所示。
在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。
注意 – 你必须在Arduino库文件中包含键盘库。将VirtualWire.lib文件复制并粘贴到库文件夹中,如下面屏幕截图的高亮部分所示。
//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”,以此类推。
//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引脚上产生指定频率(50%占空比)的方波。持续时间可以有选择的指定,否则方波会一直持续到stop()函数被调用。该引脚可以连接到压电蜂鸣器或扬声器播放音调。
警告 – 不要将引脚直接连接到任何音频输入。电压远远高于标准线路电压,并可能损坏声卡输入等。你可以使用分压器来降低电压。
你将需要以下组件:
按照电路图进行连接,如下图所示。
在计算机上打开Arduino IDE软件。使用Arduino语言进行编码控制你的电路。通过单击“New”打开一个新的草图文件。
要制作pitches.h文件,请单击串口监视器图标正下方的按钮,然后选择“New Tab”,或使用Ctrl+Shift+N。
然后粘贴以下代码:
/************************************************* * 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
#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文件中的音符。
SPI使用以下四条线:
使用以下函数,必须包括SPI.h.
SPI中有四种操作模式,如下所示:
现在,我们将两个Arduino UNO板连接在一起;一个作为主机,另一个作为从机。
接地是常见的。以下是两个电路板之间的连接的图示:
让我们看看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);
}
#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 == '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
}
}
内部集成电路(I2C)是用于微控制器和新一代专用集成电路之间的串行数据交换系统。当它们之间的距离很短(接收器和发射器通常在同一个印刷电路板上)时使用。通过两根导线建立连接。一个用于数据传输,另一个用于同步(时钟信号)。
如下图所示,一个设备始终是主设备。它在通信开始之前执行一个从芯片的寻址。这样,一个微控制器可以与112个不同的设备进行通信。波特率通常为100 Kb/sec(标准模式)或10 Kb/sec(慢波特率模式)。最近出现了波特率为3.4 Mb/s的系统。通过I2C总线通信的设备之间的距离限制在几米之内。
I2C总线由两个信号组成 – SCL和SDA。SCL是时钟信号,SDA是数据信号。当前总线主机总是产生时钟信号。一些从设备可能迫使时钟低电平以延迟主设备发送更多数据(或者在主设备尝试将数据写出之前请求更多的时间来准备数据)。这被称为“时钟伸展”。
以下是不同Arduino板的引脚:
我们有两种模式 – 主代码和从代码 – 使用I2C连接两个Arduino板。它们是:
主发射器/从接收器
主接收器/从发射器
让我们现在看看什么是主发送器和从接收器。
以下函数用于初始化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++;
}
中断(interrupt)停止Arduino的当前工作,以便可以完成一些其他工作。
假设你坐在家里和别人聊天。突然电话响了。你停止聊天,拿起电话与来电者通话。当你完成电话交谈后,你回去和电话响之前的那个人聊天。
同样,你可以把主程序想象成是与某人聊天,电话铃声使你停止聊天。中断服务程序是在电话上通话的过程。当通话结束后,你回到你聊天的主程序。这个例子准确地解释了中断如何使处理器执行操作。
主程序在电路中运行并执行一些功能。但是,当发生中断时,主程序在另一个程序执行时停止。当这个程序结束时,处理器再次返回主程序。
这里有一些关于中断的重要特征:
中断可以来自各种来源。在这种情况下,我们使用的是由数字引脚上的状态改变触发的硬件中断。
大多数Arduino设计有两个硬件中断(称为“interrupt0”和“interrupt1”)分别硬连接到数字I/O引脚2和3。
Arduino Mega有六个硬件中断,包括引脚21,20,19和18上的附加中断(“interrupt2”到“interrupt5”)。
你可以使用称为“中断服务程序”(Interrupt Service Routine,通常称为ISR)的特殊函数来定义程序。
你可以定义该程序并指定上升沿,下降沿或两者的条件。在这些特定条件下,将处理中断。
每次在输入引脚上发生事件时,都可以自动执行该函数。
有两种类型的中断:
硬件中断 – 它们响应外部事件而发生,例如外部中断引脚变为高电平或低电平。
软件中断 – 它们响应于在软件中发送的指令而发生。“Arduino语言”支持的唯一类型的中断是attachInterrupt()函数。
中断在Arduino程序中非常有用,因为它有助于解决时序问题。中断的良好应用是读取旋转编码器或观察用户输入。一般情况下,ISR应尽可能短且快。如果你的草图使用多个ISR,则一次只能运行一个。其他中断将在当前完成之后执行,其顺序取决于它们的优先级。
通常,全局变量用于在ISR和主程序之间传递数据。为了确保在ISR和主程序之间共享的变量正确更新,请将它们声明为volatile。
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和外设之间进行并行连接是短距离(最多几米)的理想解决方案。然而,在其他情况下,当需要在两个设备之间建立较长距离的通信时,不可能使用并行连接。并行接口同时传输多个位。它们通常需要数据总线 – 通过八条,十六条或更多的线路进行传输。数据以1和0的巨大波形传输。
并行通信肯定有其优势。它比串行更快,更直接,相对容易实施。然而,它需要许多的输入/输出(I / O)端口和线路。如果你曾经把一个项目从一个基本的Arduino Uno移动到一个Mega,你就知道微处理器上的I/O线是很宝贵的,而且很少。因此,我们更喜欢串行通信,牺牲针脚空间的潜在速度。
今天,大多数Arduino板都是用几种不同的串行通信系统作为标准设备。
使用哪个系统取决于以下因素:
有关串行通信的最重要的事情之一是协议,应该严格遵守。它是一套规则,必须应用这些规则才能使设备正确地解释它们相互交换的数据。幸运的是,Arduino会自动处理这个问题,这样程序员/用户的工作就可以简化为简单的写(发送的数据)和读(接收的数据)。
串行通信可以进一步分类为:
同步 – 同步的设备使用相同的时钟,它们的时序彼此同步。
异步 – 异步的设备具有各自的时钟,并由前一状态的输出触发。
很容易找出设备是否同步。如果给所有连接的设备提供相同的时钟,则它们是同步的。如果没有时钟线,它是异步的。
例如,UART(通用异步收发器)模块是异步的。
异步串行协议有一些内置的规则。这些规则只是有助于确保可靠且无误的数据传输的机制。这些避免外部时钟信号的机制是:
同步位
数据位
奇偶校验位
波特率
同步位是与每个数据包传输的两个或三个特殊位。它们是起始位和停止位。正如它们的名称,这些位分别标记数据包的开始和结束。
起始位始终只有一个,但停止位的数量可以配置为一个或两个(尽管通常保持为1)。
起始位始终由从1到0的空闲数据线指示,而停止位将通过将线保持在1处而转换回空闲状态。
每个分组中的数据量可以设置为5到9位的任意大小。当然,标准数据大小是基本8位字节,但其他大小有它们的用途。7位数据包的效率可能比8位高,特别是如果你只是传输7位ASCII字符。
用户可以选择是否应该有奇偶校验位,如果是,则奇偶校验应该是奇数还是偶数。如果数据位中的1的数目是偶数,则奇偶校验位为0。奇数的奇偶校验正好相反。
术语波特率用于表示每秒传输的位数[bps]。注意,它指的是位,而不是字节。协议通常要求每个字节与几个控制位一起传输。这意味着串行数据流中的一个字节可以包括11位。例如,如果波特率为300bps,则每秒可以传输最大37字节和最小27字节。
以下代码将使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右上角的串口监视器搜索。
在串口监视器的顶部框中键入任意内容,然后按发送键或键盘上的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随机数函数。我们有两个函数:
randomSeed(seed)函数重置Arduino的伪随机数生成器。虽然random()返回的数字的分布本质上是随机的,但是顺序是可预测的。你应该将发生器重置为某个随机值。如果你有一个未连接的模拟引脚,它可能会从周围环境中拾取随机噪音。这些可能是无线电波,宇宙射线,手机的电磁干扰,荧光灯等。
randomSeed(analogRead(5));
// randomize using noise from analog pin 5
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);
}
让我们现在重温我们对一些基本概念的知识,例如位和字节。
位只是一个二进制数字。
二进制系统使用两个数字,0和1。
与十进制数字系统类似,数字的位数不具有相同的值,位的“意义"
取决于其在二进制数中的位置。例如,十进制数666中的数字相同,但具有不同的值。
一个字节由8位组成。
如果一个位是一个数字,逻辑上字节表示数字。
可以对它们执行所有数学运算。
一个字节中的数字也不具有相同的意义。
最左边的位具有被称为最高有效位(MSB)的最大值。
最右边的位具有最小值,因此称为最低有效位(LSB)。
由于可以以256种不同的方式组合一个字节的八个0和1,所以可以由一个字节表示的最大十进制数是255(一个组合表示零)。
脉冲宽度调制或PWM是用于改变脉冲串中的脉冲宽度的常用技术。PWM有许多应用,如控制伺服和速度控制器,限制电机和LED的有效功率。
脉冲宽度调制基本上是一个随时间变化而变化的方波。基本的PWM信号如下图所示。
有很多术语与PWM相关:
On-Time(导通时间)
– 时间信号的持续时间较长。
Off-Time(关断时间)
– 时间信号的持续时间较短。
Period(周期)
– 表示为PWM信号的导通时间和关断时间的总和。
Duty Cycle(占空比)
– 它表示为在PWM信号周期内保持导通的时间信号的百分比。
如图所示,Ton表示导通时间,Toff表示信号的关断时间。周期是导通和关断时间的总和,并按照以下公式计算:
占空比用于计算为一段时间的导通时间。使用上面计算的周期,占空比计算为:
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 Due支持引脚2至13以及引脚DAC0和DAC1上的
analogWrite()。与PWM引脚不同,DAC0和DAC1是数模转换器,用作真正的模拟输出。
在调用
analogWrite()之前,不需要调用pinMode()将引脚设置为输出。
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
}