1. 产品描述
1.1 产品简介
LoRaWAN ESP32-S3 开发板是一款聚焦远距离无线通讯与便捷开发的专业硬件,凭借全方位LoRa、LoRaWAN 、Meshtastic协议兼容、HomeAssistant生态接入能力以及高易用性的硬件功能设计,为LoRa/LoRaWAN开发者与智能家居用户提供高效解决方案。
全方位支持 LoRa/LoRaWAN/Meshtastic 通讯协议,通讯兼容性强
LoRaWAN ESP32-S3开发板支持LoRa一对一通讯、LoRa一对多通讯,以及标准的LoRaWAN协议和Meshtastic组网协议,可以自由的实现开发板和开发板之间的通讯,或接入到LoRaWAN网络中。开发板采用Arduino编程,提供了易用的库文件和示例代码,无需深入了解LoRa/LoRaWAN 通讯协议协议即可使用,大幅度降低了上手门槛。
支持接入HomeAssistant(ESPHome),扩展远距离通讯能力
LoRaWAN ESP32-S3开发板支持通过ESPHome接入HomeAssistant,成为系统的 “远距离通讯拓展单元”。有效突破传统无线通讯的距离限制,提升复杂环境下(如多层建筑、大户型、户外场景)的信号覆盖与传输稳定性,拓展智能家居设备的部署范围。
功能丰富易用性高,显著提升测试效率
LoRaWAN ESP32-S3开发板在功能设计上以 “高效易用” 为核心,通过高硬件集成,显著减少测试准备时间与设备连接复杂度:
- 可视化操作与数据查看:集成 0.96 寸LCD屏幕与实体按键,无需依赖外部设备,即可实时查看设备运行数据、通讯状态等关键信息,同时通过按键快速切换显示界面,操作直观便捷。
- 便携续航,摆脱电源束缚:专门设计锂电池接口,并集成充电功能,支持外接锂电池供电,无论是室内桌面测试,还是户外移动场景使用,都能摆脱固定电源限制,使用场景更灵活。
- 易用IO接口,轻松连接传感器:配备便捷 IO 接口,无需焊接即可直接连接温湿度、光照、人体感应等各类传感器设备,解决项目搭建过程中繁琐的接线和焊接工作,高效完成项目原型的构建。
1.2 产品特性
- 支持LoRa、LoRaWAN、Meshtastic远距离通讯协议
- 支持接入HomeAssistant(ESPHome),使HomeAssistant系统支持远距离通讯
- 搭载ESP32-S3主控,支持Arduino、yaml编程
- 功能丰富易用性高,显著提升测试效率
- 集成0.96寸屏幕、按键,便于查看屏幕数据和切换显示
- 集成多组电源、I2C接口,便于连接传感器设备
- 集成锂电池接口和充电功能,便于便携使用
1.3 应用场景
- LoRa/LoRaWAN网络部署调试:通过开发板屏幕测试查看 LoRaWAN 网络信号、通讯状态,快速搭建和调整网络。
- 大户型 / 别墅智能家居扩展:在多层别墅或跨庭院住宅中,轻松连接花园传感器、车库设备与室内控制系统,解决墙体阻隔导致的信号断层问题,实现全屋设备统一管理。
- 户外环境监测场景:搭载温湿度、PM2.5 等传感器,部署于阳台、屋顶或庭院,通过远距离通讯实时回传数据至 HomeAssistant 系统,联动空调、新风设备自动调节室内环境。
- 农业 / 园艺远程管理:放置于菜园、温室或果园中,连接土壤湿度、光照传感器,即使在数百米外的室内也能实时掌握作物生长环境,触发灌溉系统自动作业。
- Meshtastic聊天设备:在偏远地区、山区徒步、森林探险、沙漠穿越等信号薄弱或无网络的户外场景中,借助 Meshtastic 协议构建去中心化的无线电通讯网络,可实时发送文字消息。
2. 技术规格
2.1 产品参数
基本参数
- 工作电压: 3.3V
- Type-C输入电压: 5V DC
- 最大充电电流:300mA
- 屏幕尺寸:0.96寸(160*80)
- 工作温度:-10~60℃
- 模块尺寸:73*45mm
LoRa参数
- 射频芯片:SX1262
- 工作频段:850~930MHz
- 发射功率:16dBm(EU868)/22dBm(US915)
- 接收灵敏度:-137dBm /125kHz SF=12
ESP32-S3参数
- 处理器:Xtensa® 双核32位LX7微处理器
- 主频:240MHz
- SRAM:512KB
- ROM:384KB
- Flash:4MB
- 无线协议:WiFi、Bluetooth 5
2.2 板载功能示意

- Key1:按键1,连接到GPIO18
- Key2:按键2,连接到GPIO0,按下按键并复位可进入boot模式,系统启动后可作为普通按键使用
- LED:LED灯,连接到GPIO21
- RST:复位按键
- 0.96' LCD:0.96寸彩色LCD屏幕,分辨率160*80
- Charge:充电指示灯
- 熄灭:未接入电源或已充满
- 常亮:充电中
- Type-C:代码烧录、供电接口
- Li-ino:3.7V锂电池接口
- BAT-ADC:锂电池电压检测(GPIO1)
- I2C:I2C接口,用于连接I2C传感器
- GPIO:GPIO接口,可作为SPI、ADC、I2S、UART、PWM等功能
- ESP32-S3:ESP32-S3-WROOM-1-N4模组
- SX1262: LoRa收发器
- IPEX1:IPEX 1代天线座,用于连接LoRa天线
2.3 板载功能引脚定义

2.4 IO功能

3. 首次使用
3.1 添加板卡教程
3.2 选择开发板

3.3 下载代码
- 将代码复制到窗口内,点击"Upload"上传代码
- 等待烧录完成,即可看见板载LED灯开始闪烁
若无法烧录、LED未闪烁,请查看常见问题
int led = 21;
void setup() {
pinMode(led,OUTPUT);
}
void loop() {
digitalWrite(led,HIGH);
delay(1000);
digitalWrite(led,LOW);
delay(1000);
}
4. ESP32通用教程
5. 开发板功能示例
5.1 LoRaWAN教程
- LoRaWAN示例需要网关配合
- LoRaWAN协议栈版本1.0.3
- 该部分仅演示部分示例,更多示例代码请在"DFRobot_LoRaWAN\examples"中查看
5.1.1 OTAA入网
功能描述及结果展示
该示例代码通过 OTAA 模式接入 LoRaWAN 网络。每 10 秒发送一次数据(“DFRobot”字符串)。支持接收下行数据并打印。若加入失败,会自动重试。
注意:需要在网关将解析数据设置为text


代码
#include "DFRobot_LoRaWAN.h"
// Data packet transmission interval
#define APP_INTERVAL_MS 10000
const uint8_t DevEUI[8] = {0xDF, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
const uint8_t AppEUI[8] = {0xDF, 0xB7, 0xB7, 0xB7, 0xB7, 0x00, 0x00, 0x00};
const uint8_t AppKey[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
uint8_t port = 2;
uint8_t buffer[255];
LoRaWAN_Node node(DevEUI, AppEUI, AppKey, CLASS_A);
TimerEvent_t appTimer;
void joinCb(bool isOk, int16_t rssi, int8_t snr)
{
if(isOk){
printf("JOIN SUCCESS\n");
TimerSetValue(&appTimer, APP_INTERVAL_MS);
TimerStart(&appTimer);
}else{
printf("OTAA connection error. Restart the connection request packet after 5 seconds.\n");
delay(5000);
node.join(joinCb); // Rejoin the LoRaWAN network
}
}
void userSendUnConfirmedPacket(void)
{
TimerSetValue(&appTimer, APP_INTERVAL_MS);
TimerStart(&appTimer);
const char * data = "DFRobot";
uint32_t datalen = strlen(data);
memcpy(buffer, data, datalen);
node.sendUnconfirmedPacket(port, buffer, /*size=*/datalen);
printf("Sending Unconfirmed Packet...\n");
}
// Receive data callback function
void rxCb(void *buffer, uint16_t size, uint8_t port, int16_t rssi, int8_t snr, bool ackReceived, uint16_t uplinkCounter, uint16_t downlinkCounter)
{
if(size != 0){
printf("data:%s\n", (uint8_t*)buffer);
}
}
void setup()
{
Serial.begin(115200);
delay(5000); // Open the serial port within 5 seconds after uploading to view full print output
if(!(node.init(/*dataRate=*/DR_4, /*txEirp=*/16))){ // Initialize the LoRaWAN node, set the data rate and Tx Eirp
printf("LoRaWAN Init Failed!\nPlease Check: DR or Region\n");
while(1);
}
TimerInit(&appTimer, userSendUnConfirmedPacket); // Initialize timer event
node.setRxCB(rxCb); // Set the callback function for receiving data
node.join(joinCb); // Join the LoRaWAN network
printf("Join Request Packet\n");
}
void loop()
{
delay(1000);
}
5.1.2 ABP入网
功能描述及结果展示
该示例代码通过 ABP 模式接入 LoRaWAN 网络(添加设备时填写任意DEVEUI即可)。每 10 秒发送一次数据(“DFRobot”字符串)。支持接收下行数据并打印。
注意:需要在网关将解析数据设置为text。


代码
#include "DFRobot_LoRaWAN.h"
#define APP_INTERVAL_MS 10000
const uint32_t nodeDevAddr = 0xDF666666;
const uint8_t nodeNwsKey[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
const uint8_t nodeAppsKey[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
};
uint8_t buffer[255];
uint8_t port = 2;
LorawanNode node(nodeDevAddr, nodeNwsKey, nodeAppsKey, CLASS_A);
TimerEvent_t appTimer;
void userSendConfirmedPacket(void)
{
TimerSetValue(&appTimer, APP_INTERVAL_MS);
TimerStart(&appTimer);
const char * data = "DFRobot";
uint32_t datalen = strlen(data);
memcpy(buffer, data, datalen);
node.sendConfirmedPacket(port, buffer, /*size=*/datalen);
printf("Sending Confirmed Packet...\n");
}
void rxCb(void *buffer,uint16_t size,uint8_t port,int16_t rssi,int8_t snr,bool ackReceived,uint16_t uplinkCounter ,uint16_t downlinkCounter)
{
if(size != 0){
printf("data:%s\n", (uint8_t*)buffer);
}
}
void setup()
{
Serial.begin(115200);
delay(5000); // Open the serial port within 5 seconds after uploading to view full print output
if(!(node.init(/*dataRate=*/DR_4, /*txEirp=*/16))){ // Initialize the LoRaWAN node, set the data rate and Tx Eirp
printf("LoRaWAN Init Failed!\nPlease Check: DR or Region\n");
while(1);
}
TimerInit(&appTimer, userSendConfirmedPacket); // Initialize timer event
node.setTxCB(txCb); // Set the callback function for sending data
node.setRxCB(rxCb); // Set the callback function for receiving data
printf("ABP Test\n");
TimerSetValue(&appTimer, APP_INTERVAL_MS);
TimerStart(&appTimer); // Start a timer to send data
}
void loop()
{
delay(1000);
}
5.1.3 LCD_OTAA
功能描述及结果展示
该示例代码通过 OTAA 模式接入 LoRaWAN 网络,每 10 秒发送一次数据(“DFRobot”字符串),使用屏幕显示网络连接、发送和接收状态。
代码
#include "DFRobot_LoRaWAN.h"
LCD_OnBoard screen;
#define BG_COLOR COLOR_RGB565_BLACK // Screen background color
#define TEXT_COLOR COLOR_RGB565_GREEN // Screen font color
#define TEXT_FONT &FreeMono9pt7b // font
#define TEXT_SIZE 1 // Screen font size
#define LINE_HEIGHT 18 // Line height
#define POX_X 0 // Screen print position X coordinate
#define POX_Y 15 // Screen print position Y coordinate
#define LINE_1 0 // Line number
#define LINE_2 1
#define LINE_3 2
#define LINE_4 3
#define APP_INTERVAL_MS 10000
const uint8_t DevEUI[8] = {0xDF, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
const uint8_t AppEUI[8] = {0xDF, 0xB7, 0xB7, 0xB7, 0xB7, 0x00, 0x00, 0x00};
const uint8_t AppKey[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
uint8_t buffer[255];
uint8_t port = 2;
uint32_t counter = 0;
LoRaWAN_Node node(DevEUI, AppEUI, AppKey, CLASS_A);
TimerEvent_t appTimer;
void joinCb(bool isOk, int16_t rssi, int8_t snr)
{
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
if(isOk){
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("JOIN SUCCESS");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Accept Packet");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Rssi = %d", rssi);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("Snr = %d", snr);
TimerSetValue(&appTimer, APP_INTERVAL_MS);
TimerStart(&appTimer);
}else{
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("OTAA join Err!");
delay(5000);
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Restart");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Join Request");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Packet");
node.join(joinCb); // Rejoin the LoRaWAN network
}
}
void userSendUnConfirmedPacket(void)
{
TimerSetValue(&appTimer, APP_INTERVAL_MS);
TimerStart(&appTimer);
const char * data = "DFRobot";
uint32_t datalen = strlen(data);
memcpy(buffer, data, datalen);
node.sendUnconfirmedPacket(port, buffer, /*size=*/datalen);
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Sending %dst", counter++);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("UnConfirmed");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("packet ...");
}
void rxCb(void *buffer, uint16_t size, uint8_t port, int16_t rssi, int8_t snr, bool ackReceived, uint16_t uplinkCounter, uint16_t downlinkCounter)
{
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Rssi = %d", rssi);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Snr = %d", snr);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("UpCount = %d", uplinkCounter);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("DownCount = %d", downlinkCounter);
}
void setup()
{
Serial.begin(115200);
screen.begin();
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("LoRaWAN Node");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Unconfirmed");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("Packet");
delay(2000);
if(!(node.init(/*dataRate=*/DR_4, /*txEirp=*/16))){ // Initialize the LoRaWAN node, set the data rate and Tx Eirp
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("LoRaWAN Init");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Failed!");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Please Check:");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("DR or Region");
while(1);
}
TimerInit(&appTimer, userSendUnConfirmedPacket); // Initialize timer event
node.setRxCB(rxCb); // Set the callback function for receiving data
node.join(joinCb); // Join the LoRaWAN network
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Join Request");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Packet");
}
void loop()
{
delay(100);
}
5.1.4 休眠深度
功能描述及结果展示
该示例代码通过 OTAA 模式接入 LoRaWAN 网络。每 10 秒发送一次数据(“DFRobot”字符串)。接收下行消息(带有 ACK 或数据)。使用屏幕显示网络连接、发送和接收状态。支持唤醒源(按键唤醒)识别和处理。
代码
#include "DFRobot_LoRaWAN.h"
#define BTN_PIN 18 // GPIO2, 3, 11, 12, 13 can all trigger external wake-up
LCD_OnBoard screen;
#define BG_COLOR COLOR_RGB565_BLACK // Screen background color
#define TEXT_COLOR COLOR_RGB565_GREEN // Screen font color
#define TEXT_FONT &FreeMono9pt7b // font
#define TEXT_SIZE 1 // Screen font size
#define LINE_HEIGHT 18 // Line height
#define POX_X 0 // Screen print position X coordinate
#define POX_Y 15 // Screen print position Y coordinate
#define LINE_1 0 // Line number
#define LINE_2 1
#define LINE_3 2
#define LINE_4 3
#define APP_INTERVAL_MS 10000
const uint8_t DevEUI[8] = {0xDF, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
const uint8_t AppEUI[8] = {0xDF, 0xB7, 0xB7, 0xB7, 0xB7, 0x00, 0x00, 0x00};
const uint8_t AppKey[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
uint8_t buffer[255];
uint8_t port = 2;
LoRaWAN_Node node(DevEUI, AppEUI, AppKey, CLASS_A);
// Rejoin count
RTC_DATA_ATTR uint8_t CurReJoinTimes = 0;
// Downlink Reception Success Flag
uint8_t rxFlag = 1;
uint32_t prevTimeStamp = 0;
const char* wakeup_reason_strings[] =
{
"ESP_SLEEP_WAKEUP_UNDEFINED",
"ESP_SLEEP_WAKEUP_ALL",
"ESP_SLEEP_WAKEUP_EXT0",
"ESP_SLEEP_WAKEUP_EXT1",
"ESP_SLEEP_WAKEUP_TIMER",
"ESP_SLEEP_WAKEUP_TOUCHPAD",
"ESP_SLEEP_WAKEUP_ULP",
"ESP_SLEEP_WAKEUP_GPIO",
"ESP_SLEEP_WAKEUP_UART",
"ESP_SLEEP_WAKEUP_WIFI",
"ESP_SLEEP_WAKEUP_COCPU",
"ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG",
"ESP_SLEEP_WAKEUP_BT"
};
// Join network callback function
void joinCb(bool isOk, int16_t rssi, int8_t snr)
{
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
if(isOk){
CurReJoinTimes = 0;
printf("JOIN SUCCESS\n");
printf("JoinAccept Packet rssi = %d snr = %d\n", rssi, snr);
printf("NetID = %06X\n", node.getNetID());
printf("DevAddr = %08X\n", node.getDevAddr());
uint8_t * NwkSKey = node.getNwkSKey();
uint8_t * AppSKey = node.getAppSKey();
printf("NwkSKey=0X");
for(uint8_t i= 0; i < 16; i++){
printf("%02X", NwkSKey[i]);
}
printf("\n");
printf("AppSKey=0X");
for(uint8_t i = 0; i < 16; i++){
printf("%02X", AppSKey[i]);
}
printf("\n");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("JOIN SUCCESS");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Accept Packet");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Rssi = %d", rssi);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("Snr = %d", snr);
delay(5000);
node.deepSleepMs(APP_INTERVAL_MS); // Deep sleep after successful network join
}else{
printf("OTAA join error\n");
printf("Check Whether the device has been registered on the gateway!\n");
printf("deviceEUI and appKey are the same as the devices registered on the gateway\n");
printf("Ensure that there is a gateway nearby\n");
printf("Check whether the antenna is normal\n");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("OTAA join Err!");
delay(2000);
// Backoff join procedure
CurReJoinTimes++;
// printf("\n\n------CurReJoinTimes = %d------\n\n", CurReJoinTimes);
uint64_t backoff_time_ms = 5000 * (1ULL << (CurReJoinTimes - 1));
backoff_time_ms = (backoff_time_ms > 300000) ? 300000 : backoff_time_ms;
node.deepSleepMs(backoff_time_ms);
}
}
void userSendConfirmedPacket(void)
{
const char * data = "DFRobot";
uint32_t datalen = strlen(data);
memcpy(buffer, data, datalen);
node.sendConfirmedPacket(port, buffer, /*size=*/datalen);
rxFlag = 0;
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Sending...");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Confirmed");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Packet");
}
// Receive data callback function
void rxCb(void *buffer, uint16_t size, uint8_t port, int16_t rssi, int8_t snr, bool ackReceived, uint16_t uplinkCounter, uint16_t downlinkCounter)
{
rxFlag = 1;
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
if(ackReceived == true){
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("this is a ACK");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Rssi = %d", rssi);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Snr = %d", snr);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("DownCount = %d", downlinkCounter);
}
delay(3000);
node.deepSleepMs(APP_INTERVAL_MS); // MCU sleep for a specified duration
}
// Handle button-triggered wakeup: display node info and return to sleep
void buttonWakeupHandler()
{
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("buttonCB");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("dataRate: %d\n", node.getDataRate());
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("txEirp: %d\n", node.getEIRP());
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("netID: %d\n", node.getNetID());
printf("LastDownlinkCounter = %d\n", node.getLastDownCounter());
printf("LastUplinkCounter = %d\n", node.getLastUplinkCounter());
delay(5000);
node.deepSleepMs(APP_INTERVAL_MS); // MCU sleep for a specified duration
}
void setup()
{
Serial.begin(115200);
screen.begin();
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("WakeUp");
delay(2000);
// Set to wake up using a button press
esp_sleep_enable_ext0_wakeup((gpio_num_t )BTN_PIN, LOW);
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
if (wakeup_reason >= ESP_SLEEP_WAKEUP_UNDEFINED && wakeup_reason <= ESP_SLEEP_WAKEUP_BT) {
printf("\n\n------Wakeup reason: [%s]------\n\n", wakeup_reason_strings[wakeup_reason]);
} else {
printf("\n\n------Wakeup reason: [UNKNOWN]------\n\n");
}
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
buttonWakeupHandler();
}
if(!(node.init(/*dataRate=*/DR_4, /*txEirp=*/16))){ // Initialize the LoRaWAN node, set the data rate and Tx Eirp
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("LoRaWAN Init");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Failed!");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Please Check:");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("DR or Region");
while(1);
}
node.setRxCB(rxCb); // Set the callback function for receiving data
if(!node.isJoined()) {
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Join Request");
node.join(joinCb); // Join the LoRaWAN network
} else {
userSendConfirmedPacket(); // Send data
}
}
void loop()
{
// Prevent prolonged downlink waiting from blocking deep sleep and increasing power consumption
uint32_t currTimeStamp = TimerGetCurrentTime();
if (currTimeStamp - prevTimeStamp >= APP_INTERVAL_MS * 2) {
prevTimeStamp = currTimeStamp;
if (!rxFlag) {
node.deepSleepMs(APP_INTERVAL_MS);
}
}
delay(1000);
}
5.2 LoRa教程
该部分仅演示部分示例,更多示例代码请在"DFRobot_LoRaWAN\examples\DFRobot_LoRaRadio"中查看
5.2.1 LoRa收发数据
功能描述及结果展示
发送端:向接收端发送数据,并在屏幕上显示发送次数
接收端:接收发送端的数据,并在屏幕上显示接收数据次数
代码
发送端
#include "DFRobot_LoRaRadio.h"
LCD_OnBoard screen;
#define BG_COLOR COLOR_RGB565_BLACK // Screen background color
#define TEXT_COLOR COLOR_RGB565_GREEN // Screen font color
#define TEXT_FONT &FreeMono9pt7b // font
#define TEXT_SIZE 1 // Screen font size
#define LINE_HEIGHT 18 // Line height
#define POX_X 0 // Screen print position X coordinate
#define POX_Y 15 // Screen print position Y coordinate
#define LINE_1 0 // Line number
#define LINE_2 1
#define LINE_3 2
#define LINE_4 3
#ifdef REGION_EU868
#define RF_FREQUENCY 868000000 // Hz
#define TX_EIRP 16 // dBm
#endif
#ifdef REGION_US915
#define RF_FREQUENCY 915000000 // Hz
#define TX_EIRP 22 // dBm
#endif
#define LORA_SPREADING_FACTOR 7
DFRobot_LoRaRadio radio;
uint8_t buffer[4] = {1, 2, 3, 4};
uint32_t counter = 0;
// Transmission complete callback function
void loraTxDone(void)
{
printf("-------------------------LoRa Tx done-----------------------------\n");
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Send %dst", counter);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("done");
}
void setup()
{
Serial.begin(115200); // Initialize serial communication with a baud rate of 115200
screen.begin();
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("LoRa Send Test");
delay(5000); // Open the serial port within 5 seconds after uploading to view full print output
radio.init(); // Initialize the LoRa node with a default bandwidth of 125 KHz
radio.setTxCB(loraTxDone); // Set the transmission complete callback function
radio.setFreq(RF_FREQUENCY); // Set the communication frequency
radio.setEIRP(TX_EIRP); // Set the Tx Eirp
radio.setSF(LORA_SPREADING_FACTOR); // Set the spreading factor
radio.setBW(BW_125); // Set the bandwidth
}
void loop()
{
printf("statistics: send %d packet\n", ++counter); // Print the prompt message
radio.sendData(buffer, /*size=*/4); // Send data
delay(3 * 1000); // Delay 3 seconds before sending next data
}
接收端
#include "DFRobot_LoRaRadio.h"
LCD_OnBoard screen;
#define BG_COLOR COLOR_RGB565_BLACK // Screen background color
#define TEXT_COLOR COLOR_RGB565_GREEN // Screen font color
#define TEXT_FONT &FreeMono9pt7b // font
#define TEXT_SIZE 1 // Screen font size
#define LINE_HEIGHT 18 // Line height
#define POX_X 0 // Screen print position X coordinate
#define POX_Y 15 // Screen print position Y coordinate
#define LINE_1 0 // Line number
#define LINE_2 1
#define LINE_3 2
#define LINE_4 3
#ifdef REGION_EU868
#define RF_FREQUENCY 868000000 // Hz
#define TX_EIRP 16 // dBm
#endif
#ifdef REGION_US915
#define RF_FREQUENCY 915000000 // Hz
#define TX_EIRP 22 // dBm
#endif
#define LORA_SPREADING_FACTOR 7
DFRobot_LoRaRadio radio;
uint8_t buffer[4] = {1, 2, 3, 4};
uint32_t counter = 0;
void loraRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
{
uint8_t i = 0;
printf("LoRa data received on channel %ld, SF=%d Rssi=%d Snr=%d \nData={",RF_FREQUENCY, LORA_SPREADING_FACTOR, rssi, snr);
for(; i < size-1; i++){
printf("0x%02x, ", payload[i]);
}
printf("0x%02x}\n\n", payload[i]);
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Recv %dst", ++counter);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("packet");
}
void loraRxError(void)
{
printf("LoRaRxError\n");
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("LoRaRxError");
}
void setup()
{
Serial.begin(115200); // Initialize serial communication with a baud rate of 115200
screen.begin();
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("LoRa Recv Test");
delay(5000); // Open the serial port within 5 seconds after uploading to view full print output
radio.init(); // Initialize the LoRa node with a default bandwidth of 125 KHz
radio.setRxCB(loraRxDone); // Set the receive complete callback function
radio.setRxErrorCB(loraRxError); // Set the receive error callback function
radio.setFreq(RF_FREQUENCY); // Set the communication frequency
radio.setSF(LORA_SPREADING_FACTOR); // Set the spreading factor
radio.setBW(BW_125); // Set the bandwidth
radio.startRx(); // Start receiving
}
void loop()
{
delay(3000);
}
6. 项目应用示例
6.1 上传温湿度数据到LoRaWAN网关
功能描述及结果展示
该示例代码通过 OTAA 模式接入 LoRaWAN 网络,每 30 秒读取一次SHT31(I2C地址0x45)温湿度传感器数据显示在屏幕上并发送到网关,然后休眠。可以通过按键(IO18),主动唤醒主控采集数据并发送。
代码
#include "DFRobot_LoRaWAN.h"
#include <DFRobot_SHT3x.h>
// Button pin
#define BTN_PIN 18 // GPIO2, 3, 11, 12, 13 can all trigger external wake-up
LCD_OnBoard screen;
#define BG_COLOR COLOR_RGB565_BLACK // Screen background color
#define TEXT_COLOR COLOR_RGB565_GREEN // Screen font color
#define TEXT_FONT &FreeMono9pt7b // font
#define TEXT_SIZE 1 // Screen font size
#define LINE_HEIGHT 18 // Line height
#define POX_X 0 // Screen print position X coordinate
#define POX_Y 15 // Screen print position Y coordinate
#define LINE_1 0 // Line number
#define LINE_2 1
#define LINE_3 2
#define LINE_4 3
// Data packet transmission interval
#define APP_INTERVAL_MS 30000
const uint8_t DevEUI[8] = {0xDF, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
const uint8_t AppEUI[8] = {0xDF, 0xB7, 0xB7, 0xB7, 0xB7, 0x00, 0x00, 0x00};
const uint8_t AppKey[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
uint8_t buffer[255];
uint8_t port = 2;
LoRaWAN_Node node(DevEUI, AppEUI, AppKey, CLASS_A);
DFRobot_SHT3x sht3x;
// Rejoin count
RTC_DATA_ATTR uint8_t CurReJoinTimes = 0;
// Join network callback function
void joinCb(bool isOk, int16_t rssi, int8_t snr)
{
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
if(isOk){
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("JOIN SUCCESS");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Accept Packet");
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_3);
screen.printf("Rssi = %d", rssi);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_4);
screen.printf("Snr = %d", snr);
delay(1000);
node.deepSleepMs(APP_INTERVAL_MS); // Deep sleep after successful network join
}else{
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("OTAA join Err!");
delay(2000);
// Backoff join procedure
CurReJoinTimes++;
uint64_t backoff_time_ms = 5000 * (1ULL << (CurReJoinTimes - 1));
backoff_time_ms = (backoff_time_ms > 300000) ? 300000 : backoff_time_ms;
node.deepSleepMs(backoff_time_ms);
}
}
void userSendConfirmedPacket(void)
{
float temperature = sht3x.getTemperatureC();
float humidity = sht3x.getHumidityRH();
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Temp: %.2f C", temperature);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_2);
screen.printf("Humi: %.2f %%", humidity);
char data[64];
snprintf((char*)data, sizeof(data), "T:%.2f,H:%.2f", temperature, humidity);
uint32_t datalen = strlen(data);
memcpy(buffer, data, datalen);
node.sendUnconfirmedPacket(port, buffer, datalen);
delay(4000); //最少需要4S延时
node.deepSleepMs(APP_INTERVAL_MS);
}
void setup()
{
Serial.begin(115200);
screen.begin();
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
while (sht3x.begin() != 0) {
screen.fillScreen(BG_COLOR);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("SHT3x Err");
delay(1000);
}
delay(1000);
// Set to wake up using a button press
esp_sleep_enable_ext0_wakeup((gpio_num_t )BTN_PIN, LOW);
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
if(!(node.init(/*dataRate=*/DR_4, /*txEirp=*/16))){ // Initialize the LoRaWAN node, set the data rate and Tx Eirp
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("LoRaWAN Init Failed!");
while(1);
}
if(!node.isJoined()) {
screen.fillScreen(BG_COLOR);
screen.setTextColor(TEXT_COLOR);
screen.setFont(TEXT_FONT);
screen.setTextSize(TEXT_SIZE);
screen.setCursor(POX_X, POX_Y + LINE_HEIGHT * LINE_1);
screen.printf("Join Request");
node.join(joinCb); // Join the LoRaWAN network
} else {
userSendConfirmedPacket(); // Send data
}
}
void loop()
{
delay(1000);
}
6.2 Meshtastic通讯
Meshtastic是一种基于LoRa技术的离网通信平台。它通过低成本、低功耗的无线电设备,实现远距离的通信。无论是在通信基础设施缺失的地区,还是在现有网络瘫痪的情况下,Meshtastic 都能提供可靠的解决方案。这个项目完全由社区驱动,并且开源,适用于户外探险、徒步旅行,应急通信、公益救援等场景。

固件
通过FLASH下载工具可以直接将固件下载到开发板中,快速体验
使用方法
- 下载Meshtastic手机APP
- 烧录固件复位设备后
- 打开Meshtastic手机APP,点击"Scan",找到"Meshtastic_xxxx",并连接(配对密码为"123456")

- 设备成功连接后,进入频道分享页面,可看到自己频道的二维码,点击"Scan"可扫描其他人的二维码进入频道

- 点击聊天页面,点击对应频道即可聊天

更多链接
6.3 接入HomeAssistant
LoRaWAN ESP32-S3开发板可接入HomeAssistant网关,可以使网关可以远距离接收到传感器数据
- 设置 -> 加载项 -> 加载项商店 -> 搜索"ESPHome" -> 选择"ESPHome Device Builder(beta)" -> 点击安装


- 在侧边栏点击"ESPHome Builder" -> 点击"NEW DEVICE" -> 在弹出窗口点击"CONTINUE" -> 输入名称,点击NEXT -> 选择ESP32-S3 -> 在弹出窗口点击"SKIP"

- 点击"EDIT"进入代码编辑页面 -> 在"captive_portal"下方添加代码


代码
# Example configuration entry
spi:
clk_pin: GPIO7
mosi_pin: GPIO6
miso_pin: GPIO5
sx126x:
dio1_pin: GPIO4
cs_pin: GPIO10
busy_pin: GPIO40
rst_pin: GPIO41
pa_power: 3
bandwidth: 125_0kHz
crc_enable: true
frequency: 433920000
modulation: LORA
hw_version: sx1262
rf_switch: true
sync_value: [0x14, 0x24]
preamble_size: 8
spreading_factor: 7
coding_rate: CR_4_6
tcxo_voltage: 1_8V
tcxo_delay: 5ms
更多配置参数可参考:https://beta.esphome.io/components/sx126x
- 烧录代码
7. FLASH下载工具使用教程
8. 常见问题
- 无法将代码下载到开发板 / 找不到COM口 / COM口不断出现又消失 / 串口不断打印复位信息
- 请按住BOOT按键,然后点击RST,再下载代码即可
9. 资料下载
- 硬件原理图
- 硬件尺寸、元件位置图
- ESP32-S3-WROOM-1-N4 模组手册
- 其他重要元件资料(电源芯片、充电芯片、屏幕等)
- 天线规格书
- 外壳文件
- 2D文件
- 3D模型文件
- KICAD文件