1. Introduction
EDGE101 is an IoT Programmable Controller Based on the ESP32 Core with Industrial Communication Interfaces and an Industrial-Grade Design.
ESP32 and Arduino are among the most popular hardware and development platforms for developers due to their excellent performance and extensive open-source libraries. Developers have created tens of thousands of innovative IoT applications using ESP32. However, most ESP32 development boards currently available only provide basic I/O functions and lack essential communication features such as RS485, CAN bus, and Ethernet, which are crucial for real-world deployment. This limitation creates significant functional gaps in common ESP32 development boards, affecting both learning and practical applications.
EDGE101 integrates RS485, CAN bus, Ethernet, Wi-Fi, Bluetooth, and RTC functionalities within a robust metal casing. It also supports PCIe slot expansion for 4G communication, offering a comprehensive and flexible IoT control solution. Additionally, it features 11 native GPIOs of the ESP32 and 3 I2C interfaces, allowing users to complete both IoT learning and deployment within a single device.
Most ESP32 development boards on the market lack necessary protection mechanisms, making them suitable only for desktop testing rather than direct IoT application deployment. EDGE101 is designed according to industrial standards, featuring a high-quality metal casing with comprehensive isolation protection, anti-static protection, lightning protection, overvoltage protection, and reverse polarity protection circuits. With a wide power supply range of 9V-26V and multiple mounting options, including rail mounting and ear-hook mounting, EDGE101 can operate stably and flexibly in various environments such as gardens, rooftops, garages, and power distribution rooms.
EDGE101 provides a detailed, free online development manual covering everything from basic I/O control and data acquisition to RS485 and CAN bus communication, as well as Wi-Fi, Bluetooth, Ethernet, 4G communication, and cloud service examples. Below is an overview of the tutorial sections:
- GPIO Control
- PWM Output
- ADC Data Acquisition
- Serial Communication
- I2C Communication
- SPI Communication
- TF Card Storage and Examples
- Timer Functions
- Watchdog Timer
- CAN Bus Communication and Examples
- RS485 Communication and Examples
- Wi-Fi Communication and Examples
- Bluetooth Communication and Examples
- Ethernet Communication and Examples
- 4G Communication Examples
- MQTT Examples
For more details, please visit the product’s WIKI tutorials.
2. Features
- ESP32 core controller with 240MHz clock speed, supporting Wi-Fi and Bluetooth wireless communication.
- Industrial-grade design with comprehensive circuit protections: isolation, ESD protection, lightning protection, overvoltage protection, and reverse polarity protection.
- Metal enclosure to prevent accidental damage from human contact, insects, or animals.
- Isolated RS485 interface.
- Isolated CANBUS interface.
- 11 native ESP32 GPIOs and 4 I2C interfaces.
- TF card slot for local data storage.
- Built-in PCIe expansion slot and nano SIM card slot, supporting 4G communication module installation.
- Multiple mounting options: DIN rail mounting, wall-mounted screw installation, flat mounting, or vertical installation.
3. Applications
- Outdoor environmental data acquisition
- Greenhouse data acquisition and automated control
- Water ingress monitoring for warehouses, base stations, excavation sites, etc.
- Compact automation equipment controller
- Robotics controller
4. Function indication
Front interface diagram
No. | Item | Description |
---|---|---|
1 | Ethernet Port (RJ45) | 10/100Mbps |
2 | Reset Button | Press to reset |
3 | Onboard Button | User-defined button |
4 | LED Indicators | Custom LED ×1, Wireless Communication LED ×1, Power LED ×1 |
5 | USB Port | Type-C |
6 | External Power Input | DC 9-26V |
7 | RS485 Port | Recommended baud rate: 9600bps | 115200bps |
8 | CAN-Bus Port | Maximum baud rate: 1Mbps |
9 | Terminal Resistor | 120Ω (RS485 ×1, CAN-Bus ×1) |
10 | Wi-Fi Antenna | 2.4G Wi-Fi & Bluetooth antenna |
11 | External Antenna | Supports installation of additional wireless modules (not included). Functions as 4G antenna if a 4G module is added. |
Back interface diagram
No. | Item | Description |
---|---|---|
1 | Grounding Terminal | Grounding connection |
2 | SD Card Slot | Supports up to 32 GB |
3 | SIM Card Slot | Nano SIM compatible |
4 | Gravity GPIO Interface | P5 P12 P14 P15 P18 P23 P33 P34 P37 P38 P39 (11 channels total) |
5 | Gravity I2C Interface | 3 groups (provides 3V3 | 5V VCC) |
5. Specification
Hardware Specifications
Category | Parameter |
---|---|
CPU Model | Dual-core ESP32 32-bit processor |
CPU Architecture | Xtensa 32-bit LX6 |
CPU Frequency | 240MHz, up to 600MIPS performance |
On-chip Flash | 16MB |
Memory | 520KB SRAM, 16KB RTC SRAM |
Hardware Interfaces
Category | Quantity | Specifications |
---|---|---|
Wi-Fi | 1 | 2.4GHz, 802.11 b/g/n, up to 150Mbps, supports STA/AP/STA+AP modes |
Bluetooth | 1 | BT4.2/BLE5.0/BLE Mesh networking |
Ethernet (RJ45) | 1 | 10/100Mbps |
Buttons | 2 | Reset button, onboard programmable button |
LED Indicators | 3 | 1x Power, 1x Customizable onboard, 1x Wireless status |
USB Port | 1 | Type-C |
External Power Input | 1 | DC 9-26V |
RS485 | 1 | Recommended baud rates: 9600bps | 115200bps |
CAN-Bus | 1 | Supports up to 1Mbps baud rate |
Terminal Resistors | 2 | 120Ω (1 for RS485, 1 for CAN-Bus) |
SD Card Slot | 1 | Supports up to 32GB |
SIM Card Slot | 1 | Nano SIM compatible |
PCIe Slot | 1 | Expandable for 4G, NB-IoT communication modules |
Gravity I2C Interfaces | 3 | Supports 100Kbps (Standard) | 400Kbps (Fast mode) |
Gravity GPIO Interfaces | 11 | Expandable for relays, digital/analog sensors; configurable as input/output/ADC |
Electrical Parameters
Category | Parameter |
---|---|
Operating Voltage | DC 9V–26V or USB Type-C 5V 2A input |
Power Protection | Surge protection, reverse polarity protection |
Protection | 2kV surge protection, 6kV ESD contact protection |
Operating Temperature | -20°C to +75°C |
Humidity | 5–90% RH (non-condensing) |
Operating Capability | Supports 24/7 continuous operation |
Standby Power Consumption | 50mA @12V (power terminal) | 100mA @5V (USB) |
Dimensions | 136.7mm × 76mm × 31mm |
Weight (bare board) | 63g |
Weight (assembled) | 335g |
6. Installation diagram
The product supports two installation methods: mounting ears and DIN rail mounting, as shown in the diagrams below.
Mounting Ears:
DIN Rail Installation:
DIN Rail Mounting Effect
7. Basic tutorial
7.1 Software Preparation
-
Download Arduino IDE: Click to Download Arduino IDE
-
Configure Arduino IDE for Edge101
Step 1: Open Arduino IDE and go to
File -> Preferences
. In the pop-up window, click the button that looks like a document.Step 2: Copy and paste the following URL into the "Additional Board Manager URLs" field:
https://downloadcd.dfrobot.com.cn/DFRobot_Edge101/package_Edge101_index.json
Then click OK.
Step 3: Go to
Tools -> Board -> Boards Manager...
as shown below:Step 4: In the search box, type "Edge101", locate the package shown below, and click Install. Wait for the download to complete, then click Close.
Step 5: Finally, set the board to "Edge101 IOT Controller" by selecting
Tools -> DFRobot Edge101 -> Edge101 IOT Controller
.Now you have completed the installation of the Edge101 SDK and can start writing and uploading code to the Edge101!
7.2 GPIO
The 40-pin expansion interface on the Edge101 mainboard provides 11 GPIOs and is equipped with Gravity 3-pin and 4-pin I2C interfaces, allowing direct connection to DFRobot's Gravity devices.
The GPIOs support internal pull-up, pull-down, or high-impedance configurations. When used as inputs, the values can be read through registers, and they support edge or level-triggered CPU interrupts.
All IO pins are bidirectional, non-inverting, and tri-state designed, supporting input, output, and tri-state control functions. Additionally, they can be multiplexed for other functions such as SDIO, UART, and SPI.
40PIN Expansion Interface Diagram
40PIN Expansion Interface Diagram
Pin Name | GPIO Function | ADC Function | Communication Function | Multiplexing Function |
---|---|---|---|---|
P5 | GPIO5, supports input/output | SPICS0 | Gravity SPICS0 | |
P12 | GPIO12, supports input/output | ADC2_CH5 | SPI-SDO | Gravity SPI-SDO |
P14 | GPIO14, supports input/output | ADC2_CH6 | SPI-CLK | Gravity SPI-CLK |
P15 | GPIO15, supports input/output | ADC2_CH3 | Onboard LED | |
P18 | GPIO18, supports input/output | I2C-SDA | Gravity I2C-SDA | |
P23 | GPIO23, supports input/output | I2C-SCL | Gravity I2C-SCL | |
P33 | GPIO33, supports input/output | U1TXD | PCIe Slot U1TXD | |
P34 | GPIO34, input only | U1RXD | PCIe Slot U1RXD | |
P37 | GPIO37, input only | ADC1_CH1 | ||
P38 | GPIO38, input only | ADC1_CH2 | Onboard Button | |
P39 | GPIO39, input only | ADC1_CH3 | SPI-SDI | Gravity SPI-SDI |
Note:
- GPIO34 to GPIO38 can only be used as inputs and do not support PULLUP or PULLDOWN modes. When using analog input, you must use the GPIOs connected to the ADC. However, if you use wireless communication such as Wi-Fi, ADC 2 will be unavailable.
- The following GPIOs have built-in pull-up or pull-down resistors:
- GPIO0: Internal pull-up
- GPIO5: Internal pull-up
- GPIO12: Internal pull-down (Default setting ensures FLASH operates at 3.3V. Forcing an external pull-up may cause the board to malfunction.)
Example: Controlling the LED
Set P38 (connected to the onboard button) as an input and P15 (connected to the onboard LED) as an output. When the button is pressed, the LED lights up.
Hardware Preparation:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Sample Code:
const int buttonPin = 38; // GPIO38 for the onboard button
const int ledPin = 15; // GPIO15 for the onboard LED
// Variable will change
int buttonState = 0; // Use a variable to store the button state
void setup() {
// If the external circuit does not have a pull-up or pull-down resistor,
// enable the internal pull-up or pull-down resistor when using GPIO as an input
// to accurately detect the signal level.
// Initialize button pin as input without enabling pull-up or pull-down
pinMode(buttonPin, INPUT);
// Initialize button pin as input with pull-up enabled
// pinMode(buttonPin, INPUT_PULLUP);
// Initialize button pin as input with pull-down enabled
// pinMode(buttonPin, INPUT_PULLDOWN);
pinMode(ledPin, OUTPUT); // Initialize LED pin as output
pinMode(buttonPin, INPUT); // Initialize button pin as input
}
void loop() {
// Read the button state
buttonState = digitalRead(buttonPin);
// If the button input is LOW, the button is pressed, and the onboard green user LED will turn on
if (buttonState == LOW) {
// Turn on the LED
digitalWrite(ledPin, LOW);
} else {
// Turn off the LED
digitalWrite(ledPin, HIGH);
}
}
Result:
When the button KEY (P38) is pressed, the LED (P15) lights up. When the button is released, the LED turns off.
7.3 PWM
Example: Adjusting LED Brightness with PWM
Create a breathing light effect on the user LED of the Edge101 board by adjusting its brightness using PWM with a frequency of 5000Hz.
Hardware Preparation:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Sample Code:
// PWM channel configuration
#define PWM_CH 0 // Use PWM channel 0
#define PWM_FREQ 5000 // Set PWM frequency to 5kHz
#define PWM_RES 13 // 13-bit resolution (range 0-8191)
#define LED_PIN 15 // LED connection pin
// Breathing light control parameters
int brightness = 0; // Current brightness value (0-255)
int fadeAmount = 5; // Brightness change step
/**
* Custom PWM output function
* @param ch PWM channel
* @param val Brightness value (0-255)
* @param maxVal Maximum input value (default is 8-bit)
*/
void ledcAnalogWrite(uint8_t ch, uint32_t val, uint32_t maxVal = 255) {
// Convert 8-bit brightness value to 13-bit duty cycle
ledcWrite(ch, (8191 / maxVal) * min(val, maxVal));
}
void setup() {
// Initialize PWM configuration
ledcSetup(PWM_CH, PWM_FREQ, PWM_RES); // Set PWM parameters
ledcAttachPin(LED_PIN, PWM_CH); // Bind pin to PWM channel
}
void loop() {
// Output the current brightness value
ledcAnalogWrite(PWM_CH, brightness);
// Update brightness value (linear gradient)
brightness += fadeAmount;
// Reverse gradient direction when reaching brightness limits
if (brightness <= 0 || brightness >= 255) {
fadeAmount = -fadeAmount;
}
delay(30); // Control breathing light speed
}
7.4 ADC
The Edge101 motherboard features a 12-bit SAR ADC, supporting 6 analog input channels with a sampling speed of 2 Msps. At any given time, each ADC can only sample one channel. Note: ADC2 cannot be used when WiFi is enabled.
Example: Single-Channel ADC Sampling
Hardware Required:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
- Gravity: Analog Angle Sensor (SKU: DFR0054) ×1
Example Code:
void setup()
{
Serial.begin(115200);
Serial.println();
}
void loop()
{
int vtmp = analogRead(37); // GPIO37 ADC1_CH1 to read voltage
Serial.printf("sample value: %d\n", vtmp);
Serial.printf("voltage: %.3fV\n", vtmp * 3.26 / 4095);
delay(500);
}
Result:
After uploading the program to the board, connect a potentiometer to pin P37 and adjust the input voltage. The serial monitor will display the measured raw digital value and the corresponding voltage.
7.5 Serial Ports
The Edge101 board has three serial ports: Serial, Serial1, and Serial2.
- Serial is connected to the USB interface for program downloading and code debugging. It will output basic information about the board upon power-up.
- Serial1 is used to extend the onboard wireless module or external serial devices.
- Serial2 is used for RS485 interface to connect industrial sensors, actuators, and other devices.
Example: Serial Read of User Button State
The following code demonstrates the functionality of reading the digital input signal from pin 38 and outputting the result to the serial monitor.
Hardware Preparation:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Sample Code:
/* Digital Input Read Example */
int pushButton = 38;
// Initialization function (runs once on reset):
void setup() {
// Initialize serial communication at a baud rate of 115200:
Serial.begin(115200);
// Set the button pin as input:
pinMode(pushButton, INPUT);
}
// Main loop function (runs repeatedly):
void loop() {
// Read the state of the input pin:
int buttonState = digitalRead(pushButton);
// Output the button state to the serial monitor:
Serial.println(buttonState);
delay(1); // Delay to ensure stable reading
}
Result:
When the onboard user button is not pressed, the serial monitor will display 1. When the button is pressed, the serial monitor will display 0.
7.6 I2C
The Edge101 board has two I2C control ports that handle communication on the two I2C buses. Each controller can be set as a master or slave. The board expansion interface uses GPIO18 as I2C SDA and GPIO23 as I2C SCL, and it uses a library compatible with the Arduino Wire library.
Example: Scanning Devices on the I2C Bus
The following code scans for devices on the I2C bus every 5 seconds and prints the slave device addresses found to the serial monitor.
Hardware Preparation:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Sample Code:
#include "Wire.h" // Include I2C communication library
void setup() {
Serial.begin(115200); // Initialize serial communication (baud rate 115200)
Wire.begin(); // Initialize I2C bus (default uses GPIO18-SDA/GPIO23-SCL)
}
void loop() {
byte error, address; // error: communication status code, address: scanned address
int nDevices = 0; // Device found counter
delay(5000); // Scan the bus every 5 seconds
Serial.println("Scanning for I2C devices ...");
// Scan the standard I2C address range (0x01~0x7F)
for(address = 0x01; address < 0x7f; address++) {
Wire.beginTransmission(address); // Try to communicate with the target address
error = Wire.endTransmission(); // Get communication status
if (error == 0) { // Status code 0 means device responded
Serial.printf("I2C device found at address 0x%02X\n", address);
nDevices++;
}
else if(error != 2) { // Status code 2 is normal, indicating no device is connected, other errors need to be reported
Serial.printf("Error %d at address 0x%02X\n", address, error);
}
}
if (nDevices == 0) { // No devices found
Serial.println("No I2C devices detected");
}
}
Result:
The serial monitor will print the scanned devices. The address 0x51 corresponds to the I2C address of the RTC chip on the board.
7.7 SPI
Example: Driving an SPI Display
Connect a DFR0664 2.0-inch TFT LCD screen to the SPI interface of the Edge101 board.
First, we need to install the DFRobot_GDL library (see TFT LCD wiki), then open the example from DFRobot_GDL->example->Basic->UI_bar.
Hardware Preparation:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
- 2.0-inch TFT LCD (SKU: DFR0664) ×1
Hardware Connections:
- Connect the LCD VCC to the +5V of the Edge101 board (Note: the LCD screen requires 5V power).
- Connect the LCD GND to the GND of the Edge101 board.
- Connect the LCD CK to the SPI interface's SCK (P14) on the Edge101 board.
- Connect the LCD SI to the SPI interface's SDO (P12) on the Edge101 board.
- Connect the LCD SO to the SPI interface's SDI (P39) on the Edge101 board.
- Connect the LCD BL to the 3.3V of the Edge101 board.
- Connect the LCD DC to P15 on the Edge101 board.
- Connect the LCD CS to P5 on the Edge101 board.
- Connect the LCD RT to P33 on the Edge101 board.
Sample Code:
This is an example displaying loading controls, showing three different types of loading controls.
/*!
* @file UI_bar.ino
* @brief Create a progress bar control on the screen.
* @n Users can customize the parameters of the progress bar or use the default parameters.
* @n Users can control the value of the progress bar through the callback function of the progress bar.
* @n The example supports Arduino Uno, Leonardo, Mega2560, FireBeetle-ESP32, FireBeetle-ESP8266, FireBeetle-M0.
* @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
* @licence The MIT License (MIT)
* @author [fengli](li.feng@dfrobot.com)
* @version V1.0
* @date 2019-12-6
* @get from https://www.dfrobot.com
* @url https://github.com/DFRobot/DFRobot_GDL/src/DFRpbot_UI
*/
#include "DFRobot_UI.h"
#include "DFRobot_GDL.h"
/*M0*/
#if defined ARDUINO_SAM_ZERO
#define TFT_DC 7
#define TFT_CS 5
#define TFT_RST 6
/*ESP32 and ESP8266*/
// LCD VCC connected to Edge101WE board +5V (40PIN expansion interface PIN2)
// LCD GND connected to Edge101WE board GND
// LCD CK connected to Edge101WE board SPI interface SCK
// LCD SI connected to Edge101WE board SPI interface SDO
// LCD SO connected to Edge101WE board SPI interface SDI
// LCD BL connected to Edge101WE board 3.3V
// LCD DC connected to Edge101WE board GPIO 15
// LCD CS connected to Edge101WE board GPIO 5
// LCD RT connected to Edge101WE board GPIO 33
#define TFT_DC 15
#define TFT_CS 5
#define TFT_RST 33
/*AVR series mainboard*/
#else
#define TFT_DC 2
#define TFT_CS 3
#define TFT_RST 4
#endif
// Constructor for hardware SPI communication
DFRobot_ST7789_240x320_HW_SPI screen(TFT_DC, TFT_CS, TFT_RST);
// Initialize UI
DFRobot_UI ui(&screen, NULL);
uint8_t value1 = 0;
uint8_t value2 = 0;
uint8_t value3 = 0;
// Callback function for progress bar1
void barCallback1(DFRobot_UI::sBar_t &obj) {
delay(50);
obj.setValue(value1);
if (value1 < 100) value1++;
}
// Callback function for progress bar2
void barCallback2(DFRobot_UI::sBar_t &obj) {
delay(50);
obj.setValue(value2);
if (value2 < 100) value2++;
}
// Callback function for progress bar3
void barCallback3(DFRobot_UI::sBar_t &obj) {
delay(50);
obj.setValue(value3);
if (value3 < 100) value3++;
}
void setup() {
Serial.begin(9600);
// Initialize UI
ui.begin();
ui.setTheme(DFRobot_UI::MODERN);
// Display a string on the screen
ui.drawString(33, screen.height() / 5 * 4, "Page of loading", COLOR_RGB565_WHITE, ui.bgColor, 2, 0);
// Create a progress bar control
DFRobot_UI::sBar_t &bar1 = ui.creatBar();
bar1.setStyle(DFRobot_UI::COLUMN);
bar1.fgColor = COLOR_RGB565_GREEN;
bar1.setCallback(barCallback1);
ui.draw(&bar1, 33, screen.height() / 5 * 3);
DFRobot_UI::sBar_t &bar2 = ui.creatBar();
bar2.setStyle(DFRobot_UI::CIRCULAR);
bar2.setCallback(barCallback2);
ui.draw(&bar2, 120, screen.height() / 5 * 2);
DFRobot_UI::sBar_t &bar3 = ui.creatBar();
bar3.fgColor = COLOR_RGB565_BLUE;
bar3.setStyle(DFRobot_UI::BAR);
bar3.setCallback(barCallback3);
ui.draw(&bar3, (screen.width() - bar3.width) / 2, screen.height() / 10);
}
void loop() {
// Refresh UI
ui.refresh();
}
Result: The display result is shown below.
7.8 SD Storage
Note: When downloading the example, select the partition scheme with a FAT system partition.
Example: Read SD Card
First, mount the SD card. If mounting fails, an error will be printed, and then the SD card type will be checked. Next, a series of operations will be performed on the SD card.
Hardware Required:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
/*
* Connect the SD card to the following pins:
*
* SD Card | FireBeetle MESH
* D2 -
* D3 GPIO5
* CMD MOSI
* VSS GND
* VDD 3.3V
* CLK SCK
* VSS GND
* D0 MISO
* D1 -
*/
#include "FS.h"
#include "SD.h"
#include "SPI.h"
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
void renameFile(fs::FS &fs, const char * path1, const char * path2){
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
void testFileIO(fs::FS &fs, const char * path){
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if(file){
len = file.size();
size_t flen = len;
start = millis();
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for(i=0; i<2048; i++){
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
void setup(){
Serial.begin(115200);
// GPIO5 connects to SD card CS
if(!SD.begin(5)){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
listDir(SD, "/", 0);
createDir(SD, "/mydir");
listDir(SD, "/", 0);
removeDir(SD, "/mydir");
listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}
void loop(){
}
Result: The serial print output is as follows.
8. Advanced Tutorial
8.1 Timer
Example: RepeatTimer
The program uses Timer 0 for timing and prints the timing results to the serial monitor. The timing stops when the user button on P38 is pressed.
Hardware Required:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
/*
* Repeat Timer Example
* This example demonstrates how to use a hardware timer on the ESP32.
* The timer calls the onTimer function once per second.
* The timer can be stopped using a button connected to PIN 38 (IO38).
* This example code is in the public domain.
*/
// Stop button connected to PIN 38 (IO38)
#define BTN_STOP_ALARM 38
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
volatile uint32_t isrCounter = 0;
volatile uint32_t lastIsrAt = 0;
void ARDUINO_ISR_ATTR onTimer(){
// Increment counter and record interrupt occurrence time
portENTER_CRITICAL_ISR(&timerMux);
isrCounter++;
lastIsrAt = millis();
portEXIT_CRITICAL_ISR(&timerMux);
// Release semaphore to notify loop of the trigger
xSemaphoreGiveFromISR(timerSemaphore, NULL);
// It is safe to use digitalRead/Write here if an output state switch is needed
}
void setup() {
Serial.begin(115200);
// Set BTN_STOP_ALARM as input mode
pinMode(BTN_STOP_ALARM, INPUT);
// Create a semaphore to notify when the timer triggers
timerSemaphore = xSemaphoreCreateBinary();
// Use the first of the four available timers (index starts at 0)
// Set prescaler value to 80
// The board's clock frequency is currently 80MHz, with 80 prescaler, the count unit is microseconds
timer = timerBegin(0, 80, true);
// Attach the onTimer function to the timer
timerAttachInterrupt(timer, &onTimer, true);
// Set timer alarm to trigger onTimer function every second (value in microseconds)
// Enable repeated alarm (third parameter)
timerAlarmWrite(timer, 1000000, true);
// Start the timer alarm
timerAlarmEnable(timer);
}
void loop() {
// If the timer has triggered
if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
uint32_t isrCount = 0, isrTime = 0;
// Read interrupt count and time
portENTER_CRITICAL(&timerMux);
isrCount = isrCounter;
isrTime = lastIsrAt;
portEXIT_CRITICAL(&timerMux);
// Print output
Serial.print("onTimer Trigger Count: ");
Serial.print(isrCount);
Serial.print(" Time: ");
Serial.print(isrTime);
Serial.println(" ms");
}
// If the button is pressed
if (digitalRead(BTN_STOP_ALARM) == LOW) {
// If the timer is still running
if (timer) {
// Stop and release the timer
timerEnd(timer);
timer = NULL;
}
}
}
Result: The serial monitor prints the timer data. When the user button on the board is pressed, the timer stops counting.!
8.2 Watchdog Timer
Example: Task Watchdog Timer (TWDT)
In this example, the watchdog timer is set with an overflow time of 3 seconds. For the first 10 seconds, the watchdog is reset every 2 seconds. After 10 seconds, the watchdog is no longer reset, causing the watchdog timer to overflow and the board to reset.
Hardware Required:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
#include <esp_task_wdt.h>
// 3-second Watchdog Timer (WDT)
#define WDT_TIMEOUT 3
void setup() {
Serial.begin(115200);
Serial.println("Configuring WDT...");
esp_task_wdt_init(WDT_TIMEOUT, true); // Enable panic, ESP32 auto-restarts on WDT timeout
esp_task_wdt_add(NULL); // Add the current thread to WDT monitoring
}
int i = 0; // WDT reset counter
int last = millis(); // Record last reset time
void loop() {
// Reset WDT every 2 seconds, stop after 5 resets
if (millis() - last >= 2000 && i < 5) {
Serial.println("Resetting WDT...");
esp_task_wdt_reset(); // Reset watchdog timer
last = millis(); // Update reset time
i++; // Increment counter
// Stop resetting after the 5th reset, wait for WDT timeout and reboot
if (i == 5) {
Serial.println("Stopping WDT reset, CPU will reboot in 3 seconds");
}
}
}
8.3 RS485 Communication
Example: RS485 Serial Data Transmission
In this example, we use AccessPort software as the debugging tool for sending and receiving serial data.
After uploading the code to a development board, use any USB/RS485/TTL protocol converter to send data to the board.
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
- USB/RS485/TTL Protocol Converter ×1
Example Code:
The program transmits the data received from the USB serial port via the RS485 interface and simultaneously receives RS485 data and sends it out via the USB serial port.
#include <ArduinoRS485.h>
RS485Class RS485;
void setup() {
Serial.begin(9600);
RS485.begin(9600); // Initialize RS485 with a baud rate of 9600
}
bool flag = false;
void loop() {
// If there is data available on the serial port
while (Serial.available()) {
if (!flag) flag = true; // Set the flag to true, indicating the start of transmission
if (flag) RS485.beginTransmission(); // Start RS485 transmission
RS485.write((char)Serial.read()); // Read data from the serial port and send it via RS485
}
// If transmission has started, end RS485 transmission
if (flag) RS485.endTransmission();
flag = false; // Reset the flag
// If there is data available on RS485
while (RS485.available()) {
Serial.write(RS485.read()); // Read data from RS485 and send it to the serial port
}
}
After uploading the program, assume the USB serial port of the development board is COM7.
Connect a USB/RS485/TTL protocol converter to the RS485 interface on the development board, and the converter's USB is connected to the computer. This will trigger the appearance of a USB serial port, COM8.
When the string "Data sent by motherboard" is entered into the development board's USB serial port (COM7), the RS485 converter at COM8 receives the transmitted string.
Similarly, when the string "Data sent by RS485 device" is entered into the RS485 converter's COM8, the development board's USB serial port (COM7) will receive the transmitted string.
8.4 CAN Communication
8.4.1 Example: CAN Bus Reception
This example demonstrates how the Edge101 development board uses the CAN Bus to receive frame data and determine the type of the frame. The user can also turn off the CAN Bus functionality using a user button.
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
- USB-CAN Converter ×1
Hardware Connection:
Example Code:
#include "DFRobot_ESP32CAN.h"
DFRobot_ESP32CAN ESP32Can;
uint8_t userKey = 38;
can_message_t message;
// External interrupt function to stop CAN
void interEvent(void){
ESP32Can.clearReceiveQueue(); // Clear the RX queue
ESP32Can.stop(); // Stop the CAN driver to prevent further transmission and reception
ESP32Can.release(); // Unload the CAN driver
detachInterrupt(userKey); // Detach the interrupt from the specified pin
}
void setup() {
pinMode(userKey, INPUT_PULLUP);
attachInterrupt(userKey,interEvent,CHANGE);
Serial.begin(115200);
/* Please refer to the structure can_general_config_t in DFRobot_ESP32CAN.h and CAN_GENERAL_CONFIG_DEFAULT(op_mode) for further understanding and modification.
Function: Change CAN mode
Modes:
CAN_MODE_NORMAL Normal send/receive/acknowledge mode
CAN_MODE_NO_ACK Send without acknowledgment mode, used for self-testing
CAN_MODE_LISTEN_ONLY Listen-only mode (no sending or acknowledgment, but can receive messages)
*/
can_general_config_t g_config = CAN_GENERAL_CONFIG(CAN_MODE_NORMAL); // Set the general configuration for initialization
/* Please refer to the structure can_timing_config_t in DFRobot_ESP32CAN.h and CAN_TIMING_CONFIG_500KBITS() for further understanding and modification.
Function: Change baud rate
Available baud rates:
CAN_TIMING_CONFIG_25KBITS()
CAN_TIMING_CONFIG_50KBITS()
CAN_TIMING_CONFIG_100KBITS()
CAN_TIMING_CONFIG_125KBITS()
CAN_TIMING_CONFIG_250KBITS()
CAN_TIMING_CONFIG_500KBITS()
CAN_TIMING_CONFIG_800KBITS()
CAN_TIMING_CONFIG_1MBITS()
*/
can_timing_config_t t_config = CAN_TIMING_CONFIG_500KBITS(); // Set the timing configuration for initialization
/* Please refer to the structure can_filter_config_t in DFRobot_ESP32CAN.h and CAN_FILTER_CONFIG_ACCEPT_ALL() for further understanding and modification.
CAN_FILTER_CONFIG_ACCEPT_ALL() {.acceptance_code = 0, .acceptance_mask = 0xFFFFFFFF, .single_filter = true}
Function: Configure filter. The default mask is all 1s, meaning that identifiers must match exactly to be received.
*/
can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
// Initialize with the configured parameters
while(!ESP32Can.init(&g_config,&t_config,&f_config)){
Serial.println("CAN init err!!!");
delay(1000);
}
// Install CAN driver, reset RX and TX queues, and reset RX message count
while(!ESP32Can.start()){
Serial.println("CAN start err!!!");
delay(1000);
}
}
void loop() {
// Receive message function, message is the CAN message on the bus, pdMS_TO_TICKS() sets the blocking time, waiting for the desired data (in milliseconds)
if(ESP32Can.receive(&message,pdMS_TO_TICKS(1000))){
// Check the received ID, multiple IDs can be accepted using '||'
if(message.identifier == 0x0006){
/* Refer to Message flags in DFRobot_ESP32CAN.h
flags:
CAN_MSG_FLAG_NONE Standard format
CAN_MSG_FLAG_EXTD Extended format
CAN_MSG_FLAG_RTR Remote frame (Remote Transmit Request)
CAN_MSG_FLAG_SS Single Shot Transmission
CAN_MSG_FLAG_SELF Self Reception Request
*/
if (message.flags == CAN_MSG_FLAG_NONE) {
Serial.println("Message is in Standard Format");
} else if(message.flags == CAN_MSG_FLAG_EXTD){
Serial.println("Message is in Extended Format");
} else if(message.flags == CAN_MSG_FLAG_RTR){
Serial.println("Message is a Remote Transmit Request");
} else if(message.flags == CAN_MSG_FLAG_SS){
Serial.println("Transmit as a Single Shot Transmission");
} else if(message.flags == CAN_MSG_FLAG_SELF){
Serial.println("Transmit as a Self Reception Request");
} else if(message.flags == CAN_MSG_FLAG_DLC_NON_COMP){
Serial.println("Message's Data length code is larger than 8. This breaks CAN2.0B compliance");
}
// message.data_length_code is by default set to 5 characters in g_config for data transmission
for (int i = 0; i < message.data_length_code; i++) {
Serial.printf("Data byte %d = %d\n", i, message.data[i]);
}
} else {
printf("Error ID:%d\n", message.identifier);
}
} else {
Serial.println("Failed to queue message for receive");
}
delay(10);
}
After uploading the code, use a USB CAN analyzer to send data to the development board.
Results:
The CAN bus on the development board A receives the data and outputs it via the USB serial port.
8.4.2 Example: CAN Bus Transmission
This example demonstrates how the Edge101 development board uses the CAN Bus to send standard frame data. The user can also turn off the CAN Bus functionality using a user button.
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
- USB-CAN Converter ×1
Hardware Connection:
Example Code:
/*!
* @file can_send.ino
* @brief This demo demonstrates the FireBeetle MESH - Industrial IoT Mainboard using CAN to send standard frame data. The CAN functionality can be turned off using a user button.
* @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
* @licence The MIT License (MIT)
* @author [yangfeng]<feng.yang@dfrobot.com>
* @version V1.0
* @date 2021-04-08
* @get from https://www.dfrobot.com
*/
#include "DFRobot_ESP32CAN.h"
DFRobot_ESP32CAN ESP32Can;
uint8_t userKey = 38;
can_message_t tx_message;
void interEvent(void){
ESP32Can.stop();
ESP32Can.release();
detachInterrupt(userKey);
}
void setup() {
pinMode(userKey, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(userKey), interEvent, CHANGE); //Enable external interrupts
Serial.begin(9600);
/** Here we provide annotations for the can_general_config_t structure. For the MESH development board, the default CAN transmit and receive I/O pins are GPIO_35 and GPIO_32.
*
* typedef struct {
* can_mode_t mode; < Mode of CAN controller
* gpio_num_t tx_io; < Transmit GPIO number
* gpio_num_t rx_io; < Receive GPIO number
* gpio_num_t clkout_io; < CLKOUT GPIO number (optional, set to -1 if unused)
* gpio_num_t bus_off_io; < Bus off indicator GPIO number (optional, set to -1 if unused)
* uint32_t tx_queue_len; < Number of messages TX queue can hold (set to 0 to disable TX Queue)
* uint32_t rx_queue_len; < Number of messages RX queue can hold
* uint32_t alerts_enabled; < Bit field of alerts to enable
* uint32_t clkout_divider; < CLKOUT divider. Can be 1 or any even number from 2 to 14 (optional, set to 0 if unused)
* int intr_flags; < Interrupt flags to set the priority of the driver's ISR. Note that to use the ESP_INTR_FLAG_IRAM, the CONFIG_CAN_ISR_IN_IRAM option should be enabled first.
* } can_general_config_t;
*
* mode:
* CAN_MODE_NORMAL, < Normal operating mode where CAN controller can send/receive/acknowledge messages
* CAN_MODE_NO_ACK, < Transmission does not require acknowledgment. Use this mode for self-testing
* CAN_MODE_LISTEN_ONLY, < The CAN controller will not influence the bus (No transmissions or acknowledgments) but can receive messages
*
* CAN_GENERAL_CONFIG_DEFAULT(op_mode) {.mode = op_mode, .tx_io = GPIO_NUM_32, .rx_io = GPIO_NUM_35, \
* .clkout_io = CAN_IO_UNUSED, .bus_off_io = CAN_IO_UNUSED, \
* .tx_queue_len = 5, .rx_queue_len = 5, \
* .alerts_enabled = CAN_ALERT_NONE, .clkout_divider = 0, \
* .intr_flags = ESP_INTR_FLAG_LEVEL1}
*/
can_general_config_t g_config = CAN_GENERAL_CONFIG(CAN_MODE_NORMAL);
/** Here we provide annotations for the can_timing_config_t structure. Users can directly use initialization macros to configure the CAN communication speed.
* typedef struct {
* uint32_t brp; < Baudrate prescaler (i.e., APB clock divider) can be any even number from 2 to 128.
* For ESP32 Rev 2 or later, multiples of 4 from 132 to 256 are also supported
* uint8_t tseg_1; < Timing segment 1 (Number of time quanta, between 1 to 16)
* uint8_t tseg_2; < Timing segment 2 (Number of time quanta, 1 to 8)
* uint8_t sjw; < Synchronization Jump Width (Max time quanta jump for synchronization from 1 to 4)
* bool triple_sampling; < Enables triple sampling when the CAN controller samples a bit
* } can_timing_config_t;
*
* CAN_TIMING_CONFIG_25KBITS() {.brp = 128, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_50KBITS() {.brp = 80, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_100KBITS() {.brp = 40, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_125KBITS() {.brp = 32, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_250KBITS() {.brp = 16, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_500KBITS() {.brp = 8, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_800KBITS() {.brp = 4, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_1MBITS() {.brp = 4, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
*/
can_timing_config_t t_config = CAN_TIMING_CONFIG_500KBITS();
/** Here we provide annotations for the can_filter_config_t structure. Users can directly use initialization macros to configure the reception filter.
*
* typedef struct {
* uint32_t acceptance_code; < 32-bit acceptance code
* uint32_t acceptance_mask; < 32-bit acceptance mask
* bool single_filter; < Use Single Filter Mode
* } can_filter_config_t;
*
* CAN_FILTER_CONFIG_ACCEPT_ALL() {.acceptance_code = 0, .acceptance_mask = 0xFFFFFFFF, .single_filter = true}
*
*/
can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
while(!ESP32Can.init(&g_config,&t_config,&f_config)){
Serial.println("CAN init err!!!");
delay(1000);
}
while(!ESP32Can.start()){
Serial.println("CAN start err!!!");
delay(1000);
}
ESP32Can.clearTransmitQueue();
tx_message.identifier = 0x0006;
tx_message.data_length_code = 4;
/** flags:
* CAN_MSG_FLAG_NONE < No message flags (Standard Frame Format)
* CAN_MSG_FLAG_EXTD < Extended Frame Format (29bit ID)
* CAN_MSG_FLAG_RTR < Message is a Remote Transmit Request
* CAN_MSG_FLAG_SS < Transmit as a Single Shot Transmission
* CAN_MSG_FLAG_SELF < Transmit as a Self Reception Request
*/
tx_message.flags = CAN_MSG_FLAG_NONE;
tx_message.data[0] = 0;
tx_message.data[1] = 1;
tx_message.data[2] = 2;
tx_message.data[3] = 3;
}
void loop() {
if(ESP32Can.transmit(&tx_message, pdMS_TO_TICKS(1000))){
Serial.println("Message queued for transmission");
} else {
Serial.println("Failed to queue message for transmission");
}
delay(1000);
}
Download the code to another board. The board sends one data frame every second. Connect the board's CAN Bus to a USB CAN analyzer.
The USB CAN analyzer receives the data sent by the board as shown in the figure below.
8.5 Bluetooth
The Edge101 mainboard supports dual-mode Bluetooth, which means it can simultaneously support both classic Bluetooth and Bluetooth Low Energy (BLE). The host can run on the same device or be distributed across different devices. The Edge101 mainboard supports both configurations.
8.5.1 Example: Classic Bluetooth (BL)
The mainboard's Bluetooth operates in Bluetooth Classic mode, generating a Bluetooth serial port.
Hardware Required:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
// This example code is in the public domain (or under CC0 license, optional).
// Author: Evandro Copercini - 2018
//
// This example creates a bridge between the serial port and classic Bluetooth (SPP),
// and demonstrates that SerialBT has the same functionality as a regular serial port.
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
BluetoothSerial SerialBT;
void setup() {
Serial.begin(115200);
SerialBT.begin("Edge101_Device"); // Set Bluetooth device name
Serial.println("The device started, now you can pair it with Bluetooth!");
}
void loop() {
// If there's data available in the serial port, send it to Bluetooth
if (Serial.available()) {
SerialBT.write(Serial.read());
}
// If there's data available in Bluetooth, send it to the serial port
if (SerialBT.available()) {
Serial.write(SerialBT.read());
}
delay(20); // Slight delay to reduce CPU usage
}
Install the Serial Bluetooth Terminal app on an Android phone. After enabling Bluetooth on the phone, search for the Edge101_Device Bluetooth device and connect to it.
Open the Serial Bluetooth Terminal app and select the Edge101_Device.
Once connected, data can be sent from the phone to the mainboard, and the mainboard will print out the data sent from the phone via the serial port. The mainboard can also send data back to the phone through the serial port.
8.5.2 Example: Bluetooth Low Energy (BLE)
This program will create a BLE device. When the user button on the mainboard is pressed, the BLE device's name will be changed, and you can observe the change of the BLE device name on your phone.
Hardware Preparation:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Sketch shows how to use SimpleBLE to advertise the name of the device and change it on the press of a button
// Useful if you want to advertise some sort of message
// Button is attached between GPIO 0 and GND, and the device name changes each time the button is pressed
#include "SimpleBLE.h" //Using the SimpleBLE library
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
SimpleBLE ble;
void onButton(){
String out = "BLE32 name: ";
out += String(millis() / 1000);
Serial.println(out);
ble.begin(out); // Change the name of BLE
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
pinMode(38, INPUT_PULLUP); //The user button on the P38 motherboard is used to change the name of BLE devices
Serial.print("Edge101WE SDK: ");
Serial.println(ESP.getSdkVersion());
ble.begin("Edge101WE SimpleBLE");//After enabling Bluetooth on the device, connect to FireBeetle MESH SimpleBLE. When the button is pressed, change the device name.
Serial.println("Press the button to change the device's name");
}
void loop() {
static uint8_t lastPinState = 1;
uint8_t pinState = digitalRead(38); //After enabling Bluetooth on the device, connect to FireBeetle MESH SimpleBLE. When the button is pressed, change the device name.
if(!pinState && lastPinState){
onButton();
}
lastPinState = pinState;
while(Serial.available()) Serial.write(Serial.read());
}
8.6 WiFi
8.6.1 Example: WiFi Scan
WiFi Scan has both synchronous and asynchronous search modes. This example uses synchronous scanning. The drawback is that it runs in blocking mode by default, meaning the program will scan for WiFi and nothing else can be done during this time. You can switch to asynchronous mode by modifying the parameters.
In this example, the WiFi is first set to station mode. If the device is in AP mode and is connected to other devices, the connection will be disconnected.
Then, the WiFi.scanNetworks() function is called to scan for WiFi networks. If networks are found, their information will be printed out.
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
/*
* This example demonstrates how to scan for WiFi networks.
* The API is almost identical to the WiFi Shield library,
* with the most obvious difference being the inclusion of different header files:
*/
#include "WiFi.h"
void setup()
{
Serial.begin(115200);
// Set WiFi to station (client) mode. If the device is in AP (hotspot) mode and connected, it will disconnect.
WiFi.mode(WIFI_STA); // Set to Station mode
WiFi.disconnect(); // Disconnect from the current WiFi connection
delay(100);
Serial.println("Setup done");
}
void loop()
{
Serial.println("scan start");
// The WiFi.scanNetworks() function will return the number of networks found
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.print(n);
Serial.println("networks found");
for (int i = 0; i < n; ++i) {
// Print the SSID (Service Set Identifier) and RSSI (Received Signal Strength Indicator) of each network
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i)); // Print network name
Serial.print(" (");
Serial.print(WiFi.RSSI(i)); // Print signal strength
Serial.print(")");
// Output " " (open network) or "*" (encrypted network) based on the encryption type
// WIFI_AUTH_OPEN represents no encryption (no password required)
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
delay(10);
}
}
Serial.println("");
// Wait for a while before scanning again
delay(5000);
}
Result: The scanned WiFi networks are printed out from the serial port.
8.6.2 Example: Web Page Configuration
Initially, the WiFi device is in AP mode, and the default IP address is 192.168.4.1. By accessing this IP via a web page, users can connect to the AP. In the input fields, users enter the SSID and password of their router's WiFi. Once the WiFi device receives this information, it switches to STA mode and connects to the network using the provided details. The advantage of this method is a 100% success rate, but it requires a button to put the device into configuration mode.
Advantages of Web Page Configuration:
- Direct input makes configuration simple, the process is clear, and the success rate is high.
- The router or hotspot to be connected to is not restricted and does not require an internet connection.
- No need to add additional interfaces to the system, making it suitable for closed or inconvenient scenarios where extra interfaces cannot be exposed.
- The configuration can be done using any device that supports WiFi and a browser, making it very flexible and practical.
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <esp_wifi.h>
const char* AP_SSID = "Edge101_"; // Hotspot name
String wifi_ssid = "";
String wifi_pass = "";
String scanNetworksID = "";// Used to store scanned WiFi
#define ROOT_HTML "<!DOCTYPE html><html><head><title>WIFI Config by DFRobot</title><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><style type=\"text/css\">.input{display: block; margin-top: 10px;}.input span{width: 100px; float: left; float: left; height: 36px; line-height: 36px;}.input input{height: 30px;width: 200px;}.btn{width: 120px; height: 35px; background-color: #000000; border:0px; color:#ffffff; margin-top:15px; margin-left:100px;}</style><body><form method=\"GET\" action=\"connect\"><label class=\"input\"><span>WiFi SSID</span><input type=\"text\" name=\"ssid\"></label><label class=\"input\"><span>WiFi PASS</span><input type=\"text\" name=\"pass\"></label><input class=\"btn\" type=\"submit\" name=\"submit\" value=\"Submit\"> <p><span> Nearby wifi:</P></form>"
WebServer server(80);
#define RESET_PIN 38 // GPIO 38 User Key for deleting WiFi information
void setup() {
Serial.begin(115200);
pinMode(RESET_PIN, INPUT_PULLUP);
// Connect to WiFi
if (!AutoConfig())
{
wifi_Config();
}
// Used to delete stored WiFi
if (digitalRead(RESET_PIN) == LOW) {
Serial.println("Delete WiFi and restart");
delay(1000);
esp_wifi_restore();
delay(10);
ESP.restart(); // Reset ESP32
}
}
void loop() {
server.handleClient();
while (WiFi.status() == WL_CONNECTED) {
// WIFI is connected
}
}
// For configuring WiFi
void wifi_Config()
{
Serial.println("scan start");
// Scan for nearby WiFi networks
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
scanNetworksID = "no networks found";
} else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
scanNetworksID += "<P>" + WiFi.SSID(i) + "</P>";
delay(10);
}
}
Serial.println("");
WiFi.mode(WIFI_AP); // Set to AP mode
boolean result = WiFi.softAP(AP_SSID, ""); // Start WiFi hotspot
if (result)
{
IPAddress myIP = WiFi.softAPIP();
// Print related information
Serial.println("");
Serial.print("Soft-AP IP address = ");
Serial.println(myIP);
Serial.println(String("MAC address = ") + WiFi.softAPmacAddress().c_str());
Serial.println("waiting ...");
} else { // Failed to start hotspot
Serial.println("WiFiAP Failed");
delay(3000);
ESP.restart(); // Reset ESP32
}
if (MDNS.begin("esp32")) {
Serial.println("MDNS responder started");
}
// Homepage
server.on("/", []() {
server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>");
});
// Connect
server.on("/connect", []() {
server.send(200, "text/html", "<html><body><font size=\"10\">Success, WiFi connecting...<br />Please close this page manually.</font></body></html>");
WiFi.softAPdisconnect(true);
// Get the entered WiFi SSID and password
wifi_ssid = server.arg("ssid");
wifi_pass = server.arg("pass");
server.close();
WiFi.softAPdisconnect();
Serial.println("WiFi Connect SSID:" + wifi_ssid + " PASS:" + wifi_pass);
// Set to STA mode and connect to WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(wifi_ssid.c_str(), wifi_pass.c_str());
uint8_t Connect_time = 0; // Used for connection timeout, reset the device if it takes too long
while (WiFi.status() != WL_CONNECTED) { // Wait for WiFi connection
delay(500);
Serial.print(".");
Connect_time++;
if (Connect_time > 80) { // Long connection time, reset the device
Serial.println("Connection timeout, check if input is correct or try again later!");
delay(3000);
ESP.restart();
}
}
Serial.println("");
Serial.println("WIFI Config Success");
Serial.printf("SSID:%s", WiFi.SSID().c_str());
Serial.print(" LocalIP:");
Serial.print(WiFi.localIP());
Serial.println("");
});
server.begin();
}
// For automatic WiFi connection on power-up
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 Failed!" );
return false;
}
8.7 Ethernet
Example: Switching Between Ethernet and WiFi
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code: You need to modify the WiFi SSID and password, then upload the program to the board.
```cpp
/*
Ethernet and WiFi network switching control
Default power-on starts in Ethernet mode:
- Switches to WiFi mode after detecting Ethernet connection timeout
- Automatically switches back to Ethernet mode when Ethernet is restored in WiFi mode
*/
#include <ETH.h>
#include <WiFi.h>
const char* ssid = "yourssid"; // WiFi network name
const char* password = "yourpasswd"; // WiFi password
// Network status flags
static bool eth_connected = false; // Ethernet connection status
bool wifi_mode = false; // WiFi mode flag
bool eth_mode = true; // Ethernet mode flag
uint64_t time_start = 0 ; // Ethernet startup timestamp
uint64_t time_connected = 0 ; // Ethernet connection success timestamp
// WiFi event callback function
void WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case ARDUINO_EVENT_ETH_START: // Ethernet start event
ETH.setHostname("esp32-ethernet"); // Set the device hostname
time_start = millis(); // Record start time
break;
case ARDUINO_EVENT_ETH_CONNECTED: // Physical layer connection established
time_connected = millis();
Serial.println("ETH Connected");
if(wifi_mode){ // If currently in WiFi mode, restart
ESP.restart();
}
break;
case ARDUINO_EVENT_ETH_GOT_IP: // Successfully obtained IP address
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress()); // Print MAC address
Serial.print(", IPv4: ");
Serial.print(ETH.localIP()); // Print IP address
if (ETH.fullDuplex()) { // Full-duplex status check
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed()); // Print connection speed
Serial.println("Mbps");
eth_connected = true; // Update connection status
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:// Physical connection disconnected
Serial.println("ETH Disconnected");
if(!wifi_mode){ // If not in WiFi mode, attempt restart
ESP.restart();
}
eth_connected = false;
eth_mode = false;
break;
case ARDUINO_EVENT_ETH_STOP: // Ethernet stop
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
}
// Network connection test function
void testClient(const char * host, uint16_t port)
{
Serial.print("\nconnecting to ");
Serial.println(host); // Output target host info
WiFiClient client;
// Attempt to establish a TCP connection
if (!client.connect(host, port)) {
Serial.println("connection failed");
return;
}
// Send HTTP request
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
// Wait for server response
while (client.connected() && !client.available());
// Read returned data
while (client.available()) {
Serial.write(client.read());
}
Serial.println("closing connection\n");
client.stop();
}
void setup()
{
Serial.begin(115200); // Initialize serial
WiFi.onEvent(WiFiEvent); // Register network event callback
ETH.begin(); // Start Ethernet
delay(5000); // Wait for 5 seconds to initialize
// Ethernet connection timeout detection (4 seconds without connection)
if((millis()-time_start>4000)&&(time_connected==0)){
// Start WiFi connection
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
wifi_mode = true; // Switch to WiFi mode
}
}
void loop()
{
// Test network in valid connection mode
if (eth_connected||wifi_mode) {
testClient("baidu.com", 80); // Test connection to Baidu server
}
delay(10000); // 10-second detection cycle
}
Next, connect the Ethernet cable to the Ethernet port on the Edge101 motherboard. When the green LED on the Ethernet port is lit, it indicates a successful connection. The orange LED blinking indicates communication.
At this point, the serial monitor will print information such as Ethernet connection success, the Ethernet MAC address, and IP address. The program will then access www.baidu.com every 10 seconds and return the retrieved data.
If the Ethernet cable is unplugged, the serial monitor will display "Ethernet Disconnected." The motherboard will then restart and attempt to connect to the network via WiFi. Once connected, it will access the website.
8.8 4G
The Edge101 motherboard does not come with a 4G module by default, but it supports an expansion board for installing a 4G module.
Example: Fetching Network Time
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code:
/*!
* @file setNTP.ino
* @brief : Network time synchronization example
* @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
* @licence The MIT License (MIT)
* @author [yangfeng]<feng.yang@dfrobot.com>
* @version V1.0
* @date 2021-08-18
*/
#include <DFRobot_AIR720UH.h>
DFRobot_AIR720UH AIR720UH;
void setup(){
int signalStrength,dataNum;
Serial.begin(115200);
Serial1.begin(115200);
while(!Serial);
AIR720UH.begin(Serial1);
// SIM card status check
Serial.println("Check SIM card......");
if(AIR720UH.checkSIMStatus()){ // Check SIM card status
Serial.println("SIM card READY");
}else{
Serial.println("SIM card ERROR, Check if you have inserted SIM card and restart AIR720UH");
while(1);
}
// Signal quality check
Serial.println("Get signal quality......");
delay(500);
signalStrength = AIR720UH.checkSignalQuality(); // Get signal strength
Serial.print("signalStrength =");
Serial.println(signalStrength);
// NTP network time synchronization configuration
delay(500);
Serial.println("set NTP ...");
while(1){
int data = AIR720UH.setNTP();
if(data == 1){
Serial.println("The network time is synchronized successfully!"); // Time synchronization successful
break;
}else if(data == 61){
Serial.println("Network error"); // Network error
break;
}else if(data == 62){
Serial.println("DNS resolution error"); // DNS resolution error
break;
}else if(data == 63){
Serial.println("Connection error"); // Connection error
break;
}else if(data == 64){
Serial.println("Service response error"); // Service response error
break;
}else if(data == 65){
Serial.println("Service response timeout"); // Service response timeout
break;
}else{
Serial.println("set error"); // Unknown error
}
}
}
void loop(){
// Continuously fetch and display the network time
char *buff = AIR720UH.getCLK();
if(buff != NULL){
Serial.println(buff); // Output format example: 2021/08/18 14:30:45
}
}
8.9 Application Layer Protocol
Example: MQTT — Publish and Subscribe
Connect to a public MQTT server, publish a "hello world" message to the "outTopic" every 2 seconds, and have the client listen to the "inTopic" to control a light based on the payload content.
Hardware Required:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
Example Code: Modify the WiFi SSID and password in the code below to your own WiFi SSID and password, then upload the program to the mainboard.
```cpp
#include <WiFi.h>
#include <PubSubClient.h>
#define LED 15 // LED control pin (adjust according to actual hardware connections)
/* Network configuration parameters (need user modification) */
const char* ssid = "your_ssid"; // WiFi network name
const char* password = "your_password"; // WiFi password
const char* mqtt_server = "broker.mqtt-dashboard.com"; // MQTT server address
WiFiClient espClient; // WiFi client instance
PubSubClient client(espClient); // MQTT client instance
long lastMsg = 0; // Last message timestamp
char msg[50]; // Message buffer
int value = 0; // Test counter
/* WiFi connection initialization */
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password); // Start WiFi connection
// Wait for successful connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros()); // Initialize random seed
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP()); // Display obtained IP address
}
/* MQTT message callback function */
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic); // Display message topic
Serial.print("] ");
// Print message content
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
// Control LED based on the first character of the message
if ((char)payload[0] == '0') {
digitalWrite(LED, LOW); // Turn off LED when receiving '0' (low level active)
} else {
digitalWrite(LED, HIGH); // Turn on LED for non-'0' messages
}
}
/* MQTT reconnection mechanism */
void reconnect() {
while (!client.connected()) { // Keep attempting to connect
Serial.print("Attempting MQTT connection...");
// Generate random client ID (to avoid duplication)
String clientId = "FireBeetleClient-";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) { // Connection attempt
Serial.println("connected");
client.publish("outTopic", "hello world"); // Publish initial message
client.subscribe("inTopic"); // Subscribe to input topic
} else {
Serial.print("failed, rc="); // Display error status code
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
/* Initialization setup */
void setup() {
pinMode(LED, OUTPUT); // Initialize LED pin as output
Serial.begin(115200); // Start serial communication
setup_wifi(); // Connect to WiFi network
client.setServer(mqtt_server, 1883); // Configure MQTT server
client.setCallback(callback); // Set message callback function
}
/* Main loop */
void loop() {
if (!client.connected()) { // Maintain MQTT connection
reconnect();
}
client.loop(); // Process MQTT messages
// Publish test message every 2 seconds
long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf(msg, 75, "hello world #%ld", value); // Generate message content
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg); // Publish to specified topic
}
}
Results: The serial output is as follows.
9. Product Dimensions
Unit: mm
Front View Dimensions
Rear View Dimensions
Top View Dimensions
Side View Dimensions
10. Downloads
-
DFR0886_3D.STP
-
DFR0886_2D.pdf
For any questions, advice or cool ideas to share, please visit the DFRobot Forum.