Beetle ESP32-C3

1.Beetle ESP32-C3简介

Beetle ESP32-C3是一款基于ESP32-C3 RISC-V 32位单核处理器芯片的主控板,专为物联网 (IoT) 设备而设计。
Beetle ESP32-C3在仅硬币大小的体积上引出了多达13个IO口,制作项目时不必再担心IO口不够用的情况,同时主控板还集成锂电池充电管理功能,可以直接连接锂电池,不需要外围模块,同时保证应用体积和安全性。
Beetle ESP32-C3配套的扩展板在未增加太大体积的情况下,引出了更多的电源,在制作项目时焊接更加方便,板载的GDI显示屏接口解决使用屏幕时的接线烦恼。
Beetle ESP32-C3支持Wi-Fi 和 Bluetooth 5 (LE) 双模通讯,降低了设备配网难度,同时还支持蓝牙 Mesh (Bluetooth Mesh) 协议和乐鑫 Wi-Fi Mesh可以实现更高的通讯稳定性和更大的覆盖面积,适用于广泛的物联网应用场景。
Beetle ESP32-C3拥有详细的示例教程,通过教程可以轻松的使用控制器的无线功能,连接阿里云、IFTTT等物联网平台,同时DFRobot商城提供了上千种传感器和执行器,这些传感器和执行器也有详细的教程,因此你可以轻松搭建出自己的物联网系统。
Beetle ESP32-C3可以使用Arduino IDE、ESP-IDF、MicroPython进行编程,C语言、python都可以轻松的操纵硬件。

2.产品特性

3.产品参数

基本参数

硬件信息

WIFI
蓝牙
接口引脚

4.功能引脚示意图

功能指示

Beetle ESP32-C3

引脚示意

引脚概述

GDI显示接口

FireBeetle Board-ESP32 V4.0

此接口为DFRbot专用GDI显示屏接口,使用18pin-FPC线连接,单线材连接屏幕,为您提供最简捷的屏幕使用方式。
以下是GDI接口使用的引脚列表

FPC PINS Beetle ESP32 C3 PINS Description
VCC 3V3 3.3V
BLK(PWM调光) 10 背光
GND GND GND
SCLK 4/SCK SPI时钟
MOSI 6/MOSI 主机输出,从机输入
MISO 5/MISO 主机输入,从机输出
DC 1 数据/命令
RES 2 复位
CS 7 TFT片选
SDCS 0 SD卡片选
FCS NC 字库
TCS 3 触摸
SCL 9/SCL I2C时钟
SDA 8/SDA I2C数据
INT NC INT
BUSY-TE NC 防撕裂引脚
X1 NC 自定义引脚1
X2 NC 自定义引脚2

使用FPC链接屏幕时根据GDL demo配置所需对应的引脚号即可,通常只需要根据不同主控配置三个引脚
支持GDI的显示屏:

5. 首次使用

5.1 Arduino环境配置

当您首次使用Beetle-ESP32-C3,您需要了解以下步骤

  1. 添加IDE中的json链接
  2. 下载主控的核心
  3. 选择开发板以及串口
  4. 打开示例程序并烧录
  5. 了解串口监视器

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

Beetle ESP32-C3

5.2 LED闪烁

板载LED灯默认为引脚10

代码

int led = 10;
void setup() {
  pinMode(led,OUTPUT);
}

void loop() {
  digitalWrite(led,HIGH);
  delay(1000);
  digitalWrite(led,LOW);
  delay(1000);
}

烧录成功

6. Beetle-ESP32C3基础教程(此处介绍为Arduino之间的差别处)

6.1 PWM输出

ESP32C3的PWM功能需要提前定义声明

示例

ESPC3的PWM由于其可以自由映射到其它端口进行输出,您需要进行几步设置,该案例将使用帮助您理解其中的步骤 该案例你可以看到LED灯逐渐变亮变暗

/*
 * LED呼吸灯示例
 */
const int ledPin = 10;  // PWM生成后实际输出引脚

//设置PWM参数
const int freq = 5000;//PWM频率
const int ledChannel = 0;//信号生成GPIO
const int resolution = 8;//8位分辨率

void setup(){
  //PWM参数设置
  ledcSetup(ledChannel, freq, resolution);

  //将生成信号通道绑定到输出通道上
  ledcAttachPin(ledPin, ledChannel);
}

void loop(){
  //逐渐变亮
  for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){   
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);
    delay(15);
  }

  //逐渐变暗
  for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);   
    delay(15);
  }
}

6.2 中断

ESP32C3中断可自由分配

6.3 串口

ESP32C3串口初始化需要映射

Serial1.begin(9600,SERIAL_8N1,/*rx =*/0,/*Tx =*/1);  

6.4 舵机

ESP32-C3不能通过Servo库驱动舵机,需要在项目->加载库->管理库中搜索安装ESP32_ISR_Servo库驱动舵机

7.进阶教程

7.1 使用SD库

SD类

File类

File类提供了读/写文件的功能,该类的功能与之前使用的串口相关函数的功能非常类似。其成员函数如下。

7.2 ESP32-C3蓝牙收发

7.2.1 ESP32-C3与手机蓝牙通信

使用该实例演示ESP32-C3与手机之间的数据传输,如果需要修改或使用数据,只需更改数据接收部分数据发送部分代码

/*
    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini

   Create a BLE server that, once we receive a connection, will send periodic notifications.
   The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
   Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" 
   Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with  "NOTIFY"

   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create a BLE Service
   3. Create a BLE Characteristic on the Service
   4. Create a BLE Descriptor on the characteristic
   5. Start the service.
   6. Start advertising.

*/

/* 该示例演示了蓝牙数据透传,烧录代码,打开串口监视器,打开手机的BLE调试助手
 * 1.即可看见ESP32-C3发送的数据--见APP使用图
 * 2.通过BLE调试助手的输入框可向ESP32-C3发送数据--见APP使用图
 * 该示例由BLE_uart示例更改而来
 */

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
uint8_t txValue = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"


//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {   //当蓝牙连接时会执行该函数
      Serial.println("蓝牙已连接");
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {  //当蓝牙断开连接时会执行该函数
      Serial.println("蓝牙已断开");
      deviceConnected = false;
      delay(500); // give the bluetooth stack the chance to get things ready
      pServer->startAdvertising(); // restart advertising

    }
};

/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理。当收到数据时自动触发
class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();//接收数据,并赋给rxValue

      //if(rxValue == "ON"){Serial.println("开灯");}   //判断接收的字符是否为"ON"

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");
        for (int i = 0; i < rxValue.length(); i++){
          Serial.print(rxValue[i]);
        }
        Serial.println();
        Serial.println("*********");
      }
    }
};
/***************************************/
/****************************************/


void setup() {
  Serial.begin(115200);
  BLEBegin();  //初始化蓝牙

}

void loop() {
/****************数据发送部分*************/
/****************************************/
  if (deviceConnected) {  //如果有蓝牙连接,就发送数据
    pTxCharacteristic->setValue("Hello");  //发送字符串
    pTxCharacteristic->notify();
    delay(10); // bluetooth stack will go into congestion, if too many packets are sent

    pTxCharacteristic->setValue("DFRobot");  //发送字符串
    pTxCharacteristic->notify();
    delay(10); // bluetooth stack will go into congestion, if too many packets are sent
  }
/****************************************/
/****************************************/
}


void BLEBegin(){
  // Create the BLE Device
  BLEDevice::init(/*BLE名称*/"UART Service");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
                    CHARACTERISTIC_UUID_TX,
                    BLECharacteristic::PROPERTY_NOTIFY
                  );

  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_RX,
                      BLECharacteristic::PROPERTY_WRITE
                    );

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

7.2.2 两个ESP32C3蓝牙通讯

使用该实例演示ESP32-C3与ESP32-C3之间的数据传输,如果需要修改或使用数据,只需更改数据接收部分数据发送部分代码

主机代码

/**
 * A BLE client example that is rich in capabilities.
 * There is a lot new capabilities implemented.
 * author unknown
 * updated by chegewara
 */

#include "BLEDevice.h"
//#include "BLEScan.h"

// The remote service we wish to connect to.
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
// The characteristic of the remote service we are interested in.
static BLEUUID    charTXUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");

static BLEUUID    charRXUUID("beb5483f-36e1-4688-b7f5-ea07361b26a8");

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pTXRemoteCharacteristic;
static BLERemoteCharacteristic* pRXRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;


/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理,当收到数据时自动触发
static void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {  //传入uint8_t* pData用于存放数据
    String BLEData = "";
    for(int i = 0; i < length; i++)  //
      BLEData += (char)pData[i];
    Serial.println("*********");
    Serial.print("Received Value: ");
    Serial.println(BLEData);
    Serial.println("*********");

    //if(BLEData == "ON"){Serial.println("开灯");}  //判断接收的字符是否为"ON"

    //Serial.print("Notify callback for characteristic ");
    //Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
    //Serial.print(" of data length ");
    //Serial.println(length);
}
/****************************************/
/****************************************/

//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};


/**
 * Scan for BLE servers and find the first one that advertises the service we are looking for.
 */
 //蓝牙扫描处理事件。当开启扫描时自动触发
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    //Serial.print("BLE Advertised Device found: ");
    //Serial.println(advertisedDevice.toString().c_str());

    // We have found a device, let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks



void setup() {
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  bleBegin();

}

void loop() {
  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }
/****************数据发送部分*************/
/****************************************/
  if (connected) {  //当连接到蓝牙从机时发送数据
    pTXRemoteCharacteristic->writeValue("我是主机");
    pTXRemoteCharacteristic->writeValue("Hello client");
  }
  if(!connected){  //当没有连接到蓝牙从机时重新扫描
    BLEDevice::getScan()->start(5,false);  // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
  }
/****************************************/
/****************************************/
  delay(1000); 
}


void bleBegin()
{
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());//扫描处理函数
  pBLEScan->setInterval(1349);//设置扫描间隔时间
  pBLEScan->setWindow(449);//主动扫描时间
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);//扫描时间,单位秒
  }


//蓝牙连接处理
bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());

    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);  // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");
    pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise)

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pTXRemoteCharacteristic = pRemoteService->getCharacteristic(charTXUUID);
    if (pTXRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charTXUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    pRXRemoteCharacteristic = pRemoteService->getCharacteristic(charRXUUID);
    if (pRXRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charRXUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our characteristic");

    if(pRXRemoteCharacteristic->canNotify())
      pRXRemoteCharacteristic->registerForNotify(notifyCallback);

    connected = true;
    return true;
}

从机代码

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID_RX "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define CHARACTERISTIC_UUID_TX "beb5483f-36e1-4688-b7f5-ea07361b26a8"
uint8_t txValue = 0;
bool deviceConnected = false;
BLECharacteristic *pTxCharacteristic;


//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {   //当蓝牙连接时会执行该函数
      Serial.println("蓝牙已连接");
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {  //当蓝牙断开连接时会执行该函数
        Serial.println("蓝牙已断开");
        deviceConnected = false;
        delay(500); // give the bluetooth stack the chance to get things ready
        BLEDevice::startAdvertising(); // restart advertising
    }
};
/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理。当收到数据时自动触发
class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();  //使用rxValue接收数据

      //if(rxValue == "ON"){Serial.println("开灯");}   //判断接收的字符是否为"ON"

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");
        for (int i = 0; i < rxValue.length(); i++)
              Serial.print(rxValue[i]);    //将接收的数据打印出来

        Serial.println();
        Serial.println("*********");
      }
    }
};
/****************************************/
/****************************************/

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  bleBegin();
}

/****************数据发送部分*************/
/****************************************/
void loop() {
  if(deviceConnected){  //当有设备连接时发送数据
    pTxCharacteristic->setValue("我是从机");
    pTxCharacteristic->notify();

    pTxCharacteristic->setValue("Hello Sever");
    pTxCharacteristic->notify();
  }
  /****************************************/
  /****************************************/
  delay(1000);
}


void bleBegin()
{
  BLEDevice::init(/*BLE名称*/"Long name works now");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID_RX,
                                         BLECharacteristic::PROPERTY_WRITE 
                                       );
  pRxCharacteristic->setCallbacks(new MyCallbacks()); 

 pTxCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID_TX,
                                         BLECharacteristic::PROPERTY_NOTIFY
                                       );
 pTxCharacteristic->addDescriptor(new BLE2902());

  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();

  }

7.3 WIFI控制LED

ESP32C3具有WIFI功能,以下示例使用ESP32C3创建了一个wifi服务器,使用客户端连接到该服务器,控制LED的亮灭

步骤

1.连接到WIFI”Beetle ESP32 C3“,已设置WIFI密码:12345678
2.访问网址 http://192.168.4.1/ON 来打开灯 访问 http://192.168.4.1/OFF 来关闭灯
3.在访问后通过点击上下 here 来便捷控制灯的亮灭而不需要输入网址进行

代码

/*
步骤:
1.连接到WIFI”Beetle ESP32 C3“,已设置WIFI密码:12345678
2.访问网址 http://192.168.4.1/ON 来打开灯 访问 http://192.168.4.1/OFF 来关闭灯
3.在访问后通过点击上下 here 来便捷控制灯的亮灭而不需要输入网址进行
*/

#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>

#define myLED 10 //设置引脚10为LED引脚
// 设置WIFI名称以及密码
const char *ssid = "Beetle ESP32 C3";//WIFI名称
const char *password = "12345678";//密码

WiFiServer server(80);//网页服务端口默认为80


void setup() {
  pinMode(myLED, OUTPUT);

  Serial.begin(115200);
  Serial.println();
  Serial.println("Configuring access point...");

  //如果想要无密码开放网络请删除password
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  server.begin();

  Serial.println("Server started");
}

void loop() {
  WiFiClient client = server.available();   // 检测等待连接

  if (client) {                             // 检测是否连接
    Serial.println("New Client.");
    String currentLine = "";                // 创建String变量来保存数据
    while (client.connected()) {            // 保持连接时一直循环
      if (client.available()) {             // 检测连接是否有数据
        char c = client.read();             // 读取接收的数据
        //Serial.write(c);                    // 打印在串行监视器
        if (c == '\n') {                    // 如果读取的是换行符

          //结尾用换行符提醒结束
          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();
             //将字符与here连接
            client.print("Click <a href=\"/ON\">here</a> to turn ON the LED.<br>");
            client.print("Click <a href=\"/OFF\">here</a> to turn OFF the LED.<br>");

            // HTTP响应为空行
            client.println();
            // 跳出循环
            break;
          } else {    // 如果有一个换行符就清除变量缓存的数据
            currentLine = "";
          }
        } else if (c != '\r') {  // 如果获得回车以外的字符
          currentLine += c;      // 获得的字符添加到变量末尾
        }

        // 检查是否获得/ON或者/OFF
        if (currentLine.endsWith("/ON")) {
          digitalWrite(myLED, HIGH);               //得到/ON时打开灯
        }
        if (currentLine.endsWith("/OFF")) {
          digitalWrite(myLED, LOW);                //得到/OFF时关闭灯
        }
      }
    }
    // 关闭连接
    client.stop();
    Serial.println("Client Disconnected.");
  }
}

结果

使用手机连接该wifi,通过浏览器访问192.168.4.1,如图所示显示ip地址为192.168.4.1,服务已开启

使用浏览器访问该ip地址得到如下图所示

尝试分别点击链接控制LED吧

成员函数

7.4 ESP-NOW数据传输

ESP-NOW是乐鑫开发的终端数据传输、无连接的快速通讯技术,适用于智能灯、遥控控制、传感器数据回传等场景。

7.4.1 获取控制器MAC地址

烧录该代码,打开串口即可看到设备MAC地址

#include "WiFi.h"

void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_MODE_STA);
}

void loop(){
  Serial.println(WiFi.macAddress());
  delay(1000);
}

7.4.2 收发数据

填写MAC地址后烧录代码,可实现两个设备间相互收发数据

#include <esp_now.h>
#include <WiFi.h>

//MAC
uint8_t MAC1[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

typedef struct struct_message {
  char a[16];
  int b;
  float c;
  bool d;
} struct_message;

struct_message sendData;
struct_message recvData;

esp_now_peer_info_t peerInfo;

//发送回调函数
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  if(status == ESP_NOW_SEND_SUCCESS){
    Serial.println("Send_Success");
  }else{
    Serial.println("Send_Fail");
  }
}

//接收回调函数
void OnDataRecv(const uint8_t * mac, const uint8_t *Data, int len) {
  memcpy(&recvData, Data, sizeof(recvData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.println(recvData.a);
  Serial.println(recvData.b);
  Serial.println(recvData.c);
  Serial.println(recvData.d);
  Serial.println("---------");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  //Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing");
    return;
  }

  //注册发送回调函数
  esp_now_register_send_cb(OnDataSent);

  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  //注册MAC1设备
  memcpy(peerInfo.peer_addr, MAC1, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }

  //注册接收回调函数
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
  strcpy(sendData.a, "DFRobot");
  sendData.b = 10;
  sendData.c = 9.9;
  sendData.d = true;

  esp_err_t result = esp_now_send(MAC1, (uint8_t *)&sendData, sizeof(sendData));

  if (result == ESP_OK) {
    Serial.println("Send success");
  }
  else {
    Serial.println("Send Fail");
  }
  delay(2000);
}

7.4.3 给多个设备发送数据

填写MAC地址后烧录代码,可同时给多个设备发送数据

#include <esp_now.h>
#include <WiFi.h>

//MAC
uint8_t MAC1[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
uint8_t MAC2[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB};

typedef struct struct_message {
  uint8_t ID;
  int data;
} struct_message;

struct_message sendData;
struct_message recvData;

esp_now_peer_info_t peerInfo;

// Callback when data is sent   发送回调函数
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  if(status == ESP_NOW_SEND_SUCCESS){
    Serial.println("Send Success");
  }else{
    Serial.println("Send Fail");
  }
}

// Callback when data is received   接收回调函数
void OnDataRecv(const uint8_t * mac, const uint8_t *Data, int len) {
  memcpy(&recvData, Data, sizeof(recvData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.println(recvData.ID);
  Serial.println(recvData.data);
  Serial.println("---------");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  //Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing");
    return;
  }

  //注册发送回调函数
  esp_now_register_send_cb(OnDataSent);

  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  //注册MAC1设备
  memcpy(peerInfo.peer_addr, MAC1, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  //注册MAC2设备
  memcpy(peerInfo.peer_addr, MAC2, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }

  //注册接收回调函数
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
  sendData.ID = 0;
  sendData.data = 10;

  //向所有注册设备发送信息
  esp_err_t result = esp_now_send(0, (uint8_t *)&sendData, sizeof(sendData));
  if (result == ESP_OK) {
    Serial.println("Send success");
  }
  else {
    Serial.println("Send Fail");
  }
  //向指定MAC设备发送信息
  //esp_err_t result = esp_now_send(MAC1, (uint8_t *)&sendData, sizeof(sendData));
  //if (result == ESP_OK) {
  //  Serial.println("Send success");
  //}
  //else {
  //  Serial.println("Send Fail");
  //}
  delay(2000);
}

8.应用示例拓展

8.1 OLED显示测量温湿度

获取温湿度显示在OLED屏幕上是非常直观有趣的项目,下面你将学会基础的OLED显示以及使用I2C接口获取温湿度传感器数据。

您还需准备

1.您需要先安装SHT3x库

关于如何安装库点击这里

2.接线图

Beetle ESP32-C3

按照上图连接好线拷贝下面代码,您将看见你周围的温湿度状况。

代码


#include <Arduino.h>
#include <U8g2lib.h> //导入字库
//#include <SPI.h>
#include <Wire.h>

#include <DFRobot_SHT3x.h>

/*
---显示屏硬件I2C接口---
U8G2_R0 不旋转,横向,绘制方向从左到右
U8G2_R1 顺时针旋转90度,绘制方向从上到下
U8G2_R2 顺时针旋转180度,绘制方向从右到左
U8G2_R3 顺时针旋转270度,绘制方向从下到上
U8G2_MIRROR 正常显示镜像内容(v2.6.x版本以上使用)   注意:U8G2_MIRROR需要与setFlipMode()配搭使用.
U8x8_PIN_NONE 表示引脚为空,不会使用复位引脚
---显示屏硬件SPI接口---
cs 按引脚接上即可(引脚可自己选择)
dc 按引脚接上即可(引脚可自己选择)
*/
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(/* rotation=*/U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

//当ADR接VDD时可选择0x45当ADR接GND时可选择0x44
//默认为0x45,RST(复位脚)不用连接
DFRobot_SHT3x sht3x(&Wire,/*address=*/0x45,/*RST=*/4);

//使用SPI需要注释上方代码,使用下方代码
//DFRobot_SHT3x   sht3x;

void setup() {
  Serial.begin(115200);
  u8g2.begin();
  u8g2.setFontPosTop();//使用drawStr显示字符串时,默认标准为显示字符的左下角坐标。本函数的功能可理解为将坐标位置改为显示字符串的左上角为坐标标准。
  //初始化传感器
  while (sht3x.begin() != 0) {
        Serial.println("Failed to Initialize the chip, please confirm the wire connection");
        delay(1000);
      }
      Serial.print("Chip serial number");
      Serial.println(sht3x.readSerialNumber());
      if(!sht3x.softReset()){
         Serial.println("Failed to Initialize the chip....");
       }
}

void loop() {
  //清理屏幕
  u8g2.clearBuffer();
  //将温度、湿度读取赋值用于显示
  float   temp = sht3x.getTemperatureC();
  float   humi = sht3x.getHumidityRH();  
  //显示温度
  u8g2.setFont(u8g2_font_osb18_tf);    // 选择字体以及大小(见官方)
  u8g2.drawStr(5,10,"Temp");//在指定位置写出字符
  u8g2.setFont(u8g2_font_t0_18b_tr);
  u8g2.setCursor(75, 15);//显示从该位置开始
  u8g2.print(temp);
  //显示湿度
  u8g2.setFont(u8g2_font_osb18_tf);    
  u8g2.drawStr(5,40,"Humi");
  u8g2.setFont(u8g2_font_t0_18b_tr);
  u8g2.setCursor(75, 45);
  u8g2.print(humi);
  u8g2.sendBuffer(); 
  delay(1000);
}

结果

成员函数

8.2 WIFI获取温湿度

本示例参照示例8.3而来,进一步学会局域网下Wifi的信息传递,你可以学会如何访问局域网下的IP地址来获得在另一处的SHT30的温湿度传感器状态

您还需准备

您还需要按照示例9.1中步骤安装传感器库以及将其与ESP32连接。

接线图

Beetle ESP32-C3

步骤

1.连接到WIFI”Beetle ESP32 C3“,已设置WIFI密码:12345678
2.访问网址 http://192.168.4.1/GET 来获取局域网中的温湿度信息
3.在温湿度显示网页您可以通过刷新来更新传感器的数据

代码

/*
本示例是SHT30连接上ESPC3通过局域网获取温湿度
*/

#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>
#include <DFRobot_SHT3x.h>
//当ADR接VDD时可选择0x45当ADR接GND时可选择0x44
//默认为0x45,RST(复位脚)不用连接
DFRobot_SHT3x sht3x(&Wire,/*address=*/0x45,/*RST=*/4);

//使用SPI需要注释上方代码,使用下方代码
//DFRobot_SHT3x   sht3x;

// 设置WIFI名称以及密码
const char *ssid = "Beetle ESP32 C3";//WIFI名称
const char *password = "12345678";//密码

WiFiServer server(80);//网页服务端口默认为80

// 显示上次传感器状态反馈状态

void setup() {
  //pinMode(myLED, OUTPUT);

  Serial.begin(115200);
  Serial.println();
  Serial.println("Configuring access point...");

  //如果想要无密码开放网络请删除password
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  server.begin();

  Serial.println("Server started");
  //初始化传感器
  while (sht3x.begin() != 0) {
        Serial.println("Failed to Initialize the chip, please confirm the wire connection");
        delay(1000);
      }
      Serial.print("Chip serial number");
      Serial.println(sht3x.readSerialNumber());
      if(!sht3x.softReset()){
         Serial.println("Failed to Initialize the chip....");
       }
}

void loop() {

WiFiClient client = server.available();   // 检测等待连接

  if (client) {                             // 检测是否连接
    Serial.println("New Client."); 
    String currentLine = "";                // 创建String变量来保存数据
    while (client.connected()) {            // 保持连接时一直循环
      if (client.available()) {             // 检测连接是否有数据
        char c = client.read();             // 读取接收的数据
        //Serial.write(c);                    // 打印在串行监视器
        if (c == '\n') {                    // 如果读取的是换行符

          //清除掉缓存的内容
          if (currentLine.length() == 0) {
            client.print(" ");
            break;
          } else {    // 如果有一个换行符就清除变量缓存的数据
            currentLine = "";
          }
        } else if (c != '\r') {  // 如果获得回车以外的字符
          currentLine += c;      // 获得的字符添加到变量末尾
        }

        // 检查是否有/GET在末尾
        if (currentLine.endsWith("/GET")) {
             //把温度、湿度读出
             float   temp = sht3x.getTemperatureC();
             float   humi = sht3x.getHumidityRH();  
             //打印在网页 
             client.print("temp (C): "); client.println(temp);
             client.print("humi (%RH): "); client.println(humi);
        }
      }
    }
    // 关闭连接
    client.stop();
    Serial.println("Client Disconnected.");
  }
  }


结果

您可以通过手机,电脑等访问网址以获得如下结果(局域网下的温湿度传感器的温湿度)。


成员函数

8.3 WIFI获取网络时间

本实例演示了从网络时间服务器获取时间,并使用ESP32自带的RTC时钟保持时间更新
本示例来自CSDN博主「Naisu Xu」,原文链接:https://blog.csdn.net/Naisu_kun/article/details/115627629

#include <WiFi.h>

const char *ssid = "********";    //WIFI名称
const char *password = "********"; //WIFI密码

const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;

void printLocalTime()
{
    struct tm timeinfo;
    if (!getLocalTime(&timeinfo))
    {
        Serial.println("Failed to obtain time");
        return;
    }
    Serial.println(&timeinfo, "%F %T %A"); // 格式化输出
}

void setup()
{
    Serial.begin(115200);
    Serial.println();

    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }
    Serial.println("WiFi connected!");

    // 从网络时间服务器上获取并设置时间
    // 获取成功后芯片会使用RTC时钟保持时间的更新
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    printLocalTime();

    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
    Serial.println("WiFi disconnected!");
}

void loop()
{
    delay(1000);
    printLocalTime();
}

struct tm结构体

struct tm {
int tm_sec; // 秒,取值0~59;
int tm_min; // 分,取值0~59;
int tm_hour; // 时,取值0~23;
int tm_mday; // 月中的日期,取值1~31;
int tm_mon; // 月,取值0~11;
int tm_year; // 年,其值等于实际年份减去1900;
int tm_wday; // 星期,取值0~6,0为周日,1为周一,依此类推;
int tm_yday; // 年中的日期,取值0~365,0代表1月1日,1代表1月2日,依此类推;
int tm_isdst; // 夏令时标识符,实行夏令时的时候,tm_isdst为正;不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负
};

struct tm结构体格式化输出

格式化字符 输出
%a 星期几的简写
%A 星期几的全称
%b 月份的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年分,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日做为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十进制年份
%z 时区名称,如果不能得到时区名称则返回空字符

8.4 WIFI获取天气

本示例用于让你学会如何获取天气信息并让你体会HTTP中获取的信息通过Json提取数据并打印的

1.您需要安装Arduino_JSON库。通过 Arduino IDE Tools -> Manage Libraries 中输入 Arduino_JSON 并安装该库


2.注册OpenWeather的账号以获取我们想要的天气信息 打开浏览器并转到 https://openweathermap.org/appid/ 按注册按钮并创建一个免费帐户。

点击 My API Keys 进入获取API界面

复制这里的Key(这个Key是你从OpenWeather上获取天气信息的唯一钥匙)


你可以将Key填入以下URL并填写城市名以及它的国家以获取城市天气信息
http://api.openweathermap.org/data/2.5/weather?q=yourCityName,yourCountryCode&APPID=yourAPIkey

下面做个示例更换yourCityName你想要的数据的城市(比如成都),yourCountryCode与该城市的国家代码(比如CN),填入yourAPIkey就是前面获得的API密钥,下面为中国成都加上API后的URL:

http://api.openweathermap.org/data/2.5/weather?q=ChengDu,CN&APPID=4de305d0a52ddaceaecba50a757e9968

将你的 URL 复制到您的浏览器中将返回一组与您当地天气相对应的信息。编写本教程的那天,我们获得了以下有关中国成都的天气的信息。

代码


/*
该示例通过学习以了解如何获得天气信息
*/

#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

//修改WIFI名称以及密码
const char* ssid = "******";//WIFI名称
const char* password = "******";//WIFI密码

//填入你获得的API Key
String openWeatherMapApiKey = "4de305d0a52ddaceaecba50a757e9968";
//示例:
//String openWeatherMapApiKey = "4de305d0a52ddaceaecba50a757e9968";

// 填写你的城市名以及国家简写
String city = "ChengDu";
String countryCode = "CN";

//示例:
//String city = "ChengDu";
//String countryCode = "CN";

//设置获取信息的间隔时间,以下用于测试所以设置为10秒
//您应当根据你需要获取数据的网站,规定时间内访问数据的次数上限来限制访问时间的最小间隔
unsigned long lastTime = 0;
//设置每10分钟获得一次天气数据
//unsigned long timerDelay = 600000;
//设置每10秒获得一次天气数据
unsigned long timerDelay = 10000;

String jsonBuffer;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("Connecting");

  //判断WIFI是否连接
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println("Timer set to 10 seconds (timerDelay variable), it will take 10 seconds before publishing the first reading.");
}

void loop() {
  //发送HTTP获取请求
  if ((millis() - lastTime) > timerDelay) {
    //检测WIFI是否已经连接
    if(WiFi.status()== WL_CONNECTED){
      String serverPath = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&APPID=" + openWeatherMapApiKey;

      //将组合好的URL放入httpGETRequest函数中通过HTTP获取请求以获得文本
      jsonBuffer = httpGETRequest(serverPath.c_str());
      Serial.println(jsonBuffer);

      //将解析的Json对象值储存在Jsonu缓冲区中
      JSONVar myObject = JSON.parse(jsonBuffer);

      //判断解析是否成功
      if (JSON.typeof(myObject) == "undefined") {
        Serial.println("Parsing input failed!");
        return;
      }

      Serial.print("JSON object = ");
      Serial.println(myObject);
      Serial.print("Temperature: ");
      //获取到的温度其实是开氏度。
      //开氏度 = 摄氏度+273.15
      double c = myObject["main"]["temp"];
      c = c-273.15;
      Serial.println(c);
      Serial.print("Pressure: ");
      //myObject["main"]["pressure"]前为{}前的引号内容,后为读取哪一个引号后数据
      Serial.println(myObject["main"]["pressure"]);
      Serial.print("Humidity: ");
      Serial.println(myObject["main"]["humidity"]);
      Serial.print("Wind Speed: ");
      Serial.println(myObject["wind"]["speed"]);
    }
    else {
      Serial.println("WiFi Disconnected");
    }
    lastTime = millis();
  }
}

String httpGETRequest(const char* serverName) {
  WiFiClient client;
  HTTPClient http;

  //连接网址
  http.begin(client, serverName);

  //发送HTTP站点请求
  int httpResponseCode = http.GET();

  //该数组用于储存获得的数据
  String payload = "{}";

  //将获得的数据放入数组
  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }

  //释放资源
  http.end();

  //返回获得的数据用于Json处理
  return payload;
}

结果

成员函数

8.5 阿里云IoT

什么是阿里云

阿里云IoT致力于实现万物互联的美好世界,为生态合作伙伴提供基于云端一体化、安全物联网基础平台等,在通过该平台高效连接,管理设备的同时,其开放能力使合作伙伴更高效、低成本地构建各种创新的物联网应用场景。 阿里云物联网平台为设备提供安全可靠的连接通信能力,向下连接海量设备,支撑设备数据采集上云;向上提供云端API,指令数据通过API调用下发至设备端,实现远程控制。 此外阿里云IoT还提供了丰富的开发服务,用户可以直接在该平台上搭建Web可视化、移动应用、服务开发等开发服务,这降低了物联网项目开发的难度,有了它,用户无需任何专业的开发技巧也可开发自己的项目。

点击下载DFRobot_Iot库

8.6 SmartConfig 一键配网+自动重连

通过该代码可使用乐鑫的ESP-TOUCH进行一键配网。
点击下载安卓版
IOS版请在App Store搜索Espressif Esptouch

#include <WiFi.h>

void SmartConfig()
{
  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig...");
  WiFi.beginSmartConfig();
  while (1)
  {
    Serial.print(".");
    delay(500);                   // wait for a second
    if (WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      break;
    }
  }
}

bool AutoConfig()
{
    WiFi.begin();
    for (int i = 0; i < 20; i++)
    {
        int wstatus = WiFi.status();
        if (wstatus == WL_CONNECTED)
        {
            Serial.println("WIFI SmartConfig Success");
            Serial.printf("SSID:%s", WiFi.SSID().c_str());
            Serial.printf(", PSW:%s\r\n", WiFi.psk().c_str());
            Serial.print("LocalIP:");
            Serial.print(WiFi.localIP());
            Serial.print(" ,GateIP:");
            Serial.println(WiFi.gatewayIP());
            return true;
        }
        else
        {
            Serial.print("WIFI AutoConfig Waiting......");
            Serial.println(wstatus);
            delay(1000);
        }
    }
    Serial.println("WIFI AutoConfig Faild!" );
    return false;
}

void setup() {
  Serial.begin(115200);
  delay(100);
  if (!AutoConfig())
  {
      SmartConfig();
  }
}

void loop() {

}

9.MicroPython教程

9.1 MicroPython环境搭建

想要在Beetle ESP32-C3上运行microPython,首先需要给Beetle ESP32-C3烧录固件

  1. 点击链接下载microPython固件
  2. 点击下载esptool Flash烧录工具
  3. 运行flash_download_tool_3.9.3.exe
  4. 选择ESP32-C3主控,然后将Beetle ESP32-C3的引脚9连接GND,然后通过USB线连接电脑
  5. 选择下载的固件,擦除flash后烧录固件

9.2 MicroPython编译器

  1. 点击下载thonny
  2. 进入软件,对解释器进行设置(Run->Configure interpreter...)
  3. 将代码复制到代码框中,保存文件到MicroPython设备中,命名为main.py
import time
from machine import Pin 

led=Pin(10,Pin.OUT)

while True:

 led.value(1)
 time.sleep(1)
 led.value(0)
 time.sleep(1)

  1. 重启Beetle ESP32-C3即可看到L灯闪烁

常见问题

烧录报错

原因

解决办法

串口无打印

解决办法

更多问题及有趣的应用,可以 访问论坛 进行查阅或发帖。

更多