Arduino中国 | Flamingo EDA

RS232串口是我们非常熟悉的一种Arduino与计算机之间进行数据交换的手段,虽然最新的Arduino在设计时都采用了USB转串口的方式,但最初一版的Arduino的确是基于RS232串口的。直到现在,RS232仍然在实际的工程项目中大量用到,不过这种方式有两个致命的弱点:一是传输距离不能太长,二是只能实现两个设备之间的点对点通信。我们这里要介绍的RS485模块正好解决了这两个问题:

RS485串行总线接口标准以差分平衡方式传输信号,具有很强的抗共模干扰的能力,允许一对双绞线上一个发送器驱动多个 负载设备,其理论的通讯距离是1200米,速率高达20Mbps,并可以用在强噪声的环境中正常工作,因此在工业通讯领域中被广泛应用。 当我们在Arduino上使用RS485时,更多的可能是借助其互连功能,将多个Arduino连接成一个RS485网络,来实现各个Arduino之间的通信。

在由RS485构成的多机串行通信系统中,一般采用的都是主从式结构:也就是说主机负责所有的通信协调过程,从机一般被动地接收主机发送过来的数据,或者根据主机的命令向主机反馈相应的数据,各个从机之间一般不进行数据交换,而是通过主机进行中转。之所以采用这种方式是因为于RS485是一种半双工通讯,发送和接收共用同一物理信道,在任一时刻都只允许一台设备处于发送状态。如果在时序上配合不好,就会发生总线冲突,使整个系统的通讯瘫痪,从而无法正常工作。

我们以一个三个结点的网络为例,介绍如何利用RS485串口模块来构建一个RS485网络,该网络中包括一台作为主机使用的Arduino(S)和两台作为从机使用的Arduino(CA, CB)。对于网络中的每一台Arduino来讲,硬件连接上我们都需要一块Arduino专用传感器扩展板、一条COM连接线和一条通用传感器连接线,其中COM连接线用来将RS485串口模块与传感器扩展板上的COM口连接起来,而通用传感器连接线则用来将RS485串口模块上的RE/DE引脚和标号为2的数字I/O口连接起来:

我们之前已经介绍过,RS485网络上的任何时候都只有一台设备处于发送状态,而其它设备则应该全部都处于接收状态。Arduino正是通过对RE/DE引脚的控制,来指定该设备是向RS485网络中发送数据,还是从RS485网络中接收数据。为了说明上的方便,在我们的例子中主设备S一直都处于发送状态,相应的RE/DE引脚一直处于高电平状态;两台从设备CA和CB一直处于接收状态,相应的RE/DE引脚则一直处于低电平状态。

在RS485串口模块上另一个需要引起我们注意的就是标记为“TERM?”的开关,它是用来控制终端电阻的,目的是为了吸收RS485网络中的反射信号,以保证正常传输的信号不受到干扰。不过该电阻只能在RS485总线上的最后一台设备上出现,这也是为什么叫做终端电阻的原因。在我们上面给出的网络拓朴图中不难看出,从机CB是总线上的最后一台设置,因此我们需要在该设备所对应的RS485串口模块上将“TERM?”开关拨到“Y”的位置:

而在主机S和从机CA上该开关都需要设置到与之相反的位置上:

由于是要将三个Arduino连接成一个RS485网络,因此我们还需要将RS485 串口模块两两连接起来,这是通过RS485串口模块上的“485 IN”和“485 THU”两个插座来实现的。具体说来,就是我们需要将前一个RS485串口模块的“485 THU”接口,与下一个RS485串口模块的“485 IN”接口连接起来,连接的时候我们可以使用模拟传感器连接线,或者是普通的杜邦线。对于我们正在构建的三个结点的RS485网络来讲,则是要求主机S的“485 THU”与从机CA的“485 IN”连接起来,然后再将从机CA的“485 THU”与从机CB的“485 IN”连接起来,实验中我们使用的是长度为2米的模拟传感器连接线。下图中从左至右依次为主机S,从机CA和从机CB:

硬件都连接好之后,下面我们就可以为各个Arduino来编写相应的程序了。下面是主机S的代码:

int EN = 2;

void setup()
{
  pinMode(EN, OUTPUT);
  Serial.begin(19200);
}

void loop()
{
// send data 
  digitalWrite(EN, HIGH);//使能发送
  Serial.print('A');
  Serial.print('B');
  delay(1000);
}

从主机S的代码不难看出,虽然采用的是RS485串口协议,但编程时使用的还是普通的串口操作语句。

下面是从机CA所使用的代码:

int ledPin = 13;
int EN = 2;
int val;

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(EN, OUTPUT);
  Serial.begin(19200);
}

void loop()
{
  // receive data
 digitalWrite(EN, LOW);//使能接收
 val = Serial.read();
  if (-1 != val) {
    if ('A' == val) {
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
    }
 }
}

下面是从机CB所使用的代码:

int ledPin = 13;
int EN = 2;
int val;

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(EN, OUTPUT);
  Serial.begin(19200);
}

void loop()
{
  // receive data
 digitalWrite(EN, LOW);//使能接收
 val = Serial.read();
  if (-1 != val) {
    if ('B' == val) {
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
    }
 }
}

从代码中不难看出,CA和CB分别响应主机S发送过来的字母A或者B,然后做相应的反应:点亮一个LED灯。在将三台Arduino都分别通电之后,你就可以看到作为主机的CA和CB在接到主机S发过来的命令之后,分别做相应的点灯动作。

最后需要说明的一点是,虽然在我们的例子中演示的是主机S不断向从机CA和CB发送数据的单向通信过程,但其实在RS485网络中也是可以实现双向通信的,只但需要在代码上做更多的工作,并且需要在主机和从面之间根据应用的需要定义一个相应的数据通信协议。

· ·

Nov/10

28

Arduino MEGA 2560 样板调试

有了之前调试Arduino UNO的经验之后,今天拿到Arduino MEGA 2560样板并完成功能调试就轻松了不少。同Arduino UNO一样,Arduino MEGA 2560一个比较重要的改动就是将串口USB部分换成用ATMEGA8U2单片机来实现,此外采用了ATMega2560芯片,存储容量为256K(对大多数Arduino项目来讲是比较奢侈了的):

由于USB转串口的功能是由ATMEGA8U2虚拟完成的,所以我们也需要先向其中写入相应的USB固件,这一步骤是借助USBTinyISP完成的,写入时使用的命令为:

avrdude -p at90usb82 -F -P usb -c usbtiny -U flash:w:MEGA-dfu_and_usbserial_combined.hex
-U lfuse:w:0xFF:m -U hfuse:w:0xD9:m -U efuse:w:0xF4:m -U lock:w:0x0F:m

在下载好USBl固件之后我们就可以用USB线将Arduino连接到电脑了,在Windows下此时会提示发现一个名为“Arduino MEGA 2560”的USB设备:

随后Windows会打开“找到新的硬件向导”对话框,选择其中的“否,暂时不”后单击“下一步”按钮:

在接下来出现的对话框中选择“从列表或指定位置安装(高级)”项后单击“下一步”按钮:

随后我们需要指定Arduino 0021安装目录下的drivers目录来进行驱动程序的安装:

如果一切正常,Windows会开始为Arduino MEGA 2560安装相应的驱动程序:

正功安装后的提示界面:

此时我们就可以在Windows的设备管理器中找到相应的Arduino MEGA 2560设备了:

接下来就可以向ATMega2560芯片中烧入Arduino的Bootloader了,这一过程同样可以借助USBTinyISP来完成。在将USBTinyISP连接好Arduion MEGA 2560之后运行Arduino 0021,然后从“Tools”下的“Board”菜单中选择“Arduino Mega 2560”:

之后再从“Tools”下的“Burn Bootloader”菜单中选择“w/ USBtinyISP”开始向ATMega2560中写入bootoloader,这个过程历时会比较长:

在烧写Bootloader的整个过程中,对烧入的内容进行验证是该过程的最后一步,此时虽然在Arduino IDE中会出现一个验证错误,但其实并没有出错,我们可以忽略这个错误:

其余的步骤就跟使用其它类型的Arduino没有区别了,具体步骤可以参考相应的使用手册。

在Arduino上进行声音的播放可以有几种方案,一种是利用语音芯片对事先存储好的声音数据进行播放,这种方案一般只能进行语音数据的播放,音质比较差,面且播放的时长比较受限;第二种办法是播放MP3文件,但这种方式需要专门的MP3解压芯片;第三种可以借助的办法就是下面要介绍的WAV声音播放模块 ,其做法是将事先录制好的WAV文件存储到SD卡中,Arduino负责从SD卡中读出未经压缩的声音文件,再送到WAV模块中进行播放:

目前这一方案受限于所采用的DAC芯片精度的影响,最高只能做到16bit,22KHz,Mono格式的WAV文件,不过这对于大部分应用场合来讲已经足够了。

使用该模块时需要事先准备好符合我们要求WAV文件,有不少音频转换软件可以完成该任务。下面我们以Audacity(http://audacity.sourceforge.net/)为例,讲述如何讲MP3文件转换成我们所需要的格式。

运行Audacity之后,选择“File”菜单下的“Open”命令,打开需要进行转换的MP3文件:

通常MP3文件都是立体声(Stereo)格式的,我们需要将其分离成两个单独的音轨,这可以通过选择左侧声音文件标题下拉框中的“Split Stereo Track”命令来完成:

为了避免这两个音轨在混音之后音量过大,我们可以分在每个音轨上将增益(Gain)设置成-6dB,修改的方法是拖动相应音轨左侧标有正负号的滑动条:

将下来我们需要从每条音频的标题下拉菜单下选择“Mono”命令,将其转换成单声道格式,注意每一路都需要做这个转换:

现在我们可以选择“Project”菜单下的“Quick Mix”命令来完成单声道文件的混音:

通过上述的步骤,我们已经将立体声(Stereo)格式的声音数据转化成单声道(Mono)格式的声音数据,此外我们还需要设置相应的采样位数和采样频率。对于采样位数的设置,我们可以从每条音频的标题下拉菜单中选择“Set Sample Format”下的“16-bit”命令,将采样位数设置为16位:

而采样频率的设置则可以通过Auda对话框底部的“Project rate”进行设置,我们的WAV播放模块最高只支持22Khz:

所有参数都设置好之后,我们就可以导出所需要的声音文件了。选择“Edit”菜单下的“Preferences…”命令,在打开的对话框中从“Uncompressed Export”下拉框中选择“WAV (Microsoft 16 bit PCM)”后单击“Ok”按钮:

最后选择“File”菜单下的“Export As WAV…”命令,导出我们所需要的WAV文件就可以了,为了确保之后Arduino能够正常处理,该WAV文件需要用字母命名,并且文件名称不能超过8个字节。为了确保产生的文件是正确的,我们还可以在Windows中右键单击该文件后,从弹出的菜单中选择“属性”命令打开属性对话框,然后从“摘要”中检查生产的文件是否符合我们的要求:

生成的文件我们可以通过读卡器将其复制到SD卡中,为了保证读取的正确性,可以考虑先格式化后再将WAV文件复制到SD卡中。注意SD卡应该格式化成FAT格式的,而不要格式化成FAT32格式的。

带有WAV文件的SD卡准备好之后,我们可以用Arduino IDC扩展板将SD卡模块和WAV声音播放模块都连接到Arduino上:

通过Arduino皤放SD卡中存储的WAV文件我们需要用到wavehc库(http://code.google.com/p/wavehc/)。我们测试时使用的是wavehc20101009.zip这个文件,你可以通过wavehc的官方网站下载该文件,也可以通过这个地址直接下载我们在测试时使用的库文件包。

在将下载后的wavhc库解压缩之后,将压缩包中的WaveHC上当复制到Arduino安装目录中的libraries目录下。wavhc库默认使用了Arduino上的2、3、4、5这4个引脚,但 我们的Arduino IDC扩展板上的IDC-6座则是与Arduino的6、7、8、9这4个引脚相连接的,因此我们需要对WaveHC目录下的WavePinDefs.h这个文件进行修改, 相应的对应关系为2->9、3->7、4->6、5->8。你可以手工修改这个文件中以MCP_DAC_开头的那些宏定义,也可以直接下载我们已经修改好的WavePinDefs.h文件

测试时我们使用的是wavhc库压缩包examples目录下的daphc,其实现的功能是不断从SD卡中查找以.WAV为扩展名的WAV文件进行播放,相应的代码为:

/*
 * This example plays every .WAV file it finds on the SD card in a loop
 */
#include "WaveHC.h"
#include "WaveUtil.h"

SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the volumes root directory
WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

uint8_t dirLevel; // indent level for file/dir names    (for prettyprinting)
dir_t dirBuf;     // buffer for directory reads

/*
 * Define macro to put error messages in flash memory
 */
#define error(msg) error_P(PSTR(msg))

// Function definitions (we define them here, but the code is below)
void play(FatReader &dir);

//////////////////////////////////// SETUP
void setup()
{
  Serial.begin(9600);           // set up Serial library at 9600 bps for debugging

  putstring_nl("\nWave test!");  // say we woke up!

  putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
  Serial.println(FreeRam());

  //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
  if (!card.init()) {         //play with 8 MHz spi (default faster!)  
    error("Card init. failed!");  // Something went wrong, lets print out why
  }

  // enable optimize read - some cards may timeout. Disable if you're having problems
  card.partialBlockRead(true);

  // Now we will look for a FAT partition!
  uint8_t part;
  for (part = 0; part < 5; part++) {   // we have up to 5 slots to look in
    if (vol.init(card, part))
      break;                           // we found one, lets bail
  }
  if (part == 5) {                     // if we ended up not finding one  :( 
    error("No valid FAT partition!");  // Something went wrong, lets print out why
  }

  // Lets tell the user about what we found
  putstring("Using partition ");
  Serial.print(part, DEC);
  putstring(", type is FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?

  // Try to open the root directory
  if (!root.openRoot(vol)) {
    error("Can't open root dir!");      // Something went wrong,
  }

  // Whew! We got past the tough parts.
  putstring_nl("Files found (* = fragmented):");

  // Print out all of the files in all the directories.
  root.ls(LS_R | LS_FLAG_FRAGMENTED);
}

//////////////////////////////////// LOOP
void loop()
{
  root.rewind();
  play(root);
}

/////////////////////////////////// HELPERS
/*
 * print error message and halt
 */
void error_P(const char *str)
{
  PgmPrint("Error: ");
  SerialPrint_P(str);
  sdErrorCheck();
  while(1);
}
/*
 * print error message and halt if SD I/O error, great for debugging!
 */
void sdErrorCheck(void)
{
  if (!card.errorCode()) return;
  PgmPrint("\r\nSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  PgmPrint(", ");
  Serial.println(card.errorData(), HEX);
  while(1);
}
/*
 * play recursively - possible stack overflow if subdirectories too nested
 */
void play(FatReader &dir)
{
  FatReader file;
  while (dir.readDir(dirBuf) > 0) {    // Read every file in the directory one at a time

    // Skip it if not a subdirectory and not a .WAV file
    if (!DIR_IS_SUBDIR(dirBuf)
         && strncmp_P((char *)&dirBuf.name[8], PSTR("WAV"), 3)) {
      continue;
    }

    Serial.println();            // clear out a new line

    for (uint8_t i = 0; i < dirLevel; i++) {
       Serial.print(' ');       // this is for prettyprinting, put spaces in front
    }
    if (!file.open(vol, dirBuf)) {        // open the file in the directory
      error("file.open failed");          // something went wrong
    }

    if (file.isDir()) {                   // check if we opened a new directory
      putstring("Subdir: ");
      printEntryName(dirBuf);
      dirLevel += 2;                      // add more spaces
      // play files in subdirectory
      play(file);                         // recursive!
      dirLevel -= 2;
    }
    else {
      // Aha! we found a file that isnt a directory
      putstring("Playing ");
      printEntryName(dirBuf);              // print it out
      if (!wave.create(file)) {            // Figure out, is it a WAV proper?
        putstring(" Not a valid WAV");     // ok skip it
      } else {
        Serial.println();                  // Hooray it IS a WAV proper!
        wave.play();                       // make some noise!

        uint8_t n = 0;
        while (wave.isplaying) {// playing occurs in interrupts, so we print dots in realtime
          putstring(".");
          if (!(++n % 32))Serial.println();
          delay(100);
        }
        sdErrorCheck();                    // everything OK?
        // if (wave.errors)Serial.println(wave.errors);     // wave decoding errors
      }
    }
  }
}

如果一切正常,此时你应该就能够在WAV声音播放模块上接的耳机或者音箱中听到你存储在SD卡中的WAV文件在播放时的效果了。上述Arduino代码在运行的时候会试图通过串口传输一些调试信息,必要的时候可以打开Arduino的串口来查看相应的原因(比如SD卡中没有正常找到)。

· · ·

Nov/10

20

Arduino UNO 样板调试

Arduino UNO已经推出一段时间了,虽然我们很早就基于官网公布的参考实现把电路板做出来了,但一直基于苦于相应的芯片非常难订购到,所以直到前两天才装好第一块样板,先上个成品图(注意,没有Arduino的商标以及MADE IN CHINA):

从硬件上看,Arduino UNO与之前Arduino 2009版本的最大不同在于USB转串口部分,Arduino 2009采用的是FTDI专用芯片FT232RL,而Arduino UNO采用的是用一块ATmega8模拟出串口的做法。这一改动着实给我们带来了不小的麻烦,第一是该方案所采用的ATmega8U2芯片基本上在市场上很难找到,另外一点就是该芯片的封装加大了焊接的难度的成本。在研究原理图的过程中,发现其在USB引脚上加入了防止静电的元件,感觉应该会更加稳定。

拿到焊好的样板之后,首先要向ATMega8U2内写入相应的USB固件(firmware)。在最新版本的Arduino-0021安装目录下的hardware\arduino\firmwares目录下,我们可以找到为Arduino UNO 编译好的USB固件文件UNO-dfu_and_usbserial_combined.hex。Arduino UNO上为ATMega8U2单片机也留出了ICSP接口,我们可以借助它来下载相应的USB固件,使用的工具仍然是USBTinyISP,其右上角为ICSP的1脚:

下载时使用的命令为:

avrdude -p at90usb82 -F -P usb -c usbtiny -U flash:w:UNO-dfu_and_usbserial_combined.hex
-U lfuse:w:0xFF:m -U hfuse:w:0xD9:m -U efuse:w:0xF4:m -U lock:w:0x0F:m

有意思的是写入USB固件时标明的芯片类型为AT90USB82,这显然与板子上使用的ATMega8U2不同,下载过程中avrdude也提示了这一点,估计两者的功能是比较类似的,或者就是同一芯片的不同版本罢了。

下载好USB固件之后,此时将Arduino UNO通过USB线连接到Windows时,就会提示有名为“Arduino UNO“的新USB设备找到,估计这也是官方要采用这一方案的原因,因为之前的版本弹出的是一个FTDI的USB设备的提示,不如现在直接找到Arduino这一USB设备酷吧;-)

接着Windows会引导我们进入“找到新的硬件向导”窗口,选取其中的“否,暂时不”选项后单击“下一步”按钮:

接下来的步骤需要安装Arduino UNO所需的驱动,选取其中的“从列表或指定位置安装(高级)”选项后单击“下一步”按钮:

Arduino UNO的USB驱动放在Arduino 0021安装目录下的drivers目录中,我们需要为Windows指明该目录为安装驱动时搜索的目录:

单击“下一步”按钮后,Windows就开始查找并安装Arduino UNO的USB驱动程序:

如果一切正常的话,我们将看到如下的成功界面:

Arduino UNO的USB驱动安装成功之后,我们可以在Windows设备管理器中找到相应的Arduino UNO串口:

USB部分搞定之后,剩余的单片机部分应该算是比较有把握的,这部分与Arduino 2009基本没有变化。首先从Arduino IDE的“Tools”菜单下选择“Board”中的“Arduino UNO”:

然后将USBTinyISP连接到Arduino UNO上的ICSP座上:

再从Arduino IDE的“Tools”菜单下选择“Burn Bootloader”中“w/ USBTinyISP”:

剩下的步骤就跟之前版本的Arduino是完全一样的了。经过测试,我们第一块Arduino UNO样板工作基本正常,目前唯一的问题是下载程序的时候TX/RX两个灯不亮,仔细检查电路后发现应该是这两个灯焊反了,明天修改一下;-)

Arduino UNO统一采用ATMega328P芯片,可问题是目前这一芯片在市场上很难找到,我们订的货也一拖再拖,什么时候能够正常供货目前还比较难确定,主要看芯片的到货情况。

· ·

通过WiFi接入局域网已经是一种越来越常见的方式了,之前我们已经介绍过如何通过有线的方式接入局域,那Arduino是不是也可能通过WiFi以无线的方式接入局域网呢?答案当然是肯定的,就是利用我们这里要介绍的基于SPI接口的WiFi无线通信模块。

要在Arduino中使用该模块,首先我们需要先从https://github.com/asynclabs/WiShield下载相应的库,或者可以直接从这里下载我们测试时所使用的版本。将下载后的库文件解压缩到Arduino(我们测试时使用的是Arduino-0021)安装目录的libraries目录下,然后重命名为WiFi并重新启动Arduino IDE。

为了实现同无线接入点(AP)或者无线路由器(Router)的通信,WiFi模块需要进行相应的配置,包括无线网络ID(SSID)和加密方式等。目前该WiFi模块能够支持WEP、WPA/TKIP-PSK和WPA2/AES-PSK三种常用的加密方式。在开始实验该WiFi模块之前,你需要先了解清楚自己的无线接入点或者无线路由器的配置,我们使用的是一款NETGEAR的无线路由器,采用WPA加密方式,其相应的配置如下图所示:

在下载的WiFi软件包中的examples目录下有一些已经写好的例子,这里我们使用的是WebServer这个程序。WebServer这个例子由两部分组成:webserver.c和WebServer.pde,其中WebServer.pde是我们需要修改的文件,主要是根据无线路由器的设置进行相应的参数调整。实验中我们修改后的代码如下所示:

#include <WiShield.h> 

#define WIRELESS_MODE_INFRA	1
#define WIRELESS_MODE_ADHOC	2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,0,14};	// IP地址
unsigned char gateway_ip[] = {192,168,0,1};	// 网关地址
unsigned char subnet_mask[] = {255,255,255,0};	// 子网掩码
const prog_char ssid[] PROGMEM = {"LOTUS"};	// SSID

unsigned char security_type = 2;	// 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"12345678"};	// max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = {	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,	// Key 0
					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Key 1
					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Key 2
					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Key 3
				};

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
//---------------------------------------------------------------------------

void setup()
{
	WiFi.init();
}

// This is the webpage that is served up by the webserver
const prog_char webpage[] PROGMEM = {"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<center><h1>Hello World!! WiFi</h1></center>"};

void loop()
{
	WiFi.run();
}

对代码的修改主要集在中如下几个部分:

  • 相关地址和ID,包括IP地址、网关地址、子网掩码和无线网络ID(SSID)
unsigned char local_ip[] = {192,168,0,14};	// IP地址
unsigned char gateway_ip[] = {192,168,0,1};	// 网关地址
unsigned char subnet_mask[] = {255,255,255,0};	// 子网掩码
const prog_char ssid[] PROGMEM = {"LOTUS"};	// SSID
  • 无线网络加密类型
unsigned char security_type = 2;

该参数取值为0时表示不加密,取值为1时表示采用WEP加密方式,取值为2时表示采用WPA/TKIP-PSK加密方式,取值为3时表示采用WPA2/AES-PSK加密方式。

  • 无线网络密码
// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"12345678"};	// max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = {	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,	// Key 0
					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Key 1
					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Key 2
					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Key 3
				};

其中security_passphrase提供给WPA/WPA2加密方式使用的,而wep_keys则是提供给WEP(128位密钥)加密方式使用的,你需要根据自己WiFi网络的设置,填入相应的参数。我们实验中采用的是WPA加密方式,所以我们只需要对security_passphrase这一参数进行设置。

在将程序下载到Arduino中以后,硬件上的连接相对比较简单,该模块采用的是SPI接口,所以我们可以使用IDC扩展板,使用6芯IDC连接线将模块连接到扩展板上就可以了:

根据所采用的加密方式不同,WiFi模块上电后需要一段初始化的时间,我们可以使用ping命令来检查模块是否已经正常到无线AP或者路由器上:

ping -t 192.168.0.14

一但连接正常,你就可以通过游览器来测试这一WiFi WebServer了:

除了这个WebServer的例子以外,在我们下载的库文件中还有其他一些例子, 有兴趣的话可以逐个运行一下。在实际使用的时候,你可以以这些例子为基础,开发自已所需要的功能。

由于WiFi模块需要对无线AP或者路由器有一定的要求,目前我们所使用的NETGEAR WGR614 v5无线路由器在测试中通过正常通过不加密或者是WPA方式加密的时候正常工作,目前WEP方式还没有通过测试,你在其它无线AP或者路由器上测试时可能会有不同的现象出现;-)

·

<< Latest posts

Older posts >>

Theme Design by devolux.nh2.me