Commit 4c190aef authored by 957dd's avatar 957dd

第三次提交

parent 8210082f
......@@ -13,9 +13,17 @@ dependencies:
source:
type: idf
version: 5.5.1
lvgl/lvgl:
component_hash: d7c1ac037ae6e85d94897f807d6e7ba0946a83e720074fc95a4f6241da9f9f53
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
version: 8.4.0
direct_dependencies:
- espressif/cJSON
- idf
manifest_hash: 67a457718a3b3cb206e122b6946d05b7c63ba9fd523dd53bfc8925a4a062f006
- lvgl/lvgl
manifest_hash: 4473d0e2ac253f075f7d119652fd5c083329ed318f83b05750b1531f4da7099a
target: esp32s3
version: 2.0.0
set(SOURCES "wifidevnum_config.c"
"mqttconf/mqttconf_commun.c"
#"led/gpio_led.c"
"boards/serial/serial.c"
"boards/gpiotrol/gpiocontrol.c"
"boards/gpiotrol/betteryread.c"
#"boards/common/board_common.c" # 统一入口文件
"drive/serial/serial.c"
"drive/serial/serialota.c"
"drive/gpiotrol/gpiocontrol.c"
"drive/gpiotrol/betteryread.c"
"hardware/rgb/ws2812_control.c"
"hardware/lcd/lcd.c"
"ota.c"
"main.c")
set(INCLUDE_DIRS "."
"mqttconf"
"boards/serial"
"boards/gpiotrol"
#"boards/common"
"drive/serial"
"drive/gpiotrol"
"hardware/lcd"
"hardware/rgb"
)
......@@ -34,6 +36,8 @@ idf_component_register(SRCS ${SOURCES}
esp_adc
mqtt
json
lvgl
esp_lcd
)
spiffs_create_partition_image(storage ../www FLASH_IN_PROJECT)
......
......@@ -6,6 +6,12 @@ config ROBIOT_WIFI_SSID
help
Hotspot Name Settings.
config STM32_OTA_URL
string "STM32 OTA URL"
default ""
help
STM32 OTA Config URL
config ROBOIOT_MQTT_URL
string "MQTT URL"
default "https://fcrs-api.yd-ss.com/device/getConfig?deviceNo="
......@@ -18,26 +24,27 @@ config ROBOIOT_MQTT_URL
help
The version number of this firmware.
choice DEVICE_STM32_SERIAL_MODE
prompt "Does it have an STM32 serial?"
default MODE_SERIAL_WHETHER_OPEN
choice DEVICE_TYPE
prompt "选择设备类型"
default TYPE_ROBOT_0502
help
选择是否有串口心跳检测
选择设备类型(默认机甲大师,机甲大师一段要选串口,使用其他需要单独选择控制)
config MODE_SERIAL_WHETHER_OPEN
bool "open stm32 serial beat"
config TYPE_ROBOT_0502
bool "机甲大师0502"
help
打开串口心跳检测(适用于将esp32s3作为中间联网使用)
机甲大师0502
config MODE_SERIAL_WHETHER_CLOSE
bool "close stm32 serial beat"
config TYPE_CAR_0101
bool "大车0101"
help
关闭串口心跳检测,使用esp32引脚控制和心跳(适用于单ESP32)
大车0101
config MODE_SERIAL_AND_GPIO
bool "open stm32 serial and gpio"
config TYPE_CAR_0102
bool "小车0102"
help
同时打开串口心跳和引脚使用()
小车0102
endchoice
......
......@@ -53,6 +53,10 @@ esp_err_t board_adc_init(void) {
return ESP_OK;
}
/**
* @brief 读取当前电压值
* @return int 返回毫伏值 (mV),读取失败返回 -1
*/
// 核心修改:返回 float
float board_get_voltage_v(void) {
int adc_raw;
......
......@@ -2,18 +2,28 @@
#define BETTERYREAD_H
#include "esp_err.h"
#include "serial.h"
#define ADC_GET_VOLTAGE_GPIO 5
float board_get_voltage_v(void);
/**
* @brief 初始化 ADC1 通道 4 (GPIO 5)
*/
esp_err_t board_adc_init(void);
/**
* @brief 读取当前电压值
* @return int 返回毫伏值 (mV),读取失败返回 -1
*/
float board_get_voltage_v(void);
#if defined(CONFIG_TYPE_CAR_0102)
#define get_voltage_v() board_get_voltage_v()
#define get_temperature() (0.0f)
#elif defined(CONFIG_TYPE_ROBOT_0502)
#define get_voltage_v() get_stm32_battery_voltage()
#define get_temperature() get_stm32_battery_tempvalue()
#elif defined(CONFIG_TYPE_CAR_0101)
#define get_voltage_v()
#else
#error "请选择正确的设备型号"
#endif
#endif
\ No newline at end of file
#include "gpiocontrol.h"
#include "esp_log.h"
#include "serial.h"
static const char *TAG = "GPIO_CONTROL";
......@@ -109,7 +110,6 @@ void car0102_speed_stop(void) {
ESP_LOGD(TAG, "电机已强制停止输出");
}
void car0102_control_motor(int mode ,int val){
if(mode == 1){
......@@ -142,9 +142,17 @@ void car0102_control_motor(int mode ,int val){
}
}
void esc_set_throttle(uint8_t percent)
void esc_set_throttle(int pin,int val)
{
if (percent > 100) percent = 100;
uint8_t percent=0;
if(pin==27&&val==0){
percent=0;
}else if(pin==27&&val==1){
percent=35;
}
uint32_t duty = ESC_MIN_DUTY +
(ESC_MAX_DUTY - ESC_MIN_DUTY) * percent / 100;
......@@ -155,3 +163,12 @@ void esc_set_throttle(uint8_t percent)
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_4, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_4);
}
void robot0502_stop(void){
serial_send_command(0x00,0x00,0xff,0x00,0x00);
esc_set_throttle(27,0);
}
void robot0502_control_motor(int mode ,int val){
serial_send_command(mode,val,0xff,0x00,0x00);
}
\ No newline at end of file
......@@ -7,7 +7,7 @@
// 引脚定义
#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电调控制引脚
......@@ -35,11 +35,33 @@
* @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(int pin,int val);
void robot0502_stop(void);
void robot0502_control_motor(int mode ,int val);
void esc_set_throttle(uint8_t percent);
#if defined(CONFIG_TYPE_CAR_0102)
// 如果是 0102 型号,重定向到它的特定函数
#define device_hardware_stop() car0102_speed_stop()
#define device_hardware_shot(pin,val) do { } while(0)
#define device_hardware_pintrol() do { } while(0)
#define device_hardware_control(mode, val) car0102_control_motor(mode, val)
#define GPIO_PWM_SERVO_10 10
#elif defined(CONFIG_TYPE_ROBOT_0502)
// 如果是其他型号
#define device_hardware_stop() robot0502_stop()
#define device_hardware_shot(pin,val) esc_set_throttle(pin,val)
#define device_hardware_pintrol() do { } while(0)
#define device_hardware_control(mode, val) robot0502_control_motor(mode ,val)
#define GPIO_PWM_SERVO_10 -1
#elif defined(CONFIG_TYPE_CAR_0101)
// 通用型号
#define device_hardware_stop() car0101_speed_stop()
#else
// 默认空操作,防止报错
#error "请选择正确的设备型号"
#endif
#endif
\ No newline at end of file
......@@ -112,7 +112,7 @@ void serial_receive_task(void *pvParameters) {
while (1) {
if(g_serial_enabled != true){
vTaskDelay(pdMS_TO_TICKS(100));
break;
continue;
}
// 1. 读取串口数据 (非阻塞或短超时)
int len = uart_read_bytes(STM32_UART_PORT, data, sizeof(data), pdMS_TO_TICKS(100));
......
......@@ -32,15 +32,5 @@ void serial_send_command(uint8_t mode, uint8_t value,uint8_t data3,uint8_t data4
// 接收处理任务入口 (在 app_main 中启动)
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
\ No newline at end of file
#include "serialota.h"
#include "serial.h" // 使用你提供的串口定义
#include "esp_http_client.h"
#include "esp_partition.h"
#include "esp_log.h"
#include "driver/uart.h"
#include <string.h>
static const char *TAG = "STM32_OTA";
// 分区元数据
#define PARTITION_SUBTYPE_STM32 0x40
#define PARTITION_NAME "stm32ota"
/**
* HTTP 事件处理:将下载的数据流写入 Flash 分区
*/
static esp_err_t _http_event_handler(esp_http_client_event_t *evt) {
static const esp_partition_t *partition = NULL;
static size_t written_len = 0;
switch (evt->event_id) {
case HTTP_EVENT_ON_CONNECTED:
partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, PARTITION_SUBTYPE_STM32, PARTITION_NAME);
if (!partition) {
ESP_LOGE(TAG, "找不到 stm32ota 分区");
return ESP_FAIL;
}
// 擦除分区(简单处理:全擦除。实际可根据 content-length 擦除)
esp_partition_erase_range(partition, 0, partition->size);
written_len = 0;
break;
case HTTP_EVENT_ON_DATA:
if (partition && evt->data_len > 0) {
esp_partition_write(partition, written_len, evt->data, evt->data_len);
written_len += evt->data_len;
ESP_LOGD(TAG, "已下载: %d bytes", written_len);
}
break;
default:
break;
}
return ESP_OK;
}
esp_err_t stm32_ota_download_from_url(const char *url) {
esp_http_client_config_t config = {
.url = url,
.event_handler = _http_event_handler,
.timeout_ms = 10000,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HEX 文件下载完成");
} else {
ESP_LOGE(TAG, "下载失败: %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
return err;
}
/**
* 简单的 Intel HEX 字符转字节
*/
static uint8_t hex2byte(const char *hex) {
uint8_t byte = 0;
for (int i = 0; i < 2; i++) {
char c = hex[i];
byte <<= 4;
if (c >= '0' && c <= '9') byte |= (c - '0');
else if (c >= 'A' && c <= 'F') byte |= (c - 'A' + 10);
else if (c >= 'a' && c <= 'f') byte |= (c - 'a' + 10);
}
return byte;
}
/**
* 核心烧录逻辑:读取分区 -> 解析 HEX -> 串口发送
*/
esp_err_t stm32_ota_start_update(void) {
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, PARTITION_SUBTYPE_STM32, PARTITION_NAME);
if (!partition) return ESP_FAIL;
// 1. 禁用普通的串口接收任务,防止冲突
set_serial_enabled(false);
vTaskDelay(pdMS_TO_TICKS(100));
// 2. 发送开始升级指令 (自定义协议)
// 假设 mode=0xF0, value=0x01 是进入 Bootloader 的指令
serial_send_command(0xF0, 0x01, 0, 0, 0);
vTaskDelay(pdMS_TO_TICKS(500)); // 等待 STM32 擦除 Flash
char line[128];
size_t offset = 0;
uint8_t bin_buf[32];
ESP_LOGI(TAG, "开始解析并发送数据...");
// 循环读取分区里的 HEX 文件行
// 注意:HEX 文件是以 ':' 开头的文本行
while (offset < partition->size) {
// 简化处理:逐字节查找换行符读取一行
int line_ptr = 0;
char c;
while (line_ptr < 127) {
esp_partition_read(partition, offset++, &c, 1);
if (c == '\n' || c == '\r') {
if (line_ptr > 0) break;
else continue;
}
line[line_ptr++] = c;
if (offset >= partition->size) break;
}
line[line_ptr] = '\0';
if (line[0] == ':') {
// 解析 Intel HEX
uint8_t len = hex2byte(&line[1]);
uint8_t type = hex2byte(&line[7]);
if (type == 0x00) { // 数据记录
for (int i = 0; i < len; i++) {
bin_buf[i] = hex2byte(&line[9 + i * 2]);
}
// 通过串口发送二进制块给 STM32
uart_write_bytes(STM32_UART_PORT, (const char *)bin_buf, len);
// 等待 STM32 的应答 (ACK: 0x06)
uint8_t ack = 0;
int rx_len = uart_read_bytes(STM32_UART_PORT, &ack, 1, pdMS_TO_TICKS(500));
if (rx_len <= 0 || ack != 0x06) {
ESP_LOGE(TAG, "STM32 无响应或校验失败");
goto error;
}
} else if (type == 0x01) { // 文件结束记录
ESP_LOGI(TAG, "解析完成");
break;
}
}
}
// 3. 结束升级,跳转 APP
serial_send_command(0xF0, 0x02, 0, 0, 0);
set_serial_enabled(true);
return ESP_OK;
error:
set_serial_enabled(true);
return ESP_FAIL;
}
\ No newline at end of file
#ifndef __SERIALOTA_H__
#define __SERIALOTA_H__
#include "esp_err.h"
/**
* @brief 从 URL 下载 HEX 文件并存入 stm32ota 分区
* @param url HEX 文件的下载链接
* @return esp_err_t ESP_OK 表示下载成功并存储
*/
esp_err_t stm32_ota_download_from_url(const char *url);
/**
* @brief 读取 stm32ota 分区中的 HEX 并通过串口烧录到 STM32
* @return esp_err_t ESP_OK 表示烧录成功
*/
esp_err_t stm32_ota_start_update(void);
#if defined(CONFIG_TYPE_ROBOT_0502)
#define stm32_ota_update() stm32_ota_start_update()
#define stm32_ota_download_url(url) stm32_ota_download_from_url(url)
#endif
#endif
\ No newline at end of file
#include "lcd.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_heap_caps.h"
static const char *TAG = "LCD_DEBUG";
static esp_lcd_panel_handle_t panel_handle = NULL;
static lv_disp_draw_buf_t draw_buf;
static lv_disp_drv_t disp_drv;
SemaphoreHandle_t lvgl_mux = NULL;
// 1. 刷新回调 - 增加日志输出,确认回调是否在跑
static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) {
esp_lcd_panel_handle_t panel = (esp_lcd_panel_handle_t)drv->user_data;
// 这里的坐标打印非常重要,看看是不是在刷新 0,0 坐标
// ESP_LOGD(TAG, "Flush: x(%d-%d), y(%d-%d)", area->x1, area->x2, area->y1, area->y2);
esp_lcd_panel_draw_bitmap(panel, area->x1, area->y1, area->x2 + 1, area->y2 + 1, color_map);
// 直接在这里同步通知完成
lv_disp_flush_ready(drv);
}
static void lvgl_tick_cb(void *arg) {
lv_tick_inc(2);
}
static void lvgl_port_task(void *arg) {
while (1) {
if (xSemaphoreTake(lvgl_mux, pdMS_TO_TICKS(100)) == pdTRUE) {
lv_timer_handler();
xSemaphoreGive(lvgl_mux);
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
static esp_err_t display_lvgl_init(void) {
lvgl_mux = xSemaphoreCreateMutex();
lv_init();
// 硬件复位
gpio_reset_pin(TFT_BL);
gpio_set_direction(TFT_BL, GPIO_MODE_OUTPUT);
gpio_set_level(TFT_BL, 1);
gpio_reset_pin(TFT_RST);
gpio_set_direction(TFT_RST, GPIO_MODE_OUTPUT);
gpio_set_level(TFT_RST, 0);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(TFT_RST, 1);
vTaskDelay(pdMS_TO_TICKS(100));
// SPI 总线
spi_bus_config_t buscfg = {
.sclk_io_num = TFT_SCLK,
.mosi_io_num = TFT_MOSI,
.miso_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = LCD_H_RES * LCD_V_RES * 2
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
// 接口配置
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_spi_config_t io_cfg = {
.dc_gpio_num = TFT_DC,
.cs_gpio_num = TFT_CS,
.pclk_hz = 10 * 1000 * 1000,
.spi_mode = 3,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.trans_queue_depth = 10,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI2_HOST, &io_cfg, &io_handle));
// 驱动安装
esp_lcd_panel_dev_config_t panel_cfg = {
.reset_gpio_num = -1,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_cfg, &panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
// 【修改点 A】:切换颜色反转测试
// 如果黑屏,尝试将 true 改为 false
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
// 【修改点 B】:设置偏移量
// 重点!! 7 针 ST7789 240x240 绝大部分需要 Y 轴偏移 80
// 如果 0,0 是黑屏,请务必尝试 0, 80
ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, 0));
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
// 分配缓冲区
size_t buf_size = LCD_H_RES * LCD_DRAW_BUF_HEIGHT * sizeof(lv_color_t);
lv_color_t *buf1 = heap_caps_malloc(buf_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, LCD_H_RES * LCD_DRAW_BUF_HEIGHT);
// 注册驱动
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = LCD_H_RES;
disp_drv.ver_res = LCD_V_RES;
disp_drv.flush_cb = lvgl_flush_cb;
disp_drv.draw_buf = &draw_buf;
disp_drv.user_data = panel_handle;
lv_disp_drv_register(&disp_drv);
// Tick 定时器
const esp_timer_create_args_t tick_args = { .callback = lvgl_tick_cb, .name = "lvgl_tick" };
esp_timer_handle_t tick_timer;
esp_timer_create(&tick_args, &tick_timer);
esp_timer_start_periodic(tick_timer, 2000);
xTaskCreatePinnedToCore(lvgl_port_task, "lvgl_task", 4096 * 2, NULL, 5, NULL, 1);
ESP_LOGI(TAG, "LVGL 初始化完成,当前偏移 ");
return ESP_OK;
}
esp_err_t lcd_init_show(void){
// 1. 初始化驱动
display_lvgl_init();
vTaskDelay(pdMS_TO_TICKS(1000));
// 2. 创建 UI (必须加锁)
if (xSemaphoreTake(lvgl_mux, portMAX_DELAY) == pdTRUE) {
// 1. 获取当前活动屏幕
lv_obj_t * screen = lv_scr_act();
// --- 设置背景为白色 (White) ---
lv_obj_set_style_bg_color(screen, lv_color_hex(0xFFFFFF), 0);
lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, 0);
// 2. 创建标签
lv_obj_t * label_cn = lv_label_create(screen);
// --- 设置字体 (Simsun 16 CJK) ---
lv_obj_set_style_text_font(label_cn, &lv_font_simsun_16_cjk, 0);
// --- 设置中文内容 (确保 VS Code 右下角显示为 UTF-8) ---
lv_label_set_text(label_cn, "电压:");
// --- 设置文字颜色为黑色 (Black) ---
lv_obj_set_style_text_color(label_cn, lv_color_hex(0x000000), 0);
// 3. 居中显示
lv_obj_center(label_cn);
xSemaphoreGive(lvgl_mux);
}
return ESP_OK;
}
\ No newline at end of file
#ifndef __LCD_H__
#define __LCD_H__
#include "esp_err.h"
#include "lvgl.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
// --- 经验证成功的引脚 ---
#define TFT_SCLK 1
#define TFT_MOSI 2
#define TFT_DC 3
#define TFT_RST 8
#define TFT_BL 9
#define TFT_CS -1
#define LCD_H_RES 240
#define LCD_V_RES 240
#define LCD_DRAW_BUF_HEIGHT 50 // 缓冲区行数
// 声明全局互斥锁,解决多核崩溃问题
extern SemaphoreHandle_t lvgl_mux;
esp_err_t lcd_init_show(void);
#endif
\ No newline at end of file
#include "ws2812_control.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_log.h"
#include "esp_system.h"
#include "esp_heap_caps.h" // 必须包含:用于 heap_caps_calloc
#include "freertos/FreeRTOS.h" // 必须包含:用于 portMAX_DELAY
#include "driver/rmt_tx.h"
#include "driver/gpio.h"
static const char *TAG = "ws2812";
// 全局变量
static rmt_channel_handle_t tx_chan = NULL;
static rmt_encoder_handle_t encoder = NULL;
static uint8_t *led_buffer = NULL;
static int led_count = 0;
// 字节编码器配置
static rmt_bytes_encoder_config_t bytes_encoder_config = {
.bit0 = {
.level0 = 1, .duration0 = T0H_NS * RMT_TICK_PER_US / 1000,
.level1 = 0, .duration1 = T0L_NS * RMT_TICK_PER_US / 1000,
},
.bit1 = {
.level0 = 1, .duration0 = T1H_NS * RMT_TICK_PER_US / 1000,
.level1 = 0, .duration1 = T1L_NS * RMT_TICK_PER_US / 1000,
},
.flags.msb_first = 1
};
static void ws2812_deinit(void) {
if (encoder) rmt_del_encoder(encoder);
if (tx_chan) {
rmt_disable(tx_chan);
rmt_del_channel(tx_chan);
}
if (led_buffer) free(led_buffer);
encoder = NULL;
tx_chan = NULL;
led_buffer = NULL;
led_count = 0;
}
esp_err_t ws2812_init(void) {
esp_err_t ret;
ws2812_deinit();
led_count = LED_COUNT;
// 修正:使用 LED_COUNT 宏,并包含 esp_heap_caps.h
led_buffer = heap_caps_calloc(led_count, 3, MALLOC_CAP_DMA);
if (!led_buffer) {
ESP_LOGE(TAG, "内存分配失败");
return ESP_ERR_NO_MEM;
}
rmt_tx_channel_config_t tx_chan_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.gpio_num = RGB_PIN, // 修正:对应 .h 中的宏
.mem_block_symbols = 64,
.resolution_hz = RMT_RESOLUTION_HZ,
.trans_queue_depth = 4,
.flags.invert_out = false,
};
ret = rmt_new_tx_channel(&tx_chan_config, &tx_chan);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "创建RMT通道失败");
free(led_buffer);
return ret;
}
ret = rmt_new_bytes_encoder(&bytes_encoder_config, &encoder);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "创建编码器失败");
rmt_del_channel(tx_chan);
free(led_buffer);
return ret;
}
ret = rmt_enable(tx_chan);
if (ret != ESP_OK) {
rmt_del_encoder(encoder);
rmt_del_channel(tx_chan);
free(led_buffer);
return ret;
}
// 修正:打印变量名统一
ESP_LOGI(TAG, "WS2812初始化完成, GPIO: %d, LED数量: %d", RGB_PIN, LED_COUNT);
return ESP_OK;
}
void ws2812_set_color(uint8_t r, uint8_t g, uint8_t b) {
if (!led_buffer || !tx_chan || !encoder) return;
for (int i = 0; i < led_count; i++) {
int idx = i * 3;
led_buffer[idx] = g;
led_buffer[idx + 1] = r;
led_buffer[idx + 2] = b;
}
rmt_transmit_config_t tx_config = {
.loop_count = 0,
.flags.eot_level = 0,
};
// 现在 portMAX_DELAY 可以识别了
rmt_transmit(tx_chan, encoder, led_buffer, led_count * 3, &tx_config);
rmt_tx_wait_all_done(tx_chan, portMAX_DELAY);
}
void ws2812_clear(void) {
ws2812_set_color(0, 0, 0);
}
#ifndef __RGB_LED_H__
#define __RGB_LED_H__
#include "esp_err.h"
#include <stdint.h>
#define RGB_PIN 48 // 连接到RGB灯带数据线
#define LED_COUNT 8 // 8个RGB灯珠
#define RMT_RESOLUTION_HZ 10000000 // RMT分辨率:10MHz (0.1us)
#define RMT_TICK_PER_US 10 // 每微秒的tick数
// RMT配置
#define T0H_NS 350 // 0码高电平时间
#define T0L_NS 800 // 0码低电平时间
#define T1H_NS 700 // 1码高电平时间
#define T1L_NS 600 // 1码低电平时间
/**
* @brief 初始化WS2812 LED灯带
* @param gpio_num 控制引脚(如GPIO_NUM_48)
* @param led_num LED数量
* @return esp_err_t ESP_OK表示成功
*/
esp_err_t ws2812_init(void);
/**
* @brief 设置所有LED颜色
* @param r 红色值 (0-255)
* @param g 绿色值 (0-255)
* @param b 蓝色值 (0-255)
*/
void ws2812_set_color(uint8_t r, uint8_t g, uint8_t b);
/**
* @brief 清除所有LED(关闭)
*/
void ws2812_clear(void);
#endif
\ No newline at end of file
......@@ -15,3 +15,4 @@ dependencies:
# # All dependencies of `main` are public by default.
# public: true
espressif/cJSON: '*'
lvgl/lvgl: ^8.3.11
#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
......@@ -10,11 +10,16 @@
#include "betteryread.h"
#include "gpiocontrol.h"
#include "serial.h"
#include "ws2812_control.h"
#include "ota.h"
#include "lcd.h"
#include "esp_lcd_panel_ops.h"
static const char *TAG = "MAIN";
static bool init_task_triggered = false;
LV_FONT_DECLARE(lv_font_simsun_16_cjk);
static void wifi_event_handler(void* arg, esp_event_base_t base, int32_t id, void* data) {
if (base == IP_EVENT && id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) data;
......@@ -38,26 +43,27 @@ 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
#if defined(CONFIG_TYPE_CAR_0102)
ESP_ERROR_CHECK(board_adc_init());
ESP_ERROR_CHECK(gpiocontrol_init());
ESP_LOGI(TAG, "使用CAR_0102");
#elif defined(TYPE_ROBOT_0502)
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, "使用自带引脚控制模式");
ESP_LOGI(TAG, "使用ROBOT_0502");
#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);
#error "请选择正确的设备型号"
#endif
return ESP_OK;
}
void app_main(void) {
vTaskDelay(pdMS_TO_TICKS(10000));
//vTaskDelay(pdMS_TO_TICKS(10000));
esp_err_t ret = nvs_flash_init();
......@@ -75,6 +81,7 @@ void app_main(void) {
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(ws2812_init());
if (wifi_ret == ESP_OK) {
read_from_nvs("wifi_pass", pass, sizeof(pass));
......@@ -87,8 +94,7 @@ void app_main(void) {
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL);
esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &wifi_event_handler, NULL, NULL);
xTaskCreate(button_monitor_task, "btn_task", 4096, NULL, 5, NULL);
button_monitor_task_init();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
......@@ -108,8 +114,10 @@ void app_main(void) {
esp_wifi_connect();
}else{
ESP_LOGI(TAG, "无保存wifi 信息,启动wifi 配置页面");
ws2812_set_color(155, 0, 0);
nowifidata_start_config_web();
}
}
\ No newline at end of file
......@@ -24,6 +24,7 @@
#include "gpiocontrol.h"
#include "betteryread.h"
#include "ota.h"
#include "ws2812_control.h"
static const char *TAG = "MQTT_MGR";
#define DEFAULT_MQTT_HOST "119.45.167.177"
......@@ -44,8 +45,7 @@ static esp_mqtt_client_handle_t client_list[MAX_MQTT_CLIENTS] = {NULL};
static int client_count = 0;
static esp_timer_handle_t g_hb_timer = NULL;
static
static int mqttabnormal_exit_count = 0;
int mqtt_send_deviceota_info(void);
......@@ -65,13 +65,8 @@ static void handle_remote_control(const char *data) {
if (pin_ctrl) {
int pin = cJSON_GetObjectItem(pin_ctrl, "pin")->valueint;
int val = cJSON_GetObjectItem(pin_ctrl, "val")->valueint;
if(pin == 27&&val == 1) esc_set_throttle(25);
if(pin == 27&&val == 0) esc_set_throttle(0);
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);
device_hardware_shot(pin,val);
}
} else if (m_type && m_type->valueint == 3 && body) {
cJSON *pwm_ctrl = cJSON_GetObjectItem(body, "pwm_ctrl");
......@@ -80,13 +75,7 @@ static void handle_remote_control(const char *data) {
int type = cJSON_GetObjectItem(pwm_ctrl, "type")->valueint;
int val = cJSON_GetObjectItem(pwm_ctrl, "val")->valueint;
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
#elif DEVICE_SERIAL_BEAT ==1
car0102_control_motor(mode, val);
#else
ESP_LOGW(TAG,"看情况");
#endif
device_hardware_control(mode, val);
}
}
......@@ -104,26 +93,12 @@ static char* generate_hb_payload() {
cJSON_AddStringToObject(body, "ip", g_sta_ip);
char id_full[64], volat[16];
char id_full[64], volat[16],tempvalue[16];
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(tempvalue, sizeof(tempvalue), "%.2f", get_stm32_battery_tempvalue());
snprintf(volat, sizeof(volat), "%.2f",get_voltage_v());
snprintf(tempvalue, sizeof(tempvalue), "%.2f", get_temperature());
cJSON_AddStringToObject(body, "tempvalue", tempvalue);
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, "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);
......@@ -177,11 +152,14 @@ void ota_msg_send_task(void *pvParameters) {
// 在任务内部进行延迟,不阻塞其他程序
vTaskDelay(pdMS_TO_TICKS(delay_seconds * 1000));
ESP_LOGI("OTA_TASK", "延迟结束,正在发送 MQTT OTA 信息...");
// 执行你的 MQTT 发送逻辑
mqtt_send_deviceota_info();
ws2812_set_color(0, 0, 0);
// 2. 关键:发送完毕后,任务自行销毁,实现“自动取消”和内存释放
ESP_LOGI("OTA_TASK", "发送完成,任务已自动退出并销毁");
vTaskDelete(NULL);
......@@ -218,6 +196,7 @@ static void common_mqtt_event_handler(void *handler_args, esp_event_base_t base,
ESP_LOGI(TAG, "[%s] 已连接", ip);
if(strcmp(ip,DEFAULT_MQTT_HOST)==0){
start_ota_report_timer(5);
ws2812_set_color(0, 0, 255);
}
char s1[64], s2[64];
snprintf(s1, sizeof(s1), "app2dev/%s", g_device_id);
......@@ -230,6 +209,7 @@ static void common_mqtt_event_handler(void *handler_args, esp_event_base_t base,
if (event->data_len > 0) {
char *tmp = malloc(event->data_len + 1);
if (tmp) {
mqttabnormal_exit_count = 0;
memcpy(tmp, event->data, event->data_len);
tmp[event->data_len] = '\0';
handle_remote_control(tmp);
......@@ -366,10 +346,6 @@ start_timer:
vTaskDelete(NULL);
}
void mqtt_manager_init_sequence(void) {
xTaskCreate(config_pull_and_init_task, "mqtt_init", 10240, NULL, 5, NULL);
}
// 新增停止函数
void mqtt_manager_stop(void) {
ESP_LOGW(TAG, "正在停止 MQTT 服务...");
......@@ -438,37 +414,37 @@ exit:
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;
// }
// }
/*
* @brief MQTT 异常任务
*/
void mqtt_abnormal_exittask(void *pvParameters)
{
vTaskDelay(pdMS_TO_TICKS(3000));
ESP_LOGI(TAG, "MQTT异常任务启动");
while(1){
if(client_list[0] == NULL) {
vTaskDelay(pdMS_TO_TICKS(1000));
continue;
}
if(mqttabnormal_exit_count>5){
device_hardware_stop();
mqttabnormal_exit_count=6;
}
mqttabnormal_exit_count++;
vTaskDelay(pdMS_TO_TICKS(100));
}
// }
//#elif defined(CONFIG_MODE_SERIAL_AND_GPIO)
}
/* MQTT 异常任务初始化*/
void mqtt_abnormal_exittask_init(void) {
xTaskCreate(mqtt_abnormal_exittask, "mqtt_exit", 512, NULL, 5, NULL);
}
// #endif
\ No newline at end of file
/**
* @brief MQTT 初始化任务
*/
void mqtt_manager_init_sequence(void) {
xTaskCreate(config_pull_and_init_task, "mqtt_init", 10240, NULL, 5, NULL);
}
\ No newline at end of file
......@@ -15,6 +15,7 @@
#include "esp_spiffs.h"
#include "mqttconf_commun.h"
#include "serial.h"
#include "ws2812_control.h"
static const char *TAG = "WIFI_CFG";
static bool wifi_editable = false;
......@@ -154,6 +155,7 @@ void dns_server_task(void *pvParameters) {
memcpy(rx_buffer + len, answer, sizeof(answer));
sendto(sock, rx_buffer, len + sizeof(answer), 0, (struct sockaddr *)&source_addr, sizeof(source_addr));
}
}
}
......@@ -165,6 +167,7 @@ esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err) {
}
void start_config_web() {
ws2812_set_color(255, 0, 255);
esp_wifi_stop();
esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
......@@ -176,7 +179,6 @@ void start_config_web() {
esp_wifi_set_config(WIFI_IF_AP, &ap_cfg);
esp_wifi_start();
xTaskCreate(dns_server_task, "dns", 3072, NULL, 5, NULL);
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
if (httpd_start(&server, &config) == ESP_OK) {
......@@ -205,7 +207,15 @@ void button_monitor_task(void* arg) {
bool web_started = false;
while (1) {
if (gpio_get_level(BTN_WIFI_IO) == 0) {
if (++wifi_cnt == 30) {
if(!wifi_editable){
ws2812_set_color(255, 127, 0);
vTaskDelay(pdMS_TO_TICKS(50));
ws2812_set_color(0, 0, 0);
}
if (++wifi_cnt == 20) {
wifi_editable = true;
if(!web_started){
mqtt_manager_stop(); // 停止 MQTT
......@@ -217,7 +227,14 @@ void button_monitor_task(void* arg) {
} else wifi_cnt = 0;
if (gpio_get_level(BTN_DEVID_IO) == 0) {
if (++dev_cnt == 30) {
if(!devid_editable){
ws2812_set_color(255, 255, 0);
vTaskDelay(pdMS_TO_TICKS(50));
ws2812_set_color(0, 0, 0);
}
if (++dev_cnt == 20) {
devid_editable = true;
if(!web_started){
mqtt_manager_stop();
......@@ -227,6 +244,15 @@ void button_monitor_task(void* arg) {
}
}
} else dev_cnt = 0;
vTaskDelay(pdMS_TO_TICKS(100));
}
}
/*
* 按键监控任务初始化
*/
void button_monitor_task_init(void)
{
xTaskCreate(button_monitor_task, "btn_task", 4096, NULL, 5, NULL);
}
\ No newline at end of file
......@@ -6,14 +6,15 @@
// 引脚定义 (ESP32-S3 默认 BOOT 键一般是 0)
#define BTN_WIFI_IO 0
#define BTN_DEVID_IO 4
//#define BTN_BUT_ID 3 //未使用
// 函数声明
void save_to_nvs(const char* key, const char* value);
esp_err_t read_from_nvs(const char* key, char* buf, size_t len);
void button_monitor_task(void* arg);
void start_config_web(void);
esp_err_t init_spiffs(void);
void nowifidata_start_config_web(void);
void button_monitor_task_init(void);
#endif
\ No newline at end of file
......@@ -5,4 +5,5 @@ phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 0x600000,
ota_1, app, ota_1, , 0x600000,
storage, data, spiffs, , 0x50000,
stm32otadata, data, stm32, , 0x100000
\ No newline at end of file
# 使用 0x40 作为自定义数据类型的标识
stm32ota, data, 0x40, , 0x60000
\ No newline at end of file
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