打印

快捷开发 任性连接 :ESP32 Thing开发板评测

[复制链接]
4234|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1.简介, 外观与资源
ESP32 ThingSparkfun最新推出的一款WiFi+BLE的开发板,专门面向IoT类的应用.由于拥有WiFi与蓝牙(双模)的双重连接方式,所以给开发者的创意余地非常丰富.最令人兴奋的是这个开发板可以使用Arduino IDE来开发.这里跟大家分享一下此开发的使用体验,以及如何设置开发环境并使用它来开发你的下一个IoT应用.
因为开发板本身非常小巧,并无专门的箱子,这里就没有开箱图了.直接上板子的图:
正面图
反面图

评分
参与人数 1威望 +3 收起 理由
Cary_Liu + 3 赞一个!

相关帖子

沙发
zhanzr21|  楼主 | 2017-3-8 00:42 | 只看该作者


Uno板子放在一起
Arduino Uno放在一起的感觉有点奇怪的感觉,功能多了N,尺寸却小了这么多.
Mouser发货单
这是Mouser的发货单,发货单只是提到是个WiFi开发板没有提到蓝牙.
板子的资源如下:
·        双核的TensilicaLX6 处理器
·        最高运行频率240MHz
·        520kB内部SRAM
·        集成802.11BGN WiFi 收发器
·        集成双模蓝牙 (经典和 BLE)
·        2.2 -3.6V工作电压
·        2.5 µA深睡眠电流
·        28个GPIO
·        10电极电容式触摸控制
·        硬件加速加密 (AES, SHA2, ECC, RSA-4096)
·        4MB外部Flash
·        集成锂电池充电电路
这里将资源与板子简单对应一下子:
资源对应
这是Sparkfun提供的引脚扩展分配图:
引脚扩展图

使用特权

评论回复
板凳
zhanzr21|  楼主 | 2017-3-8 00:47 | 只看该作者
2.硬件与原理图简析
硬件方面,首先ESP32 SOC比较令人感兴趣.这里做个简单介绍.
2.1 ESP32简介
这是上海乐鑫出的一款ESP8266的升级版本.从数据手册来看此SOC的核心为:
• Xtensa® 双核 32 LX6 处理器, 频率最高240 MHz, 性能最高600 DMIPS(ESP8266的内核是单核的Tensilica LX106,最高80MHz)
每个核都支持:
•      7级流水线
•      16/24位两种指令集
•      FPU
•      DSP指令,比如32位乘法器,32位除法器,40位MAC
•       70个中断源,32个向量

外设与无线接口这里就不详列了,读者可以参考数据手册.
Xtensa LX6及其系列产品使用的是Xtensa公司的一款专门为无线与多媒体应用优化设计的内核. 这个公司2013年被Cadence收购. 简而言之,这个处理器优化原理就是类似于ASIC与通用处理器之间的一个中间路线: 有一个通用的架构,有一些可配置单元,在综合成最终处理器时去除不需要的部分,从而实现了成本尺寸性能几个方面很好的优化.
Xtensa LX vs通用处理器
关于这个内核的详情这里就不多展开了, 感兴趣的可以看**后面的参考连接.
这是ESP32Block:
ESP32 SOC功能Block
除了无线方面很强大之外,其他外设几乎也是应有尽有.摄像头接口与外部动态存储器接口是作者第一眼望过去能举出的没有的外设.
原理图的整个文件将在后面附上连接. 这里就分析其中两点:
2.2 USB与充电部分

USB+LDO部分
此处注意当有USB电源与电池双电源的时候,Q1管子的Gate极被拉高,而导致DS截止.这样只使用USB进行供电.当没有USB连接,Gate极被R7拉低而使得DS导通,这样电池电压通过Q1与VIN连接.这是一种典型的低成本USB/电池电源设计, 当然如果有稍稍智能一点的电源管理芯片则不必如此费事.
充电部分原理图
此处使用充电片MCP73831的PROG脚的下拉电阻来设置充电电流: I = 1000/Rprog. 板子上原来使用2K电阻,则充电电流为500mA.这个电流对大多数主板来讲应该还是嫌高了一些.故此本人把这里改成了2.55K的电阻.
另外提一句, 如果大家想自己制作这个板子的话.电源部分的LDO与充电片MCP73831都有很多国产的替代型号. 比如LDO使用RT9193或者ME6211系列替代, MCP73831的话,国产的TP4054,FM4054替代型号也非常多. 这里说的替代都是管脚兼容的.
2.3 串口下载部分
串口下载逻辑
这里使用串口的DTR与RTS两个信号比较聪明地做了个自动下载的逻辑. 具体这样的: 如果DTR为低,RTS的下降沿将SOC切换到运行状态.如果RTS为高,DTR的上升沿将SOC切换到bootloader状态.这个逻辑在Arduino类的使用串口下载的板子设计中用得很广泛.




使用特权

评论回复
地板
zhanzr21|  楼主 | 2017-3-8 00:49 | 只看该作者
3.开发环境建立与第一个程序-Arduino方式
准备工作(篇幅原因只写Windows环境,Mac,Linux的请参考后面的连接):
1.    安装好标准的Arduino IDE, 作者使用1.8.1
2.    找到扩展包的路径,如果没有改过就应该在这个路径: C:/Users/[YOUR_USER_NAME]/Documents/Arduino/. 作者电脑上是这个路径: D:\Documents\Arduino. 打开一个命令行窗口,运行下面命令创建目录:
mkdir hardware
cd hardware
mkdir espressif
cd espressif
3.    安装好git工具,作者使用cygwin环境的git命令, 其他版本应该都差不多.
3.1 下载扩展包
用这个git路径下载:
git clone https://github.com/espressif/arduino-esp32.git esp32
下载扩展包
3.2 下载SDK
下载好扩展包后, 用扩展包中的一个集成工具来下载SDK.
下载SDK
这两个步骤下载都非常快.


使用特权

评论回复
5
zhanzr21|  楼主 | 2017-3-8 00:53 | 只看该作者
3.3 设置Arduino IDE
现在就可以使用Arduino IDE来开发程序了.插入ESP32 Thing开发板, 刚开始会有一个安装驱动的过程. 成功后, 设备与打印机中显示一个FTDI虚拟串口.
开发板子驱动安装成功
右键点这个串口可以查看其串口号,后面下载程序要用,作者电脑上是COM6.
打开Arduino IDE,选板子:
选择ESP32 Thing开发板子
再选择下载串口, 就是上面说的那个串口号:
选择下载串口
到这一步就可以写代码了.
根据使用经验,下载程序有时不成功(超时). 这时需要按下用户按钮再试一次.
下载的波特率最高可以设置为921600, 但是经过试验115200下载成功率最高.
这是官方的说明:
## Hint
Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process
3.4 第一个程序:闪灯与串口
开发板子上的默认LED连接在Pin5,类似于Uno板子上面的Pin13上的LED. 这个程序驱动LED闪烁并且定时发送串口字符串.
建立一个Sketch,输入如下代码:
int ledPin = 5;

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

void loop()
{
    Serial.println("Hello, My first ESP32 Thing program!");
    Serial.println(__DATE__" "__TIME__);   
    digitalWrite(ledPin, HIGH);
    delay(800);
    digitalWrite(ledPin, LOW);
    delay(800);
}
下载成功打开串口窗口:
第一个程序输出


使用特权

评论回复
6
zhanzr21|  楼主 | 2017-3-8 00:54 | 只看该作者
3.5 第二个程序:连接WiFi网络获取HTTP页面
这个程序连接至WiFi网络并且下载一个网站(比如www.21ic.com)的默认首页.代码如下:
#include <WiFi.h>

// WiFi network name and password:
const char * networkName = "WIFI路由器SSID名称";
const char * networkPswd = "WIFI密码";

// Internet domain to request from:
const char * hostDomain = "www.21ic.com";
const int hostPort = 80;

const int BUTTON_PIN = 0;
const int LED_PIN = 5;

void setup()
{
  // Initilize hardware:
  Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);

  // Connect to the WiFi network (see function below loop)
  connectToWiFi(networkName, networkPswd);

  digitalWrite(LED_PIN, LOW); // LED off
  Serial.print("Press user button 0 to connect to ");
  Serial.println(hostDomain);
}

void loop()
{
  if (digitalRead(BUTTON_PIN) == LOW)
  { // Check if button has been pressed
    while (digitalRead(BUTTON_PIN) == LOW)
      ; // Wait for button to be released

    digitalWrite(LED_PIN, HIGH); // Turn on LED
    requestURL(hostDomain, hostPort); // Connect to server
    digitalWrite(LED_PIN, LOW); // Turn off LED
  }
}

void connectToWiFi(const char * ssid, const char * pwd)
{
  int ledState = 0;

  printLine();
  Serial.println("Connecting to WiFi network: " + String(ssid));

  WiFi.begin(ssid, pwd);

  while (WiFi.status() != WL_CONNECTED)
  {
    // Blink LED while we're connecting:
    digitalWrite(LED_PIN, ledState);
    ledState = (ledState + 1) % 2; // Flip ledState
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("WiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void requestURL(const char * host, uint8_t port)
{
  printLine();
  Serial.println("Connecting to domain: " + String(host));

  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  if (!client.connect(host, port))
  {
    Serial.println("connection failed");
    return;
  }
  Serial.println("Connected!");
  printLine();

  // This will send the request to the server
  client.print((String)"GET / HTTP/1.1\r\n" +
               "Host: " + String(host) + "\r\n" +
               "Connection: close\r\n\r\n");
  unsigned long timeout = millis();
  while (client.available() == 0)
  {
    if (millis() - timeout > 5000)
    {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }

  // Read all the lines of the reply from server and print them to Serial
  while (client.available())
  {
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
  client.stop();
}

void printLine()
{
  Serial.println();
  for (int i=0; i<30; i++)
    Serial.print("-");
  Serial.println();
}
注意填写WIFISSID与密码, 编译下载. 先连接网络, 成功连接WiFI网络之后需要用户按一下用户按钮,一切正常的话就开始下载默认页面.大致结果如此:
HTTP程序输出


使用特权

评论回复
7
zhanzr21|  楼主 | 2017-3-8 00:56 | 只看该作者
3.6 第三个程序:UDP发送
这个程序连接WiFi网络,并且向服务端的UDP端口定时发送随机数.代码如下:
/*
*  This sketch sends random data over UDP on a ESP32 device
*
*/
#include <WiFi.h>
#include <WiFiUdp.h>

// WiFi network name and password:
const char * networkName = "WIFI路由器SSID名称";
const char * networkPswd = "WIFI密码";

//IP address to send UDP data to:
// either use the ip address of the server or
// a network broadcast address
const char * udpAddress = "开网络助手的主机IP";
const int udpPort = 20000;

//Are we currently connected?
boolean connected = false;

//The udp library class
WiFiUDP udp;

void setup(){
  // Initilize hardware serial:
  Serial.begin(115200);
  
  //Connect to the WiFi network
  connectToWiFi(networkName, networkPswd);
}

void loop(){
  int tmpRand;
  //only send data when connected
  if(connected){
    //Send a packet
    udp.beginPacket(udpAddress,udpPort);
    tmpRand = rand();
    udp.printf("UDP Demo,It is a random number: %d\n", tmpRand);
    udp.endPacket();
    Serial.printf("Sending %d\n", tmpRand);
  }
  //Wait for 1 second
  delay(1000);
}

void connectToWiFi(const char * ssid, const char * pwd){
  Serial.println("Connecting to WiFi network: " + String(ssid));

  // delete old config
  WiFi.disconnect(true);
  //register event handler
  WiFi.onEvent(WiFiEvent);
  
  //Initiate connection
  WiFi.begin(ssid, pwd);

  Serial.println("Waiting for WIFI connection...");
}

//wifi event handler
void WiFiEvent(WiFiEvent_t event){
    switch(event) {
      case SYSTEM_EVENT_STA_GOT_IP:
          //When connected set
          Serial.print("Connected! IP address: ");
          Serial.println(WiFi.localIP());  
          //initializes the UDP state
          //This initializes the transfer buffer
          udp.begin(WiFi.localIP(),udpPort);
          connected = true;
          break;
      case SYSTEM_EVENT_STA_DISCONNECTED:
          Serial.println("WiFi lost connection");
          connected = false;
          break;
    }
}
编译下载,打开网络调试器,设置好端口,开始接收.
输出大致如下:
图 UDP输出

使用特权

评论回复
8
zhanzr21|  楼主 | 2017-3-8 00:57 | 只看该作者
3.7 第四个程序:改变蓝牙设备名
需要指出的是,截止此文开发板子的Arduino支持包目前还不完全(至少是已经实现了但是没有给出接口),比如蓝牙相关库,模拟输出功能等等. 所以,要使用暂时没有Arduino库的功能还得使用Native的方式来开发.
蓝牙的库函数根据乐鑫官方的说法是正在紧锣密鼓开发完善中. 这个蓝牙程序也是改自乐鑫官方的例子,启动后开启蓝牙,手机的蓝牙界面可以发现它.因为开启的是BLE蓝牙,所以你手机得支持BLE才能发现这个设备的. 经典蓝牙的功能目前没有开出Arduino接口.另外用户按钮每次被按,设备的名称也会改变(需要手机端刷新显示才能看到).代码如下:
#include "SimpleBLE.h"
SimpleBLE ble;

void onButton(){
    String out = "BLE32 at: ";
    out += String(rand() % 100);
    Serial.println(out);
    ble.begin(out);
}

void setup() {
    Serial.begin(115200);
    Serial.setDebugOutput(true);
    ble.begin("ESP32 SimpleBLE");
    Serial.println("Press the user button to change the device name");
}

void loop() {
    static uint8_t lastPinState = 1;
    uint8_t pinState = digitalRead(0);
    if(!pinState && lastPinState){
        onButton();
    }
    lastPinState = pinState;
    while(Serial.available()) Serial.write(Serial.read());
}
打开手机的蓝牙界面即可发现该设备,此时按一下用户按钮,再在手机上点刷新蓝牙设备,即可看到名称已经变换.
a.手机上发现蓝牙设备 b.按下用户按钮后改名

使用特权

评论回复
9
zhanzr21|  楼主 | 2017-3-8 01:00 | 只看该作者
3.8 第五个程序:硬件模拟输出
由于ESP32有硬件DAC,所以可以直接使用DAC引脚输出模拟波形, 而非Uno板子上那种PWM仿DAC输出.这里就是上文所讲的代码中实现了,但是没有给出接口和例子的功能.只有通过翻cpp的底层HAL库文件才能了解调用方法.
首先这板子上有两个硬件DAC引脚,和其他引脚不同,这两个引脚被固定在Pin25, Pin26这两个位置,不能被再映射.
两个DAC引脚
下面的代码在两个通道上输出模拟波形. DAC1输出正弦波, DAC2输出锯齿波.代码如下:
void setup()
{
    //Setup DAC1
    pinMode(25, ANALOG);
    //Setup DAC2
    pinMode(26, ANALOG);     
}

void loop()
{
    uint8_t val1 = 0;
    uint8_t val2 = 0;
    static uint32_t x_idx = 0;

    //DAC1: Sine Wave
    val1 = INT8_MAX * (1 + sin(x_idx/(10*PI)));
    dacWrite(25, val1);

    //DAC2: Saw Wave
    val2 = (x_idx ++) % UINT8_MAX;
    dacWrite(26, val2);
}
用示波器分别看两个通道的输出:
图 DAC1输出
图 DAC2输出



使用特权

评论回复
10
zhanzr21|  楼主 | 2017-3-8 01:02 | 只看该作者
4. Native方式开发环境建立
Native方式的开发环境比较灵活, 有很多种方法设置. 这里使用最流行的一种:IDF(Iot Development Framework).先下载这个文件建立类Unix环境:
之后解压到比如D,将会生成一个msys32的子目录.
之后打开一个命令行窗口,运行如下命令:
MSYS2命令
会弹出一个MSYSShell窗口,在窗口中开始git下载.
GIT下载IDF所需文件
敲回车后开始下载,这个过程有点长,可以当做Coffee Time或者Tea Time.下载成功后就可以开始开发了.(网络不好的同学可以使用GUI工具在这个目录下载: https://github.com/espressif/esp-idf后解压也可以).

建立好环境后,先导出一个环境变量: export IDF_PATH="D:/idf_sdk_dir/esp-idf",试着运行一下gcc:
gcc版本
如此的话说明环境已经配置好了.
再回到上一级目录,下载一个工程模板.
下载工程模板
接下来就是GCC+Makefile开发的一些通用的做法了.比如进入工程模版目录,make menuconfig就是图形化配置工程, make clean清除工程, make编译连接,make flash烧写,等等.这里不一一列举了.

5. 总结,参考与测试代码 下载地址
总而言之,此开发板非常强大,运行速度,Flash/内存容量,无线通信接口都是同类开发板子中最为出类拔萃的. 除了Cadence与乐鑫合作的SOC处理器硬件上比较优秀之外, 硬件厂商与开源社区共同创建的开发环境也是此开发板子的耀眼的亮点. 要想快速开发IoT应用当然首选Arduino. 追求性能与功能完全的可以使用Native开发.目前Arduino还未覆盖所有硬件资源是唯一瑕疵. 但是相信在开源社区与厂商的共同努力之下,这一问题将会在不远的将来会得到解决.
参考**:
ESP32数据手册:
开发板原理图:
硬件设计文件:
ESP32 Thing HookupGuide:
引脚分配图:
乐鑫的资源下载地址:
Native开发环境参考页面:


使用特权

评论回复
11
zhanzr21|  楼主 | 2017-3-8 09:33 | 只看该作者
自顶一下

使用特权

评论回复
12
zhanzr21|  楼主 | 2017-3-8 09:34 | 只看该作者
为什么关注的人这么少呢,这板子不错啊!

使用特权

评论回复
13
zhanzr21|  楼主 | 2017-3-8 09:36 | 只看该作者
现在超级喜欢能用Arduino IDE开发的板子

使用特权

评论回复
14
Cary_Liu| | 2017-3-8 21:55 | 只看该作者
顶。ESP32确实不错

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:每天都進步

91

主题

1013

帖子

34

粉丝