Commit 8210082f authored by 957dd's avatar 957dd

更新了部分代码

parent 2be6a78d
...@@ -15,6 +15,6 @@ ...@@ -15,6 +15,6 @@
"--query-driver=**", "--query-driver=**",
"--compile-commands-dir=c:\\Users\\17122\\Desktop\\机甲大师自话\\H60\\esp32project\\RobotMiddle\\build" "--compile-commands-dir=c:\\Users\\17122\\Desktop\\机甲大师自话\\H60\\esp32project\\RobotMiddle\\build"
], ],
"idf.portWin": "COM24", "idf.portWin": "COM6",
"idf.flashType": "UART" "idf.flashType": "UART"
} }
set(SOURCES "wifidevnum_config.c" set(SOURCES "wifidevnum_config.c"
"mqttconf/mqttconf_commun.c" "mqttconf/mqttconf_commun.c"
#"led/gpio_led.c" #"led/gpio_led.c"
"serial/serial.c" "boards/serial/serial.c"
"boards/gpiotrol/gpiocontrol.c"
"boards/gpiotrol/betteryread.c"
#"boards/common/board_common.c" # 统一入口文件
"ota.c"
"main.c") "main.c")
set(INCLUDE_DIRS "." "mqttconf" "serial") set(INCLUDE_DIRS "."
"mqttconf"
"boards/serial"
"boards/gpiotrol"
#"boards/common"
)
idf_component_register(SRCS ${SOURCES} idf_component_register(SRCS ${SOURCES}
INCLUDE_DIRS ${INCLUDE_DIRS} INCLUDE_DIRS ${INCLUDE_DIRS}
#HOLE_ARCHIVE REQUIRES
driver
esp_https_ota
app_update
nvs_flash
esp_https_ota
esp_http_client
esp_http_server
spiffs
esp-tls # <--- 替换掉刚才报错的 esp_crt_bundle
esp_netif
esp_event
esp_wifi
esp_adc
mqtt
json
) )
spiffs_create_partition_image(storage ../www FLASH_IN_PROJECT) spiffs_create_partition_image(storage ../www FLASH_IN_PROJECT)
...@@ -6,18 +6,40 @@ config ROBIOT_WIFI_SSID ...@@ -6,18 +6,40 @@ config ROBIOT_WIFI_SSID
help help
Hotspot Name Settings. Hotspot Name Settings.
config OTA_VERSION_URL
string "OTA Version URL"
default "wu"
help
The application will access this URL to check for updates.
config ROBOIOT_MQTT_URL config ROBOIOT_MQTT_URL
string "MQTT URL" string "MQTT URL"
default "https://fcrs-api.yd-ss.com/device/getConfig?deviceNo=" default "https://fcrs-api.yd-ss.com/device/getConfig?deviceNo="
help help
MQTT Config URL MQTT Config URL
config MY_APP_VERSION
string "Project Version"
default "1.0.1"
help
The version number of this firmware.
choice DEVICE_STM32_SERIAL_MODE
prompt "Does it have an STM32 serial?"
default MODE_SERIAL_WHETHER_OPEN
help
选择是否有串口心跳检测
config MODE_SERIAL_WHETHER_OPEN
bool "open stm32 serial beat"
help
打开串口心跳检测(适用于将esp32s3作为中间联网使用)
config MODE_SERIAL_WHETHER_CLOSE
bool "close stm32 serial beat"
help
关闭串口心跳检测,使用esp32引脚控制和心跳(适用于单ESP32)
config MODE_SERIAL_AND_GPIO
bool "open stm32 serial and gpio"
help
同时打开串口心跳和引脚使用()
endchoice
endmenu endmenu
#include"application.h"
#include <stdio.h>
#include <string.h>
#ifndef APPLICATION_H
#define APPLICATION_H
#include "esp_err.h"
#endif
\ No newline at end of file
#include "betteryread.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_log.h"
static const char *TAG = "ADC_CONTROL";
// 全局句柄
static adc_oneshot_unit_handle_t adc1_handle;
static adc_cali_handle_t adc_cali_handle = NULL;
static bool do_calibration = false;
// 校准初始化函数(内部使用)
static bool example_adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle) {
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
// ESP32-S3 支持 Curve Fitting 校准方式
if (!calibrated) {
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.chan = channel,
.atten = atten,
.bitwidth = ADC_BITWIDTH_DEFAULT,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
*out_handle = handle;
ESP_LOGI(TAG, "ADC初始化成功");
return calibrated;
}
esp_err_t board_adc_init(void) {
adc_oneshot_unit_init_cfg_t init_config1 = {
.unit_id = ADC_UNIT_1,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_4, &config));
// 初始化校准
do_calibration = example_adc_calibration_init(ADC_UNIT_1, ADC_CHANNEL_4, ADC_ATTEN_DB_12, &adc_cali_handle);
return ESP_OK;
}
// 核心修改:返回 float
float board_get_voltage_v(void) {
int adc_raw;
int voltage_mv;
esp_err_t ret = adc_oneshot_read(adc1_handle, ADC_CHANNEL_4, &adc_raw);
if (ret != ESP_OK) return -1.0f;
if (do_calibration) {
// 先获取校准后的毫伏值 (int)
adc_cali_raw_to_voltage(adc_cali_handle, adc_raw, &voltage_mv);
// 转换为伏特并返回小数
return (float)voltage_mv / 1000.0f;
} else {
return (float)(adc_raw * 3100) / 4095.0f / 1000.0f;
}
}
\ No newline at end of file
#ifndef BETTERYREAD_H
#define BETTERYREAD_H
#include "esp_err.h"
#define ADC_GET_VOLTAGE_GPIO 5
/**
* @brief 初始化 ADC1 通道 4 (GPIO 5)
*/
esp_err_t board_adc_init(void);
/**
* @brief 读取当前电压值
* @return int 返回毫伏值 (mV),读取失败返回 -1
*/
float board_get_voltage_v(void);
#endif
\ No newline at end of file
#include "gpiocontrol.h"
#include "esp_log.h"
static const char *TAG = "GPIO_CONTROL";
// 定义 LEDC 通道结构体
static const ledc_channel_config_t ledc_channels[] = {
{
.gpio_num = GPIO_PWM_MOTOR_6,
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_0,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = 0, // 初始停止
.hpoint = 0
},
{
.gpio_num = GPIO_PWM_MOTOR_7,
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_1,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = 0, // 初始停止
.hpoint = 0
},
{
.gpio_num = GPIO_PWM_SERVO_10,
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_2,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = SERVO_INIT_90_DEG, // 舵机初始化为 90 度
.hpoint = 0
},
{
.gpio_num = GPIO_PWM_ESC_15,
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_3,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = ESC_MIN_DUTY,
.hpoint = 0
},
{
.gpio_num = GPIO_PWM_ESC_16,
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_4,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = ESC_MIN_DUTY,
.hpoint = 0
}
};
esp_err_t gpiocontrol_init(void) {
// 1. 配置定时器
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
// 2. 配置 3 个通道
for (int i = 0; i < 5; i++) {
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channels[i]));
}
ESP_LOGI(TAG, "PWM 初始化完成 (GPIO 6, 7 为电机, GPIO 10 为舵机 90度)");
return ESP_OK;
}
void set_servo_angle(uint32_t angle) {
if (angle > 180) angle = 180;
// 将 0-180 度线性映射到 SERVO_MIN_DUTY 和 SERVO_MAX_DUTY 之间
uint32_t duty = SERVO_MIN_DUTY + (angle * (SERVO_MAX_DUTY - SERVO_MIN_DUTY) / 180);
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_2, duty);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_2);
}
/**
* @brief 设置电机驱动引脚占空比 (GPIO 6, 7)
* @param gpio GPIO_PWM_MOTOR_6 或 GPIO_PWM_MOTOR_7
* @param duty_percent 0 到 100 之间的百分比
*/
void set_motor_speed(int gpio, uint32_t duty_percent) {
if (duty_percent > 100) duty_percent = 100;
// 百分比转换为 13-bit 数值 (0-8191)
uint32_t duty = (duty_percent * 8191) / 100;
ledc_channel_t channel = (gpio == GPIO_PWM_MOTOR_6) ? LEDC_CHANNEL_0 : LEDC_CHANNEL_1;
ledc_set_duty(LEDC_MODE, channel, duty);
ledc_update_duty(LEDC_MODE, channel);
}
void car0102_speed_stop(void) {
// 将电机引脚占空比降为 0
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_0, 0);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_0);
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_1, 0);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_1);
ESP_LOGD(TAG, "电机已强制停止输出");
}
void car0102_control_motor(int mode ,int val){
if(mode == 1){
if(val <50){
set_motor_speed(GPIO_PWM_MOTOR_6,0);
set_motor_speed(GPIO_PWM_MOTOR_7,0);
}else{
set_motor_speed(GPIO_PWM_MOTOR_6,val/2-10);
set_motor_speed(GPIO_PWM_MOTOR_7,0);
}
}else if(mode == 2){
if(val <50){
set_motor_speed(GPIO_PWM_MOTOR_6,0);
set_motor_speed(GPIO_PWM_MOTOR_7,0);
}else{
set_motor_speed(GPIO_PWM_MOTOR_6,0);
set_motor_speed(GPIO_PWM_MOTOR_7,val/2-10);
}
}
if(mode == 3){
if(val <45) set_servo_angle(90);
else if(val<70) set_servo_angle(50+val+7);
else if(val>=70) set_servo_angle(135);
}else if(mode == 4){
if(val <45) set_servo_angle(90);
else if(val<70) set_servo_angle(130-val-7);
else if(val>=70) set_servo_angle(45);
}
}
void esc_set_throttle(uint8_t percent)
{
if (percent > 100) percent = 100;
uint32_t duty = ESC_MIN_DUTY +
(ESC_MAX_DUTY - ESC_MIN_DUTY) * percent / 100;
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_3, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_3);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_4, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_4);
}
\ No newline at end of file
#ifndef GPIOCONTROL_H
#define GPIOCONTROL_H
#include "driver/ledc.h"
#include "esp_err.h"
// 引脚定义
#define GPIO_PWM_MOTOR_6 6
#define GPIO_PWM_MOTOR_7 7
#define GPIO_PWM_SERVO_10 10
#define GPIO_PWM_ESC_15 15 // C615电调控制引脚
#define GPIO_PWM_ESC_16 16 // C615电调控制引脚
// LEDC 配置定义
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 13位分辨率 (0-8191)
#define FREQUENCY 50 // 频率 50Hz
// 舵机角度换算 (基于 50Hz, 13-bit 分辨率)
// 0.5ms (0度) -> 约 205
// 1.5ms (90度) -> 约 614
// 2.5ms (180度) -> 约 1024
#define SERVO_MIN_DUTY 205 // 0.5ms
#define SERVO_MAX_DUTY 1024 // 2.5ms
#define SERVO_INIT_90_DEG 614 // 1.5ms (90度)
// ===== ESC PWM (50Hz, 13bit) =====
#define ESC_MIN_DUTY 410 // 1.0ms
#define ESC_MID_DUTY 614 // 1.5ms
#define ESC_MAX_DUTY 819 // 2.0ms
/**
* @brief 初始化所有 PWM 引脚 (6, 7, 10)
*/
esp_err_t gpiocontrol_init(void);
void car0102_speed_stop(void);
void car0102_control_motor(int mode ,int val);
void esc_set_throttle(uint8_t percent);
#endif
\ No newline at end of file
...@@ -101,6 +101,11 @@ void recserial_data(uint8_t *data){ ...@@ -101,6 +101,11 @@ void recserial_data(uint8_t *data){
void serial_receive_task(void *pvParameters) { void serial_receive_task(void *pvParameters) {
uint8_t data[128]; uint8_t data[128];
uint8_t frame_buf[8]; uint8_t frame_buf[8];
vTaskDelay(pdMS_TO_TICKS(1000));
esp_err_t wifi_result = (esp_err_t)pvParameters;
if(wifi_result!=ESP_OK){
vTaskDelay(pdMS_TO_TICKS(2000));
}
serial_send_command(0x00,0x00,0x00,0x00,0x00); serial_send_command(0x00,0x00,0x00,0x00,0x00);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include "esp_err.h" #include "esp_err.h"
#include <stdbool.h> #include <stdbool.h>
#include "sdkconfig.h"
// 定义串口参数 (根据实际引脚修改) // 定义串口参数 (根据实际引脚修改)
#define STM32_UART_PORT UART_NUM_1 #define STM32_UART_PORT UART_NUM_1
...@@ -31,5 +32,15 @@ void serial_send_command(uint8_t mode, uint8_t value,uint8_t data3,uint8_t data4 ...@@ -31,5 +32,15 @@ void serial_send_command(uint8_t mode, uint8_t value,uint8_t data3,uint8_t data4
// 接收处理任务入口 (在 app_main 中启动) // 接收处理任务入口 (在 app_main 中启动)
void serial_receive_task(void *pvParameters); void serial_receive_task(void *pvParameters);
#if defined(CONFIG_ODE_SERIAL_WHETHER_OPEN)
#define DEVICE_SERIAL_BEAT 0
#elif defined(CONFIG_MODE_SERIAL_WHETHER_CLOSE)
#define DEVICE_SERIAL_BEAT 1
#elif defined(CONFIG_MODE_SERIAL_AND_GPIO)
#define DEVICE_SERIAL_BEAT 2
#else
#define DEVICE_SERIAL_BEAT 999
#endif
#endif #endif
\ No newline at end of file
#include "gpio_led.h"
\ No newline at end of file
#ifndef __GPIO_LED_H__
#define __GPIO_LED_H__
#endif
\ No newline at end of file
...@@ -7,7 +7,10 @@ ...@@ -7,7 +7,10 @@
#include "esp_netif.h" #include "esp_netif.h"
#include "wifidevnum_config.h" #include "wifidevnum_config.h"
#include "mqttconf_commun.h" #include "mqttconf_commun.h"
#include "betteryread.h"
#include "gpiocontrol.h"
#include "serial.h" #include "serial.h"
#include "ota.h"
static const char *TAG = "MAIN"; static const char *TAG = "MAIN";
static bool init_task_triggered = false; static bool init_task_triggered = false;
...@@ -34,20 +37,49 @@ static void wifi_event_handler(void* arg, esp_event_base_t base, int32_t id, voi ...@@ -34,20 +37,49 @@ static void wifi_event_handler(void* arg, esp_event_base_t base, int32_t id, voi
} }
} }
esp_err_t device_type_init(void){
#if DEVICE_SERIAL_BEAT ==0
ESP_ERROR_CHECK(serial_init());//初始化串口
ESP_LOGI(TAG, "使用仅串口控制模式");
xTaskCreate(serial_receive_task, "serial_rx", 4096, (void*)wifi_ret, 10, NULL);
#elif DEVICE_SERIAL_BEAT ==1
ESP_ERROR_CHECK(board_adc_init());
ESP_ERROR_CHECK(gpiocontrol_init());
ESP_LOGI(TAG, "使用自带引脚控制模式");
#else
ESP_ERROR_CHECK(board_adc_init());
ESP_ERROR_CHECK(gpiocontrol_init());
ESP_ERROR_CHECK(serial_init());//初始化串口
ESP_LOGI(TAG, "使用串口和自带引脚同时使用控制模式");
xTaskCreate(serial_receive_task, "serial_rx", 4096, NULL, 10, NULL);
#endif
return ESP_OK;
}
void app_main(void) { void app_main(void) {
vTaskDelay(pdMS_TO_TICKS(10000));
esp_err_t ret = nvs_flash_init(); esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase()); ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init(); ret = nvs_flash_init();
} }
ESP_ERROR_CHECK(ret); ESP_ERROR_CHECK(ret);
char ssid[32] = {0}, pass[64] = {0};
esp_err_t wifi_ret=read_from_nvs("wifi_ssid", ssid, sizeof(ssid));
ESP_ERROR_CHECK(init_spiffs()); // 启动 Web 前挂载 SPIFFS ESP_ERROR_CHECK(init_spiffs()); // 启动 Web 前挂载 SPIFFS
ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(serial_init());//初始化串口
if (wifi_ret == ESP_OK) {
read_from_nvs("wifi_pass", pass, sizeof(pass));
ESP_ERROR_CHECK(device_type_init());
// 关键:创建 STA 模式的网络接口句柄 // 关键:创建 STA 模式的网络接口句柄
esp_netif_create_default_wifi_sta(); esp_netif_create_default_wifi_sta();
...@@ -57,9 +89,6 @@ void app_main(void) { ...@@ -57,9 +89,6 @@ void app_main(void) {
xTaskCreate(button_monitor_task, "btn_task", 4096, NULL, 5, NULL); xTaskCreate(button_monitor_task, "btn_task", 4096, NULL, 5, NULL);
char ssid[32] = {0}, pass[64] = {0};
if (read_from_nvs("wifi_ssid", ssid, sizeof(ssid)) == ESP_OK) {
read_from_nvs("wifi_pass", pass, sizeof(pass));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg); esp_wifi_init(&cfg);
...@@ -78,6 +107,9 @@ void app_main(void) { ...@@ -78,6 +107,9 @@ void app_main(void) {
esp_wifi_start(); esp_wifi_start();
esp_wifi_connect(); esp_wifi_connect();
xTaskCreate(serial_receive_task, "serial_rx", 4096, NULL, 10, NULL);
}else{
ESP_LOGI(TAG, "无保存wifi 信息,启动wifi 配置页面");
nowifidata_start_config_web();
} }
} }
\ No newline at end of file
...@@ -18,6 +18,12 @@ ...@@ -18,6 +18,12 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "serial.h" #include "serial.h"
#include "esp_ota_ops.h"
#include "esp_app_format.h"
#include "gpiocontrol.h"
#include "betteryread.h"
#include "ota.h"
static const char *TAG = "MQTT_MGR"; static const char *TAG = "MQTT_MGR";
#define DEFAULT_MQTT_HOST "119.45.167.177" #define DEFAULT_MQTT_HOST "119.45.167.177"
...@@ -30,7 +36,7 @@ typedef struct { ...@@ -30,7 +36,7 @@ typedef struct {
int len; int len;
} http_response_t; } http_response_t;
static char g_device_id[32] = {0}; char g_device_id[32] = {0};
static char g_sta_ip[16] = "0.0.0.0"; static char g_sta_ip[16] = "0.0.0.0";
// 存储所有活跃的 MQTT 客户端句柄,用于心跳群发 // 存储所有活跃的 MQTT 客户端句柄,用于心跳群发
...@@ -38,14 +44,19 @@ static esp_mqtt_client_handle_t client_list[MAX_MQTT_CLIENTS] = {NULL}; ...@@ -38,14 +44,19 @@ static esp_mqtt_client_handle_t client_list[MAX_MQTT_CLIENTS] = {NULL};
static int client_count = 0; static int client_count = 0;
static esp_timer_handle_t g_hb_timer = NULL; static esp_timer_handle_t g_hb_timer = NULL;
static
int mqtt_send_deviceota_info(void);
/** /**
* @brief 远程控制解析 * @brief 远程控制解析
*/ */
static void handle_remote_control(const char *data) { static void handle_remote_control(const char *data) {
if (!data) return; if (!data) return;
cJSON *root = cJSON_Parse(data); cJSON *root = cJSON_Parse(data);
if (!root) return;
cJSON *head = cJSON_GetObjectItem(root, "head"); cJSON *head = cJSON_GetObjectItem(root, "head");
if(head==NULL) ota_update_recmqtt(data);
if (head && cJSON_IsObject(head)) { if (head && cJSON_IsObject(head)) {
cJSON *m_type = cJSON_GetObjectItem(head, "message_type"); cJSON *m_type = cJSON_GetObjectItem(head, "message_type");
cJSON *body = cJSON_GetObjectItem(root, "body"); cJSON *body = cJSON_GetObjectItem(root, "body");
...@@ -54,9 +65,12 @@ static void handle_remote_control(const char *data) { ...@@ -54,9 +65,12 @@ static void handle_remote_control(const char *data) {
if (pin_ctrl) { if (pin_ctrl) {
int pin = cJSON_GetObjectItem(pin_ctrl, "pin")->valueint; int pin = cJSON_GetObjectItem(pin_ctrl, "pin")->valueint;
int val = cJSON_GetObjectItem(pin_ctrl, "val")->valueint; int val = cJSON_GetObjectItem(pin_ctrl, "val")->valueint;
gpio_reset_pin(pin); if(pin == 27&&val == 1) esc_set_throttle(25);
gpio_set_direction(pin, GPIO_MODE_OUTPUT); if(pin == 27&&val == 0) esc_set_throttle(0);
gpio_set_level(pin, val); if(pin == 5&&val == 1) esc_set_throttle(100);
if(pin == 7&&val == 1) esc_set_throttle(0);
ESP_LOGW(TAG, "GPIO控制: Pin %d -> %d", pin, val); ESP_LOGW(TAG, "GPIO控制: Pin %d -> %d", pin, val);
} }
} else if (m_type && m_type->valueint == 3 && body) { } else if (m_type && m_type->valueint == 3 && body) {
...@@ -66,36 +80,58 @@ static void handle_remote_control(const char *data) { ...@@ -66,36 +80,58 @@ static void handle_remote_control(const char *data) {
int type = cJSON_GetObjectItem(pwm_ctrl, "type")->valueint; int type = cJSON_GetObjectItem(pwm_ctrl, "type")->valueint;
int val = cJSON_GetObjectItem(pwm_ctrl, "val")->valueint; int val = cJSON_GetObjectItem(pwm_ctrl, "val")->valueint;
ESP_LOGW(TAG, "PWM指令: m:%d t:%d v:%d", mode, type, val); ESP_LOGW(TAG, "PWM指令: m:%d t:%d v:%d", mode, type, val);
#if DEVICE_SERIAL_BEAT ==0
serial_send_command(mode, val, 0, 0,0); // 串口下发给STM32 serial_send_command(mode, val, 0, 0,0); // 串口下发给STM32
#elif DEVICE_SERIAL_BEAT ==1
car0102_control_motor(mode, val);
#else
ESP_LOGW(TAG,"看情况");
#endif
} }
} }
} }
cJSON_Delete(root); cJSON_Delete(root);
} }
/** /**
* @brief 构造心跳包内容 * @brief 构造心跳包内容
*/ */
static char* generate_hb_payload() { static char* generate_hb_payload() {
cJSON *root = cJSON_CreateObject(); cJSON *root = cJSON_CreateObject();
cJSON *body = cJSON_CreateObject(); cJSON *body = cJSON_CreateObject();
cJSON_AddStringToObject(body, "ip", g_sta_ip); cJSON_AddStringToObject(body, "ip", g_sta_ip);
char id_full[64], volat[16], tempvalue[16]; char id_full[64], volat[16];
snprintf(id_full, sizeof(id_full), "app2dev/%s", g_device_id); snprintf(id_full, sizeof(id_full), "app2dev/%s", g_device_id);
#if DEVICE_SERIAL_BEAT ==0
char tempvalue[16];
snprintf(volat, sizeof(volat), "%.2f", get_stm32_battery_voltage()); snprintf(volat, sizeof(volat), "%.2f", get_stm32_battery_voltage());
snprintf(tempvalue, sizeof(tempvalue), "%.2f", get_stm32_battery_tempvalue()); snprintf(tempvalue, sizeof(tempvalue), "%.2f", get_stm32_battery_tempvalue());
cJSON_AddStringToObject(body, "tempvalue", tempvalue);
cJSON_AddStringToObject(body, "device_ID", id_full);
cJSON_AddStringToObject(body, "voltage", volat); cJSON_AddStringToObject(body, "voltage", volat);
#elif DEVICE_SERIAL_BEAT ==1
snprintf(volat, sizeof(volat), "%.2f", board_get_voltage_v());
cJSON_AddStringToObject(body, "voltage", volat);
#else
char volat_stm32[16], tempvalue[16];
snprintf(volat_stm32, sizeof(volat_stm32), "%.2f", get_stm32_battery_voltage());
snprintf(tempvalue, sizeof(tempvalue), "%.2f", get_stm32_battery_tempvalue());
cJSON_AddStringToObject(body, "tempvalue", tempvalue); cJSON_AddStringToObject(body, "tempvalue", tempvalue);
cJSON_AddStringToObject(body, "version", "1.1.0"); cJSON_AddStringToObject(body, "stm32_voltage", volat_stm32);
snprintf(volat, sizeof(volat), "%.2f", board_get_voltage_v());
cJSON_AddStringToObject(body, "esp32_voltage", volat);
#endif
cJSON_AddStringToObject(body, "device_ID", id_full);
cJSON_AddStringToObject(body, "version", CONFIG_MY_APP_VERSION);
cJSON_AddItemToObject(root, "body", body); cJSON_AddItemToObject(root, "body", body);
cJSON *head = cJSON_CreateObject(); cJSON *head = cJSON_CreateObject();
cJSON_AddNumberToObject(head, "message_type", 1); cJSON_AddNumberToObject(head, "message_type", 1);
cJSON_AddItemToObject(root, "head", head); cJSON_AddItemToObject(root, "head", head);
char *out = cJSON_PrintUnformatted(root); char *out = cJSON_PrintUnformatted(root);
cJSON_Delete(root); cJSON_Delete(root);
return out; return out;
...@@ -130,6 +166,46 @@ static void mqtt_heartbeat_timer_cb(void *arg) { ...@@ -130,6 +166,46 @@ static void mqtt_heartbeat_timer_cb(void *arg) {
free(json); free(json);
} }
// 定时器句柄
TimerHandle_t ota_msg_timer;
// 定时器触发后的回调函数
void ota_msg_send_task(void *pvParameters) {
// 将传入的参数转回延迟秒数
int delay_seconds = (int)pvParameters;
// 在任务内部进行延迟,不阻塞其他程序
vTaskDelay(pdMS_TO_TICKS(delay_seconds * 1000));
ESP_LOGI("OTA_TASK", "延迟结束,正在发送 MQTT OTA 信息...");
// 执行你的 MQTT 发送逻辑
mqtt_send_deviceota_info();
// 2. 关键:发送完毕后,任务自行销毁,实现“自动取消”和内存释放
ESP_LOGI("OTA_TASK", "发送完成,任务已自动退出并销毁");
vTaskDelete(NULL);
}
/**
* @brief 启动延迟发送
* @param delay_seconds 延迟几秒发送
*/
void start_ota_report_timer(int delay_seconds) {
ESP_LOGI("OTA_TASK", "创建一次性任务,将在 %d 秒后执行", delay_seconds);
// 创建一个独立任务
// 栈大小设置为 4096,足以应对 MQTT 和 JSON 操作,防止溢出
xTaskCreate(
ota_msg_send_task, // 任务函数
"ota_msg_task", // 任务名称
4096, // 栈深度 (Stack Size)
(void *)delay_seconds,// 传递延迟时间作为参数
5, // 优先级 (根据需要调整)
NULL // 不需要保存任务句柄
);
}
/** /**
* @brief MQTT 事件回调 * @brief MQTT 事件回调
*/ */
...@@ -140,6 +216,9 @@ static void common_mqtt_event_handler(void *handler_args, esp_event_base_t base, ...@@ -140,6 +216,9 @@ static void common_mqtt_event_handler(void *handler_args, esp_event_base_t base,
switch (event->event_id) { switch (event->event_id) {
case MQTT_EVENT_CONNECTED: case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "[%s] 已连接", ip); ESP_LOGI(TAG, "[%s] 已连接", ip);
if(strcmp(ip,DEFAULT_MQTT_HOST)==0){
start_ota_report_timer(5);
}
char s1[64], s2[64]; char s1[64], s2[64];
snprintf(s1, sizeof(s1), "app2dev/%s", g_device_id); snprintf(s1, sizeof(s1), "app2dev/%s", g_device_id);
snprintf(s2, sizeof(s2), "ser2dev/%s", g_device_id); snprintf(s2, sizeof(s2), "ser2dev/%s", g_device_id);
...@@ -154,6 +233,7 @@ static void common_mqtt_event_handler(void *handler_args, esp_event_base_t base, ...@@ -154,6 +233,7 @@ static void common_mqtt_event_handler(void *handler_args, esp_event_base_t base,
memcpy(tmp, event->data, event->data_len); memcpy(tmp, event->data, event->data_len);
tmp[event->data_len] = '\0'; tmp[event->data_len] = '\0';
handle_remote_control(tmp); handle_remote_control(tmp);
free(tmp); free(tmp);
} }
} }
...@@ -314,3 +394,81 @@ void mqtt_manager_stop(void) { ...@@ -314,3 +394,81 @@ void mqtt_manager_stop(void) {
ESP_LOGI(TAG, "MQTT 服务已完全停止"); ESP_LOGI(TAG, "MQTT 服务已完全停止");
} }
/**
* @brief 发送设备信息到 MQTT(JSON 格式)
* @return 0 成功,-1 失败
*/
int mqtt_send_deviceota_info(void)
{
cJSON *root = NULL;
char *json_str = NULL;
int ret = -1;
/* 1. 创建 JSON 对象 */
root = cJSON_CreateObject();
if (!root) {
return -1;
}
/* 2. 添加字段(直接读取全局变量) */
cJSON_AddStringToObject(root, "device_id", g_device_id);
const esp_app_desc_t *app_desc = esp_app_get_description();
const char* running_version = app_desc->version;
cJSON_AddStringToObject(root, "version", running_version);
/* 3. JSON 转字符串(紧凑格式,适合 MQTT) */
json_str = cJSON_PrintUnformatted(root);
if (!json_str) {
goto exit;
}
/* 4. MQTT 发送 */
esp_mqtt_client_publish(client_list[0], "esp32updata",json_str, 0, 1, 0);
exit:
if (json_str) {
free(json_str);
}
if (root) {
cJSON_Delete(root);
}
return ret;
}
// #if defined(CONFIG_ODE_SERIAL_WHETHER_OPEN)
// void mqtt_abnormal_exittask(void *pvParameters)
// {
// ESP_LOGI(TAG, "MQTT异常任务启动");
// while(1){
// if(client_list[0] == NULL) {
// vTaskDelay(pdMS_TO_TICKS(1000));
// continue;
// }
// }
// }
// #elif defined(CONFIG_MODE_SERIAL_WHETHER_CLOSE)
// void mqtt_abnormal_exittask(void *pvParameters)
// {
// ESP_LOGI(TAG, "MQTT异常任务启动");
// while(1){
// if(client_list[0] == NULL) {
// vTaskDelay(pdMS_TO_TICKS(1000));
// continue;
// }
// }
// }
//#elif defined(CONFIG_MODE_SERIAL_AND_GPIO)
// #endif
\ No newline at end of file
...@@ -8,4 +8,7 @@ ...@@ -8,4 +8,7 @@
// 启动所有 MQTT 相关逻辑 // 启动所有 MQTT 相关逻辑
void mqtt_manager_init_sequence(void); void mqtt_manager_init_sequence(void);
void mqtt_manager_stop(void); void mqtt_manager_stop(void);
#endif #endif
\ No newline at end of file
#include "OTA.h" #include "ota.h"
\ No newline at end of file #include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_app_format.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_crt_bundle.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "wifidevnum_config.h" // 假设你有封装好的 read_from_nvs 和 save_to_nvs
#include "esp_spiffs.h"
#include <cJSON.h>
#include <string.h>
static const char *TAG = "OTA_UPDATE";
/**
* @brief HTTP 事件处理
*/
esp_err_t _ota_http_event_handler(esp_http_client_event_t *evt) {
switch (evt->event_id) {
case HTTP_EVENT_ERROR: ESP_LOGE(TAG, "HTTP_EVENT_ERROR"); break;
case HTTP_EVENT_ON_CONNECTED: ESP_LOGI(TAG, "已连接到服务器"); break;
case HTTP_EVENT_ON_FINISH: ESP_LOGI(TAG, "数据传输完成"); break;
default: break;
}
return ESP_OK;
}
/**
* @brief 启动 OTA
*/
void start_ota_update(const char* url) {
ESP_LOGI(TAG, "正在从 URL 启动 OTA: %s", url);
esp_http_client_config_t config = {
.url = url,
.crt_bundle_attach = esp_crt_bundle_attach,
.event_handler = _ota_http_event_handler,
.keep_alive_enable = true,
.timeout_ms = 10000,
};
esp_https_ota_config_t ota_config = {
.http_config = &config,
};
ESP_LOGI(TAG, "正在下载并写入固件... 请勿断电");
esp_err_t ret = esp_https_ota(&ota_config);
// 在这里获取更新后的分区指针
const esp_partition_t *updated_partition = esp_ota_get_next_update_partition(NULL);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "OTA 升级成功!即将重启...");
ESP_LOGI(TAG, "找到更新分区: %s (偏移: 0x%08x)",
updated_partition->label, updated_partition->address);
esp_err_t set_err = esp_ota_set_boot_partition(updated_partition);
if (set_err == ESP_OK) {
ESP_LOGI(TAG, "启动分区设置成功!");
// 验证设置结果
const esp_partition_t *boot_partition = esp_ota_get_boot_partition();
const esp_partition_t *running_partition = esp_ota_get_running_partition();
ESP_LOGI(TAG, "当前运行分区: %s (0x%08x)",
running_partition->label, running_partition->address);
ESP_LOGI(TAG, "下次启动分区: %s (0x%08x)",
boot_partition->label, boot_partition->address);
// 等待设置完成
vTaskDelay(2000 / portTICK_PERIOD_MS);
esp_restart();
}else {
ESP_LOGE(TAG, "设置启动分区失败: %s", esp_err_to_name(set_err));
}
} else {
ESP_LOGE(TAG, "OTA 升级失败: %s", esp_err_to_name(ret));
}
}
/**
* @brief MQTT 消息处理函数:解析 JSON 并判断是否需要更新
*/
int ota_update_recmqtt(const char *json_data) {
if (json_data == NULL) return -1;
cJSON *root = cJSON_Parse(json_data);
if (root == NULL) return -1;
ESP_LOGI(TAG, "当前固件运行版本: %s", CONFIG_MY_APP_VERSION);
// 2. 解析云端发来的新版本号
cJSON *new_version_obj = cJSON_GetObjectItem(root, "new_version");
if (!cJSON_IsString(new_version_obj) || (new_version_obj->valuestring == NULL)) {
cJSON_Delete(root);
return -1;
}
const char* cloud_version = new_version_obj->valuestring;
// 3. 版本对比
if (strcmp(CONFIG_MY_APP_VERSION, cloud_version) == 0) {
ESP_LOGI(TAG, "当前已是最新版本 (%s),跳过更新。", CONFIG_MY_APP_VERSION);
cJSON_Delete(root);
return 0;
}
ESP_LOGI(TAG, "检测到新版本: %s -> %s",CONFIG_MY_APP_VERSION, cloud_version);
// 5. 解析下载地址并启动更新
cJSON *esp32_url = cJSON_GetObjectItem(root, "esp32_url");
if (cJSON_IsString(esp32_url) && (esp32_url->valuestring != NULL)) {
start_ota_update(esp32_url->valuestring);
} else {
ESP_LOGE(TAG, "JSON 中未找到有效的 esp32_url");
}
cJSON_Delete(root);
return 0;
}
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
#include "esp_err.h" #include "esp_err.h"
int ota_update_recmqtt(const char *json_data);
#endif #endif
\ No newline at end of file
...@@ -188,7 +188,14 @@ void start_config_web() { ...@@ -188,7 +188,14 @@ void start_config_web() {
} }
} }
void nowifidata_start_config_web(void) {
wifi_editable = true;
devid_editable = true;
start_config_web();
}
void button_monitor_task(void* arg) { void button_monitor_task(void* arg) {
gpio_config_t io_conf = { gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << BTN_WIFI_IO) | (1ULL << BTN_DEVID_IO), .pin_bit_mask = (1ULL << BTN_WIFI_IO) | (1ULL << BTN_DEVID_IO),
.mode = GPIO_MODE_INPUT, .pull_up_en = 1 .mode = GPIO_MODE_INPUT, .pull_up_en = 1
......
...@@ -14,4 +14,6 @@ void button_monitor_task(void* arg); ...@@ -14,4 +14,6 @@ void button_monitor_task(void* arg);
void start_config_web(void); void start_config_web(void);
esp_err_t init_spiffs(void); esp_err_t init_spiffs(void);
void nowifidata_start_config_web(void);
#endif #endif
\ No newline at end of file
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
nvs, data, nvs, , 0x6000, nvs, data, nvs, , 0x6000,
otadata, data, ota, , 0x2000, otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000, phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 0x400000, ota_0, app, ota_0, , 0x600000,
ota_1, app, ota_1, , 0x400000, ota_1, app, ota_1, , 0x600000,
storage, data, spiffs, , 0x50000, storage, data, spiffs, , 0x50000,
stm32otadata, data, stm32, , 0x100000
\ No newline at end of file
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
</head> </head>
<body> <body>
<div class="card"> <div class="card">
<h1>🦉 设备配置中心</h1> <h1>🦉 飞驰设备配置中心</h1>
<form action='/save' method='POST'> <form action='/save' method='POST'>
<b>WiFi 配置 %s</b> <b>WiFi 配置 %s</b>
<input name='ssid' placeholder='WiFi名称' %s> <input name='ssid' placeholder='WiFi名称' %s>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment