Wifiduino文档
- WiFi-Duino使用教程(1)环境准备
- WiFi-Duino使用教程(2):用浏览器控制板载LED,Hello WiFi-Duino!
- WiFi-Duino使用教程(3):控制板载LED升级!在世界任何一个有网络的地方控制板载
WiFi-Duino使用教程(1)环境准备
简介
WiFi-Duino是和Arduino系列编程软件兼容的硬件开发板,如果您之前还没接触过Arduino,或者使用的是较老版本的Arduino(Arduino UNO,Arduino Diecimila等),那么请仔细阅读本教程。如果您是Arduino老手,那么请直接阅读接下来的教程,有任何疑问请联系我。
WiFi-Duino采用的是和Arduino Leonardo以及Arduino Yun相同的相同的ATmega32U4主控,与之前较老的Arduino UNO和Arduino Diecimila相比有诸多变化,鉴于大部分国内Arduino爱好者使用的还是Arduino Diecimila及其变种,这里列举一些不同点:
- SRAM从2K增加到2.5K,可以改善运行时内存不足的情况。
- 硬件引脚有一些改变(主要是 SPI 和 TWI),请参见WiFi-Duino官方页面硬件章节。
- 主控运行程序的同时管理和USB的连接。
之前的Arduino大多使用USB转串口芯片完成电脑和主控连接,完成下载程序或者数据交流的功能,ATmega32U4集成了USB接口,硬件上直接和USB相连,不再需要USB转串口芯片。这么做增加了使用的灵活性,例如可以模拟键盘鼠标等USB设备,同时也带来了一些其他使用上的变化,请仔细阅读本教程中的注意事项。
软件安装
Wifi-Duino使用Arduino系列编程软件进行编程,请先前往下载页面下载Arduino编程软件,WiFi-Duino函数库。
WiFi-Duino函数库的安装方法有两种:
-
打开Arduino软件,执行Sketch > Import Library > Add Library…,选择下载的WiFi-Duino函数库压缩包即可。
-
如果您更喜欢手动安装,请将下载得到的WiFi-Duino函数库解压后,将wiFiDuino文件夹复制到libraries目录下,在Windows下libraries文件夹的路径是:
My Documents\Arduino\libraries\
Mac下libraries文件夹的路径是:
Documents/Arduino/libraries/
Linux下libraries文件夹的路径是:
Home/Username/sketchbook/libraries/
安装完毕之后,打开Arduino(如已经打开请重启Arduino),执行File > Examples > wiFiDuino 即可查看官方示范。
驱动安装
- MAC OSX第一次连接WiFi-Duino时,系统可能会出现”键盘设置助理”(中文)或者”keyboard setup assistant”(英文),直接关闭即可。
- Linux大部分Linux发行版无需安装驱动即可正常使用。
- Windows第一次第一次连接WiFi-Duino时,请取消自动安装驱动,然后执行以下步骤(以Win7为例):
- 开始菜单 > 控制面板 > 硬件 > 设备管理器。
- 找到 其他设备 > 未知设备 , 右键打开属性对话框。
- 执行 驱动程序 > 更新驱动程序(P)…。
- 执行 浏览计算机以查找驱动程序软件(P)。
- 在接下来的对话框中,浏览到Arduino的安装目录的drivers子目录下,继续安装即可。
注意事项
- 复位的时候,串口会重新枚举,串口会从硬件管理器中消失再重新出现。Arduino Diecimila在复位时,USB转串口芯片会保持和系统的连接,而在WiFi-Duino中,因为USB连接由ATmega32U4管理,当ATmega32U4复位时,USB连接也会重新建立。
- 当建立串口连接(例如打开串口监视器),WiFi-Duino本身不会复位。Arduino Diecimila在建立串口连接时,电脑会发出复位信号,并使得Arduino中的程序重新运行,而在WiFi-Duino中,这并不会发生。这意味着可能在你打开串口监视器时,看不到在此之前WiFi-Duino发送的数据,为了让程序等待电脑打开串口监视器之后再运行,您可以使用以下代码:
...Serial.begin(9600); // 等待串口打开,否则什么都不做: while (!Serial) ;...
- 增加了模拟USB设备(键盘,鼠标等)的功能。使用新的处理器的一个好处就是,可以使用您的WiFi-Duino模拟键盘,鼠标等USB设备,具体的使用请参考Mouse Keyboard library。需要注意的是在模拟USB设备的时候,WiFi-Duino无法进行程序下载,您需要设置合适的唤醒程序(例如一个按键),停止模拟之后再进行程序下载。
- 板载串口端口的处理和Leonardo和Yun相同, 库函数中的Serial代表的是USB连接模拟的串口端,而不是板上标注TX和RX的串口,如果您想使用该硬件串口,请使用Serial1, 当使用板载WiFi功能时,该串口将被占用,如果需要连接其他串口设备,建议使用SoftwareSerial。
- 数字引脚12的处理当使用板载WiFi功能时,数字引脚12将被占用,请勿使用该端口进行输入或者输出的操作。
当你完成了软件,库函数以及驱动的安装之后,请连接WiFi-Duino,并打开File > examples > wifiDuino > LED_OnBoard,接下来的教程:WiFi-Duino使用教程(2):用浏览器控制板载LED,Hello WiFi-Duino!,会指导您走进物联网开发的第一步。
WiFi-Duino使用教程(2):用浏览器控制板载LED,Hello WiFi-Duino!
简介
这段时间博客的停更,大部分时间在处理WiFi-Duino的配套库函数wifiDuino,现在大部分的API已经确定下来,说好的教程也将陆续发布,这篇教程将会展示:
- 如何使用WiFi-Duino新建一个热点,并在WiFi-Duino上运行一个简单的Http服务器,向浏览器输出消息。
- 如何使用WiFi-Duino连接到周围的热点,并在收到Http请求时,输出在flash中储存的网页,并根据不同的路径响应控制板载LED的亮灭。
Hello World!
下面的程序使用WiFi-Duino新建一个名为WiFi-Duino的热点,并且建立了服务器等待Http请求:
/*
* Hello World!
* "Hello World!" from WiFi-Duino board
* Author: Winterland
* Doc: http://www.winterland.com/wifiduino
*/
#include <wifiDuino.h>
/* 板载LED引脚 */
#define led 13
/* 定义数组储存接收到的Http请求 */
char request[32] = "";
void setup()
{
/* 初始化LED为亮 */
pinMode( led, OUTPUT );
digitalWrite( led, HIGH );
/* 启动WiFi-Duino,如果未启动则需等待30s */
wifiDuino.begin();
/* 设置WiFi-Duino为热点模式 */
wifiDuino.setMode( WIFI_MODE_AP );
/*
* 设置WiFi-Duino的热点参数
* 热点名称:WiFi-Duino 加密方式:自动 热点密码:122334345
*/
wifiDuino.setWiFiConfig( "WiFi-Duino", "auto", "122334345" );
/* 写入网络配置,如果和之前的配置不同则需等待30s */
wifiDuino.writeConfig();
/* 在555端口启动服务器 */
wifiDuino.startServer( "555" );
/* 关闭LED,表示可以访问 */
digitalWrite( led, LOW );
}
void loop()
{
/* 等待Http请求 */
if ( wifiDuino.waitHttpRequest( request, 32, 500 ) )
{
/* 判断请求路径 */
if ( !strcmp( request, "/" ) )
{
/* 路径正确,显示Hello World! */
wifiDuino.sendHttpMessage( "Hello World!" );
}else
/* 路径错误,显示404消息 */
wifiDuino.sendHttpMessage( "404 Not Found!" );
}
}
wiFiDuino的API十分简洁,不过需要注意以下几点:
-
wifiDuino.begin()会判断WiFi-Duino是否已经启动完毕,如果已经启动完毕,则跳过,如果没有,则会等待30s(wifi模块启动)。
-
wifiDuino.writeConfig()会判断要写入的网络配置和当前WiFi-Duino的网络配置是否相同,如果相同,则跳过,如果不同,则会写入配置并等待30s(wifi模块重启)。
-
综上两点,第一次运行程序会等待最长60s的时间,所以在程序中使用板载LED用来显示服务器是否启动,服务器启动之后LED会熄灭,在正常情况下(配置参数已写入),wifi模块启动之后服务器就会立即启动。
-
AP模式下加密方式设置为auto,则会使用wpa2方式加密,请保证设置的密码大于或等于8位0。
-
AP模式下,服务器地址为固定值:192.168.1.254,程序中在555端口启动服务器,因此使用浏览器访问地址为:
http://192.168.1.254:555
浏览器控制板载LED
在上面的例子中,我们使用sendHttpMessage发送Http文本,sendHttpMessage的设计目的是为了发送短消息,函数参数也是储存在内存中的字符数组:
static void wifiDuino.sendHttpMessage(char* p);
如果需要输出网页的话,请使用sendHttpPage函数:
static void sendHttpPage(PGM_P webpage);
函数接受一个PROGMEM指针,也就是储存在atmega32u4芯片的flash区的指针,一般单片机的flash容量远远大于ram,所以可以用来储存一些复杂的网页。程序代码如下:
/*
* LED_OnBoard Control the LED on WiFi-Duino board
* Author: Winterland
* Doc: http://www.winterland.com/wifiduino
*/
#include <wifiDuino.h>
/* 板载LED */
#define led 13
/* 定义数组储存接收到的Http请求 */
char request[32] = "";
/* 在flash空间中储存网页 */
char webPage[] PROGMEM = "<html>" "<head><title>" "multipackets Test" "</title></head>" "<body>" "<a href='/ledon'>LED ON</a><br>" "<a href='/ledoff'>LED OFF</a><br>" "</body>" "</html>";
void setup()
{
/* 初始化LED */
pinMode( led, OUTPUT );
Serial.begin( 9600 );
wifiDuino.begin();
/* 设置WiFi-Duino为网卡模式 */
wifiDuino.setMode( WIFI_MODE_ADAPTER );
/* 设置您的WiFi环境配置 */
wifiDuino.setWiFiConfig( "您所在的WiFi名称", "auto", "您所在的WiFi密码" );
/* 关闭DHCP,以免找不到服务器地址 */
wifiDuino.setDHCP( DHCP_DISABLE );
/* 手动设置ip配置 */
wifiDuino.setIpConfig( "192.168.1.254", "255.255.255.0", "192.168.1.1" ); wifiDuino.setDnsConfig( "192.168.1.254", "8.8.8.8" );
wifiDuino.writeConfig();
/* 在555端口启动服务器 */
wifiDuino.startServer( "555" );
/* 在接收到Http请求之前闪烁LED */
while ( true )
{
digitalWrite( led, HIGH );
delay( 500 );
digitalWrite( led, LOW );
if ( wifiDuino.waitHttpRequest( request, 32, 500 ) )
{
wifiDuino.sendHttpPage( webPage );
break;
}
}
}
void loop()
{
if ( wifiDuino.waitHttpRequest( request, 32, 500 ) )
{
if ( !strcmp( request, "/ledon" ) )
{
/* 访问路径为"/ledon",打开LED */
digitalWrite( led, HIGH );
}
/* 访问路径为"/ledoff",关闭LED */
if ( !strcmp( request, "/ledoff" ) )
{
digitalWrite( led, LOW );
}
/* 输出网页 */
wifiDuino.sendHttpPage( webPage );
}
}
这个例子使用到了WiFi-Duino的网卡模式,WiFi-Duino在接受了环境WiFi配置之后会连接到路由器上,连接到相同路由器的用户都可以访问到WiFi-Duino上的服务器。用浏览器打开:
http://192.168.1.254:555
会显示一个含有两个链接的网页,用鼠标点击试试吧,在网卡模式下需要注意以下几点:
- WiFi-Duino处于网卡模式时,ip可以设置为自动或者手动分配(setDHCP),如果您希望在WiFi-Duino上建立服务器接收请求的话,建议手动分配一个固定ip,因为此时服务器地址就是网卡所在ip地址,如果设置为自动分配,则无法确定用户访问地址(如果有路由器管理权限的话可以登录路由器后台查看当前ip分配情况,但也很麻烦)。
- 如果无法访问,请检查路由器是否开启AP隔离,AP隔离时局域网内无法互相访问。
下一篇教程WiFi-Duino使用教程(3):控制板载LED升级!在世界任何一个有网络的地方控制板载LED,将会讲述如何使用WiFi-Duino连接到物联网平台Yeelink,实现互联网远程遥控。
WiFi-Duino使用教程(3):控制板载LED升级!在世界任何一个有网络的地方控制板载
上一篇教程WiFi-Duino使用教程(2):用浏览器控制板载LED,Hello WiFi-Duino!展示了如何使用WiFi-Duino新建一个热点,或者连接到周围的路由器上,并新建一个server来响应http请求,这篇教程将会展示:
- 如何使用yeelink新建一个数据节点,并获得数据节点的访问地址。
- 如何使用WiFi-Duino连接到周围的热点,并通过网络查询储存在yeelink上的数据节点。
Yeelink是一个面向硬件的云数据平台,用户可以在联网的环境下上传和下载数据,例如开关控制信号,传感器数值等,这里我们仍然使用板载LED为例子,不同的时由于使用了云服务,在任何联网的地方都可以实现控制。
首先去Yeelink的网站申请一个帐号,然后再用户中心里可以看到Yeelink的后台管理页面,添加一个新设备,并在管理设备页面中添加一个传感器,由于是控制LED,类型选择开关,添加成功后你将获得如下的状态URL:
打开这个URL,你会得到如下的JSON格式字符串:
{"timestamp":"1970-01-01T07:00:00","value":0}
其中value就对应着云端服务器中改传感器节点的值,改变这个值的方法有很多,你可以直接在设备管理页面上点击那个开关按钮,或者下载Yeelink的手机APP,登录之后同样可以管理设备,访问这个URL就会返回传感器节点的值。
所以接下来我们在WiFi-Duino中的程序中,简单的polling一下这个URL返回的字符串,然后截取相应的0或者1即可控制LED开关。不过在Yeelink的官方文档中,推荐在发送的HTTP请求中,附上ApiKey等Header域,我们也遵守这个原则,ApiKey可以在用户中心的账户设置页面中找到。
下面是WiFi-Duino的代码,请确保WiFi-Duino工作在适配器模式并且连接上因特网:
#include <wifiDuino.h>
#define LED 13
/* 你的传感器节点的地址 */
#define URL "/v1.0/device/4283/sensor/10701/datapoints"
void setup()
{
pinMode( LED, OUTPUT );
Serial.begin( 9600 );
wifiDuino.begin();
wifiDuino.setMode( WIFI_MODE_ADAPTER );
wifiDuino.setWiFiConfig( "你的wifi名称", "auto", "你的wifi密码" );
wifiDuino.setDHCP( DHCP_ENABLE );
wifiDuino.writeConfig();
wifiDuino.startClient( "api.yeelink.net", "80" );
}
void loop()
{
char respond[256] = "";
wifiDuino.sendHttpRequest( URL, "api.yeelink.net", HTTP_GET, false );
/* 每2秒钟查询一次传感器状态 */
if ( wifiDuino.waitRawData( respond, 256, 2000 ) )
{
Serial.println( respond );
char* state;
if ( state = strstr( respond, "value" ) )
{
state += 7;
if ( *state == '0' )
{
digitalWrite( LED, LOW );
}else
digitalWrite( LED, HIGH );
}
}
}
OK,是不是很简单,打开Yeelink的APP试试看吧。
wifiDuino函数库手册(一):WiFi模块设置手册 | Winter's Land
这篇文章中将详细解释wifiDuino中和硬件交互的函数接口,包括切换热点/网卡模式,更改WiFi配置等:
//wait for WiFi-Duino started and enter AT command mode.
基本操作
wifiDuino.waitHttpRequest
static void begin();
检查WiFi-Duino是否启动,如果已经启动则设置WiFi-Duino进入配置模式并立即返回,如果还在启动中则等待30s再检查。
/*Set working mode, available options are:
WIFI_MODE_AP: Create a WiFi access point with WiFi configurations.
WIFI_MODE_ADAPTER: Connect to an environment WiFi access point with WiFi configurations.
*/
wifiDuino.setMode
static void setMode(char mode);
//mode 工作模式
//选项:WIFI_MODE_AP 热点模式,WIFI_MODE_ADAPTER,适配器模式
设置WiFi-Duino工作模式。热点模式下WiFi-Duino会新建热点供其他设备连接,适合无路由器时的遥控设备,适配器模式下WiFi-Duino会连接周围的路由器,适合局域网控制或者连接远程云服务。
wifiDuino.setWiFiConfig
static void setWiFiConfig(char* SSID, char* encrypt, char* password);
//SSID WiFI名称,encrypt WiFI 加密方式,password WiFi密码
//encrypt选项:
//none: 无密码
//wep_open: wep加密,开放认证
//wep: wep加密,加密认证
//wpa_tkip: wpa tkip 加密
//wpa_aes: wpa aes 加密
//wpa2_tkip: wpa2 tkip 加密
//wpa2_aes: wpa2 aes 加密
//wpawpa2_tkip: wpa/wpa2 tkip 加密
//wpawpa2_aes: wpa/wpa2 aes 加密
//auto: 自动选择,默认。
设置WiFi-Duino的WiFi参数,当处于热点模式时,该参数为WiFi-Duino建立热点的参数,当处于适配器模式时,该参数为WiFi-Duino连接的路由器WiFi参数,对于encrypt选项建议选择auto。
wifiDuino.writeConfig
static void writeConfig();
写入网络配置参数,如果发现设置参数需要重启,则自动重启WiFi模块(等待30s)。
适配器模式操作
wifiDuino.setDHCP
static void setDHCP(char dhcp);
//dhcp DHCP选项:DHCP_ENABLE DHCP开启,DHCP_DISABLE DHCP关闭
设置IP地址分配方式,对此不了解的同学请参考动态主机设置协议。如果关闭了DHCP设置,请使用下面的函数手动配置IP等参数。
wifiDuino.setIpConfig wifiDuino.setDnsConfig
static void setIpConfig(char* ip, char* mask, char* gateway);
//ip IP地址,mask 子网掩码,gateway 网关。
static void setDnsConfig(char* dns1, char* dns2);
//dns1 DNS地址1,dns2 DNS地址2
在DHCP关闭时手动设置网络参数。请参考您的路由器设置进行配置。
当处于热点模式时,WiFi-Duino和路由器一样有自己的网络参数:
网关:192.168.1.1
IP地址:192.168.1.254
子网掩码:255.255.255.0
支持DNS分配客户端IP地址。
wifiDuino函数库手册(二):处理HTTP请求和应答 | Winter's Land
阅读这篇文章需要对HTTP协议有基本的了解,不了解的同学可以查看之前写的一篇文章:HTTP协议简介,这篇文章中将详细解释wifiDuino为方便物联网开发设计的函数及其使用:
服务器模式相关函数:
wifiDuino.startServer
static void startServer(char *port);
//port 服务器监听端口号
在指定端口启动服务器。
wifiDuino.waitHttpRequest
static bool waitHttpRequest(char* url, uint8_t url_len, uint16_t timeout);
//url 保存请求路径的指针,url_len 允许的请求路径长度,timeout 等待时间(ms)
等待HTTP GET请求,函数接到请求之后会将请求的路径写入url对应内存区域,并会立即返回ture,超过timeout时间仍未收到请求则返回false,注意:请求超过了定义的url_len,仍会返回true。剩余部分将从串口缓存中清除。举例:
...
char urlBuffer[128] = "";
while( wifiDuino.waitHttpRequest( urlBuffer, 128, 1000 ) ){
//处理请求
}
...
wifiDuino.sendHttpPage
static void sendHttpPage(PGM_P webpage);
//webpage flash区域指针
发送保存在flash区域的字符串内容(网页),并添加适当的header(Content-Type: text/html),函数使用循环输出保存在flash区域的字符串,由于避免了使用内存。因此适合发送一些较大的网页(内嵌javascript脚本,css等)举例:
...
char webPage[] PROGMEM =
"<html>"
//网页内容
"</html>";
...
wifiDuino.sendHttpPage(webPage);
...
wifiDuino.sendHttpMessage
static void sendHttpMessage(char *message);
//message 发送的消息
发送一个字符串(在内存中的),并添加适当的header(Content-Type: text/plain),由于字符串是储存在内存中,适合发送短消息,例如配合网页中的javascript实现ajax,举例:
...
char msg[] = "Hello WiFi-Duino!"
wifiDuino.sendHttpMessage(nsg);
...
客户端相关函数
wifiDuino.startClient
static void startClient(char *remoteDomain, char *remotePort);
//remoteDomain 目标服务器域名,port 目标服务器端口号
建立与目标服务器指定端口的TCP连接。
wifiDuino.sendHttpRequest
static void sendHttpRequest(char *url, char* host, char* method ="GET", char* customFields = NULL, char* body = NULL);
//url 保存请求的指针,host 请求目标域名,method 请求方法(默认为GET)
//customFields 请求header中的自定义项目(默认为空),body 请求的消息体(默认为空)
发送HTTP请求,这个函数在wifiDuino中被特别设计成一个较为通用的接口,可以发送不同类型的HTTP请求以满足不同的服务器的需求,同时省去字符串拼接的麻烦。举例:
...
wifiDuino.sendHttpRequest("/", "www.baidu.com");
//向www.baidu.com发出GET请求。
...
...
char host[] = "api.yeelink.net";
char apiKey[] = "U-ApiKey:af3c800cb5e89af8ec88f8f4e828f0f3";
wifiDuino.sendHttpRequest("/v1.0/device/4283/sensor/7758/datapoints", host, apiKey);
//向api.yeelink.net/v1.0/device/4283/sensor/7758/datapoints 发出GET请求,并在header中附加apiKey认证信息。
...
wifiDuino.waitHttpRespond
static bool waitHttpRespond(char* respond, uint16_t len, uint16_t timeout);
//respond 保存响应的指针,len 允许的响应路径长度,timeout 等待时间(ms)
等待HTTP响应,函数接到响应之后会自动识别内容的header,将内容body的写入respond对应的内存区域,并会立即返回ture,超过timeout时间仍未收到请求则返回false,注意:响应超过了定义的len,仍会返回true,此时respond中只保存了响应的一部分,剩余部分将从串口缓存中清除。举例:
...
char contentBuffer[512] = "";
if( wifiDuino.waitHttpRespond( contentBuffer, 512, 5000 ) ){
//处理响应内容
}
...
TCP操作相关函数
wifiDuino.sendRawData
static void sendRawData(char *data);
//data 发送的数据(内存中)
向底层TCP连接直接发送内存中的字符串数据,类似Arduino中的print。
wifiDuino.sendRawDataPGM
static void sendRawDataPGM(PGM_P data);
//data 发送的数据(flash中)
向底层TCP连接直接发送flash中的字符串数据。
wifiDuino.waitRawData
static void waitRawData(char* data, uint16_t len, uint16_t timeout);
//respond 保存数据的指针,len 允许的响应路径长度,timeout 等待时间(ms)
等待TCP连接接收数据并存入内存,并会立即返回ture,超过timeout时间仍未收到请求则返回false,注意:数据超过了定义的len,仍会返回true,并且剩余部分将保留在串口缓存中。举例:
...
char contentBuffer[512] = "";
while( wifiDuino.waitRawData( contentBuffer, 512, 5000 ) ){
//处理响应内容
...
//所有消息接收完毕循环终止
}
...
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。