首页
统计
留言
投币
友链
关于
Search
1
抖音鸡汤(一)
15 阅读
2
扩展:268条PCB Layout设计规范!
7 阅读
3
新版Keilv5安装相关问题大全
7 阅读
4
Arduino库介绍——AccelStepper
6 阅读
5
Ubuntu系统——虚拟机ubuntu22.04没有网
3 阅读
基础
CPP语法
算法题
硬件设计
PCBLayout
电子设计
单片机
ESP32
STM32
STC51
Arduino
LuatOS
FreeRTOS
LVGL
Linux
QT
树莓派
T113S3
Linux系统
Linux应用开发
Linux驱动开发
IoT
MQTT
Lora
NB-IOT
米家
涂鸦
AI
OpenCV
项目
杂谈 | 日记
投资笔记
登录
Search
标签搜索
Arduino
ESP32
PCBLayout
鸡汤
ubuntu
步进电机
KEIL
CPP
QT
OTA
会焊工的程序猿
累计撰写
10
篇文章
累计收到
0
条评论
首页
栏目
基础
CPP语法
算法题
硬件设计
PCBLayout
电子设计
单片机
ESP32
STM32
STC51
Arduino
LuatOS
FreeRTOS
LVGL
Linux
QT
树莓派
T113S3
Linux系统
Linux应用开发
Linux驱动开发
IoT
MQTT
Lora
NB-IOT
米家
涂鸦
AI
OpenCV
项目
杂谈 | 日记
投资笔记
页面
统计
留言
投币
友链
关于
搜索到
2
篇与
的结果
2026-02-02
ESP32网络远程OTA升级
什么是OTA?OTA(Over-the-AirTechnology)即空中下载技术,是通过移动通信的空中接口实现对移动终端设备及SIM卡数据进行远程管理的技术。OTA升级是物联网(IOT)产品设计的一个非常重要的部分,能够实现智能设备系统漏洞修复、系统升级,通过固件和软件的升级,提供更好的服务。OTA固件升级功能不仅能够更新固件,而且还能重新配置芯片上硬件资源。同时,设备固件可通过OTA固件升级流程获得更新的补丁和更多安全算法防范病毒攻击。ESP32支持OTA,为什么要使用OTA?ESP32集成了2.4GHzWi-Fi和蓝牙双模,以其超高的射频性能、稳定性、通用性和可靠性,以及超低的功耗,满足不同的功耗需求,适用于各种物联网应用场景,受到低成本系统和制造商的欢迎。此外,使用ESP32 OTA还可以实现远程控制,即通过网络来远程控制设备。例如,我们可以通过网络将新的固件发送到设备,实现设备的远程升级。总之,使用OTA可以提高设备的维护效率,方便我们进行远程控制和升级。因此,ESP32支持OTA升级是非常有用的功能。如何在ESP32上实现OTA?通过http请求获取远程固件,实现升级,因此必须有一个固件的下载地址,本次示例是基于Arduino的 HTTPUpdate.h ,MQTT云平台使用的是巴法云的物联网平台服务。 该平台提供地址不变的最新版固件地址,且提供可追溯历史版本的固件地址,通过巴法物联网云平台示例源码示例源码主要分为 main.cpp和 dapensonOTA.hpp组成 ,使用到MQTT,因此添加 #include <PubSubClient.h>,github下载最新发行版即可。首先将示例代码烧录到开发板,串口打印消息记录版本号;下一步修改固件输出信息,并上传至巴法云OTA,从云端下发OTA升级指令触发升级操作。等待升级完成并串口打印比对修改过的固件输出信息,验证是否成功。/* Project: [巴法云mqtt灯控] Author: [Dapenson] Date: [2022-12-14] Description: [通过配置接入信息接入巴法云,并可通过巴法云的APP控制灯的开关和亮度,灯控使用pwm函数analogWrite()控制,输入on/off/on#亮度,] Revisions: [2022-12-14] - [添加on和off的判断,当打开on的时候,亮度默认为10%] [2022-12-14] - [新增OTA功能,需在wifi配置留下一个特定wifi,用于OTA升级,收到Dapenson-Update关键字后会自动升级,串口打印日志] ... */ #include <Arduino.h> #include <WiFi.h> #include <PubSubClient.h> #include "dapensonOTA.hpp" /***************** 函数声明 *************************/ void serialEvent(); void lightControl(int brightness); void mqttCallback(char *topic, byte *payload, unsigned int length); void connectWIFI(); void connectMQTT(); void setup(); void loop(); /***************** 全局变量 *************************/ #define LED_PIN 2 #define MQTT_SERVER "bemfa.com" // 定义MQTT服务器的地址 #define MQTT_PORT 9501 // 定义MQTT服务器的端口 #define MQTT_CLIENT_ID "f5c5108e75xxxxxxxx6ebbf2" // 定义客户端的ID=私钥 #define MQTT_USERNAME "myusername" // 定义用户名=任意 #define MQTT_PASSWORD "mypassword" // 定义密码= 任意 #define TOPIC_SUBSCRIBE "HLlight002" // 定义订阅的主题 // 定义多组Wi-Fi配置信息 const char *ssid[] = {"Hangxxxx", "cc", "c", "Dapenson"}; const char *password[] = {"1axxxx", "mmmmmxxxx", "187xxxx", "Dapenson"}; int brightness_tar = 0; // 定义目标亮度值,初始为灭 // 定义串口输入缓冲区大小 #define INPUT_BUFFER_SIZE 64 // 定义MQTT客户端对象 WiFiClient espClient; PubSubClient mqttClient(espClient); /***************** 函数定义 *************************/ // 定义灯控函数 void lightControl(int brightness) { // 限制频率和占空比在合理范围内 (1Hz - 10000Hz, 0% - 100%) // https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/ledc.html#api brightness = constrain(brightness, 0, 100); int dutyCycle = map(brightness, 0, 100, 0, 255); analogWrite(LED_PIN, dutyCycle); Serial.printf("Set brightness to %d%%\n", brightness); } // 定义MQTT回调函数,用于处理从服务器接收到的消息 void mqttCallback(char *topic, byte *payload, unsigned int length) { // 将接收到的消息转换为字符串 char message[length + 1]; memcpy(message, payload, length); message[length + 1] = '\0'; Serial.printf("Message arrived [%s]%d: %s\n", topic, length, message); // 检测是否升级指令 if (strstr(message, "Dapenson-Update") != NULL) { updateBin(); // 执行升级函数,完成后直接重启 } brightness_tar = 0; if (strstr(message, "on") != NULL) { brightness_tar = 10; int dutyCycle = 0; // 如果成功解析出1个整数,则执行 if 语句中的代码。 if (sscanf(message, "on#%d", &dutyCycle) == 1) { // 将提取到的值赋值给目标值 brightness_tar = dutyCycle; } } // 调用灯控函数,设置灯的状态 lightControl(brightness_tar); } // 定义连接Wi-Fi函数 void connectWIFI() { // 连接Wi-Fi网络 bool connected = false; for (int i = 0; i < 3; i++) { int time_connect = 0; WiFi.begin(ssid[i], password[i]); while (WiFi.status() != WL_CONNECTED) { if (time_connect > 10) { time_connect = 0; break; } delay(1000); Serial.print("Connecting to WiFi..."); Serial.println(ssid[i]); time_connect++; } if (WiFi.status() == WL_CONNECTED) { connected = true; Serial.printf("Connected to %s , IP :%s\n", ssid[i], WiFi.localIP().toString().c_str()); break; } } // 如果没有连接到Wi-Fi网络,则输出错误信息 if (!connected) { Serial.println("Failed to connect to WiFi!"); delay(5000); ESP.restart(); } } // 连接MQTT服务器 void connectMQTT() { if (!mqttClient.connected()) { Serial.println("Connecting to MQTT server..."); if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) { Serial.println("Connected to MQTT: " MQTT_SERVER); // 订阅主题 mqttClient.subscribe(TOPIC_SUBSCRIBE); Serial.println("subscribed to topic: " TOPIC_SUBSCRIBE); } } } void setup() { Serial.begin(115200); delay(100); getVersion(); // 获取版本号 // 初始化GPIO8引脚为输出模式 pinMode(LED_PIN, OUTPUT); // 将12、13引脚拉低 pinMode(12, OUTPUT); pinMode(13, OUTPUT); digitalWrite(12, LOW); digitalWrite(13, LOW); // 调用灯控函数,设置灯的状态 lightControl(brightness_tar); // 连接Wi-Fi connectWIFI(); // 设置MQTT服务器的地址和端口 mqttClient.setServer(MQTT_SERVER, MQTT_PORT); // 设置MQTT回调函数 mqttClient.setCallback(mqttCallback); } void loop() { delay(2); // 判断 WiFi 连接状态 if (WiFi.status() != WL_CONNECTED) { // 如果没有连接到 WiFi,则进行连接 connectWIFI(); } if (!mqttClient.connected()) { connectMQTT(); } // 处理MQTT消息 mqttClient.loop(); } // 串口0事件 void serialEvent() { // 检查串口是否有数据可读 if (Serial.available()) { // 定义串口输入缓冲区 char inputBuffer[INPUT_BUFFER_SIZE]; // 读取串口输入到缓冲区 Serial.readBytesUntil('\n', inputBuffer, INPUT_BUFFER_SIZE); // 提取占空比 int dutyCycle = 0; if (sscanf(inputBuffer, "on#%d", &dutyCycle) == 1) { // 将提取到的值赋值给目标值 brightness_tar = dutyCycle; // 发布消息到主题 mqttClient.publish(TOPIC_SUBSCRIBE, inputBuffer, sizeof(inputBuffer)); Serial.printf("Published message: %s\n", inputBuffer); } } }#ifndef DAPENSON_OTA_H #define DAPENSON_OTA_H #include <Arduino.h> #ifdef ESP8266 #include <ESP8266WiFi.h> #include <ESP8266httpUpdate.h> #elif defined(ESP32) #include <HTTPUpdate.h> #include <WiFi.h> #endif /***************** 函数声明 *************************/ void update_started(); void update_finished(); void update_progress(int cur, int total); void update_error(int err); void updateBin(); void getVersion(); /***************** 全局变量 *************************/ String upUrl = "http://bin.bemfa.com/b/1BcZjVjNTEwOGU3NTRkNjZkZmI3YTRjYzAwY2U2ZWJiZjI=otaTest.bin"; // 固件链接,在巴法云控制台复制、粘贴到这里即可 void getVersion() { Serial.println(F("=====================================")); Serial.println(F("Version: 1.1.0")); Serial.println(F("Author: Dapenson")); Serial.println(F("Date: 2022-12-14")); Serial.println(F("=====================================")); } // 当升级开始时,打印日志 void update_started() { Serial.println("CALLBACK: HTTP update process started"); } // 当升级结束时,打印日志 void update_finished() { Serial.println("CALLBACK: HTTP update process finished"); } // 当升级中,打印日志 void update_progress(int cur, int total) { Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total); } // 当升级失败时,打印日志 void update_error(int err) { Serial.printf("CALLBACK: HTTP update fatal error code %d\n", err); } /** * 固件升级函数 * 在需要升级的地方,加上这个函数即可,例如setup中加的updateBin(); * 原理:通过http请求获取远程固件,实现升级 */ void updateBin() { Serial.println("start update"); WiFiClient UpdateClient; #ifdef ESP8266 ESPhttpUpdate.onStart(update_started); // 当升级开始时 ESPhttpUpdate.onEnd(update_finished); // 当升级结束时 ESPhttpUpdate.onProgress(update_progress); // 当升级中 ESPhttpUpdate.onError(update_error); // 当升级失败时 t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl); #elif defined(ESP32) httpUpdate.onStart(update_started); // 当升级开始时 httpUpdate.onEnd(update_finished); // 当升级结束时 httpUpdate.onProgress(update_progress); // 当升级中 httpUpdate.onError(update_error); // 当升级失败时 t_httpUpdate_return ret = httpUpdate.update(UpdateClient, upUrl); #endif switch (ret) { case HTTP_UPDATE_FAILED: // 当升级失败 Serial.println("[update] Update failed."); break; case HTTP_UPDATE_NO_UPDATES: // 当无升级 Serial.println("[update] Update no Update."); break; case HTTP_UPDATE_OK: // 当升级成功 Serial.println("[update] Update ok."); break; } delay(10000); ESP.restart(); } #endif
2026年02月02日
2 阅读
0 评论
0 点赞
2026-01-21
Arduino库介绍——AccelStepper
仓库地址: https://github.com/waspinator/AccelStepper.git以下为 AccelStepper 常用 API 的简要注释(速查表,示例签名为伪代码以便快速理解):// 类与构造 AccelStepper(interface, pin1, pin2, pin3 = -, pin4 = -, enablePin = -) // interface: 驱动类型(2线/4线/驱动器等)。构造器也有简化形式用于 STEP/DIR 驱动。 // 运动参数设置 setMaxSpeed(float maxSpeed) // 设置最大速度(步/秒) setAcceleration(float accel) // 设置加速度(步/秒^2) setSpeed(float speed) // 直接设置当前速度(步/秒),不改变目标位置 maxSpeed() / acceleration() / speed() // 返回对应参数值(getter) // 位置与目标 moveTo(long absolute) // 设置目标绝对位置(步数) move(long relative) // 相对移动(步数) targetPosition() // 返回目标位置 currentPosition() // 返回当前已记录的位置 setCurrentPosition(long pos) // 重置当前位置计数器 distanceToGo() // 返回剩余步数(target - current) // 运行控制(需要在 loop 中反复调用 run* 来推进电机) run() // 以加速度/速度曲线移动一步;需要频繁调用(非阻塞) runSpeed() // 以当前 speed 速度移动(不处理加速度) runToPosition() // 阻塞直到到达目标位置 runToNewPosition(long position) // 设置目标并阻塞到达 // 紧急停止/软停止 stop() // 触发减速到停止并更新目标(软停止,非立即硬刹) isRunning() // 判断是否仍在移动(库版本可能有此方法) // 引脚与输出控制 enableOutputs() / disableOutputs() // 使能/禁能输出(使能引脚高/低依驱动需求) setEnablePin(pin) // 指定使能引脚(如需) setPinsInverted(dirInvert, stepInvert, enableInvert, ...) // 反转引脚逻辑(视硬件需要) // 其它 setMinPulseWidth(unsigned int us) // 设置步脉冲最小宽度(微秒) stop(); // 请求平滑停止(见上)测试A4988芯片驱动步进电机#include <Arduino.h> #include <AccelStepper.h> const uint8_t STEP_PIN = 2; const uint8_t DIR_PIN = 3; // AccelStepper in DRIVER mode for STEP/DIR drivers (A4988) AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN); void setup() { stepper.setMaxSpeed(1000); // 步/秒 stepper.setAcceleration(400); // 步/秒^2 stepper.setCurrentPosition(0); stepper.setMinPulseWidth(1); // 最小脉冲宽度(微秒),根据 A4988 要求调整 } void loop() { // 简单往返示例:到达目标后切换目标位置 if (stepper.distanceToGo() == 0) { if (stepper.currentPosition() == 0) stepper.moveTo(2000); else stepper.moveTo(0); } stepper.run(); // 非阻塞,需在 loop 中频繁调用以推进运动 }
2026年01月21日
6 阅读
0 评论
0 点赞