Add initial board, HAL, and executor modules
This commit is contained in:
1 parent
3b9e129c88
commit
0b2eebe76d
82 files changed
+20611
No files matched your search
@@ -0,0 +1,25 @@
|
||||
#ifndef BOARD_SELECTION_H
|
||||
#define BOARD_SELECTION_H
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// 根据menuconfig的配置选择不同的board版本
|
||||
#ifdef CONFIG_BOARD_VERSION_V1_1_11
|
||||
#include "02_physical/boards/board_v1_1_11/board_sweekar.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_12)
|
||||
#include "02_physical/boards/board_v1_1_12/board_sweekar.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_13)
|
||||
#include "02_physical/boards/board_v1_1_13/board_sweekar.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_14)
|
||||
#include "02_physical/boards/board_v1_1_14/board_sweekar.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_16)
|
||||
#include "02_physical/boards/board_v1_1_16/board_sweekar.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_17)
|
||||
#include "02_physical/boards/board_v1_1_17/board_sweekar.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_18)
|
||||
#include "02_physical/boards/board_v1_1_18/board_sweekar.h"
|
||||
#else
|
||||
#include "02_physical/boards/board_v1_1_11/board_sweekar.h"
|
||||
#endif
|
||||
|
||||
#endif // BOARD_SELECTION_H
|
||||
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* @file board.cc
|
||||
* @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "esp_check.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "i2c_bus.h"
|
||||
}
|
||||
|
||||
#include "board_sweekar.h"
|
||||
#include "config.h"
|
||||
#include "drv8428.h"
|
||||
#include "aw8646.h"
|
||||
|
||||
#define TAG "board_sweekar"
|
||||
|
||||
BoardSweekar::BoardSweekar()
|
||||
{
|
||||
#ifdef CONFIG_STEPPER_DRIVER_AW8646
|
||||
stepper_driver_ = new Aw8646Driver(io_expansion_);
|
||||
#else
|
||||
stepper_driver_ = new Drv8428Driver(io_expansion_);
|
||||
#endif
|
||||
}
|
||||
|
||||
BoardSweekar::~BoardSweekar()
|
||||
{
|
||||
if (stepper_driver_) {
|
||||
delete stepper_driver_;
|
||||
stepper_driver_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @file board.h
|
||||
* @brief 板级外设初始化类
|
||||
*/
|
||||
/**
|
||||
* @brief 步进电机初始化函数
|
||||
*
|
||||
* 配置LEDC定时器和通道用于PWM输出,设置步进电机的工作模式、使能状态、细分模式和方向,
|
||||
* 并初始化PWM占空比为50%。初始化过程中若出现错误,会通过ESP_LOGE输出错误信息及错误码。
|
||||
*/
|
||||
void BoardSweekar::StepperMotorInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) STEP 引脚改为普通 GPIO
|
||||
gpio_config_t io_cfg;
|
||||
io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO;
|
||||
io_cfg.mode = GPIO_MODE_OUTPUT;
|
||||
io_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_cfg.intr_type = GPIO_INTR_DISABLE;
|
||||
err = gpio_config(&io_cfg);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 初始电平拉低
|
||||
gpio_set_level(STEPPER_STEP_IO, 0);
|
||||
|
||||
// 2) 检查 I2C 总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) 初始化驱动对象并初始化
|
||||
if (stepper_driver_) {
|
||||
err = stepper_driver_->Init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达串口初始化函数
|
||||
*
|
||||
* 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚,
|
||||
* 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免
|
||||
* 与自定义中断冲突。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突)
|
||||
// 增加 RX/TX FIFO 深度以处理突发数据
|
||||
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4,
|
||||
0, NULL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达中断引脚初始化函数
|
||||
*
|
||||
* 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能
|
||||
* (如需使用中断需单独进行配置)。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarGpioInit(void)
|
||||
{
|
||||
// GPIO配置结构体
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚
|
||||
.mode = GPIO_MODE_INPUT, // 设置为输入模式
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉
|
||||
.intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置)
|
||||
};
|
||||
|
||||
// 配置GPIO
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2C总线及从机设备初始化函数
|
||||
*
|
||||
* 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。
|
||||
* 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。
|
||||
* 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::I2CMasterInit(void)
|
||||
{
|
||||
static const char *I2C_INIT = "I2C_INIT";
|
||||
|
||||
// 初始化IO扩展板复位引脚
|
||||
gpio_config_t reset_io_conf = {
|
||||
.pin_bit_mask = (1ULL << IO_EXPAND_RSTN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&reset_io_conf);
|
||||
|
||||
// 执行复位时序:先拉低100ms,再拉高并等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板复位完成");
|
||||
|
||||
// 创建统一的I2C总线(使用ESP-ADF的i2c_bus)
|
||||
i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C0_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C0_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = 100000,
|
||||
},
|
||||
};
|
||||
|
||||
// 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线)
|
||||
bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg);
|
||||
if (bus_handle_ == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create I2C bus");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
// ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信
|
||||
|
||||
// 验证线性马达设备是否存在
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR);
|
||||
}
|
||||
// 验证IO扩展板设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化其他设备
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR);
|
||||
}
|
||||
// 验证陀螺仪设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR);
|
||||
}
|
||||
|
||||
// 为IO扩展板设置总线句柄和设备地址(使用7位地址)
|
||||
io_expansion_.bus_handle_ = bus_handle_;
|
||||
io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1;
|
||||
|
||||
// 为线性马达设置总线句柄和设备地址(使用7位地址)
|
||||
linear_motor_.bus_handle_ = bus_handle_;
|
||||
linear_motor_.device_addr_ = LINEAR_MOTOR_I2C_SLAVE_ADDR << 1;
|
||||
|
||||
ESP_LOGI(I2C_INIT, "I2C总线初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 开启VBAT to VBAT_5V
|
||||
*
|
||||
* 创建开启升压的电源管理单元
|
||||
*
|
||||
*/
|
||||
void BoardSweekar::VbatToVbat5vInit(void)
|
||||
{
|
||||
// 配置VBAT_5V引脚为输出模式
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << VBAT_5V_PIN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
// 使能VBAT_5V
|
||||
gpio_set_level(VBAT_5V_PIN, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "stepper_motor.h"
|
||||
#include "stepper_driver.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "gyroscope.h"
|
||||
#include "touch_sensor.h"
|
||||
|
||||
class BoardSweekar
|
||||
{
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄
|
||||
|
||||
public:
|
||||
BoardSweekar();
|
||||
~BoardSweekar();
|
||||
|
||||
IOExpansionBoard io_expansion_; // IO扩展板对象
|
||||
LinearMotor linear_motor_; // 线性马达对象
|
||||
Gyroscope gyroscope_; // 陀螺仪对象
|
||||
TouchSensor touch_sensor_; // 触摸传感器对象
|
||||
StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象
|
||||
|
||||
StepperDriver* GetStepperDriver() const { return stepper_driver_; }
|
||||
|
||||
// 初始化步进电机
|
||||
void StepperMotorInit(void);
|
||||
|
||||
// 初始化串口
|
||||
void MillimeterWaveRadarUartInit(void);
|
||||
|
||||
//初始化毫米波雷达的中断引脚
|
||||
void MillimeterWaveRadarGpioInit(void);
|
||||
|
||||
// 初始化I2C总线
|
||||
esp_err_t I2CMasterInit(void);
|
||||
|
||||
// 初始化VBAT toVBAT_5V引脚
|
||||
void VbatToVbat5vInit(void);
|
||||
|
||||
// 获取I2C总线句柄
|
||||
i2c_bus_handle_t GetBusHandle() const { return bus_handle_; }
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
/* 定义引脚分配 */
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @brief 定义了引脚的分配。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h" // 用于 esp_rom_delay_us
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/timer.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义
|
||||
#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "linear_motor.h"
|
||||
#include "gyroscope.h"
|
||||
|
||||
#define TAG_BOARD "SWEEKAR_ESP32"
|
||||
/*I2C总线引脚定义*/
|
||||
#define I2C0_MASTER_PORT I2C_NUM_0
|
||||
#define I2C0_MASTER_SDA_IO GPIO_NUM_2
|
||||
#define I2C0_MASTER_SCL_IO GPIO_NUM_3
|
||||
|
||||
/* 步进电机引脚设置 */
|
||||
#define LEDC_OUTPUT_IO GPIO_NUM_42 // 步进电机LEDC引脚输入
|
||||
|
||||
/* 定义屏幕驱动控制引脚 */
|
||||
#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚
|
||||
#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL
|
||||
#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚
|
||||
#define ST7789_PIN_CS GPIO_NUM_40 // SPI片选引脚
|
||||
#define ST7789_PIN_BL GPIO_NUM_NC // 背光引脚
|
||||
#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚
|
||||
#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS)
|
||||
|
||||
#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数)
|
||||
#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数)
|
||||
|
||||
/* 毫米波雷达配置参数 */
|
||||
/* 定义毫米波雷达的中断引脚 */
|
||||
#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35
|
||||
// UART 配置参数
|
||||
#define RADAR_UART_NUM UART_NUM_1 // 使用 UART0
|
||||
#define UART_TX_PIN GPIO_NUM_NC // GPIO43 作为 TX(根据实际硬件连接调整)
|
||||
#define UART_RX_PIN GPIO_NUM_39 // GPIO44 作为 RX
|
||||
#define BAUD_RATE 9600 // 波特率
|
||||
#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小
|
||||
|
||||
/* IO扩展硬件配置常量 */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000)
|
||||
#define I2C_IO_EXPAND_SLAVE_ADDR 0x5B // AW9523BTQR器件地址
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚
|
||||
#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚
|
||||
|
||||
/* 定义线性马达的I2C从机配置常量 */
|
||||
#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址
|
||||
|
||||
/* 定义陀螺仪的I2C从机配置常量 */
|
||||
#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址
|
||||
#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚
|
||||
|
||||
/* 原生触摸引脚配置 */
|
||||
// 触摸按键数量配置
|
||||
// #define TOUCH_BUTTON_NUM 4
|
||||
#define TOUCH_BUTTON_NUM 3
|
||||
// 触摸通道定义
|
||||
#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11
|
||||
#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12
|
||||
#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13
|
||||
// #define TOUCH_PAD_CHANNEL_4 TOUCH_PAD_NUM14 // GPIO14
|
||||
|
||||
/* ES8311音频编解码器配置 (ESP-ADF兼容) */
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
/* I2S GPIO定义 */
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
/* PA引脚定义 */
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_8
|
||||
|
||||
/* I2C配置 */
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3
|
||||
#define AUDIO_CODEC_ES8311_ADDR 0x18
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x40
|
||||
|
||||
/* WS2812 RGB LED配置 */
|
||||
#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚
|
||||
#define WS2812_NUM_LEDS 2 // WS2812 LED数量
|
||||
|
||||
/* 创建VBAT to VBAT_5V */
|
||||
#define VBAT_5V_PIN GPIO_NUM_8 // VBAT_5V引脚
|
||||
|
||||
/* 定义按键的中断引脚 */
|
||||
#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,732 @@
|
||||
#include "io_expansion_board.h"
|
||||
#include "millimeter_wave_radar.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "freertos/portable.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_rom_sys.h"
|
||||
/**
|
||||
* @file io_expansion_board.cc
|
||||
* @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能
|
||||
* @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、
|
||||
* LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard::IOExpansionBoard()
|
||||
: bus_handle_(nullptr),
|
||||
device_addr_(0),
|
||||
i2c_task_event_group_(nullptr),
|
||||
xI2CReadTaskHandle_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
IOExpansionBoard::~IOExpansionBoard()
|
||||
{
|
||||
// 删除任务
|
||||
if (xI2CReadTaskHandle_) {
|
||||
vTaskDelete(xI2CReadTaskHandle_);
|
||||
}
|
||||
|
||||
// if(pI2CReadTaskStackBuffer) {
|
||||
// heap_caps_free(pI2CReadTaskStackBuffer);
|
||||
// pI2CReadTaskStackBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// if(pxI2CReadTaskBuffer) {
|
||||
// vPortFree(pxI2CReadTaskBuffer);
|
||||
// pxI2CReadTaskBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// 删除事件组
|
||||
if (i2c_task_event_group_) {
|
||||
vEventGroupDelete(i2c_task_event_group_);
|
||||
}
|
||||
|
||||
// 移除中断处理
|
||||
if (interrupt_gpio_ != GPIO_NUM_NC) {
|
||||
gpio_isr_handler_remove(interrupt_gpio_);
|
||||
}
|
||||
|
||||
// 删除IO扩展板设备
|
||||
// 使用i2c_bus API时不需要手动删除设备句柄
|
||||
// bus_handle_由board_sweekar统一管理
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 静态中断处理函数
|
||||
*/
|
||||
void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg)
|
||||
{
|
||||
IOExpansionBoard* instance = static_cast<IOExpansionBoard*>(arg);
|
||||
if (!instance) return;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
// 设置事件标志位
|
||||
if (instance->i2c_task_event_group_) {
|
||||
xEventGroupSetBitsFromISR(
|
||||
instance->i2c_task_event_group_,
|
||||
BIT0,
|
||||
&xHigherPriorityTaskWoken
|
||||
);
|
||||
}
|
||||
|
||||
// // 唤醒挂起的I2C任务
|
||||
// if (instance->xI2CReadTaskHandle_) {
|
||||
// if (xTaskResumeFromISR(instance->xI2CReadTaskHandle_) == pdTRUE) {
|
||||
// xHigherPriorityTaskWoken = pdTRUE;
|
||||
// }
|
||||
// }
|
||||
|
||||
// 触发上下文切换
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num)
|
||||
{
|
||||
// 配置IO扩展板中断引脚
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
||||
io_conf.pin_bit_mask = 1ULL << gpio_num;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
|
||||
esp_err_t err = gpio_config(&io_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
// 配置中断服务
|
||||
err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
// 注册中断处理函数
|
||||
err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
// 创建事件组
|
||||
i2c_task_event_group_ = xEventGroupCreate();
|
||||
if (!i2c_task_event_group_) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化硬件复位引脚
|
||||
* 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num)
|
||||
{
|
||||
reset_gpio_ = gpio_num;
|
||||
|
||||
// 配置复位引脚
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.pin_bit_mask = 1ULL << gpio_num;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
esp_err_t err = gpio_config(&io_conf);
|
||||
gpio_set_level(gpio_num, 1); // 复位引脚拉高
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 复位IO扩展板
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::ResetIoExpand()
|
||||
{
|
||||
if (reset_gpio_ == GPIO_NUM_NC) {
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// 复位IO扩展板
|
||||
gpio_set_level(reset_gpio_, 0);
|
||||
esp_rom_delay_us(30);
|
||||
gpio_set_level(reset_gpio_, 1);
|
||||
uint8_t ctl_val;
|
||||
//配置P0_0-P0_7的端口为推挽输出模式
|
||||
esp_err_t err = IoexpandReadReg(CTL, &ctl_val);
|
||||
ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式
|
||||
err = IoexpandWriteReg(CTL, ctl_val);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data)
|
||||
{
|
||||
return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从寄存器读取数据
|
||||
* @param reg_addr 寄存器地址(如INPUT_PORT0、ID等)
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果(ESP_OK为成功)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data)
|
||||
{
|
||||
if (data == nullptr){ // 检查输入参数有效性
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// 使用i2c_bus_read_bytes进行寄存器读取
|
||||
esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1);
|
||||
if (err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
//设置IO扩展板为输入模式或是输出模式
|
||||
/*
|
||||
* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。
|
||||
* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测)
|
||||
* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测)
|
||||
* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测)
|
||||
* P0_3 暂时未使用。
|
||||
* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测)
|
||||
* P0_5 对应CHRG引脚(待测)
|
||||
* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测)
|
||||
* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测)
|
||||
*
|
||||
*
|
||||
* P1_0 对应EG800K_PWR。(待测)
|
||||
* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测)
|
||||
* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测)
|
||||
* P1_3 暂时未使用。
|
||||
* P1_4 对应步进电机的细分模式M1引脚。(待测)
|
||||
* P1_5 对应步进电机的细分模式M0引脚。(待测)
|
||||
* P1_6 对应步进电机的睡眠引脚。(待测)
|
||||
* P1_7 对应RADAR_O雷达的输出引脚。(待测)
|
||||
* */
|
||||
esp_err_t IOExpansionBoard::IoexpandSetMode(void)
|
||||
{
|
||||
uint8_t ctl_val;
|
||||
//配置P0_0-P0_7的端口为推挽输出模式
|
||||
esp_err_t err = IoexpandReadReg(CTL, &ctl_val);
|
||||
ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式
|
||||
err = IoexpandWriteReg(CTL, ctl_val);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功");
|
||||
}
|
||||
// 配置P0_0-P0_7的端口为输入还是输出:0-输出;1-输入
|
||||
// err = IoexpandWriteReg(CONFIG_PORT0, 0x04); // 0000 0100
|
||||
err = IoexpandWriteReg(CONFIG_PORT0, 0x24); // 0010 0100
|
||||
// err = IoexpandWriteReg(CONFIG_PORT0, 0x2C); // 0010 1100 0-2,0-3,0-5都是输入
|
||||
|
||||
// D 1101
|
||||
// 9 1001
|
||||
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功");
|
||||
}
|
||||
// 配置P1_0-P1_7的端口输出:0-输出;1-输入
|
||||
// err = IoexpandWriteReg(CONFIG_PORT1, 0x84);
|
||||
err = IoexpandWriteReg(CONFIG_PORT1, 0x80); // 1000 0000
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功");
|
||||
}
|
||||
// 配置P0_0-P0_7的初始为高电平
|
||||
// 配置P1_0-P1_7的初始为高电平
|
||||
err = IoexpandWriteReg(OUTPUT_PORT0, 0xFD); // 1111 1101
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功");
|
||||
}
|
||||
err = IoexpandWriteReg(OUTPUT_PORT1, 0x7E); // 0111 1110
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功");
|
||||
}
|
||||
|
||||
err = IoexpandWriteReg(INT_PORT1, 0x7F); // 0111 1111
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
*/
|
||||
void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
switch (mode) {
|
||||
case 1: //全步输出模式 低低电平
|
||||
/* code */
|
||||
printf("设置步进电机为全步模式\n");
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
case 2: //非圆 1/2 高低电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
case 3: //1/4 步 低高电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
case 4: //1/8 步 高高电平
|
||||
/* code */
|
||||
printf("设置步进电机为1/8步模式\n");
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
default: //全步输入模式 低低电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(enable){
|
||||
// 进入工作状态mode
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << enable_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入睡眠状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << enable_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief 设置步进电机运行方向
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(dir){
|
||||
// 方向为正转
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入工作状态mode
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << nsleep_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入睡眠状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << nsleep_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************IO扩展板LCD引脚配置参数***********************************************/
|
||||
/**
|
||||
* @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入命令模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << bl_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入数据模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << bl_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入复位模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << reset_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入工作模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << reset_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/
|
||||
/**
|
||||
* @brief 设置 毫米波雷达的中断引脚
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入输入模式
|
||||
IoexpandReadReg(INPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << interrupt_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(INPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入输出模式
|
||||
IoexpandReadReg(INPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << interrupt_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(INPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置 LCD_CS引脚电平(低电平为选中状态,高电平为不选中状态)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入选中状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << cs_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入不选中状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << cs_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief I2C数据读取任务主体
|
||||
*/
|
||||
void IOExpansionBoard::I2cReadTask(void* pvParameters)
|
||||
{
|
||||
IOExpansionBoard* instance = static_cast<IOExpansionBoard*>(pvParameters);
|
||||
if (!instance) {
|
||||
vTaskDelete(nullptr);
|
||||
return;
|
||||
}
|
||||
// 初始化复位引脚
|
||||
esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败");
|
||||
}
|
||||
// 初始化IO扩展板子的中断引脚
|
||||
err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败");
|
||||
}
|
||||
// 设置IO扩展板模式
|
||||
instance->IoexpandSetMode();
|
||||
// 设置LCD屏幕背光引脚(初始为关闭)
|
||||
err = instance->SetLcdBlMode(LCD_BL_HIGH, LCD_BL_PORT, LCD_BL_PIN);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕背光引脚失败");
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕背光引脚成功");
|
||||
}
|
||||
// 设置LCD屏幕复位引脚
|
||||
err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败");
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功");
|
||||
}
|
||||
uint8_t current_val;
|
||||
for (;;) {
|
||||
// 等待中断事件触发
|
||||
if (instance->i2c_task_event_group_) {
|
||||
xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
}
|
||||
// 读取I2C数据
|
||||
instance->IoexpandReadReg(INPUT_PORT1,¤t_val);
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "读取数据: 0x%0X", current_val);
|
||||
if(current_val & (1 << 7)){
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚(P1_7)\n");
|
||||
// 调用毫米波雷达回调函数
|
||||
if (instance->radar_) {
|
||||
instance->radar_->TriggerRadarDetectCallback();
|
||||
}
|
||||
}
|
||||
|
||||
// vTaskSuspend(nullptr); // 挂起任务等待下次唤醒
|
||||
}
|
||||
}
|
||||
|
||||
// bool IOExpansionBoard::AllocateStaticTaskMemory()
|
||||
// {
|
||||
// printf("IO拓展芯片创建任务前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
// printf("IO拓展芯片创建任务前 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
// // 分配任务栈(PSRAM)
|
||||
// const size_t TASK_STACK_SIZE = 4096;
|
||||
// pI2CReadTaskStackBuffer = (StackType_t*)heap_caps_malloc(
|
||||
// TASK_STACK_SIZE * sizeof(StackType_t),
|
||||
// MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
|
||||
// );
|
||||
|
||||
// if (!pI2CReadTaskStackBuffer) {
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task stack from PSRAM");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // 分配任务控制块(内部RAM)
|
||||
// pxI2CReadTaskBuffer = (StaticTask_t*)pvPortMalloc(sizeof(StaticTask_t));
|
||||
// if (!pxI2CReadTaskBuffer) {
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task TCB from internal RAM");
|
||||
// heap_caps_free(pI2CReadTaskStackBuffer);
|
||||
// pI2CReadTaskStackBuffer = nullptr;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory allocated successfully");
|
||||
// printf("IO拓展芯片创建任务后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
// printf("IO拓展芯片创建任务后 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// void IOExpansionBoard::FreeStaticTaskMemory()
|
||||
// {
|
||||
// if (pI2CReadTaskStackBuffer != nullptr) {
|
||||
// heap_caps_free(pI2CReadTaskStackBuffer);
|
||||
// pI2CReadTaskStackBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// if (pxI2CReadTaskBuffer != nullptr) {
|
||||
// vPortFree(pxI2CReadTaskBuffer);
|
||||
// pxI2CReadTaskBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory freed");
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void IOExpansionBoard::CreateI2cReadTask()
|
||||
{
|
||||
printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
if (xI2CReadTaskHandle_) {
|
||||
return; // 任务已创建
|
||||
}
|
||||
|
||||
xTaskCreateWithCaps(
|
||||
I2cReadTask,
|
||||
"i2c_read_task",
|
||||
I2C_TASK_STACK,
|
||||
this,
|
||||
I2C_TASK_PRIORITY,
|
||||
&xI2CReadTaskHandle_,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
|
||||
);
|
||||
|
||||
if (xI2CReadTaskHandle_ == NULL) {
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task");
|
||||
} else {
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully");
|
||||
}
|
||||
printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务 (整合初始化和任务创建)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::StartTask()
|
||||
{
|
||||
// 再创建任务
|
||||
if (!xI2CReadTaskHandle_) {
|
||||
CreateI2cReadTask();
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
#ifndef IO_EXPANSION_BOARD_H
|
||||
#define IO_EXPANSION_BOARD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
class MillimeterWaveRadar;
|
||||
|
||||
/* 寄存器地址 */
|
||||
#define INPUT_PORT0 0x00 // 输入端口0寄存器
|
||||
#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取)
|
||||
#define OUTPUT_PORT0 0x02 // 输出端口0寄存器
|
||||
#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平
|
||||
#define CONFIG_PORT0 0x04 // 配置端口0寄存器
|
||||
#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式
|
||||
#define INT_PORT0 0x06 // 中断端口0寄存器
|
||||
#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的)
|
||||
#define CTL 0x11 // 全局控制寄存器
|
||||
#define ID 0x23 // 芯片ID寄存器(0x23)
|
||||
|
||||
/***********************************IO扩展板电机引脚配置参数*************************************/
|
||||
/* 设置步进电机方向 */
|
||||
#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转
|
||||
#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转
|
||||
#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4
|
||||
|
||||
/* 设置步进电机细分模式 */
|
||||
#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5
|
||||
#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4
|
||||
#define STEPPER_MOTOR_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
|
||||
/* 设置步进电机睡眠引脚 */
|
||||
#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式
|
||||
#define STEPPER_MOTOR_WORK true //步进电机进入工作模式
|
||||
#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
/* 设置电机的使能引脚 */
|
||||
#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平
|
||||
#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平
|
||||
|
||||
/* 设置毫米波雷达对应IO扩展板的中断引脚 */
|
||||
#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7
|
||||
#define RADAR_INTERRUPT_PORT CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口INPUT_PORT1
|
||||
#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态
|
||||
#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态
|
||||
/* 任务配置常量 */
|
||||
#define WRITE_BUF_SIZE 2 // I2C单次写入字节数
|
||||
#define READ_BUF_SIZE 2 // I2C单次读取字节数
|
||||
#define I2C_TASK_PRIORITY 2 // 任务优先级(中等)
|
||||
#define I2C_TASK_STACK 4096 // 任务栈大小(4KB)
|
||||
|
||||
/***********************************IO扩展板LCD引脚配置参数*************************************/
|
||||
/* 设置LCD的BL引脚 */
|
||||
#define LCD_BL_PIN 6 //LCD背光引脚
|
||||
#define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define LCD_BL_HIGH true //LCD背光引脚状态为高电平
|
||||
#define LCD_BL_LOW false //LCD背光引脚状态为低电平
|
||||
|
||||
/* 设置LCD的RST引脚 */
|
||||
#define LCD_RST_PIN 1 //LCD复位引脚
|
||||
#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_RST_HIGH true //LCD复位引脚状态为高电平
|
||||
#define LCD_RST_LOW false //LCD复位引脚状态为低电平
|
||||
|
||||
/* 设置LCD的CS引脚 */
|
||||
#define LCD_CS_PIN 2 //LCD片选引脚
|
||||
#define LCD_CS_PORT OUTPUT_PORT1 //LCD片选引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_CS_HIGH true //LCD片选引脚状态为高电平
|
||||
#define LCD_CS_LOW false //LCD片选引脚状态为低电平
|
||||
|
||||
#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签
|
||||
#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签
|
||||
|
||||
// GPIO引脚定义
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚
|
||||
|
||||
/**
|
||||
* @class IOExpansionBoard
|
||||
* @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作
|
||||
*/
|
||||
class IOExpansionBoard
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 设置毫米波雷达指针
|
||||
* @param radar 毫米波雷达对象指针
|
||||
*/
|
||||
void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; };
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetIoExpand();
|
||||
|
||||
/**
|
||||
* @brief 初始化I2C主机通信
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
// esp_err_t IoExpansionI2cInit();
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void CreateI2cReadTask();
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务(整合初始化和任务创建)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StartTask();
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief 读寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要读出的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data);
|
||||
|
||||
// /**
|
||||
// * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断
|
||||
// * @param reg_addr 寄存器地址
|
||||
// * @return esp_err_t 操作结果
|
||||
// */
|
||||
// esp_err_t SetInterruptStatus(bool status);
|
||||
|
||||
/**
|
||||
* @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandSetMode();
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
* @param mode 模式:1/2/4/8/16/32/64
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的方向
|
||||
* @param dir 方向
|
||||
* @param OUTPUT_PORT 输出端口
|
||||
* @param pin 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的睡眠模式
|
||||
* @param 是否进入睡眠模式
|
||||
* @param 输出端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能引脚状态
|
||||
* @param 使能状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的BL引脚状态
|
||||
* @param BL状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的RST引脚状态
|
||||
* @param RST状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的CS引脚状态
|
||||
* @param CS状态(低电平为选中状态,高电平为不选中状态)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断引脚
|
||||
* @param 毫米波雷达的中断引脚模式
|
||||
* @param 输入端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin);
|
||||
|
||||
// 公共成员变量
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
uint8_t device_addr_; // I2C设备地址
|
||||
|
||||
private:
|
||||
// 静态成员函数
|
||||
MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调
|
||||
static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数
|
||||
|
||||
// /**
|
||||
// * @brief 分配静态任务所需的内存
|
||||
// * @return bool 分配是否成功
|
||||
// */
|
||||
// bool AllocateStaticTaskMemory();
|
||||
|
||||
// /**
|
||||
// * @brief 释放静态任务分配的内存
|
||||
// */
|
||||
// void FreeStaticTaskMemory();
|
||||
|
||||
// 实例成员变量
|
||||
EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组
|
||||
TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄
|
||||
bool is_initialized_ = false; // 初始化状态标记(新增)
|
||||
gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚
|
||||
gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚
|
||||
|
||||
// StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM)
|
||||
// StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* @file board.cc
|
||||
* @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "esp_check.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "i2c_bus.h"
|
||||
}
|
||||
|
||||
#include "board_sweekar.h"
|
||||
#include "config.h"
|
||||
#define TAG "board_sweekar"
|
||||
/**
|
||||
* @file board.h
|
||||
* @brief 板级外设初始化类
|
||||
*/
|
||||
/**
|
||||
* @brief 步进电机初始化函数
|
||||
*
|
||||
* 配置LEDC定时器和通道用于PWM输出,设置步进电机的工作模式、使能状态、细分模式和方向,
|
||||
* 并初始化PWM占空比为50%。初始化过程中若出现错误,会通过ESP_LOGE输出错误信息及错误码。
|
||||
*/
|
||||
void BoardSweekar::StepperMotorInit(void)
|
||||
{
|
||||
// 配置LEDC用于PWM输出
|
||||
ledc_timer_config_t ledc_timer = {
|
||||
.speed_mode = LEDC_MODE,
|
||||
.duty_resolution = LEDC_DUTY_RES,
|
||||
.timer_num = LEDC_TIMER,
|
||||
.freq_hz = LEDC_FREQ_HZ,
|
||||
.clk_cfg = LEDC_USE_APB_CLK,
|
||||
};
|
||||
esp_err_t err = ledc_timer_config(&ledc_timer);
|
||||
if (err != ESP_OK){
|
||||
ESP_LOGE(TAG_BOARD, "步进电机LEDC定时器配置失败,错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 配置LEDC通道
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.gpio_num = LEDC_OUTPUT_IO,
|
||||
.speed_mode = LEDC_MODE,
|
||||
.channel = LEDC_CHANNEL,
|
||||
.timer_sel = LEDC_TIMER,
|
||||
.duty = 0, // 初始占空比0
|
||||
.hpoint = 0
|
||||
};
|
||||
err = ledc_channel_config(&ledc_channel);
|
||||
if (err != ESP_OK){
|
||||
ESP_LOGE(TAG_BOARD, "步进电机LEDC通道配置失败,错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 检查I2C总线是否已初始化
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置步进电机工作模式,使能电机,设置步进电机细分模式,设置步进电机方向
|
||||
err = io_expansion_.SetMotorSleepMode(STEPPER_MOTOR_WORK, STEPPER_MOTOR_SLEEP_PORT, STEPPER_MOTOR_WORK);
|
||||
if (err != ESP_OK){
|
||||
ESP_LOGE(TAG_BOARD, "步进电机初始化失败,错误码: 0x%x", err);
|
||||
}
|
||||
err = io_expansion_.SetMotorEnableMode(STEPPER_MOTOR_ENABLE_DISABLE, STEPPER_MOTOR_ENABLE_PORT, STEPPER_MOTOR_ENABLE_PIN);
|
||||
if (err != ESP_OK){
|
||||
ESP_LOGE(TAG_BOARD, "步进电机初始化失败,错误码: 0x%x", err);
|
||||
}
|
||||
io_expansion_.SetStepperMicrostepMode(4, STEPPER_MOTOR_MADE_PORT, STEPPER_MOTOR_M0_PIN, STEPPER_MOTOR_M1_PIN);
|
||||
err = io_expansion_.StepperMotorSetDir(STEPPER_MOTOR_LEFT, STEPPER_MOTOR_DIR_PORT, STEPPER_MOTOR_DIR_PIN);
|
||||
if (err != ESP_OK){
|
||||
ESP_LOGE(TAG_BOARD, "步进电机初始化失败,错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 初始PWM占空比设为0%
|
||||
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0);
|
||||
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达串口初始化函数
|
||||
*
|
||||
* 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚,
|
||||
* 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免
|
||||
* 与自定义中断冲突。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = RADAR_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突)
|
||||
// 增加 RX/TX FIFO 深度以处理突发数据
|
||||
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4,
|
||||
0, NULL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达中断引脚初始化函数
|
||||
*
|
||||
* 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能
|
||||
* (如需使用中断需单独进行配置)。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarGpioInit(void)
|
||||
{
|
||||
// GPIO配置结构体
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚
|
||||
.mode = GPIO_MODE_INPUT, // 设置为输入模式
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉
|
||||
.intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置)
|
||||
};
|
||||
|
||||
// 配置GPIO
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2C总线及从机设备初始化函数
|
||||
*
|
||||
* 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。
|
||||
* 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。
|
||||
* 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::I2CMasterInit(void)
|
||||
{
|
||||
static const char *I2C_INIT = "I2C_INIT";
|
||||
|
||||
// 初始化IO扩展板复位引脚
|
||||
gpio_config_t reset_io_conf = {
|
||||
.pin_bit_mask = (1ULL << IO_EXPAND_RSTN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&reset_io_conf);
|
||||
|
||||
// 执行复位时序:先拉低100ms,再拉高并等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板复位完成");
|
||||
|
||||
// 创建统一的I2C总线(使用ESP-ADF的i2c_bus)
|
||||
i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C0_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C0_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = 100000,
|
||||
},
|
||||
};
|
||||
|
||||
// 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线)
|
||||
bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg);
|
||||
if (bus_handle_ == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create I2C bus");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
// ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信
|
||||
|
||||
// 验证线性马达设备是否存在
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR);
|
||||
}
|
||||
// 验证IO扩展板设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化其他设备
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR);
|
||||
}
|
||||
// 验证陀螺仪设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR);
|
||||
}
|
||||
|
||||
// 为IO扩展板设置总线句柄和设备地址(使用7位地址)
|
||||
io_expansion_.bus_handle_ = bus_handle_;
|
||||
io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1;
|
||||
|
||||
// 为线性马达设置总线句柄和设备地址(使用7位地址)
|
||||
linear_motor_.bus_handle_ = bus_handle_;
|
||||
linear_motor_.device_addr_ = LINEAR_MOTOR_I2C_SLAVE_ADDR << 1;
|
||||
|
||||
ESP_LOGI(I2C_INIT, "I2C总线初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 开启VBAT to VBAT_5V
|
||||
*
|
||||
* 创建开启升压的电源管理单元
|
||||
*
|
||||
*/
|
||||
void BoardSweekar::VbatToVbat5vInit(void)
|
||||
{
|
||||
// 配置VBAT_5V引脚为输出模式
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << VBAT_5V_PIN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
// 使能VBAT_5V
|
||||
gpio_set_level(VBAT_5V_PIN, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "stepper_motor.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "gyroscope.h"
|
||||
#include "touch_sensor.h"
|
||||
|
||||
class BoardSweekar
|
||||
{
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄
|
||||
|
||||
public:
|
||||
IOExpansionBoard io_expansion_; // IO扩展板对象
|
||||
LinearMotor linear_motor_; // 线性马达对象
|
||||
Gyroscope gyroscope_; // 陀螺仪对象
|
||||
TouchSensor touch_sensor_; // 触摸传感器对象
|
||||
// 初始化步进电机
|
||||
void StepperMotorInit(void);
|
||||
|
||||
// 初始化串口
|
||||
void MillimeterWaveRadarUartInit(void);
|
||||
|
||||
//初始化毫米波雷达的中断引脚
|
||||
void MillimeterWaveRadarGpioInit(void);
|
||||
|
||||
// 初始化I2C总线
|
||||
esp_err_t I2CMasterInit(void);
|
||||
|
||||
// 初始化VBAT toVBAT_5V引脚
|
||||
void VbatToVbat5vInit(void);
|
||||
|
||||
// 获取I2C总线句柄
|
||||
i2c_bus_handle_t GetBusHandle() const { return bus_handle_; }
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,139 @@
|
||||
/* 定义引脚分配 */
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @brief 定义了引脚的分配。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h" // 用于 esp_rom_delay_us
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/timer.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义
|
||||
#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "linear_motor.h"
|
||||
#include "gyroscope.h"
|
||||
|
||||
#define TAG_BOARD "SWEEKAR_ESP32"
|
||||
/*I2C总线引脚定义*/
|
||||
#define I2C0_MASTER_PORT I2C_NUM_0
|
||||
#define I2C0_MASTER_SDA_IO GPIO_NUM_2
|
||||
#define I2C0_MASTER_SCL_IO GPIO_NUM_3
|
||||
|
||||
/* 步进电机引脚设置 */
|
||||
#define LEDC_OUTPUT_IO GPIO_NUM_42 // 步进电机LEDC引脚输入
|
||||
|
||||
/* 定义屏幕驱动控制引脚 */
|
||||
#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚
|
||||
#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL
|
||||
#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚
|
||||
#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚
|
||||
#define ST7789_PIN_BL GPIO_NUM_NC // 背光引脚
|
||||
#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚
|
||||
#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS)
|
||||
|
||||
#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数)
|
||||
#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数)
|
||||
|
||||
/* 毫米波雷达配置参数 */
|
||||
/* 定义毫米波雷达的中断引脚 */
|
||||
#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35
|
||||
// UART 配置参数
|
||||
#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1
|
||||
#define UART_TX_PIN GPIO_NUM_40 // GPIO43 作为 TX(根据实际硬件连接调整)
|
||||
#define UART_RX_PIN GPIO_NUM_39 // GPIO44 作为 RX
|
||||
#define RADAR_BAUD_RATE 9600 // 雷达波特率
|
||||
#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小
|
||||
|
||||
/* IO扩展硬件配置常量 */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000)
|
||||
#define I2C_IO_EXPAND_SLAVE_ADDR 0x5B // AW9523BTQR器件地址
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚
|
||||
#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚
|
||||
|
||||
/* 定义线性马达的I2C从机配置常量 */
|
||||
#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址
|
||||
|
||||
/* 定义陀螺仪的I2C从机配置常量 */
|
||||
#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址
|
||||
#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚
|
||||
|
||||
/* 原生触摸引脚配置 */
|
||||
// 触摸按键数量配置
|
||||
// #define TOUCH_BUTTON_NUM 4
|
||||
#define TOUCH_BUTTON_NUM 3
|
||||
// 触摸通道定义
|
||||
// #define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11
|
||||
#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12
|
||||
#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13
|
||||
#define TOUCH_PAD_CHANNEL_4 TOUCH_PAD_NUM14 // GPIO14
|
||||
|
||||
/* ES8311音频编解码器配置 (ESP-ADF兼容) */
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
/* I2S GPIO定义 */
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
/* PA引脚定义 */
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
|
||||
/* I2C配置 */
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3
|
||||
#define AUDIO_CODEC_ES8311_ADDR 0x18
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x40
|
||||
|
||||
/* WS2812 RGB LED配置 */
|
||||
#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚
|
||||
#define WS2812_NUM_LEDS 2 // WS2812 LED数量
|
||||
|
||||
/* 创建VBAT to VBAT_5V */
|
||||
#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚
|
||||
|
||||
/* 定义按键的中断引脚 */
|
||||
#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚
|
||||
#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,724 @@
|
||||
#include "io_expansion_board.h"
|
||||
#include "millimeter_wave_radar.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "freertos/portable.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_rom_sys.h"
|
||||
/**
|
||||
* @file io_expansion_board.cc
|
||||
* @brief IO扩展板功能实现类,包含I2C通信、GPIO中断配置、外设控制等功能
|
||||
* @details 实现了IO扩展板的初始化(中断引脚、复位引脚)、寄存器读写、步进电机控制(细分模式、使能、方向、睡眠状态)、
|
||||
* LCD相关引脚控制(背光、复位、片选)、毫米波雷达中断引脚配置等功能,并提供I2C数据读取任务的创建与管理
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard::IOExpansionBoard()
|
||||
: bus_handle_(nullptr),
|
||||
device_addr_(0),
|
||||
i2c_task_event_group_(nullptr),
|
||||
xI2CReadTaskHandle_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
IOExpansionBoard::~IOExpansionBoard()
|
||||
{
|
||||
// 删除任务
|
||||
if (xI2CReadTaskHandle_) {
|
||||
vTaskDelete(xI2CReadTaskHandle_);
|
||||
}
|
||||
|
||||
// if(pI2CReadTaskStackBuffer) {
|
||||
// heap_caps_free(pI2CReadTaskStackBuffer);
|
||||
// pI2CReadTaskStackBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// if(pxI2CReadTaskBuffer) {
|
||||
// vPortFree(pxI2CReadTaskBuffer);
|
||||
// pxI2CReadTaskBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// 删除事件组
|
||||
if (i2c_task_event_group_) {
|
||||
vEventGroupDelete(i2c_task_event_group_);
|
||||
}
|
||||
|
||||
// 移除中断处理
|
||||
if (interrupt_gpio_ != GPIO_NUM_NC) {
|
||||
gpio_isr_handler_remove(interrupt_gpio_);
|
||||
}
|
||||
|
||||
// 删除IO扩展板设备
|
||||
// 使用i2c_bus API时不需要手动删除设备句柄
|
||||
// bus_handle_由board_sweekar统一管理
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 静态中断处理函数
|
||||
*/
|
||||
void IRAM_ATTR IOExpansionBoard::GpioIsrHandler(void* arg)
|
||||
{
|
||||
IOExpansionBoard* instance = static_cast<IOExpansionBoard*>(arg);
|
||||
if (!instance) return;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
// 设置事件标志位
|
||||
if (instance->i2c_task_event_group_) {
|
||||
xEventGroupSetBitsFromISR(
|
||||
instance->i2c_task_event_group_,
|
||||
BIT0,
|
||||
&xHigherPriorityTaskWoken
|
||||
);
|
||||
}
|
||||
|
||||
// // 唤醒挂起的I2C任务
|
||||
// if (instance->xI2CReadTaskHandle_) {
|
||||
// if (xTaskResumeFromISR(instance->xI2CReadTaskHandle_) == pdTRUE) {
|
||||
// xHigherPriorityTaskWoken = pdTRUE;
|
||||
// }
|
||||
// }
|
||||
|
||||
// 触发上下文切换
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::InterruptGpioInit(gpio_num_t gpio_num)
|
||||
{
|
||||
// 配置IO扩展板中断引脚
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
||||
io_conf.pin_bit_mask = 1ULL << gpio_num;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
|
||||
esp_err_t err = gpio_config(&io_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
// 配置中断服务
|
||||
err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断服务安装失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
// 注册中断处理函数
|
||||
err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断处理函数添加失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
// 创建事件组
|
||||
i2c_task_event_group_ = xEventGroupCreate();
|
||||
if (!i2c_task_event_group_) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "事件组创建失败");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d中断初始化完成", gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化硬件复位引脚
|
||||
* 设置为上拉,需要复位,需要输出低电平为20us的脉冲信号
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::ResetGpioInit(gpio_num_t gpio_num)
|
||||
{
|
||||
reset_gpio_ = gpio_num;
|
||||
|
||||
// 配置复位引脚
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.pin_bit_mask = 1ULL << gpio_num;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
esp_err_t err = gpio_config(&io_conf);
|
||||
gpio_set_level(gpio_num, 1); // 复位引脚拉高
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO配置失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "GPIO%d复位引脚初始化完成", gpio_num);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 复位IO扩展板
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::ResetIoExpand()
|
||||
{
|
||||
if (reset_gpio_ == GPIO_NUM_NC) {
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位引脚未初始化");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// 复位IO扩展板
|
||||
gpio_set_level(reset_gpio_, 0);
|
||||
esp_rom_delay_us(30);
|
||||
gpio_set_level(reset_gpio_, 1);
|
||||
uint8_t ctl_val;
|
||||
//配置P0_0-P0_7的端口为推挽输出模式
|
||||
esp_err_t err = IoexpandReadReg(CTL, &ctl_val);
|
||||
ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式
|
||||
err = IoexpandWriteReg(CTL, ctl_val);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "复位失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "复位成功");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::IoexpandWriteReg(uint8_t reg_addr, uint8_t data)
|
||||
{
|
||||
return i2c_bus_write_bytes(bus_handle_, device_addr_, ®_addr, 1, &data, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从寄存器读取数据
|
||||
* @param reg_addr 寄存器地址(如INPUT_PORT0、ID等)
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果(ESP_OK为成功)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::IoexpandReadReg(uint8_t reg_addr, uint8_t* data)
|
||||
{
|
||||
if (data == nullptr){ // 检查输入参数有效性
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// 使用i2c_bus_read_bytes进行寄存器读取
|
||||
esp_err_t err = i2c_bus_read_bytes(bus_handle_, device_addr_, ®_addr, 1, data, 1);
|
||||
if (err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "读取寄存器失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
//设置IO扩展板为输入模式或是输出模式
|
||||
/*
|
||||
* 这里需要根据实际情况设置IO扩展板的模式,比如输入模式还是输出模式,以及各个引脚的配置。
|
||||
* P0_0 对应NFC_RST引脚,需要设置为输出模式,低电平有效。(待测)
|
||||
* P0_1 对应USB_VBUS引脚,需要设置为输出模式,低电平有效。(待测)
|
||||
* P0_2 对应BTN_RIGHT_EAR引脚,需要设置为输出模式,低电平有效。(待测)
|
||||
* P0_3 暂时未使用。
|
||||
* P0_4 对应步进电机方向引脚,需要设置为输出模式,根据需求设置。(待测)
|
||||
* P0_5 对应CHRG引脚(待测)
|
||||
* P0_6 LCD_DC引脚,需要设置为输出模式,根据需求设置电平。(待测)
|
||||
* P0_7 对应步进电机的使能引脚,需要设置为输出模式,根据需求设置。(待测)
|
||||
*
|
||||
*
|
||||
* P1_0 对应EG800K_PWR。(待测)
|
||||
* P1_1 对应LCD_RST,需要设置为输出模式,低电平有效。(待测)
|
||||
* P1_2 对应LCD_CS,需要设置为输出模式,低电平有效。(待测)
|
||||
* P1_3 暂时未使用。
|
||||
* P1_4 对应步进电机的细分模式M1引脚。(待测)
|
||||
* P1_5 对应步进电机的细分模式M0引脚。(待测)
|
||||
* P1_6 对应步进电机的睡眠引脚。(待测)
|
||||
* P1_7 对应RADAR_O雷达的输出引脚。(待测)
|
||||
* */
|
||||
esp_err_t IOExpansionBoard::IoexpandSetMode(void)
|
||||
{
|
||||
uint8_t ctl_val;
|
||||
//配置P0_0-P0_7的端口为推挽输出模式
|
||||
esp_err_t err = IoexpandReadReg(CTL, &ctl_val);
|
||||
ctl_val |= (1 << 4); // 设置D[4]位为1(GPOMD=1),切换P0为推挽模式
|
||||
err = IoexpandWriteReg(CTL, ctl_val);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功");
|
||||
}
|
||||
// 配置P0_0-P0_7的端口为输入还是输出:0-输出;1-输入
|
||||
// err = IoexpandWriteReg(CONFIG_PORT0, 0x04); // 0000 0100
|
||||
err = IoexpandWriteReg(CONFIG_PORT0, 0x24); // 0010 0100
|
||||
// err = IoexpandWriteReg(CONFIG_PORT0, 0x2C); // 0010 1100 0-2,0-3,0-5都是输入
|
||||
|
||||
// D 1101
|
||||
// 9 1001
|
||||
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口成功");
|
||||
}
|
||||
// 配置P1_0-P1_7的端口输出:0-输出;1-输入
|
||||
// err = IoexpandWriteReg(CONFIG_PORT1, 0x84);
|
||||
err = IoexpandWriteReg(CONFIG_PORT1, 0x80); // 1000 0000
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口成功");
|
||||
}
|
||||
// 配置P0_0-P0_7的初始为高电平
|
||||
// 配置P1_0-P1_7的初始为高电平
|
||||
err = IoexpandWriteReg(OUTPUT_PORT0, 0xFD); // 1111 1101
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P0端口初始值成功");
|
||||
}
|
||||
err = IoexpandWriteReg(OUTPUT_PORT1, 0x7E); // 0111 1110
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口初始值成功");
|
||||
}
|
||||
|
||||
err = IoexpandWriteReg(INT_PORT1, 0x7F); // 0111 1111
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能失败,错误码:0x%x", err);
|
||||
return err;
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "配置P1端口中断使能成功");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
*/
|
||||
void IOExpansionBoard::SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
switch (mode) {
|
||||
case 1: //全步输出模式 低低电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
case 2: //非圆 1/2 高低电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
case 3: //1/4 步 低高电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
case 4: //1/8 步 高高电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
default: //全步输入模式 低低电平
|
||||
/* code */
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m0_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << m1_pin);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
if(IoexpandWriteReg(OUTPUT_PORT, current_val) != ESP_OK){
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "设置步进电机细分模式失败");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(enable){
|
||||
// 进入工作状态mode
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << enable_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入睡眠状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << enable_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief 设置步进电机运行方向
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(dir){
|
||||
// 方向为正转
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机是否进入睡眠或者工作状态(高电平进入工作状态,低电平进入睡眠状态)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入工作状态mode
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << nsleep_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入睡眠状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << nsleep_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************IO扩展板LCD引脚配置参数***********************************************/
|
||||
/**
|
||||
* @brief 设置 LCD_BL引脚电平(高电平为命令模式,低电平为数据模式)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入命令模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << bl_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入数据模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << bl_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置 LCD_RST引脚电平(高电平为复位模式,低电平为工作模式)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t reset_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入复位模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << reset_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入工作模式
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << reset_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************IO扩展板的输入引脚配置以及中断引脚定义***********************************************/
|
||||
/**
|
||||
* @brief 设置 毫米波雷达的中断引脚
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入输入模式
|
||||
IoexpandReadReg(INPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << interrupt_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(INPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入输出模式
|
||||
IoexpandReadReg(INPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << interrupt_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(INPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置 LCD_CS引脚电平(低电平为选中状态,高电平为不选中状态)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin)
|
||||
{
|
||||
uint8_t current_val;
|
||||
if(mode){
|
||||
// 进入选中状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val &= ~(1 << cs_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
else{
|
||||
// 进入不选中状态
|
||||
IoexpandReadReg(OUTPUT_PORT, ¤t_val);
|
||||
ESP_LOGW(TAG_I2C_IO_EXPAND_TASK, "0x%x", current_val);
|
||||
current_val |= (1 << cs_pin);
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "!!!!!!!!!0x%x", current_val);
|
||||
return IoexpandWriteReg(OUTPUT_PORT, current_val);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief I2C数据读取任务主体
|
||||
*/
|
||||
void IOExpansionBoard::I2cReadTask(void* pvParameters)
|
||||
{
|
||||
IOExpansionBoard* instance = static_cast<IOExpansionBoard*>(pvParameters);
|
||||
if (!instance) {
|
||||
vTaskDelete(nullptr);
|
||||
return;
|
||||
}
|
||||
// 初始化复位引脚
|
||||
esp_err_t err = instance->ResetGpioInit(IO_EXPAND_RSTN);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO复位初始化失败");
|
||||
}
|
||||
// 初始化IO扩展板子的中断引脚
|
||||
err = instance->InterruptGpioInit(GPIO_INPUT_PIN_SEL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "GPIO中断初始化失败");
|
||||
}
|
||||
// 设置IO扩展板模式
|
||||
instance->IoexpandSetMode();
|
||||
|
||||
// 设置LCD屏幕复位引脚
|
||||
err = instance->SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚失败");
|
||||
}
|
||||
else{
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "设置LCD屏幕复位引脚成功");
|
||||
}
|
||||
instance->IoexpandWriteReg(OUTPUT_PORT0, 0xff);
|
||||
uint8_t current_val;
|
||||
for (;;) {
|
||||
// 等待中断事件触发
|
||||
if (instance->i2c_task_event_group_) {
|
||||
xEventGroupWaitBits(instance->i2c_task_event_group_, BIT0, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
}
|
||||
// 读取I2C数据
|
||||
instance->IoexpandReadReg(INPUT_PORT1,¤t_val);
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "读取数据: 0x%0X", current_val);
|
||||
if(current_val & (1 << 7)){
|
||||
ESP_LOGI(TAG_GPIO_IO_EXPAND_DETECT, "检测到中断来自雷达引脚(P1_7)\n");
|
||||
// 调用毫米波雷达回调函数
|
||||
if (instance->radar_) {
|
||||
instance->radar_->TriggerRadarDetectCallback();
|
||||
}
|
||||
}
|
||||
|
||||
// vTaskSuspend(nullptr); // 挂起任务等待下次唤醒
|
||||
}
|
||||
}
|
||||
|
||||
// bool IOExpansionBoard::AllocateStaticTaskMemory()
|
||||
// {
|
||||
// printf("IO拓展芯片创建任务前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
// printf("IO拓展芯片创建任务前 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
// // 分配任务栈(PSRAM)
|
||||
// const size_t TASK_STACK_SIZE = 4096;
|
||||
// pI2CReadTaskStackBuffer = (StackType_t*)heap_caps_malloc(
|
||||
// TASK_STACK_SIZE * sizeof(StackType_t),
|
||||
// MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
|
||||
// );
|
||||
|
||||
// if (!pI2CReadTaskStackBuffer) {
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task stack from PSRAM");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // 分配任务控制块(内部RAM)
|
||||
// pxI2CReadTaskBuffer = (StaticTask_t*)pvPortMalloc(sizeof(StaticTask_t));
|
||||
// if (!pxI2CReadTaskBuffer) {
|
||||
// ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to allocate task TCB from internal RAM");
|
||||
// heap_caps_free(pI2CReadTaskStackBuffer);
|
||||
// pI2CReadTaskStackBuffer = nullptr;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory allocated successfully");
|
||||
// printf("IO拓展芯片创建任务后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
// printf("IO拓展芯片创建任务后 Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// void IOExpansionBoard::FreeStaticTaskMemory()
|
||||
// {
|
||||
// if (pI2CReadTaskStackBuffer != nullptr) {
|
||||
// heap_caps_free(pI2CReadTaskStackBuffer);
|
||||
// pI2CReadTaskStackBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// if (pxI2CReadTaskBuffer != nullptr) {
|
||||
// vPortFree(pxI2CReadTaskBuffer);
|
||||
// pxI2CReadTaskBuffer = nullptr;
|
||||
// }
|
||||
|
||||
// ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static task memory freed");
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void IOExpansionBoard::CreateI2cReadTask()
|
||||
{
|
||||
printf("创建I2C读取任务之前:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
printf("创建I2C读取任务之前:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
if (xI2CReadTaskHandle_) {
|
||||
return; // 任务已创建
|
||||
}
|
||||
|
||||
xTaskCreateWithCaps(
|
||||
I2cReadTask,
|
||||
"i2c_read_task",
|
||||
I2C_TASK_STACK,
|
||||
this,
|
||||
I2C_TASK_PRIORITY,
|
||||
&xI2CReadTaskHandle_,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
|
||||
);
|
||||
|
||||
if (xI2CReadTaskHandle_ == NULL) {
|
||||
ESP_LOGE(TAG_I2C_IO_EXPAND_TASK, "Failed to create static I2C read task");
|
||||
} else {
|
||||
ESP_LOGI(TAG_I2C_IO_EXPAND_TASK, "Static I2C read task created successfully");
|
||||
}
|
||||
printf("创建I2C读取任务之后:Internal Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
printf("创建I2C读取任务之后:PSRAM Free: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务 (整合初始化和任务创建)
|
||||
*/
|
||||
esp_err_t IOExpansionBoard::StartTask()
|
||||
{
|
||||
// 再创建任务
|
||||
if (!xI2CReadTaskHandle_) {
|
||||
CreateI2cReadTask();
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
#ifndef IO_EXPANSION_BOARD_H
|
||||
#define IO_EXPANSION_BOARD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
class MillimeterWaveRadar;
|
||||
|
||||
/* 寄存器地址 */
|
||||
#define INPUT_PORT0 0x00 // 输入端口0寄存器
|
||||
#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取)
|
||||
#define OUTPUT_PORT0 0x02 // 输出端口0寄存器
|
||||
#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平
|
||||
#define CONFIG_PORT0 0x04 // 配置端口0寄存器
|
||||
#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式
|
||||
#define INT_PORT0 0x06 // 中断端口0寄存器
|
||||
#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的)
|
||||
#define CTL 0x11 // 全局控制寄存器
|
||||
#define ID 0x23 // 芯片ID寄存器(0x23)
|
||||
|
||||
/***********************************IO扩展板电机引脚配置参数*************************************/
|
||||
/* 设置步进电机方向 */
|
||||
#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转
|
||||
#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转
|
||||
#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4
|
||||
|
||||
/* 设置步进电机细分模式 */
|
||||
#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5
|
||||
#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4
|
||||
#define STEPPER_MOTOR_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
|
||||
/* 设置步进电机睡眠引脚 */
|
||||
#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式
|
||||
#define STEPPER_MOTOR_WORK true //步进电机进入工作模式
|
||||
#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
/* 设置电机的使能引脚 */
|
||||
#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平
|
||||
#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平
|
||||
|
||||
/* 设置毫米波雷达对应IO扩展板的中断引脚 */
|
||||
#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7
|
||||
#define RADAR_INTERRUPT_PORT CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口INPUT_PORT1
|
||||
#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态
|
||||
#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态
|
||||
/* 任务配置常量 */
|
||||
#define WRITE_BUF_SIZE 2 // I2C单次写入字节数
|
||||
#define READ_BUF_SIZE 2 // I2C单次读取字节数
|
||||
#define I2C_TASK_PRIORITY 2 // 任务优先级(中等)
|
||||
#define I2C_TASK_STACK 4096 // 任务栈大小(4KB)
|
||||
|
||||
/***********************************IO扩展板LCD引脚配置参数*************************************/
|
||||
/* 设置LCD的BL引脚 */
|
||||
#define LCD_BL_PIN 6 //LCD背光引脚
|
||||
#define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define LCD_BL_HIGH true //LCD背光引脚状态为高电平
|
||||
#define LCD_BL_LOW false //LCD背光引脚状态为低电平
|
||||
|
||||
/* 设置LCD的RST引脚 */
|
||||
#define LCD_RST_PIN 1 //LCD复位引脚
|
||||
#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_RST_HIGH true //LCD复位引脚状态为高电平
|
||||
#define LCD_RST_LOW false //LCD复位引脚状态为低电平
|
||||
|
||||
/* 设置LCD的CS引脚 */
|
||||
#define LCD_CS_PIN 2 //LCD片选引脚
|
||||
#define LCD_CS_PORT OUTPUT_PORT1 //LCD片选引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_CS_HIGH true //LCD片选引脚状态为高电平
|
||||
#define LCD_CS_LOW false //LCD片选引脚状态为低电平
|
||||
|
||||
#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签
|
||||
#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签
|
||||
|
||||
// GPIO引脚定义
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚
|
||||
|
||||
/**
|
||||
* @class IOExpansionBoard
|
||||
* @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作
|
||||
*/
|
||||
class IOExpansionBoard
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 设置毫米波雷达指针
|
||||
* @param radar 毫米波雷达对象指针
|
||||
*/
|
||||
void setRadar(MillimeterWaveRadar* radar) { radar_ = radar; };
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetIoExpand();
|
||||
|
||||
/**
|
||||
* @brief 初始化I2C主机通信
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
// esp_err_t IoExpansionI2cInit();
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void CreateI2cReadTask();
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务(整合初始化和任务创建)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StartTask();
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief 读寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要读出的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data);
|
||||
|
||||
// /**
|
||||
// * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断
|
||||
// * @param reg_addr 寄存器地址
|
||||
// * @return esp_err_t 操作结果
|
||||
// */
|
||||
// esp_err_t SetInterruptStatus(bool status);
|
||||
|
||||
/**
|
||||
* @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandSetMode();
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
* @param mode 模式:1/2/4/8/16/32/64
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT, uint8_t m0_pin, uint8_t m1_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的方向
|
||||
* @param dir 方向
|
||||
* @param OUTPUT_PORT 输出端口
|
||||
* @param pin 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的睡眠模式
|
||||
* @param 是否进入睡眠模式
|
||||
* @param 输出端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能引脚状态
|
||||
* @param 使能状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的BL引脚状态
|
||||
* @param BL状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的RST引脚状态
|
||||
* @param RST状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的CS引脚状态
|
||||
* @param CS状态(低电平为选中状态,高电平为不选中状态)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdCsMode(bool mode, uint8_t OUTPUT_PORT, uint8_t cs_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断引脚
|
||||
* @param 毫米波雷达的中断引脚模式
|
||||
* @param 输入端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin);
|
||||
|
||||
// 公共成员变量
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
uint8_t device_addr_; // I2C设备地址
|
||||
|
||||
private:
|
||||
// 静态成员函数
|
||||
MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调
|
||||
static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数
|
||||
|
||||
// /**
|
||||
// * @brief 分配静态任务所需的内存
|
||||
// * @return bool 分配是否成功
|
||||
// */
|
||||
// bool AllocateStaticTaskMemory();
|
||||
|
||||
// /**
|
||||
// * @brief 释放静态任务分配的内存
|
||||
// */
|
||||
// void FreeStaticTaskMemory();
|
||||
|
||||
// 实例成员变量
|
||||
EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组
|
||||
TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄
|
||||
bool is_initialized_ = false; // 初始化状态标记(新增)
|
||||
gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚
|
||||
gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚
|
||||
|
||||
// StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM)
|
||||
// StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* @file board.cc
|
||||
* @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "esp_check.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "i2c_bus.h"
|
||||
}
|
||||
|
||||
#include "board_sweekar.h"
|
||||
#include "config.h"
|
||||
#define TAG "board_sweekar"
|
||||
|
||||
/*========================== 步进电机相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 步进电机初始化函数
|
||||
* 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式
|
||||
* 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化
|
||||
*/
|
||||
void BoardSweekar::StepperMotorInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) STEP 引脚改为普通 GPIO(不再用 LEDC)
|
||||
gpio_config_t io_cfg;
|
||||
io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO;
|
||||
io_cfg.mode = GPIO_MODE_OUTPUT;
|
||||
io_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_cfg.intr_type = GPIO_INTR_DISABLE;
|
||||
err = gpio_config(&io_cfg);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 初始电平拉低,保证上电不乱跳
|
||||
gpio_set_level(STEPPER_STEP_IO, 0);
|
||||
|
||||
// 2) 检查 I2C 总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) 通过 IO 扩展板配置步进驱动芯片:睡眠/使能/细分/方向
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_WORK,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_WORK
|
||||
);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机睡眠模式配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
STEPPER_MOTOR_ENABLE_DISABLE,
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机使能配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 细分设置:这里仍然用原来的 1/8 细分
|
||||
io_expansion_.SetStepperMicrostepMode(
|
||||
4,
|
||||
STEPPER_MOTOR_M0_MADE_PORT,
|
||||
STEPPER_MOTOR_M0_PIN,
|
||||
STEPPER_MOTOR_M1_MADE_PORT,
|
||||
STEPPER_MOTOR_M1_PIN
|
||||
);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机细分模式配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 默认方向先设一个(比如“上升”方向)
|
||||
err = io_expansion_.StepperMotorSetDir(
|
||||
STEPPER_MOTOR_LEFT,
|
||||
STEPPER_MOTOR_DIR_PORT,
|
||||
STEPPER_MOTOR_DIR_PIN
|
||||
);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机方向配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
/*========================== 毫米波雷达相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达串口初始化函数
|
||||
*
|
||||
* 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚,
|
||||
* 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免
|
||||
* 与自定义中断冲突。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = RADAR_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突)
|
||||
// 增加 RX/TX FIFO 深度以处理突发数据
|
||||
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4,
|
||||
0, NULL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达中断引脚初始化函数
|
||||
*
|
||||
* 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能
|
||||
* (如需使用中断需单独进行配置)。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarGpioInit(void)
|
||||
{
|
||||
// GPIO配置结构体
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚
|
||||
.mode = GPIO_MODE_INPUT, // 设置为输入模式
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉
|
||||
.intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置)
|
||||
};
|
||||
|
||||
// 配置GPIO
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief I2C总线及从机设备初始化函数
|
||||
*
|
||||
* 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。
|
||||
* 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。
|
||||
* 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::I2CMasterInit(void)
|
||||
{
|
||||
static const char *I2C_INIT = "I2C_INIT";
|
||||
|
||||
// 初始化IO扩展板复位引脚
|
||||
gpio_config_t reset_io_conf = {
|
||||
.pin_bit_mask = (1ULL << IO_EXPAND_RSTN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&reset_io_conf);
|
||||
|
||||
// 执行复位时序:先拉低100ms,再拉高并等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板复位完成");
|
||||
|
||||
// 创建统一的I2C总线(使用ESP-ADF的i2c_bus)
|
||||
i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C0_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C0_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = 100000,
|
||||
},
|
||||
};
|
||||
|
||||
// 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线)
|
||||
bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg);
|
||||
if (bus_handle_ == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create I2C bus");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
// ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信
|
||||
|
||||
// 验证线性马达设备是否存在
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR);
|
||||
}
|
||||
// 验证IO扩展板设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化其他设备
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR);
|
||||
}
|
||||
// 验证陀螺仪设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR);
|
||||
}
|
||||
|
||||
// 为IO扩展板设置总线句柄和设备地址(使用7位地址)
|
||||
io_expansion_.bus_handle_ = bus_handle_;
|
||||
io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1;
|
||||
|
||||
// 为线性马达设置总线句柄和设备地址(使用7位地址)
|
||||
linear_motor_.bus_handle_ = bus_handle_;
|
||||
linear_motor_.device_addr_ = LINEAR_MOTOR_I2C_SLAVE_ADDR << 1;
|
||||
|
||||
ESP_LOGI(I2C_INIT, "I2C总线初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*========================== VBAT to VBAT_5V相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 开启VBAT to VBAT_5V
|
||||
*
|
||||
* 创建开启升压的电源管理单元
|
||||
*
|
||||
*/
|
||||
void BoardSweekar::VbatToVbat5vInit(void)
|
||||
{
|
||||
// 配置VBAT_5V引脚为输出模式
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << VBAT_5V_PIN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
// 使能VBAT_5V
|
||||
gpio_set_level(VBAT_5V_PIN, 1);
|
||||
}
|
||||
|
||||
/*========================== 底座控制串口相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 底座控制命令串口初始化函数
|
||||
*/
|
||||
void BoardSweekar::BaseBoardControlUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BASE_BOARD_CTL_UART_BAUDRATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动
|
||||
ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
0, NULL, 0));
|
||||
|
||||
base_board_control_.SetUartPort(BASE_BOARD_CTL_UART_PORT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "stepper_motor.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "gyroscope.h"
|
||||
#include "touch_sensor.h"
|
||||
#include "base_board_control.h"
|
||||
|
||||
class BoardSweekar
|
||||
{
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄
|
||||
|
||||
public:
|
||||
IOExpansionBoard io_expansion_; // IO扩展板对象
|
||||
LinearMotor linear_motor_; // 线性马达对象
|
||||
Gyroscope gyroscope_; // 陀螺仪对象
|
||||
TouchSensor touch_sensor_; // 触摸传感器对象
|
||||
BaseBoardControl base_board_control_; // 底座控制对象
|
||||
|
||||
|
||||
// 初始化步进电机
|
||||
void StepperMotorInit(void);
|
||||
|
||||
// 初始化串口
|
||||
void MillimeterWaveRadarUartInit(void);
|
||||
|
||||
//初始化毫米波雷达的中断引脚
|
||||
void MillimeterWaveRadarGpioInit(void);
|
||||
|
||||
// 初始化I2C总线
|
||||
esp_err_t I2CMasterInit(void);
|
||||
|
||||
// 初始化VBAT toVBAT_5V引脚
|
||||
void VbatToVbat5vInit(void);
|
||||
|
||||
// 初始化底座控制串口
|
||||
void BaseBoardControlUartInit(void);
|
||||
|
||||
// 获取I2C总线句柄
|
||||
i2c_bus_handle_t GetBusHandle() const { return bus_handle_; }
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
/* 定义引脚分配 */
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @brief 定义了引脚的分配。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h" // 用于 esp_rom_delay_us
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/timer.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义
|
||||
#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "linear_motor.h"
|
||||
#include "gyroscope.h"
|
||||
|
||||
#define TAG_BOARD "SWEEKAR_ESP32"
|
||||
/*I2C总线引脚定义*/
|
||||
#define I2C0_MASTER_PORT I2C_NUM_0
|
||||
#define I2C0_MASTER_SDA_IO GPIO_NUM_2
|
||||
#define I2C0_MASTER_SCL_IO GPIO_NUM_3
|
||||
|
||||
/* 步进电机配置 */
|
||||
#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚
|
||||
#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进)
|
||||
|
||||
/* 定义屏幕驱动控制引脚 */
|
||||
#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚
|
||||
#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL
|
||||
#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚
|
||||
#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚
|
||||
#define ST7789_PIN_BL GPIO_NUM_NC // 背光引脚
|
||||
#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚
|
||||
#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS)
|
||||
|
||||
#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数)
|
||||
#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数)
|
||||
|
||||
/* 毫米波雷达配置参数 */
|
||||
/* 定义毫米波雷达的中断引脚 */
|
||||
#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35
|
||||
// UART 配置参数
|
||||
#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1
|
||||
#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整)
|
||||
#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX
|
||||
#define RADAR_BAUD_RATE 9600 // 雷达波特率
|
||||
#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小
|
||||
|
||||
/* IO扩展硬件配置常量 */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000)
|
||||
#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚
|
||||
#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚
|
||||
|
||||
/* 定义线性马达的I2C从机配置常量 */
|
||||
#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址
|
||||
|
||||
/* 定义陀螺仪的I2C从机配置常量 */
|
||||
#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址
|
||||
#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚
|
||||
|
||||
/* 原生触摸引脚配置 */
|
||||
// 触摸按键数量配置
|
||||
#define TOUCH_BUTTON_NUM 3
|
||||
// 触摸通道定义
|
||||
#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11
|
||||
#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12
|
||||
#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13
|
||||
|
||||
/* ES8311音频编解码器配置 (ESP-ADF兼容) */
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
/* I2S GPIO定义 */
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
/* PA引脚定义 */
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
|
||||
/* I2C配置 */
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3
|
||||
#define AUDIO_CODEC_ES8311_ADDR 0x18
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x40
|
||||
|
||||
/* WS2812 RGB LED配置 */
|
||||
#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚
|
||||
#define WS2812_NUM_LEDS 2 // WS2812 LED数量
|
||||
|
||||
/* 创建VBAT to VBAT_5V */
|
||||
#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚
|
||||
|
||||
/* 定义按键的中断引脚 */
|
||||
#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚
|
||||
#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚
|
||||
|
||||
/* 底座控制命令串口配置 */
|
||||
#define BASE_BOARD_CTL_UART_PORT UART_NUM_0
|
||||
#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43
|
||||
#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44
|
||||
#define BASE_BOARD_CTL_UART_BAUDRATE 115200
|
||||
#define BASE_BOARD_CTL_UART_BUF_SIZE 256
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,419 @@
|
||||
#ifndef IO_EXPANSION_BOARD_H
|
||||
#define IO_EXPANSION_BOARD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <functional>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
class MillimeterWaveRadar;
|
||||
class PhotoInterrupter;
|
||||
class AdcBatteryMonitor;
|
||||
|
||||
// 回调函数类型定义
|
||||
typedef std::function<void()> RadarCallback;
|
||||
typedef std::function<void()> PhotoInterrupterStartCallback;
|
||||
typedef std::function<void()> PhotoInterrupterEndCallback;
|
||||
typedef std::function<void()> BatteryChargingCallback;
|
||||
typedef std::function<void()> BatteryFullCallback;
|
||||
typedef std::function<void()> BatteryNotChargingCallback;
|
||||
|
||||
/* 寄存器地址 */
|
||||
#define INPUT_PORT0 0x00 // 输入端口0寄存器
|
||||
#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取)
|
||||
#define OUTPUT_PORT0 0x02 // 输出端口0寄存器
|
||||
#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平
|
||||
#define CONFIG_PORT0 0x04 // 配置端口0寄存器
|
||||
#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式
|
||||
#define INT_PORT0 0x06 // 中断端口0寄存器
|
||||
#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的)
|
||||
#define CTL 0x11 // 全局控制寄存器
|
||||
#define ID 0x23 // 芯片ID寄存器(0x23)
|
||||
|
||||
/***********************************IO扩展板电机引脚配置参数*************************************/
|
||||
/* 设置步进电机方向 */
|
||||
#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转
|
||||
#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转
|
||||
#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4
|
||||
#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4
|
||||
|
||||
/* 设置步进电机细分模式 */
|
||||
#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5
|
||||
#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5
|
||||
|
||||
#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4
|
||||
#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4
|
||||
|
||||
/* 设置步进电机睡眠引脚 */
|
||||
#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式
|
||||
#define STEPPER_MOTOR_WORK true //步进电机进入工作模式
|
||||
#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
/* 设置电机的使能引脚 */
|
||||
#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平
|
||||
#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平
|
||||
|
||||
/* 设置毫米波雷达对应IO扩展板的中断引脚 */
|
||||
#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7
|
||||
#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口
|
||||
#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1
|
||||
#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态
|
||||
#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态
|
||||
/* 任务配置常量 */
|
||||
#define WRITE_BUF_SIZE 2 // I2C单次写入字节数
|
||||
#define READ_BUF_SIZE 2 // I2C单次读取字节数
|
||||
#define I2C_TASK_PRIORITY 2 // 任务优先级(中等)
|
||||
#define I2C_TASK_STACK 4096 // 任务栈大小(4KB)
|
||||
|
||||
// 光学传感器引脚定义
|
||||
#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2)
|
||||
#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3)
|
||||
#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
/***********************************IO扩展板LCD引脚配置参数*************************************/
|
||||
/* 设置LCD的BL引脚 */
|
||||
#define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6
|
||||
#define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6
|
||||
#define LCD_BL_HIGH true //LCD背光引脚状态为高电平
|
||||
#define LCD_BL_LOW false //LCD背光引脚状态为低电平
|
||||
|
||||
/* 设置LCD的RST引脚 */
|
||||
#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1
|
||||
#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1
|
||||
#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_RST_HIGH true //LCD复位引脚状态为高电平
|
||||
#define LCD_RST_LOW false //LCD复位引脚状态为低电平
|
||||
|
||||
/* 设置PA控制引脚 */
|
||||
#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2
|
||||
#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2
|
||||
#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define PA_CTRL_HIGH true //PA控制引脚状态为高电平
|
||||
#define PA_CTRL_LOW false //PA控制引脚状态为低电平
|
||||
|
||||
// 电池充电检测引脚定义
|
||||
#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3
|
||||
#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3
|
||||
|
||||
#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5)
|
||||
#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
|
||||
#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签
|
||||
#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签
|
||||
|
||||
// GPIO引脚定义
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_45 // IO扩展板复位引脚
|
||||
|
||||
/**
|
||||
* @class IOExpansionBoard
|
||||
* @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作
|
||||
*/
|
||||
class IOExpansionBoard
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 设置毫米波雷达指针
|
||||
* @param radar 毫米波雷达对象指针
|
||||
*/
|
||||
void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; };
|
||||
|
||||
/**
|
||||
* @brief 设置限位开关指针
|
||||
* @param photo_interrupter 限位开关对象指针
|
||||
*/
|
||||
void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; };
|
||||
|
||||
/**
|
||||
* @brief 设置电池监控器指针
|
||||
* @param battery_monitor 电池监控器对象指针
|
||||
*/
|
||||
void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; };
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetIoExpand();
|
||||
|
||||
/**
|
||||
* @brief 初始化I2C主机通信
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
// esp_err_t IoExpansionI2cInit();
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void CreateI2cReadTask();
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务(整合初始化和任务创建)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StartTask();
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief 读寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要读出的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口0寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort0(uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口1寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort1(uint8_t *data);
|
||||
|
||||
// /**
|
||||
// * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断
|
||||
// * @param reg_addr 寄存器地址
|
||||
// * @return esp_err_t 操作结果
|
||||
// */
|
||||
// esp_err_t SetInterruptStatus(bool status);
|
||||
|
||||
/**
|
||||
* @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandSetMode();
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
* @param mode 模式:1/2/4/8/16/32/64
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的方向
|
||||
* @param dir 方向
|
||||
* @param OUTPUT_PORT 输出端口
|
||||
* @param pin 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的睡眠模式
|
||||
* @param 是否进入睡眠模式
|
||||
* @param 输出端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能引脚状态
|
||||
* @param 使能状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的BL引脚状态
|
||||
* @param BL状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的RST引脚状态
|
||||
* @param RST状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置PA控制引脚状态
|
||||
* @param PA_CTRL状态(低电平为选中状态,高电平为不选中状态)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetPaCtrlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t pa_ctrl_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断引脚
|
||||
* @param 毫米波雷达的中断引脚模式
|
||||
* @param 输入端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin);
|
||||
|
||||
/**
|
||||
* @brief 计算Port0的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort0();
|
||||
|
||||
/**
|
||||
* @brief 计算Port1的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort1();
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断回调函数
|
||||
* @param callback 雷达中断回调函数
|
||||
*/
|
||||
void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器开始中断回调函数
|
||||
* @param callback 光学传感器开始中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器结束中断回调函数
|
||||
* @param callback 光学传感器结束中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充电中断回调函数
|
||||
* @param callback 电池充电中断回调函数
|
||||
*/
|
||||
void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充满中断回调函数
|
||||
* @param callback 电池充满中断回调函数
|
||||
*/
|
||||
void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池非充电中断回调函数
|
||||
* @param callback 电池非充电中断回调函数
|
||||
*/
|
||||
void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; }
|
||||
|
||||
// 公共成员变量
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
uint8_t device_addr_; // I2C设备地址
|
||||
|
||||
private:
|
||||
// 静态成员函数
|
||||
MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调
|
||||
PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调
|
||||
AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调
|
||||
static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数
|
||||
|
||||
// 成员变量用于状态跟踪
|
||||
uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态
|
||||
uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态
|
||||
bool radar_last_state_ = false; // 雷达引脚上一次的状态
|
||||
bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态
|
||||
bool battery_full_last_state_ = false; // 电池充满状态上一次的状态
|
||||
|
||||
// 回调函数成员变量
|
||||
RadarCallback radar_callback_ = nullptr;
|
||||
PhotoInterrupterStartCallback photo_start_callback_ = nullptr;
|
||||
PhotoInterrupterEndCallback photo_end_callback_ = nullptr;
|
||||
BatteryChargingCallback battery_charging_callback_ = nullptr;
|
||||
BatteryFullCallback battery_full_callback_ = nullptr;
|
||||
BatteryNotChargingCallback battery_not_charging_callback_ = nullptr;
|
||||
|
||||
// PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调
|
||||
// /**
|
||||
// * @brief 分配静态任务所需的内存
|
||||
// * @return bool 分配是否成功
|
||||
// */
|
||||
// bool AllocateStaticTaskMemory();
|
||||
|
||||
// /**
|
||||
// * @brief 释放静态任务分配的内存
|
||||
// */
|
||||
// void FreeStaticTaskMemory();
|
||||
|
||||
// 实例成员变量
|
||||
EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组
|
||||
TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄
|
||||
bool is_initialized_ = false; // 初始化状态标记(新增)
|
||||
gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚
|
||||
gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚
|
||||
|
||||
// StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM)
|
||||
// StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,702 @@
|
||||
/**
|
||||
* @file board.cc
|
||||
* @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "esp_check.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
}
|
||||
|
||||
#include "board_sweekar.h"
|
||||
#include "config.h"
|
||||
#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明
|
||||
#include "drv8428.h"
|
||||
#include "aw8646.h"
|
||||
|
||||
#define TAG "board_sweekar"
|
||||
|
||||
BoardSweekar::BoardSweekar()
|
||||
: base_board_hal_uart_(BASE_BOARD_CTL_UART_PORT)
|
||||
{
|
||||
#ifdef CONFIG_STEPPER_DRIVER_AW8646
|
||||
stepper_driver_ = new Aw8646Driver(io_expansion_);
|
||||
#else
|
||||
stepper_driver_ = new Drv8428Driver(io_expansion_);
|
||||
#endif
|
||||
}
|
||||
|
||||
BoardSweekar::~BoardSweekar()
|
||||
{
|
||||
if (stepper_driver_) {
|
||||
delete stepper_driver_;
|
||||
stepper_driver_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*========================== 步进电机相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 步进电机初始化函数
|
||||
* 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式
|
||||
* 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化
|
||||
*/
|
||||
void BoardSweekar::StepperMotorInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) STEP 引脚改为普通 GPIO(不再用 LEDC)
|
||||
gpio_config_t io_cfg;
|
||||
io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO;
|
||||
io_cfg.mode = GPIO_MODE_OUTPUT;
|
||||
io_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_cfg.intr_type = GPIO_INTR_DISABLE;
|
||||
err = gpio_config(&io_cfg);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 初始电平拉低,保证上电不乱跳
|
||||
gpio_set_level(STEPPER_STEP_IO, 0);
|
||||
|
||||
// 2) 检查 I2C 总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) 初始化驱动对象并初始化
|
||||
if (stepper_driver_) {
|
||||
err = stepper_driver_->Init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCD IO引脚初始化函数(消除与步进电机的耦合)
|
||||
*
|
||||
* 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作
|
||||
* 此函数独立于步进电机初始化,专门处理LCD相关的IO配置
|
||||
*/
|
||||
void BoardSweekar::LcdIoInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) 检查I2C总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) 执行硬件复位,确保IO扩展板处于已知状态
|
||||
err = io_expansion_.ResetIoExpand();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功");
|
||||
}
|
||||
|
||||
// 3) 配置IO扩展板模式(端口方向等)
|
||||
err = io_expansion_.IoexpandSetMode();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功");
|
||||
}
|
||||
|
||||
// 4) 初始化LCD复位引脚:设置为高电平
|
||||
err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功");
|
||||
}
|
||||
|
||||
io_expansion_.SetLedEnMode(true);
|
||||
}
|
||||
|
||||
/*========================== 毫米波雷达相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达串口初始化函数
|
||||
*
|
||||
* 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚,
|
||||
* 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免
|
||||
* 与自定义中断冲突。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = RADAR_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 122,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突)
|
||||
// 增加 RX/TX FIFO 深度以处理突发数据
|
||||
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4,
|
||||
0, NULL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达中断引脚初始化函数
|
||||
*
|
||||
* 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能
|
||||
* (如需使用中断需单独进行配置)。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarGpioInit(void)
|
||||
{
|
||||
// GPIO配置结构体
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚
|
||||
.mode = GPIO_MODE_INPUT, // 设置为输入模式
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉
|
||||
.intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置)
|
||||
};
|
||||
|
||||
// 配置GPIO
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief I2C总线及从机设备初始化函数
|
||||
*
|
||||
* 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。
|
||||
* 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。
|
||||
* 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::I2CMasterInit(void)
|
||||
{
|
||||
static const char *I2C_INIT = "I2C_INIT";
|
||||
|
||||
// 初始化IO扩展板复位引脚
|
||||
gpio_config_t reset_io_conf = {
|
||||
.pin_bit_mask = (1ULL << IO_EXPAND_RSTN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&reset_io_conf);
|
||||
|
||||
// 执行复位时序:先拉低100ms,再拉高并等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板复位完成");
|
||||
|
||||
// 创建统一的I2C总线(使用ESP-ADF的i2c_bus)
|
||||
i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C0_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C0_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = 100000,
|
||||
},
|
||||
.clk_flags = 0,
|
||||
};
|
||||
|
||||
// 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线)
|
||||
bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg);
|
||||
if (bus_handle_ == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create I2C bus");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
// ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信
|
||||
|
||||
// 验证线性马达设备是否存在
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR);
|
||||
}
|
||||
// 验证IO扩展板设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化其他设备
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR);
|
||||
}
|
||||
// 验证陀螺仪设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR);
|
||||
}
|
||||
|
||||
// 为IO扩展板设置总线句柄和设备地址(使用7位地址)
|
||||
io_expansion_.bus_handle_ = bus_handle_;
|
||||
io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1;
|
||||
|
||||
// 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法
|
||||
// linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性
|
||||
|
||||
ESP_LOGI(I2C_INIT, "I2C总线初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*========================== VBAT to VBAT_5V相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 开启VBAT to VBAT_5V
|
||||
*
|
||||
* 创建开启升压的电源管理单元
|
||||
*
|
||||
*/
|
||||
void BoardSweekar::VbatToVbat5vInit(void)
|
||||
{
|
||||
if (VBAT_5V_PIN == GPIO_NUM_NC) {
|
||||
return;
|
||||
}
|
||||
// 配置VBAT_5V引脚为输出模式
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (VBAT_5V_PIN != GPIO_NUM_NC) ? (1ULL << VBAT_5V_PIN) : 0,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
// 使能VBAT_5V
|
||||
gpio_set_level(VBAT_5V_PIN, 1);
|
||||
}
|
||||
|
||||
/*========================== 底座控制串口相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 底座控制命令串口初始化函数
|
||||
*/
|
||||
void BoardSweekar::BaseBoardControlUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BASE_BOARD_CTL_UART_BAUDRATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 122,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动
|
||||
ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
0, NULL, 0));
|
||||
|
||||
base_board_control_.Init(&base_board_hal_uart_);
|
||||
}
|
||||
|
||||
/*========================== SD卡相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief SD卡初始化函数
|
||||
*
|
||||
* 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器
|
||||
* 并配置SD卡,为后续的文件系统操作做准备。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeSdcard(void)
|
||||
{
|
||||
static const char *SDCARD_TAG = "SDCARD_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(SDCARD_TAG, "Initializing SD card");
|
||||
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGW(SDCARD_TAG, "SD card already initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 初始化外设管理
|
||||
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
|
||||
periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM
|
||||
periph_set_ = esp_periph_set_init(&periph_cfg);
|
||||
if (!periph_set_) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// 初始化SD卡外设
|
||||
ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
is_sdcard_initialized_ = true;
|
||||
ESP_LOGI(SDCARD_TAG, "SD card initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口实现
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备可能依赖)
|
||||
* 2. IO扩展板(可能影响其他设备)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. 其他外设
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardware(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化触摸传感器
|
||||
touch_sensor_.SetI2cHandle(bus_handle_);
|
||||
touch_sensor_.Begin();
|
||||
ESP_LOGI(HW_INIT_TAG, "Touch sensor initialized");
|
||||
|
||||
// 6. 初始化其他必要外设
|
||||
// BaseBoardControlUartInit(); // 底座控制串口(demo5需要)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized");
|
||||
|
||||
// 初始化底座控制
|
||||
// base_board_control_.Init();
|
||||
// ESP_LOGI(HW_INIT_TAG, "Base board control initialized");
|
||||
|
||||
// 可选外设(根据具体应用需求)
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
StepperMotorInit();
|
||||
|
||||
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,执行相应的功耗优化策略:
|
||||
* - IDLE模式:关闭非必要外设,保持快速响应
|
||||
* - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电
|
||||
* - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低
|
||||
*/
|
||||
esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode);
|
||||
|
||||
if (mode == current_power_mode_) {
|
||||
ESP_LOGW(POWER_TAG, "Already in power mode %d", mode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 保存当前模式,以便恢复
|
||||
power_mode_t previous_mode = current_power_mode_;
|
||||
|
||||
switch (mode) {
|
||||
case POWER_MODE_NORMAL:
|
||||
// 正常模式,不需要特殊处理
|
||||
break;
|
||||
|
||||
case POWER_MODE_IDLE:
|
||||
// 空闲模式:关闭非必要外设
|
||||
ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals");
|
||||
|
||||
// 关闭SD卡(如果正在使用,需要先卸载)
|
||||
if (is_sdcard_initialized_) {
|
||||
// 注意:这里只是示例,实际应用中需要确保没有文件操作
|
||||
ESP_LOGW(POWER_TAG, "SD card still active in idle mode");
|
||||
}
|
||||
|
||||
// 关闭显示背光
|
||||
// 关闭非必要GPIO的上拉/下拉
|
||||
// 降低I2C时钟频率
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep");
|
||||
|
||||
// 设置唤醒源(需要根据具体需求配置)
|
||||
// esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒
|
||||
// esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒
|
||||
|
||||
// 进入轻度睡眠
|
||||
// ret = esp_light_sleep_start();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret));
|
||||
current_power_mode_ = previous_mode;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up");
|
||||
|
||||
// 保存必要的RTC数据
|
||||
// rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO
|
||||
|
||||
// 设置深度睡眠唤醒源
|
||||
// esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒
|
||||
|
||||
// 进入深度睡眠
|
||||
// esp_deep_sleep_start();
|
||||
// 注意:深度睡眠后系统会重启,不会返回
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
current_power_mode_ = mode;
|
||||
ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。
|
||||
*/
|
||||
esp_err_t BoardSweekar::ExitLowPowerMode(void) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Exiting low power mode");
|
||||
|
||||
if (current_power_mode_ == POWER_MODE_NORMAL) {
|
||||
ESP_LOGW(POWER_TAG, "Already in normal mode");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 根据之前的功耗模式执行相应的恢复操作
|
||||
switch (current_power_mode_) {
|
||||
case POWER_MODE_IDLE:
|
||||
// 恢复空闲模式
|
||||
ESP_LOGI(POWER_TAG, "Restoring from idle mode");
|
||||
|
||||
// 重新初始化必要的外设
|
||||
// 恢复I2C时钟频率
|
||||
// 重新开启显示背光
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠唤醒后会自动继续执行
|
||||
ESP_LOGI(POWER_TAG, "Woken up from light sleep");
|
||||
|
||||
// 重新配置时钟(如果需要)
|
||||
// 重新初始化外设
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠后系统会重启,不会执行到这里
|
||||
ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 恢复到正常模式
|
||||
current_power_mode_ = POWER_MODE_NORMAL;
|
||||
ESP_LOGI(POWER_TAG, "Successfully exited low power mode");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。
|
||||
*/
|
||||
esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) {
|
||||
static const char *POWER_TAG = "POWER_MODULE";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module);
|
||||
|
||||
// 更新电源状态位图
|
||||
if (enable) {
|
||||
power_state_flags_ |= (1 << module);
|
||||
} else {
|
||||
power_state_flags_ &= ~(1 << module);
|
||||
}
|
||||
|
||||
switch (module) {
|
||||
case HW_MODULE_I2C:
|
||||
if (!enable && bus_handle_) {
|
||||
// 注意:I2C总线通常不建议完全关闭,可能影响多个设备
|
||||
ESP_LOGW(POWER_TAG, "I2C bus power control not recommended");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_SDCARD:
|
||||
if (enable && !is_sdcard_initialized_) {
|
||||
ret = InitializeSdcard();
|
||||
} else if (!enable && is_sdcard_initialized_) {
|
||||
// 卸载SD卡文件系统
|
||||
// 注意:需要确保没有打开的文件
|
||||
ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_LCD:
|
||||
// LCD背光控制
|
||||
// LCD电源引脚控制(如果有)
|
||||
break;
|
||||
|
||||
case HW_MODULE_AUDIO:
|
||||
// 音频编解码器电源控制
|
||||
// 需要与AudioPlayer协调
|
||||
break;
|
||||
|
||||
case HW_MODULE_MOTOR:
|
||||
// 步进电机驱动器电源控制
|
||||
// 电机睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_GYROSCOPE:
|
||||
// 陀螺仪电源控制
|
||||
// 设置陀螺仪为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_TOUCH:
|
||||
// 触摸传感器电源控制
|
||||
// 设置触摸传感器为睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_RADAR:
|
||||
// 毫米波雷达电源控制
|
||||
// 设置雷达为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_IO_EXPAND:
|
||||
// IO扩展板电源控制
|
||||
// 设置扩展板为低功耗模式
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled");
|
||||
} else {
|
||||
ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "stepper_motor.h"
|
||||
#include "stepper_driver.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "gyroscope.h"
|
||||
#include "touch_sensor.h"
|
||||
#include "base_board_control.h"
|
||||
#include "base_board_hal_uart.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗模式枚举
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用
|
||||
POWER_MODE_IDLE, // 空闲模式,关闭非必要外设
|
||||
POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒
|
||||
POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行
|
||||
} power_mode_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件模块枚举,用于精细化电源管理
|
||||
*/
|
||||
typedef enum {
|
||||
HW_MODULE_I2C, // I2C总线
|
||||
HW_MODULE_SDCARD, // SD卡
|
||||
HW_MODULE_LCD, // LCD显示
|
||||
HW_MODULE_AUDIO, // 音频编解码器
|
||||
HW_MODULE_MOTOR, // 步进电机
|
||||
HW_MODULE_GYROSCOPE, // 陀螺仪
|
||||
HW_MODULE_TOUCH, // 触摸传感器
|
||||
HW_MODULE_RADAR, // 毫米波雷达
|
||||
HW_MODULE_IO_EXPAND, // IO扩展板
|
||||
} hardware_module_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件板级管理器
|
||||
*
|
||||
* 采用高内聚低耦合设计原则,统一管理所有硬件资源。
|
||||
* 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。
|
||||
*/
|
||||
class BoardSweekar
|
||||
{
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄
|
||||
esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄
|
||||
bool is_sdcard_initialized_ = false; // SD卡初始化状态
|
||||
power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式
|
||||
uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启)
|
||||
|
||||
public:
|
||||
BoardSweekar();
|
||||
~BoardSweekar();
|
||||
|
||||
IOExpansionBoard io_expansion_; // IO扩展板对象
|
||||
Gyroscope gyroscope_; // 陀螺仪对象
|
||||
TouchSensor touch_sensor_; // 触摸传感器对象
|
||||
BaseBoardHalUart base_board_hal_uart_; // 底座控制HAL对象
|
||||
BaseBoardControl base_board_control_; // 底座控制对象
|
||||
StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象
|
||||
|
||||
StepperDriver* GetStepperDriver() const { return stepper_driver_; }
|
||||
|
||||
// 初始化步进电机
|
||||
void StepperMotorInit(void);
|
||||
|
||||
// 初始化LCD IO引脚(消除与步进电机的耦合)
|
||||
void LcdIoInit(void);
|
||||
|
||||
// 初始化串口
|
||||
void MillimeterWaveRadarUartInit(void);
|
||||
|
||||
//初始化毫米波雷达的中断引脚
|
||||
void MillimeterWaveRadarGpioInit(void);
|
||||
|
||||
// 初始化I2C总线
|
||||
esp_err_t I2CMasterInit(void);
|
||||
|
||||
// 初始化VBAT toVBAT_5V引脚
|
||||
void VbatToVbat5vInit(void);
|
||||
|
||||
// 初始化底座控制串口
|
||||
void BaseBoardControlUartInit(void);
|
||||
|
||||
// 初始化SD卡(推荐使用统一的硬件初始化)
|
||||
esp_err_t InitializeSdcard(void);
|
||||
|
||||
// 获取SD卡初始化状态
|
||||
bool IsSdcardInitialized() const { return is_sdcard_initialized_; }
|
||||
|
||||
// 获取外设管理句柄(供需要访问SD卡的模块使用)
|
||||
esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; }
|
||||
|
||||
// 获取I2C总线句柄
|
||||
i2c_bus_handle_t GetBusHandle() const { return bus_handle_; }
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。
|
||||
* 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardware(void);
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为复杂应用优化)
|
||||
*
|
||||
* 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。
|
||||
* 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardwareComplete(void);
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置,优化启动流程。
|
||||
*
|
||||
* @param app_type 应用类型(demo5、音频播放器、显示应用等)
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeHardwareForApplication(int app_type);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、
|
||||
* 调整时钟频率等。支持多种功耗模式以适应不同应用场景。
|
||||
*
|
||||
* @param mode 功耗模式
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t EnterLowPowerMode(power_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复,重新初始化必要的硬件资源。
|
||||
*
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ExitLowPowerMode(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前功耗模式
|
||||
*
|
||||
* @return power_mode_t 当前功耗模式
|
||||
*/
|
||||
power_mode_t GetPowerMode(void) const { return current_power_mode_; }
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。
|
||||
*
|
||||
* @param module 硬件模块
|
||||
* @param enable true为开启,false为关闭
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetModulePower(hardware_module_t module, bool enable);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* @file board_sweekar_complete_init.cc
|
||||
* @brief 完整的统一硬件初始化实现
|
||||
*
|
||||
* 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。
|
||||
* 专为demo5等复杂应用场景设计。
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为demo5优化)
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备依赖)
|
||||
* 2. IO扩展板(控制其他外设)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. LCD IO引脚(显示相关)
|
||||
* 5. 底座控制串口(通信)
|
||||
* 6. 底座控制模块(业务逻辑)
|
||||
* 7. 其他外设(根据应用需求)
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardwareComplete(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT_COMPLETE";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础,其他设备依赖)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚(显示相关)
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化底座控制串口(demo5需要)
|
||||
BaseBoardControlUartInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized");
|
||||
|
||||
// 6. 初始化底座控制模块
|
||||
base_board_control_.Init();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized");
|
||||
|
||||
// 7. 设置IO扩展板的PA控制模式(demo5需要)
|
||||
io_expansion_.SetPaCtrlMode(true);
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set");
|
||||
|
||||
// 8. 可选外设(根据具体应用需求启用)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals...");
|
||||
//
|
||||
// // 毫米波雷达(如需要)
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized");
|
||||
//
|
||||
// // VBAT升压(如需要)
|
||||
// VbatToVbat5vInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized");
|
||||
//
|
||||
// // 步进电机(如需要)
|
||||
// StepperMotorInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized");
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ===");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) {
|
||||
static const char *APP_INIT_TAG = "APP_HW_INIT";
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type);
|
||||
|
||||
// 基础硬件初始化(所有应用都需要)
|
||||
esp_err_t ret = InitializeAllHardwareComplete();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (app_type) {
|
||||
case APP_TYPE_DEMO5: // 宠物游戏demo
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)...");
|
||||
|
||||
// Demo5需要的额外初始化
|
||||
// 触摸传感器、陀螺仪、RGB LED等会在应用层初始化
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_AUDIO_PLAYER: // 音频播放器
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player...");
|
||||
|
||||
// 音频应用需要确保音频编解码器正确初始化
|
||||
// 这部分通常在AudioPlayer类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_DISPLAY_ONLY: // 纯显示应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only...");
|
||||
|
||||
// 显示应用需要确保LCD相关硬件正确配置
|
||||
// 这部分通常在Display类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_MINIMAL: // 最小化应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application...");
|
||||
|
||||
// 最小化配置,只保留最基本的功能
|
||||
// 关闭非必要外设以节省功耗
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete");
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration");
|
||||
break;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 硬件初始化状态报告
|
||||
*
|
||||
* 提供详细的硬件初始化状态报告,便于调试和问题排查
|
||||
*/
|
||||
void BoardSweekar::ReportHardwareStatus(void) {
|
||||
static const char *STATUS_TAG = "HW_STATUS";
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ===");
|
||||
|
||||
// I2C总线状态
|
||||
ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// SD卡状态
|
||||
ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized");
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available");
|
||||
}
|
||||
|
||||
// IO扩展板状态
|
||||
ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured");
|
||||
|
||||
// 底座控制状态
|
||||
ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// 功耗管理状态
|
||||
ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode");
|
||||
ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_);
|
||||
ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_);
|
||||
|
||||
// 内存状态
|
||||
ESP_LOGI(STATUS_TAG, "Memory Status:");
|
||||
ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ===");
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/* 定义引脚分配 */
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @brief 定义了引脚的分配。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h" // 用于 esp_rom_delay_us
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/timer.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义
|
||||
#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "linear_motor.h"
|
||||
#include "gyroscope.h"
|
||||
|
||||
#define TAG_BOARD "SWEEKAR_ESP32"
|
||||
/*I2C总线引脚定义*/
|
||||
#define I2C0_MASTER_PORT I2C_NUM_0
|
||||
#define I2C0_MASTER_SDA_IO GPIO_NUM_2
|
||||
#define I2C0_MASTER_SCL_IO GPIO_NUM_3
|
||||
|
||||
/* 步进电机配置 */
|
||||
#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚
|
||||
#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进)
|
||||
|
||||
/* 定义屏幕驱动控制引脚 */
|
||||
#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚
|
||||
#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL
|
||||
#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚
|
||||
#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚
|
||||
#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚
|
||||
#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚
|
||||
#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS)
|
||||
|
||||
#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数)
|
||||
#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数)
|
||||
|
||||
/* 毫米波雷达配置参数 */
|
||||
/* 定义毫米波雷达的中断引脚 */
|
||||
#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35
|
||||
// UART 配置参数
|
||||
#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1
|
||||
#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整)
|
||||
#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX
|
||||
#define RADAR_BAUD_RATE 9600 // 雷达波特率
|
||||
#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小
|
||||
|
||||
/* IO扩展硬件配置常量 */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000)
|
||||
#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚
|
||||
#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/* 定义线性马达的I2C从机配置常量 */
|
||||
#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址
|
||||
|
||||
/* 定义陀螺仪的I2C从机配置常量 */
|
||||
#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址
|
||||
#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚
|
||||
|
||||
/* 原生触摸引脚配置 */
|
||||
// 触摸按键数量配置
|
||||
#define TOUCH_BUTTON_NUM 3
|
||||
// 触摸通道定义
|
||||
#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11
|
||||
#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12
|
||||
#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13
|
||||
|
||||
/* ES8311音频编解码器配置 (ESP-ADF兼容) */
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
/* I2S GPIO定义 */
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
/* PA引脚定义 */
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
|
||||
/* I2C配置 */
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3
|
||||
#define AUDIO_CODEC_ES8311_ADDR 0x18
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x40
|
||||
|
||||
/* WS2812 RGB LED配置 */
|
||||
#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚
|
||||
#define WS2812_NUM_LEDS 2 // WS2812 LED数量
|
||||
|
||||
/* 创建VBAT to VBAT_5V */
|
||||
#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚
|
||||
|
||||
/* 定义按键的中断引脚 */
|
||||
#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚
|
||||
#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚
|
||||
|
||||
/* 底座控制命令串口配置 */
|
||||
#define BASE_BOARD_CTL_UART_PORT UART_NUM_0
|
||||
#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43
|
||||
#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44
|
||||
#define BASE_BOARD_CTL_UART_BAUDRATE 115200
|
||||
#define BASE_BOARD_CTL_UART_BUF_SIZE 256
|
||||
|
||||
/* 背光控制引脚配置 */
|
||||
#define BL_PIN GPIO_NUM_45
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,421 @@
|
||||
#ifndef IO_EXPANSION_BOARD_H
|
||||
#define IO_EXPANSION_BOARD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <functional>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
class MillimeterWaveRadar;
|
||||
class PhotoInterrupter;
|
||||
class AdcBatteryMonitor;
|
||||
|
||||
// 回调函数类型定义
|
||||
typedef std::function<void()> RadarCallback;
|
||||
typedef std::function<void()> PhotoInterrupterStartCallback;
|
||||
typedef std::function<void()> PhotoInterrupterEndCallback;
|
||||
typedef std::function<void()> BatteryChargingCallback;
|
||||
typedef std::function<void()> BatteryFullCallback;
|
||||
typedef std::function<void()> BatteryNotChargingCallback;
|
||||
|
||||
/* 寄存器地址 */
|
||||
#define INPUT_PORT0 0x00 // 输入端口0寄存器
|
||||
#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取)
|
||||
#define OUTPUT_PORT0 0x02 // 输出端口0寄存器
|
||||
#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平
|
||||
#define CONFIG_PORT0 0x04 // 配置端口0寄存器
|
||||
#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式
|
||||
#define INT_PORT0 0x06 // 中断端口0寄存器
|
||||
#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的)
|
||||
#define CTL 0x11 // 全局控制寄存器
|
||||
#define ID 0x23 // 芯片ID寄存器(0x23)
|
||||
|
||||
/***********************************IO扩展板电机引脚配置参数*************************************/
|
||||
/* 设置步进电机方向 */
|
||||
#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转
|
||||
#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转
|
||||
#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4
|
||||
#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4
|
||||
|
||||
/* 设置步进电机细分模式 */
|
||||
#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5
|
||||
#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5
|
||||
|
||||
#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4
|
||||
#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4
|
||||
|
||||
/* 设置步进电机睡眠引脚 */
|
||||
#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式
|
||||
#define STEPPER_MOTOR_WORK true //步进电机进入工作模式
|
||||
#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
/* 设置电机的使能引脚 */
|
||||
#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平
|
||||
#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平
|
||||
|
||||
/* 设置毫米波雷达对应IO扩展板的中断引脚 */
|
||||
#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7
|
||||
#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口
|
||||
#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1
|
||||
#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态
|
||||
#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态
|
||||
/* 任务配置常量 */
|
||||
#define WRITE_BUF_SIZE 2 // I2C单次写入字节数
|
||||
#define READ_BUF_SIZE 2 // I2C单次读取字节数
|
||||
#define I2C_TASK_PRIORITY 2 // 任务优先级(中等)
|
||||
#define I2C_TASK_STACK 4096 // 任务栈大小(4KB)
|
||||
|
||||
// 光学传感器引脚定义
|
||||
#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2)
|
||||
#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3)
|
||||
#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
/***********************************IO扩展板LCD引脚配置参数*************************************/
|
||||
// /* 设置LCD的BL引脚 */
|
||||
// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6
|
||||
// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6
|
||||
// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平
|
||||
// #define LCD_BL_LOW false //LCD背光引脚状态为低电平
|
||||
|
||||
/* 设置LCD的RST引脚 */
|
||||
#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1
|
||||
#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1
|
||||
#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_RST_HIGH true //LCD复位引脚状态为高电平
|
||||
#define LCD_RST_LOW false //LCD复位引脚状态为低电平
|
||||
|
||||
/* 设置PA控制引脚 */
|
||||
#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2
|
||||
#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2
|
||||
#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define PA_CTRL_HIGH true //PA控制引脚状态为高电平
|
||||
#define PA_CTRL_LOW false //PA控制引脚状态为低电平
|
||||
|
||||
// 电池充电检测引脚定义
|
||||
#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3
|
||||
#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3
|
||||
|
||||
#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5)
|
||||
#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
|
||||
#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签
|
||||
#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签
|
||||
|
||||
// GPIO引脚定义
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚
|
||||
// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/**
|
||||
* @class IOExpansionBoard
|
||||
* @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作
|
||||
*/
|
||||
class IOExpansionBoard
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 设置毫米波雷达指针
|
||||
* @param radar 毫米波雷达对象指针
|
||||
*/
|
||||
void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; };
|
||||
|
||||
/**
|
||||
* @brief 设置限位开关指针
|
||||
* @param photo_interrupter 限位开关对象指针
|
||||
*/
|
||||
void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; };
|
||||
|
||||
/**
|
||||
* @brief 设置电池监控器指针
|
||||
* @param battery_monitor 电池监控器对象指针
|
||||
*/
|
||||
void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; };
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetIoExpand();
|
||||
|
||||
/**
|
||||
* @brief 初始化I2C主机通信
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
// esp_err_t IoExpansionI2cInit();
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void CreateI2cReadTask();
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务(整合初始化和任务创建)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StartTask();
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief 读寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要读出的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口0寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort0(uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口1寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort1(uint8_t *data);
|
||||
|
||||
// /**
|
||||
// * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断
|
||||
// * @param reg_addr 寄存器地址
|
||||
// * @return esp_err_t 操作结果
|
||||
// */
|
||||
// esp_err_t SetInterruptStatus(bool status);
|
||||
|
||||
/**
|
||||
* @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandSetMode();
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
* @param mode 模式:1/2/4/8/16/32/64
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的方向
|
||||
* @param dir 方向
|
||||
* @param OUTPUT_PORT 输出端口
|
||||
* @param pin 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的睡眠模式
|
||||
* @param 是否进入睡眠模式
|
||||
* @param 输出端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能引脚状态
|
||||
* @param 使能状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的BL引脚状态
|
||||
* @param BL状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin);
|
||||
|
||||
esp_err_t SetLedEnMode(bool mode);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的RST引脚状态
|
||||
* @param RST状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置PA控制引脚状态
|
||||
* @param mode PA_CTRL状态(true为高电平,false为低电平)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetPaCtrlMode(bool mode);
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断引脚
|
||||
* @param 毫米波雷达的中断引脚模式
|
||||
* @param 输入端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin);
|
||||
|
||||
/**
|
||||
* @brief 计算Port0的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort0();
|
||||
|
||||
/**
|
||||
* @brief 计算Port1的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort1();
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断回调函数
|
||||
* @param callback 雷达中断回调函数
|
||||
*/
|
||||
void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器开始中断回调函数
|
||||
* @param callback 光学传感器开始中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器结束中断回调函数
|
||||
* @param callback 光学传感器结束中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充电中断回调函数
|
||||
* @param callback 电池充电中断回调函数
|
||||
*/
|
||||
void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充满中断回调函数
|
||||
* @param callback 电池充满中断回调函数
|
||||
*/
|
||||
void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池非充电中断回调函数
|
||||
* @param callback 电池非充电中断回调函数
|
||||
*/
|
||||
void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; }
|
||||
|
||||
// 公共成员变量
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
uint8_t device_addr_; // I2C设备地址
|
||||
|
||||
private:
|
||||
// 静态成员函数
|
||||
MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调
|
||||
PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调
|
||||
AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调
|
||||
static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数
|
||||
|
||||
// 成员变量用于状态跟踪
|
||||
uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态
|
||||
uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态
|
||||
bool radar_last_state_ = false; // 雷达引脚上一次的状态
|
||||
bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态
|
||||
bool battery_full_last_state_ = false; // 电池充满状态上一次的状态
|
||||
|
||||
// 回调函数成员变量
|
||||
RadarCallback radar_callback_ = nullptr;
|
||||
PhotoInterrupterStartCallback photo_start_callback_ = nullptr;
|
||||
PhotoInterrupterEndCallback photo_end_callback_ = nullptr;
|
||||
BatteryChargingCallback battery_charging_callback_ = nullptr;
|
||||
BatteryFullCallback battery_full_callback_ = nullptr;
|
||||
BatteryNotChargingCallback battery_not_charging_callback_ = nullptr;
|
||||
|
||||
// PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调
|
||||
// /**
|
||||
// * @brief 分配静态任务所需的内存
|
||||
// * @return bool 分配是否成功
|
||||
// */
|
||||
// bool AllocateStaticTaskMemory();
|
||||
|
||||
// /**
|
||||
// * @brief 释放静态任务分配的内存
|
||||
// */
|
||||
// void FreeStaticTaskMemory();
|
||||
|
||||
// 实例成员变量
|
||||
EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组
|
||||
TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄
|
||||
bool is_initialized_ = false; // 初始化状态标记(新增)
|
||||
gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚
|
||||
gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚
|
||||
|
||||
// StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM)
|
||||
// StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @file power_management_config.h
|
||||
* @brief 功耗管理配置和策略定义
|
||||
* @author Embedded Software Expert
|
||||
* @date 2025年1月
|
||||
*
|
||||
* 这个文件定义了功耗管理的配置参数、策略和优化建议,
|
||||
* 为系统提供灵活的功耗管理方案。
|
||||
*/
|
||||
|
||||
#ifndef POWER_MANAGEMENT_CONFIG_H
|
||||
#define POWER_MANAGEMENT_CONFIG_H
|
||||
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗管理配置结构体
|
||||
*/
|
||||
typedef struct {
|
||||
// 睡眠模式配置
|
||||
uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒)
|
||||
uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒)
|
||||
|
||||
// 唤醒源配置
|
||||
bool enable_timer_wakeup; // 启用定时器唤醒
|
||||
bool enable_gpio_wakeup; // 启用GPIO唤醒
|
||||
bool enable_touch_wakeup; // 启用触摸唤醒
|
||||
gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号
|
||||
int wakeup_level; // 唤醒电平(0或1)
|
||||
|
||||
// 功耗优化配置
|
||||
bool disable_bt_in_sleep; // 睡眠时关闭蓝牙
|
||||
bool disable_wifi_in_sleep; // 睡眠时关闭WiFi
|
||||
bool reduce_cpu_frequency; // 降低CPU频率
|
||||
uint32_t cpu_frequency_hz; // CPU频率(Hz)
|
||||
|
||||
// 外设功耗配置
|
||||
bool power_down_sdcard; // 睡眠时关闭SD卡电源
|
||||
bool power_down_display; // 睡眠时关闭显示电源
|
||||
bool power_down_audio; // 睡眠时关闭音频电源
|
||||
bool power_down_motor; // 睡眠时关闭电机电源
|
||||
|
||||
// RTC内存配置
|
||||
bool preserve_rtc_memory; // 保留RTC内存
|
||||
size_t rtc_memory_size; // RTC内存大小
|
||||
} power_management_config_t;
|
||||
|
||||
/**
|
||||
* @brief 默认功耗管理配置
|
||||
*/
|
||||
#define DEFAULT_POWER_CONFIG { \
|
||||
.light_sleep_duration_us = 1000000, /* 1秒 */ \
|
||||
.deep_sleep_duration_us = 30000000, /* 30秒 */ \
|
||||
.enable_timer_wakeup = true, /* 启用定时器唤醒 */ \
|
||||
.enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \
|
||||
.enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \
|
||||
.wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \
|
||||
.wakeup_level = 0, /* 低电平唤醒 */ \
|
||||
.disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \
|
||||
.disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \
|
||||
.reduce_cpu_frequency = true, /* 降低CPU频率 */ \
|
||||
.cpu_frequency_hz = 80000000, /* 80MHz */ \
|
||||
.power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \
|
||||
.power_down_display = true, /* 睡眠时关闭显示 */ \
|
||||
.power_down_audio = true, /* 睡眠时关闭音频 */ \
|
||||
.power_down_motor = true, /* 睡眠时关闭电机 */ \
|
||||
.preserve_rtc_memory = true, /* 保留RTC内存 */ \
|
||||
.rtc_memory_size = 4096, /* 4KB RTC内存 */ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 各功耗模式的详细配置
|
||||
*/
|
||||
static const power_management_config_t idle_mode_config = {
|
||||
.light_sleep_duration_us = 500000, // 500ms轻度睡眠
|
||||
.deep_sleep_duration_us = 0, // 不使用深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = false, // 保持蓝牙连接
|
||||
.disable_wifi_in_sleep = false, // 保持WiFi连接
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000, // 40MHz
|
||||
.power_down_sdcard = false, // 保持SD卡(可能有后台任务)
|
||||
.power_down_display = true, // 关闭显示背光
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 2048,
|
||||
};
|
||||
|
||||
static const power_management_config_t light_sleep_config = {
|
||||
.light_sleep_duration_us = 0, // 直接进入轻度睡眠
|
||||
.deep_sleep_duration_us = 0,
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000,
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 4096,
|
||||
};
|
||||
|
||||
static const power_management_config_t deep_sleep_config = {
|
||||
.light_sleep_duration_us = 0,
|
||||
.deep_sleep_duration_us = 60000000, // 60秒深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 10000000, // 10MHz
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 8192,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 功耗统计和监控结构体
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t total_sleep_time_us; // 总睡眠时间
|
||||
uint64_t total_wake_time_us; // 总唤醒时间
|
||||
uint32_t sleep_count; // 睡眠次数
|
||||
uint32_t wake_count; // 唤醒次数
|
||||
uint32_t average_sleep_duration_us; // 平均睡眠时长
|
||||
uint32_t average_wake_duration_us; // 平均唤醒时长
|
||||
float estimated_power_saving_percent; // 估计的功耗节省百分比
|
||||
} power_statistics_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗优化建议
|
||||
*
|
||||
* 基于硬件特性和使用模式,提供功耗优化建议
|
||||
*/
|
||||
typedef enum {
|
||||
OPTIMIZATION_NONE = 0,
|
||||
OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率
|
||||
OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设
|
||||
OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠
|
||||
OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠
|
||||
OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态
|
||||
OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存
|
||||
OPTIMIZATION_BATCH_OPERATIONS, // 批量操作
|
||||
} power_optimization_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件回调
|
||||
*/
|
||||
typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_EVENT_MODE_CHANGE, // 功耗模式改变
|
||||
POWER_EVENT_SLEEP_START, // 睡眠开始
|
||||
POWER_EVENT_SLEEP_END, // 睡眠结束
|
||||
POWER_EVENT_WAKEUP, // 系统唤醒
|
||||
POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发
|
||||
} power_event_t;
|
||||
|
||||
#endif // POWER_MANAGEMENT_CONFIG_H
|
||||
@@ -0,0 +1,738 @@
|
||||
/**
|
||||
* @file board.cc
|
||||
* @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "esp_check.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
}
|
||||
|
||||
#include "board_sweekar.h"
|
||||
#include "config.h"
|
||||
#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明
|
||||
#include "drv8428.h"
|
||||
#include "aw8646.h"
|
||||
|
||||
#define TAG "board_sweekar"
|
||||
|
||||
BoardSweekar::BoardSweekar()
|
||||
{
|
||||
#ifdef CONFIG_STEPPER_DRIVER_AW8646
|
||||
stepper_driver_ = new Aw8646Driver(io_expansion_);
|
||||
#else
|
||||
stepper_driver_ = new Drv8428Driver(io_expansion_);
|
||||
#endif
|
||||
|
||||
// Initialize Shutdown Control Pin (GPIO_NUM_13) and pull it HIGH
|
||||
// This is required to keep the main power on.
|
||||
#ifdef SHUTDOWN_CTRL_PIN
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << SHUTDOWN_CTRL_PIN);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(SHUTDOWN_CTRL_PIN, 1);
|
||||
ESP_LOGI(TAG, "Initialized SHUTDOWN_CTRL_PIN (%d) to HIGH", SHUTDOWN_CTRL_PIN);
|
||||
#endif
|
||||
}
|
||||
|
||||
BoardSweekar::~BoardSweekar()
|
||||
{
|
||||
if (stepper_driver_) {
|
||||
delete stepper_driver_;
|
||||
stepper_driver_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*========================== 步进电机相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 步进电机初始化函数
|
||||
* 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式
|
||||
* 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化
|
||||
*/
|
||||
void BoardSweekar::StepperMotorInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) STEP 引脚改为普通 GPIO(不再用 LEDC)
|
||||
gpio_config_t io_cfg;
|
||||
io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO;
|
||||
io_cfg.mode = GPIO_MODE_OUTPUT;
|
||||
io_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_cfg.intr_type = GPIO_INTR_DISABLE;
|
||||
err = gpio_config(&io_cfg);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 初始电平拉低,保证上电不乱跳
|
||||
gpio_set_level(STEPPER_STEP_IO, 0);
|
||||
|
||||
// 2) 检查 I2C 总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) 初始化驱动对象并初始化
|
||||
if (stepper_driver_) {
|
||||
err = stepper_driver_->Init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCD IO引脚初始化函数(消除与步进电机的耦合)
|
||||
*
|
||||
* 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作
|
||||
* 此函数独立于步进电机初始化,专门处理LCD相关的IO配置
|
||||
*/
|
||||
void BoardSweekar::LcdIoInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) 检查I2C总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) 执行硬件复位,确保IO扩展板处于已知状态
|
||||
err = io_expansion_.ResetIoExpand();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功");
|
||||
}
|
||||
|
||||
// 3) 配置IO扩展板模式(端口方向等)
|
||||
err = io_expansion_.IoexpandSetMode();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功");
|
||||
}
|
||||
|
||||
// 4) 初始化LCD复位引脚:设置为高电平
|
||||
err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功");
|
||||
}
|
||||
}
|
||||
|
||||
/*========================== 毫米波雷达相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达串口初始化函数
|
||||
*
|
||||
* 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚,
|
||||
* 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免
|
||||
* 与自定义中断冲突。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = RADAR_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突)
|
||||
// 增加 RX/TX FIFO 深度以处理突发数据
|
||||
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4,
|
||||
0, NULL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行系统关机(拉高 SHUTDOWN_CTRL_PIN 切断电源)
|
||||
*/
|
||||
void BoardSweekar::SystemShutdown(void)
|
||||
{
|
||||
#ifdef SHUTDOWN_CTRL_PIN
|
||||
ESP_LOGI(TAG, "Executing System Shutdown... Pulling SHUTDOWN_CTRL_PIN (%d) HIGH", SHUTDOWN_CTRL_PIN);
|
||||
gpio_set_level(SHUTDOWN_CTRL_PIN, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
#else
|
||||
ESP_LOGW(TAG, "SHUTDOWN_CTRL_PIN is not defined. Cannot execute hardware shutdown.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达中断引脚初始化函数
|
||||
*
|
||||
* 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能
|
||||
* (如需使用中断需单独进行配置)。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarGpioInit(void)
|
||||
{
|
||||
// GPIO配置结构体
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚
|
||||
.mode = GPIO_MODE_INPUT, // 设置为输入模式
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉
|
||||
.intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置)
|
||||
};
|
||||
|
||||
// 配置GPIO
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief I2C总线及从机设备初始化函数
|
||||
*
|
||||
* 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。
|
||||
* 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。
|
||||
* 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::I2CMasterInit(void)
|
||||
{
|
||||
static const char *I2C_INIT = "I2C_INIT";
|
||||
|
||||
// 初始化IO扩展板复位引脚
|
||||
gpio_config_t reset_io_conf = {
|
||||
.pin_bit_mask = (1ULL << IO_EXPAND_RSTN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&reset_io_conf);
|
||||
|
||||
// 执行复位时序:先拉低100ms,再拉高并等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板复位完成");
|
||||
|
||||
// 创建统一的I2C总线(使用ESP-ADF的i2c_bus)
|
||||
i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C0_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C0_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = 100000,
|
||||
},
|
||||
};
|
||||
|
||||
// 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线)
|
||||
bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg);
|
||||
if (bus_handle_ == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create I2C bus");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
// ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信
|
||||
|
||||
// 验证线性马达设备是否存在
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR);
|
||||
}
|
||||
// 验证IO扩展板设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化其他设备
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR);
|
||||
}
|
||||
// 验证陀螺仪设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR);
|
||||
}
|
||||
|
||||
// 为IO扩展板设置总线句柄和设备地址(使用7位地址)
|
||||
io_expansion_.bus_handle_ = bus_handle_;
|
||||
io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1;
|
||||
|
||||
// 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法
|
||||
// linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性
|
||||
|
||||
ESP_LOGI(I2C_INIT, "I2C总线初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*========================== VBAT to VBAT_5V相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 开启VBAT to VBAT_5V
|
||||
*
|
||||
* 创建开启升压的电源管理单元
|
||||
*
|
||||
*/
|
||||
void BoardSweekar::VbatToVbat5vInit(void)
|
||||
{
|
||||
// 配置VBAT_5V引脚为输出模式
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << VBAT_5V_PIN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
// 使能VBAT_5V
|
||||
gpio_set_level(VBAT_5V_PIN, 1);
|
||||
}
|
||||
|
||||
/*========================== 底座控制串口相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 底座控制命令串口初始化函数
|
||||
*/
|
||||
// 根据配置选择通信方式的HAL头文件
|
||||
#ifdef CONFIG_BASE_BOARD_COMM_I2C
|
||||
#include "base_board_hal_i2c.h"
|
||||
#else
|
||||
#include "base_board_hal_uart.h"
|
||||
#endif
|
||||
|
||||
void BoardSweekar::BaseBoardControlInit(void)
|
||||
{
|
||||
#ifdef CONFIG_BASE_BOARD_COMM_I2C
|
||||
// I2C Mode
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "I2C bus not initialized before BaseBoardControlInit");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建 I2C HAL 实例
|
||||
BaseBoardHalI2c *hal = new BaseBoardHalI2c(bus_handle_);
|
||||
base_board_control_.Init(hal);
|
||||
ESP_LOGI(TAG, "BaseBoardControl I2C initialized");
|
||||
#else
|
||||
// UART Mode
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BASE_BOARD_CTL_UART_BAUDRATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动
|
||||
ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
0, NULL, 0));
|
||||
|
||||
BaseBoardHalUart *hal = new BaseBoardHalUart(BASE_BOARD_CTL_UART_PORT);
|
||||
base_board_control_.Init(hal);
|
||||
ESP_LOGI(TAG, "BaseBoardControl UART initialized");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================== SD卡相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief SD卡初始化函数
|
||||
*
|
||||
* 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器
|
||||
* 并配置SD卡,为后续的文件系统操作做准备。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeSdcard(void)
|
||||
{
|
||||
static const char *SDCARD_TAG = "SDCARD_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(SDCARD_TAG, "Initializing SD card");
|
||||
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGW(SDCARD_TAG, "SD card already initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 初始化外设管理
|
||||
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
|
||||
periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM
|
||||
periph_set_ = esp_periph_set_init(&periph_cfg);
|
||||
if (!periph_set_) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// 初始化SD卡外设
|
||||
ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
is_sdcard_initialized_ = true;
|
||||
ESP_LOGI(SDCARD_TAG, "SD card initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口实现
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备可能依赖)
|
||||
* 2. IO扩展板(可能影响其他设备)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. 其他外设
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardware(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化其他必要外设
|
||||
// BaseBoardControlUartInit(); // 底座控制串口(demo5需要)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized");
|
||||
|
||||
// 初始化底座控制
|
||||
// base_board_control_.Init();
|
||||
// ESP_LOGI(HW_INIT_TAG, "Base board control initialized");
|
||||
|
||||
// 可选外设(根据具体应用需求)
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
StepperMotorInit();
|
||||
|
||||
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,执行相应的功耗优化策略:
|
||||
* - IDLE模式:关闭非必要外设,保持快速响应
|
||||
* - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电
|
||||
* - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低
|
||||
*/
|
||||
esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode);
|
||||
|
||||
if (mode == current_power_mode_) {
|
||||
ESP_LOGW(POWER_TAG, "Already in power mode %d", mode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 保存当前模式,以便恢复
|
||||
power_mode_t previous_mode = current_power_mode_;
|
||||
|
||||
switch (mode) {
|
||||
case POWER_MODE_NORMAL:
|
||||
// 正常模式,不需要特殊处理
|
||||
break;
|
||||
|
||||
case POWER_MODE_IDLE:
|
||||
// 空闲模式:关闭非必要外设
|
||||
ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals");
|
||||
|
||||
// 关闭SD卡(如果正在使用,需要先卸载)
|
||||
if (is_sdcard_initialized_) {
|
||||
// 注意:这里只是示例,实际应用中需要确保没有文件操作
|
||||
ESP_LOGW(POWER_TAG, "SD card still active in idle mode");
|
||||
}
|
||||
|
||||
// 关闭显示背光
|
||||
// 关闭非必要GPIO的上拉/下拉
|
||||
// 降低I2C时钟频率
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep");
|
||||
|
||||
// 设置唤醒源(需要根据具体需求配置)
|
||||
// esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒
|
||||
// esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒
|
||||
|
||||
// 进入轻度睡眠
|
||||
// ret = esp_light_sleep_start();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret));
|
||||
current_power_mode_ = previous_mode;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up");
|
||||
|
||||
// 保存必要的RTC数据
|
||||
// rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO
|
||||
|
||||
// 设置深度睡眠唤醒源
|
||||
// esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒
|
||||
|
||||
// 进入深度睡眠
|
||||
// esp_deep_sleep_start();
|
||||
// 注意:深度睡眠后系统会重启,不会返回
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
current_power_mode_ = mode;
|
||||
ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。
|
||||
*/
|
||||
esp_err_t BoardSweekar::ExitLowPowerMode(void) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Exiting low power mode");
|
||||
|
||||
if (current_power_mode_ == POWER_MODE_NORMAL) {
|
||||
ESP_LOGW(POWER_TAG, "Already in normal mode");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 根据之前的功耗模式执行相应的恢复操作
|
||||
switch (current_power_mode_) {
|
||||
case POWER_MODE_IDLE:
|
||||
// 恢复空闲模式
|
||||
ESP_LOGI(POWER_TAG, "Restoring from idle mode");
|
||||
|
||||
// 重新初始化必要的外设
|
||||
// 恢复I2C时钟频率
|
||||
// 重新开启显示背光
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠唤醒后会自动继续执行
|
||||
ESP_LOGI(POWER_TAG, "Woken up from light sleep");
|
||||
|
||||
// 重新配置时钟(如果需要)
|
||||
// 重新初始化外设
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠后系统会重启,不会执行到这里
|
||||
ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 恢复到正常模式
|
||||
current_power_mode_ = POWER_MODE_NORMAL;
|
||||
ESP_LOGI(POWER_TAG, "Successfully exited low power mode");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。
|
||||
*/
|
||||
esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) {
|
||||
static const char *POWER_TAG = "POWER_MODULE";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module);
|
||||
|
||||
// 更新电源状态位图
|
||||
if (enable) {
|
||||
power_state_flags_ |= (1 << module);
|
||||
} else {
|
||||
power_state_flags_ &= ~(1 << module);
|
||||
}
|
||||
|
||||
switch (module) {
|
||||
case HW_MODULE_I2C:
|
||||
if (!enable && bus_handle_) {
|
||||
// 注意:I2C总线通常不建议完全关闭,可能影响多个设备
|
||||
ESP_LOGW(POWER_TAG, "I2C bus power control not recommended");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_SDCARD:
|
||||
if (enable && !is_sdcard_initialized_) {
|
||||
ret = InitializeSdcard();
|
||||
} else if (!enable && is_sdcard_initialized_) {
|
||||
// 卸载SD卡文件系统
|
||||
// 注意:需要确保没有打开的文件
|
||||
ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_LCD:
|
||||
// LCD背光控制
|
||||
// LCD电源引脚控制(如果有)
|
||||
break;
|
||||
|
||||
case HW_MODULE_AUDIO:
|
||||
// 音频编解码器电源控制
|
||||
// 需要与AudioPlayer协调
|
||||
break;
|
||||
|
||||
case HW_MODULE_MOTOR:
|
||||
// 步进电机驱动器电源控制
|
||||
// 电机睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_GYROSCOPE:
|
||||
// 陀螺仪电源控制
|
||||
// 设置陀螺仪为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_TOUCH:
|
||||
// 触摸传感器电源控制
|
||||
// 设置触摸传感器为睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_RADAR:
|
||||
// 毫米波雷达电源控制
|
||||
// 设置雷达为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_IO_EXPAND:
|
||||
// IO扩展板电源控制
|
||||
// 设置扩展板为低功耗模式
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled");
|
||||
} else {
|
||||
ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
// #include "stepper_motor.h" // !
|
||||
#include "stepper_driver.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "gyroscope.h"
|
||||
// #include "touch_sensor.h" // !
|
||||
#include "base_board_control.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗模式枚举
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用
|
||||
POWER_MODE_IDLE, // 空闲模式,关闭非必要外设
|
||||
POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒
|
||||
POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行
|
||||
} power_mode_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件模块枚举,用于精细化电源管理
|
||||
*/
|
||||
typedef enum {
|
||||
HW_MODULE_I2C, // I2C总线
|
||||
HW_MODULE_SDCARD, // SD卡
|
||||
HW_MODULE_LCD, // LCD显示
|
||||
HW_MODULE_AUDIO, // 音频编解码器
|
||||
HW_MODULE_MOTOR, // 步进电机
|
||||
HW_MODULE_GYROSCOPE, // 陀螺仪
|
||||
HW_MODULE_TOUCH, // 触摸传感器
|
||||
HW_MODULE_RADAR, // 毫米波雷达
|
||||
HW_MODULE_IO_EXPAND, // IO扩展板
|
||||
} hardware_module_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件板级管理器
|
||||
*
|
||||
* 采用高内聚低耦合设计原则,统一管理所有硬件资源。
|
||||
* 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。
|
||||
*/
|
||||
class BoardSweekar
|
||||
{
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄
|
||||
esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄
|
||||
bool is_sdcard_initialized_ = false; // SD卡初始化状态
|
||||
power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式
|
||||
uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启)
|
||||
|
||||
public:
|
||||
BoardSweekar();
|
||||
~BoardSweekar();
|
||||
|
||||
IOExpansionBoard io_expansion_; // IO扩展板对象
|
||||
Gyroscope gyroscope_; // 陀螺仪对象
|
||||
// TouchSensor touch_sensor_; // 触摸传感器对象 //!
|
||||
BaseBoardControl base_board_control_; // 底座控制对象
|
||||
StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象
|
||||
|
||||
StepperDriver* GetStepperDriver() const { return stepper_driver_; }
|
||||
|
||||
// 初始化步进电机
|
||||
void StepperMotorInit(void);
|
||||
|
||||
// 初始化LCD IO引脚(消除与步进电机的耦合)
|
||||
void LcdIoInit(void);
|
||||
|
||||
// 初始化串口
|
||||
void MillimeterWaveRadarUartInit(void);
|
||||
|
||||
//初始化毫米波雷达的中断引脚
|
||||
void MillimeterWaveRadarGpioInit(void);
|
||||
|
||||
// 初始化I2C总线
|
||||
esp_err_t I2CMasterInit(void);
|
||||
|
||||
// 初始化VBAT toVBAT_5V引脚
|
||||
void VbatToVbat5vInit(void);
|
||||
|
||||
// 初始化底座控制串口
|
||||
void BaseBoardControlInit(void);
|
||||
|
||||
// 初始化SD卡(推荐使用统一的硬件初始化)
|
||||
esp_err_t InitializeSdcard(void);
|
||||
|
||||
// 获取SD卡初始化状态
|
||||
bool IsSdcardInitialized() const { return is_sdcard_initialized_; }
|
||||
|
||||
// 获取外设管理句柄(供需要访问SD卡的模块使用)
|
||||
esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; }
|
||||
|
||||
// 获取I2C总线句柄
|
||||
i2c_bus_handle_t GetBusHandle() const { return bus_handle_; }
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。
|
||||
* 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardware(void);
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为复杂应用优化)
|
||||
*
|
||||
* 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。
|
||||
* 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardwareComplete(void);
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置,优化启动流程。
|
||||
*
|
||||
* @param app_type 应用类型(demo5、音频播放器、显示应用等)
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeHardwareForApplication(int app_type);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、
|
||||
* 调整时钟频率等。支持多种功耗模式以适应不同应用场景。
|
||||
*
|
||||
* @param mode 功耗模式
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t EnterLowPowerMode(power_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复,重新初始化必要的硬件资源。
|
||||
*
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ExitLowPowerMode(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前功耗模式
|
||||
*
|
||||
* @return power_mode_t 当前功耗模式
|
||||
*/
|
||||
power_mode_t GetPowerMode(void) const { return current_power_mode_; }
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。
|
||||
*
|
||||
* @param module 硬件模块
|
||||
* @param enable true为开启,false为关闭
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetModulePower(hardware_module_t module, bool enable);
|
||||
|
||||
/**
|
||||
* @brief 执行系统关机(拉高 SHUTDOWN_CTRL_PIN)
|
||||
*/
|
||||
void SystemShutdown(void);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* @file board_sweekar_complete_init.cc
|
||||
* @brief 完整的统一硬件初始化实现
|
||||
*
|
||||
* 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。
|
||||
* 专为demo5等复杂应用场景设计。
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为demo5优化)
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备依赖)
|
||||
* 2. IO扩展板(控制其他外设)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. LCD IO引脚(显示相关)
|
||||
* 5. 底座控制串口(通信)
|
||||
* 6. 底座控制模块(业务逻辑)
|
||||
* 7. 其他外设(根据应用需求)
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardwareComplete(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT_COMPLETE";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础,其他设备依赖)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚(显示相关)
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化底座控制串口(demo5需要)
|
||||
BaseBoardControlUartInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized");
|
||||
|
||||
// 6. 初始化底座控制模块
|
||||
base_board_control_.Init();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized");
|
||||
|
||||
// 7. 设置IO扩展板的PA控制模式(demo5需要)
|
||||
io_expansion_.SetPaCtrlMode(true);
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set");
|
||||
|
||||
// 8. 可选外设(根据具体应用需求启用)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals...");
|
||||
//
|
||||
// // 毫米波雷达(如需要)
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized");
|
||||
//
|
||||
// // VBAT升压(如需要)
|
||||
// VbatToVbat5vInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized");
|
||||
//
|
||||
// // 步进电机(如需要)
|
||||
// StepperMotorInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized");
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ===");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) {
|
||||
static const char *APP_INIT_TAG = "APP_HW_INIT";
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type);
|
||||
|
||||
// 基础硬件初始化(所有应用都需要)
|
||||
esp_err_t ret = InitializeAllHardwareComplete();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (app_type) {
|
||||
case APP_TYPE_DEMO5: // 宠物游戏demo
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)...");
|
||||
|
||||
// Demo5需要的额外初始化
|
||||
// 触摸传感器、陀螺仪、RGB LED等会在应用层初始化
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_AUDIO_PLAYER: // 音频播放器
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player...");
|
||||
|
||||
// 音频应用需要确保音频编解码器正确初始化
|
||||
// 这部分通常在AudioPlayer类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_DISPLAY_ONLY: // 纯显示应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only...");
|
||||
|
||||
// 显示应用需要确保LCD相关硬件正确配置
|
||||
// 这部分通常在Display类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_MINIMAL: // 最小化应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application...");
|
||||
|
||||
// 最小化配置,只保留最基本的功能
|
||||
// 关闭非必要外设以节省功耗
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete");
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration");
|
||||
break;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 硬件初始化状态报告
|
||||
*
|
||||
* 提供详细的硬件初始化状态报告,便于调试和问题排查
|
||||
*/
|
||||
void BoardSweekar::ReportHardwareStatus(void) {
|
||||
static const char *STATUS_TAG = "HW_STATUS";
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ===");
|
||||
|
||||
// I2C总线状态
|
||||
ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// SD卡状态
|
||||
ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized");
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available");
|
||||
}
|
||||
|
||||
// IO扩展板状态
|
||||
ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured");
|
||||
|
||||
// 底座控制状态
|
||||
ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// 功耗管理状态
|
||||
ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode");
|
||||
ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_);
|
||||
ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_);
|
||||
|
||||
// 内存状态
|
||||
ESP_LOGI(STATUS_TAG, "Memory Status:");
|
||||
ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ===");
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/* 定义引脚分配 */
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @brief 定义了引脚的分配。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h" // 用于 esp_rom_delay_us
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/timer.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/timer_group_struct.h" // 包含TIMERG0、TIMERG1的结构体定义
|
||||
#include "soc/timer_group_reg.h" // 包含定时器相关寄存器宏定义
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/uart_reg.h"
|
||||
// #include "linear_motor.h"
|
||||
#include "gyroscope.h"
|
||||
|
||||
#define TAG_BOARD "SWEEKAR_ESP32"
|
||||
/*I2C总线引脚定义*/
|
||||
#define I2C0_MASTER_PORT I2C_NUM_0
|
||||
#define I2C0_MASTER_SDA_IO GPIO_NUM_2
|
||||
#define I2C0_MASTER_SCL_IO GPIO_NUM_3
|
||||
|
||||
/* 步进电机配置 */
|
||||
#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚
|
||||
#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进)
|
||||
|
||||
/* 定义屏幕驱动控制引脚 */
|
||||
#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚
|
||||
#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL
|
||||
#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚
|
||||
#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚
|
||||
#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚
|
||||
#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚
|
||||
#define LCD_BL_ACTIVE_LEVEL 1 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS)
|
||||
|
||||
#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数)
|
||||
#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数)
|
||||
|
||||
/* 毫米波雷达配置参数 */
|
||||
/* 定义毫米波雷达的中断引脚 */
|
||||
#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35
|
||||
// UART 配置参数
|
||||
#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1
|
||||
#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整)
|
||||
#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX
|
||||
#define RADAR_BAUD_RATE 9600 // 雷达波特率
|
||||
#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小
|
||||
|
||||
/* IO扩展硬件配置常量 */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000)
|
||||
#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚
|
||||
#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/* 定义线性马达的I2C从机配置常量 */
|
||||
#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址
|
||||
|
||||
/* 定义陀螺仪的I2C从机配置常量 */
|
||||
#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址
|
||||
#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚
|
||||
|
||||
/* AW触摸芯片配置 */
|
||||
#define AW_TOUCH_IRQ_PIN GPIO_NUM_11 // AW触摸芯片中断引脚
|
||||
#define NFC_RST_PIN GPIO_NUM_12 // NFC复位引脚
|
||||
#define SHUTDOWN_CTRL_PIN GPIO_NUM_13 // 关机控制引脚
|
||||
|
||||
/* 原生触摸引脚配置 (v1.1.16已改为上述功能,保留定义需谨慎) */
|
||||
// 触摸按键数量配置
|
||||
#define TOUCH_BUTTON_NUM 3
|
||||
// 触摸通道定义 - 注意:v1.1.16如果不使用ESP32原生触摸,这些定义可能不再适用
|
||||
// 但为了兼容编译,可以保留或注释
|
||||
#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 (Now AW_IRQ)
|
||||
#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 (Now NFC_RST)
|
||||
#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 (Now SHUTDOWN)
|
||||
|
||||
/* ES8311音频编解码器配置 (ESP-ADF兼容) */
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
/* I2S GPIO定义 */
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
/* PA引脚定义 */
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
|
||||
/* I2C配置 */
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3
|
||||
#define AUDIO_CODEC_ES8311_ADDR 0x18
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x40
|
||||
|
||||
/* WS2812 RGB LED配置 */
|
||||
#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚
|
||||
#define WS2812_NUM_LEDS 2 // WS2812 LED数量
|
||||
|
||||
/* 创建VBAT to VBAT_5V */
|
||||
#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚
|
||||
|
||||
/* 定义按键的中断引脚 */
|
||||
#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚
|
||||
#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚
|
||||
|
||||
/* 底座控制命令串口配置 */
|
||||
#define BASE_BOARD_CTL_UART_PORT UART_NUM_0
|
||||
#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43
|
||||
#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44
|
||||
#define BASE_BOARD_CTL_UART_BAUDRATE 115200
|
||||
#define BASE_BOARD_CTL_UART_BUF_SIZE 256
|
||||
|
||||
/* 背光控制引脚配置 */
|
||||
#define BL_PIN GPIO_NUM_45
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,432 @@
|
||||
#ifndef IO_EXPANSION_BOARD_H
|
||||
#define IO_EXPANSION_BOARD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <functional>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
class MillimeterWaveRadar;
|
||||
class PhotoInterrupter;
|
||||
class AdcBatteryMonitor;
|
||||
|
||||
// 回调函数类型定义
|
||||
typedef std::function<void()> RadarCallback;
|
||||
typedef std::function<void()> PhotoInterrupterStartCallback;
|
||||
typedef std::function<void()> PhotoInterrupterEndCallback;
|
||||
typedef std::function<void()> BatteryChargingCallback;
|
||||
typedef std::function<void()> BatteryFullCallback;
|
||||
typedef std::function<void()> BatteryNotChargingCallback;
|
||||
|
||||
/* 寄存器地址 */
|
||||
#define INPUT_PORT0 0x00 // 输入端口0寄存器
|
||||
#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取)
|
||||
#define OUTPUT_PORT0 0x02 // 输出端口0寄存器
|
||||
#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平
|
||||
#define CONFIG_PORT0 0x04 // 配置端口0寄存器
|
||||
#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式
|
||||
#define INT_PORT0 0x06 // 中断端口0寄存器
|
||||
#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的)
|
||||
#define CTL 0x11 // 全局控制寄存器
|
||||
#define ID 0x23 // 芯片ID寄存器(0x23)
|
||||
|
||||
/***********************************IO扩展板电机引脚配置参数*************************************/
|
||||
/* 设置步进电机方向 */
|
||||
#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转
|
||||
#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转
|
||||
#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4
|
||||
#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4
|
||||
|
||||
/* 设置步进电机细分模式 */
|
||||
#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5
|
||||
#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5
|
||||
|
||||
#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4
|
||||
#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4
|
||||
|
||||
/* 设置步进电机睡眠引脚 */
|
||||
#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式
|
||||
#define STEPPER_MOTOR_WORK true //步进电机进入工作模式
|
||||
#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
/* 设置电机的使能引脚 */
|
||||
#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平
|
||||
#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平
|
||||
|
||||
/* 设置毫米波雷达对应IO扩展板的中断引脚 */
|
||||
#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7
|
||||
#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口
|
||||
#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1
|
||||
#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态
|
||||
#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态
|
||||
/* 任务配置常量 */
|
||||
#define WRITE_BUF_SIZE 2 // I2C单次写入字节数
|
||||
#define READ_BUF_SIZE 2 // I2C单次读取字节数
|
||||
#define I2C_TASK_PRIORITY 2 // 任务优先级(中等)
|
||||
#define I2C_TASK_STACK 4096 // 任务栈大小(4KB)
|
||||
|
||||
// 光学传感器引脚定义
|
||||
#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2)
|
||||
#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3)
|
||||
#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
/***********************************LED_EN 电源控制(WS2812/背光等)*************************************/
|
||||
// v1.1.16: LED_EN 高电平有效,低电平无效;端口为 IO 扩展 P0_1
|
||||
#define LED_EN_PIN 1
|
||||
#define LED_EN_PORT OUTPUT_PORT0
|
||||
#define LED_EN_CONFIG CONFIG_PORT0
|
||||
|
||||
/***********************************IO扩展板LCD引脚配置参数*************************************/
|
||||
// /* 设置LCD的BL引脚 */
|
||||
// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6
|
||||
// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6
|
||||
// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平
|
||||
// #define LCD_BL_LOW false //LCD背光引脚状态为低电平
|
||||
|
||||
/* 设置LCD的RST引脚 */
|
||||
#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1
|
||||
#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1
|
||||
#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_RST_HIGH true //LCD复位引脚状态为高电平
|
||||
#define LCD_RST_LOW false //LCD复位引脚状态为低电平
|
||||
|
||||
/* 设置PA控制引脚 */
|
||||
#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2
|
||||
#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2
|
||||
#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define PA_CTRL_HIGH true //PA控制引脚状态为高电平
|
||||
#define PA_CTRL_LOW false //PA控制引脚状态为低电平
|
||||
|
||||
// 电池充电检测引脚定义
|
||||
#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3
|
||||
#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3
|
||||
|
||||
#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5)
|
||||
#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
|
||||
#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签
|
||||
#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签
|
||||
|
||||
// GPIO引脚定义
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚
|
||||
// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/**
|
||||
* @class IOExpansionBoard
|
||||
* @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作
|
||||
*/
|
||||
class IOExpansionBoard
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 设置毫米波雷达指针
|
||||
* @param radar 毫米波雷达对象指针
|
||||
*/
|
||||
void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; };
|
||||
|
||||
/**
|
||||
* @brief 设置限位开关指针
|
||||
* @param photo_interrupter 限位开关对象指针
|
||||
*/
|
||||
void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; };
|
||||
|
||||
/**
|
||||
* @brief 设置电池监控器指针
|
||||
* @param battery_monitor 电池监控器对象指针
|
||||
*/
|
||||
void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; };
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetIoExpand();
|
||||
|
||||
/**
|
||||
* @brief 初始化I2C主机通信
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
// esp_err_t IoExpansionI2cInit();
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void CreateI2cReadTask();
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务(整合初始化和任务创建)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StartTask();
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief 读寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要读出的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口0寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort0(uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口1寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort1(uint8_t *data);
|
||||
|
||||
// /**
|
||||
// * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断
|
||||
// * @param reg_addr 寄存器地址
|
||||
// * @return esp_err_t 操作结果
|
||||
// */
|
||||
// esp_err_t SetInterruptStatus(bool status);
|
||||
|
||||
/**
|
||||
* @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandSetMode();
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
* @param mode 模式:1/2/4/8/16/32/64
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的方向
|
||||
* @param dir 方向
|
||||
* @param OUTPUT_PORT 输出端口
|
||||
* @param pin 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的睡眠模式
|
||||
* @param 是否进入睡眠模式
|
||||
* @param 输出端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能引脚状态
|
||||
* @param 使能状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的BL引脚状态
|
||||
* @param BL状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的RST引脚状态
|
||||
* @param RST状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置 LED_EN 引脚状态(v1.1.16:高电平有效,低电平无效)
|
||||
* @param enable true: 开启(置高),false: 关闭(置低)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLedEnMode(bool enable);
|
||||
|
||||
/**
|
||||
* @brief 设置PA控制引脚状态
|
||||
* @param mode PA_CTRL状态(true为高电平,false为低电平)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetPaCtrlMode(bool mode);
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断引脚
|
||||
* @param 毫米波雷达的中断引脚模式
|
||||
* @param 输入端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin);
|
||||
|
||||
/**
|
||||
* @brief 计算Port0的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort0();
|
||||
|
||||
/**
|
||||
* @brief 计算Port1的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort1();
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断回调函数
|
||||
* @param callback 雷达中断回调函数
|
||||
*/
|
||||
void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器开始中断回调函数
|
||||
* @param callback 光学传感器开始中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器结束中断回调函数
|
||||
* @param callback 光学传感器结束中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充电中断回调函数
|
||||
* @param callback 电池充电中断回调函数
|
||||
*/
|
||||
void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充满中断回调函数
|
||||
* @param callback 电池充满中断回调函数
|
||||
*/
|
||||
void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池非充电中断回调函数
|
||||
* @param callback 电池非充电中断回调函数
|
||||
*/
|
||||
void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; }
|
||||
|
||||
// 公共成员变量
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
uint8_t device_addr_; // I2C设备地址
|
||||
|
||||
private:
|
||||
// 静态成员函数
|
||||
MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调
|
||||
PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调
|
||||
AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调
|
||||
static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数
|
||||
|
||||
// 成员变量用于状态跟踪
|
||||
uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态
|
||||
uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态
|
||||
bool radar_last_state_ = false; // 雷达引脚上一次的状态
|
||||
bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态
|
||||
bool battery_full_last_state_ = false; // 电池充满状态上一次的状态
|
||||
|
||||
// 回调函数成员变量
|
||||
RadarCallback radar_callback_ = nullptr;
|
||||
PhotoInterrupterStartCallback photo_start_callback_ = nullptr;
|
||||
PhotoInterrupterEndCallback photo_end_callback_ = nullptr;
|
||||
BatteryChargingCallback battery_charging_callback_ = nullptr;
|
||||
BatteryFullCallback battery_full_callback_ = nullptr;
|
||||
BatteryNotChargingCallback battery_not_charging_callback_ = nullptr;
|
||||
|
||||
// PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调
|
||||
// /**
|
||||
// * @brief 分配静态任务所需的内存
|
||||
// * @return bool 分配是否成功
|
||||
// */
|
||||
// bool AllocateStaticTaskMemory();
|
||||
|
||||
// /**
|
||||
// * @brief 释放静态任务分配的内存
|
||||
// */
|
||||
// void FreeStaticTaskMemory();
|
||||
|
||||
// 实例成员变量
|
||||
EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组
|
||||
TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄
|
||||
bool is_initialized_ = false; // 初始化状态标记(新增)
|
||||
gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚
|
||||
gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚
|
||||
|
||||
// StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM)
|
||||
// StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @file power_management_config.h
|
||||
* @brief 功耗管理配置和策略定义
|
||||
* @author Embedded Software Expert
|
||||
* @date 2025年1月
|
||||
*
|
||||
* 这个文件定义了功耗管理的配置参数、策略和优化建议,
|
||||
* 为系统提供灵活的功耗管理方案。
|
||||
*/
|
||||
|
||||
#ifndef POWER_MANAGEMENT_CONFIG_H
|
||||
#define POWER_MANAGEMENT_CONFIG_H
|
||||
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗管理配置结构体
|
||||
*/
|
||||
typedef struct {
|
||||
// 睡眠模式配置
|
||||
uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒)
|
||||
uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒)
|
||||
|
||||
// 唤醒源配置
|
||||
bool enable_timer_wakeup; // 启用定时器唤醒
|
||||
bool enable_gpio_wakeup; // 启用GPIO唤醒
|
||||
bool enable_touch_wakeup; // 启用触摸唤醒
|
||||
gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号
|
||||
int wakeup_level; // 唤醒电平(0或1)
|
||||
|
||||
// 功耗优化配置
|
||||
bool disable_bt_in_sleep; // 睡眠时关闭蓝牙
|
||||
bool disable_wifi_in_sleep; // 睡眠时关闭WiFi
|
||||
bool reduce_cpu_frequency; // 降低CPU频率
|
||||
uint32_t cpu_frequency_hz; // CPU频率(Hz)
|
||||
|
||||
// 外设功耗配置
|
||||
bool power_down_sdcard; // 睡眠时关闭SD卡电源
|
||||
bool power_down_display; // 睡眠时关闭显示电源
|
||||
bool power_down_audio; // 睡眠时关闭音频电源
|
||||
bool power_down_motor; // 睡眠时关闭电机电源
|
||||
|
||||
// RTC内存配置
|
||||
bool preserve_rtc_memory; // 保留RTC内存
|
||||
size_t rtc_memory_size; // RTC内存大小
|
||||
} power_management_config_t;
|
||||
|
||||
/**
|
||||
* @brief 默认功耗管理配置
|
||||
*/
|
||||
#define DEFAULT_POWER_CONFIG { \
|
||||
.light_sleep_duration_us = 1000000, /* 1秒 */ \
|
||||
.deep_sleep_duration_us = 30000000, /* 30秒 */ \
|
||||
.enable_timer_wakeup = true, /* 启用定时器唤醒 */ \
|
||||
.enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \
|
||||
.enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \
|
||||
.wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \
|
||||
.wakeup_level = 0, /* 低电平唤醒 */ \
|
||||
.disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \
|
||||
.disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \
|
||||
.reduce_cpu_frequency = true, /* 降低CPU频率 */ \
|
||||
.cpu_frequency_hz = 80000000, /* 80MHz */ \
|
||||
.power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \
|
||||
.power_down_display = true, /* 睡眠时关闭显示 */ \
|
||||
.power_down_audio = true, /* 睡眠时关闭音频 */ \
|
||||
.power_down_motor = true, /* 睡眠时关闭电机 */ \
|
||||
.preserve_rtc_memory = true, /* 保留RTC内存 */ \
|
||||
.rtc_memory_size = 4096, /* 4KB RTC内存 */ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 各功耗模式的详细配置
|
||||
*/
|
||||
static const power_management_config_t idle_mode_config = {
|
||||
.light_sleep_duration_us = 500000, // 500ms轻度睡眠
|
||||
.deep_sleep_duration_us = 0, // 不使用深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = false, // 保持蓝牙连接
|
||||
.disable_wifi_in_sleep = false, // 保持WiFi连接
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000, // 40MHz
|
||||
.power_down_sdcard = false, // 保持SD卡(可能有后台任务)
|
||||
.power_down_display = true, // 关闭显示背光
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 2048,
|
||||
};
|
||||
|
||||
static const power_management_config_t light_sleep_config = {
|
||||
.light_sleep_duration_us = 0, // 直接进入轻度睡眠
|
||||
.deep_sleep_duration_us = 0,
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000,
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 4096,
|
||||
};
|
||||
|
||||
static const power_management_config_t deep_sleep_config = {
|
||||
.light_sleep_duration_us = 0,
|
||||
.deep_sleep_duration_us = 60000000, // 60秒深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 10000000, // 10MHz
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 8192,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 功耗统计和监控结构体
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t total_sleep_time_us; // 总睡眠时间
|
||||
uint64_t total_wake_time_us; // 总唤醒时间
|
||||
uint32_t sleep_count; // 睡眠次数
|
||||
uint32_t wake_count; // 唤醒次数
|
||||
uint32_t average_sleep_duration_us; // 平均睡眠时长
|
||||
uint32_t average_wake_duration_us; // 平均唤醒时长
|
||||
float estimated_power_saving_percent; // 估计的功耗节省百分比
|
||||
} power_statistics_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗优化建议
|
||||
*
|
||||
* 基于硬件特性和使用模式,提供功耗优化建议
|
||||
*/
|
||||
typedef enum {
|
||||
OPTIMIZATION_NONE = 0,
|
||||
OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率
|
||||
OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设
|
||||
OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠
|
||||
OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠
|
||||
OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态
|
||||
OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存
|
||||
OPTIMIZATION_BATCH_OPERATIONS, // 批量操作
|
||||
} power_optimization_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件回调
|
||||
*/
|
||||
typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_EVENT_MODE_CHANGE, // 功耗模式改变
|
||||
POWER_EVENT_SLEEP_START, // 睡眠开始
|
||||
POWER_EVENT_SLEEP_END, // 睡眠结束
|
||||
POWER_EVENT_WAKEUP, // 系统唤醒
|
||||
POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发
|
||||
} power_event_t;
|
||||
|
||||
#endif // POWER_MANAGEMENT_CONFIG_H
|
||||
@@ -0,0 +1,780 @@
|
||||
/**
|
||||
* @file board.cc
|
||||
* @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "esp_check.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
}
|
||||
|
||||
#include "board_sweekar.h"
|
||||
#include "config.h"
|
||||
#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明
|
||||
#include "drv8428.h"
|
||||
#include "aw8646.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "audio_mem.h"
|
||||
#include "esp_timer.h"
|
||||
#include "base_board_hal_i2c.h"
|
||||
|
||||
#define TAG "board_sweekar"
|
||||
|
||||
static BoardSweekar* s_board_instance = nullptr;
|
||||
|
||||
BoardSweekar* BoardSweekar::GetInstance()
|
||||
{
|
||||
if (s_board_instance == nullptr) {
|
||||
static BoardSweekar global_board;
|
||||
s_board_instance = &global_board;
|
||||
}
|
||||
return s_board_instance;
|
||||
}
|
||||
|
||||
BoardSweekar::BoardSweekar()
|
||||
{
|
||||
#ifdef CONFIG_STEPPER_DRIVER_AW8646
|
||||
stepper_driver_ = new Aw8646Driver(io_expansion_);
|
||||
#else
|
||||
stepper_driver_ = new Drv8428Driver(io_expansion_);
|
||||
#endif
|
||||
|
||||
// Initialize Shutdown Control Pin (GPIO_NUM_13) and pull it HIGH
|
||||
// This is required to keep the main power on.
|
||||
#ifdef SHUTDOWN_CTRL_PIN
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << SHUTDOWN_CTRL_PIN);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
// 拉低开机
|
||||
gpio_set_level(SHUTDOWN_CTRL_PIN, 0);
|
||||
ESP_LOGI(TAG, "Initialized SHUTDOWN_CTRL_PIN (%d) to LOW (Power ON)", SHUTDOWN_CTRL_PIN);
|
||||
#endif
|
||||
}
|
||||
|
||||
BoardSweekar::~BoardSweekar()
|
||||
{
|
||||
if (stepper_driver_) {
|
||||
delete stepper_driver_;
|
||||
stepper_driver_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BoardSweekar::SetAudioAmplifier(bool enable) {
|
||||
// 隐藏具体的硬件实现细节(比如当前版本是通过 IO 扩展板控制的)
|
||||
io_expansion_.SetPaCtrlMode(enable);
|
||||
ESP_LOGI(TAG, "Audio Amplifier %s", enable ? "ENABLED" : "DISABLED");
|
||||
}
|
||||
|
||||
/*========================== 步进电机相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 步进电机初始化函数
|
||||
* 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式
|
||||
* 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化
|
||||
*/
|
||||
void BoardSweekar::StepperMotorInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) STEP 引脚改为普通 GPIO(不再用 LEDC)
|
||||
gpio_config_t io_cfg;
|
||||
io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO;
|
||||
io_cfg.mode = GPIO_MODE_OUTPUT;
|
||||
io_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_cfg.intr_type = GPIO_INTR_DISABLE;
|
||||
err = gpio_config(&io_cfg);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 初始电平拉低,保证上电不乱跳
|
||||
gpio_set_level(STEPPER_STEP_IO, 0);
|
||||
|
||||
// 2) 检查 I2C 总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) 初始化驱动对象并初始化
|
||||
if (stepper_driver_) {
|
||||
err = stepper_driver_->Init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCD IO引脚初始化函数(消除与步进电机的耦合)
|
||||
*
|
||||
* 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作
|
||||
* 此函数独立于步进电机初始化,专门处理LCD相关的IO配置
|
||||
*/
|
||||
void BoardSweekar::LcdIoInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) 检查I2C总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) 执行硬件复位,确保IO扩展板处于已知状态
|
||||
err = io_expansion_.ResetIoExpand();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功");
|
||||
}
|
||||
|
||||
// 3) 配置IO扩展板模式(端口方向等)
|
||||
err = io_expansion_.IoexpandSetMode();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功");
|
||||
}
|
||||
|
||||
// 4) 初始化LCD复位引脚:设置为高电平
|
||||
err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功");
|
||||
}
|
||||
|
||||
// 5) 初始化LED_EN电源为关闭状态 (PMOS高电平关)
|
||||
// 只有在需要亮灯时,由ActuatorActor主动开启,避免平静状态下常亮
|
||||
err = io_expansion_.SetLedEnMode(false);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "初始化LED_EN电源(关闭)失败, 错误码: 0x%x", err);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "初始化LED_EN电源(关闭)成功");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行系统关机
|
||||
* 内部拉高 SHUTDOWN_CTRL_PIN 引脚切断电源
|
||||
*/
|
||||
void BoardSweekar::SystemShutdown(void)
|
||||
{
|
||||
#ifdef SHUTDOWN_CTRL_PIN
|
||||
ESP_LOGI(TAG, "Executing System Shutdown... Pulling SHUTDOWN_CTRL_PIN (%d) HIGH", SHUTDOWN_CTRL_PIN);
|
||||
// 用户指定:拉高可以完成关机动作
|
||||
gpio_set_level(SHUTDOWN_CTRL_PIN, 1);
|
||||
|
||||
// 给一点时间让电源完全断开
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
#else
|
||||
ESP_LOGW(TAG, "SHUTDOWN_CTRL_PIN is not defined. Cannot execute hardware shutdown.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================== 毫米波雷达相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达串口初始化函数
|
||||
*
|
||||
* 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚,
|
||||
* 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免
|
||||
* 与自定义中断冲突。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = RADAR_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突)
|
||||
// 增加 RX/TX FIFO 深度以处理突发数据
|
||||
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4,
|
||||
0, NULL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达中断引脚初始化函数
|
||||
*
|
||||
* 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能
|
||||
* (如需使用中断需单独进行配置)。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarGpioInit(void)
|
||||
{
|
||||
// GPIO配置结构体
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚
|
||||
.mode = GPIO_MODE_INPUT, // 设置为输入模式
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉
|
||||
.intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置)
|
||||
};
|
||||
|
||||
// 配置GPIO
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief I2C总线及从机设备初始化函数
|
||||
*
|
||||
* 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。
|
||||
* 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。
|
||||
* 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::I2CMasterInit(void)
|
||||
{
|
||||
static const char *I2C_INIT = "I2C_INIT";
|
||||
|
||||
// 初始化IO扩展板复位引脚
|
||||
gpio_config_t reset_io_conf = {
|
||||
.pin_bit_mask = (1ULL << IO_EXPAND_RSTN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&reset_io_conf);
|
||||
|
||||
// 执行复位时序:先拉低100ms,再拉高并等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板复位完成");
|
||||
|
||||
// 创建统一的I2C总线(使用ESP-ADF的i2c_bus)
|
||||
i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C0_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C0_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = 100000,
|
||||
},
|
||||
};
|
||||
|
||||
// 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线)
|
||||
bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg);
|
||||
if (bus_handle_ == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create I2C bus");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
// ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信
|
||||
|
||||
// 验证线性马达设备是否存在
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR);
|
||||
}
|
||||
// 验证IO扩展板设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化其他设备
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR);
|
||||
}
|
||||
// 验证陀螺仪设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR);
|
||||
}
|
||||
|
||||
// 为IO扩展板设置总线句柄和设备地址(使用7位地址)
|
||||
io_expansion_.bus_handle_ = bus_handle_;
|
||||
io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1;
|
||||
|
||||
// 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法
|
||||
// linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性
|
||||
|
||||
ESP_LOGI(I2C_INIT, "I2C总线初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*========================== VBAT to VBAT_5V相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 开启VBAT to VBAT_5V
|
||||
*
|
||||
* 创建开启升压的电源管理单元
|
||||
*
|
||||
*/
|
||||
void BoardSweekar::VbatToVbat5vInit(void)
|
||||
{
|
||||
// 配置VBAT_5V引脚为输出模式
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << VBAT_5V_PIN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
// 使能VBAT_5V
|
||||
gpio_set_level(VBAT_5V_PIN, 1);
|
||||
}
|
||||
|
||||
/*========================== 底座控制串口相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 底座控制命令串口初始化函数
|
||||
*/
|
||||
// 根据配置选择通信方式的HAL头文件
|
||||
#ifdef CONFIG_BASE_BOARD_COMM_I2C
|
||||
#include "base_board_hal_i2c.h"
|
||||
#else
|
||||
#include "base_board_hal_uart.h"
|
||||
#endif
|
||||
|
||||
void BoardSweekar::BaseBoardControlInit(void)
|
||||
{
|
||||
#ifdef CONFIG_BASE_BOARD_COMM_I2C
|
||||
// I2C Mode
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "I2C bus not initialized before BaseBoardControlInit");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建 I2C HAL 实例
|
||||
BaseBoardHalI2c *hal = new BaseBoardHalI2c(bus_handle_);
|
||||
base_board_control_.Init(hal);
|
||||
ESP_LOGI(TAG, "BaseBoardControl I2C initialized");
|
||||
#else
|
||||
// UART Mode
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BASE_BOARD_CTL_UART_BAUDRATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动
|
||||
ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
0, NULL, 0));
|
||||
|
||||
BaseBoardHalUart *hal = new BaseBoardHalUart(BASE_BOARD_CTL_UART_PORT);
|
||||
base_board_control_.Init(hal);
|
||||
ESP_LOGI(TAG, "BaseBoardControl UART initialized");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================== SD卡相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief SD卡初始化函数
|
||||
*
|
||||
* 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器
|
||||
* 并配置SD卡,为后续的文件系统操作做准备。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeSdcard(void)
|
||||
{
|
||||
static const char *SDCARD_TAG = "SDCARD_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(SDCARD_TAG, "Initializing SD card");
|
||||
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGW(SDCARD_TAG, "SD card already initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 初始化外设管理
|
||||
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
|
||||
periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM
|
||||
periph_set_ = esp_periph_set_init(&periph_cfg);
|
||||
if (!periph_set_) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// 初始化SD卡外设
|
||||
ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
is_sdcard_initialized_ = true;
|
||||
ESP_LOGI(SDCARD_TAG, "SD card initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口实现
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备可能依赖)
|
||||
* 2. IO扩展板(可能影响其他设备)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. 其他外设
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardware(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化底座控制
|
||||
if (bus_handle_ != nullptr) {
|
||||
BaseBoardHalI2c *hal_i2c = new BaseBoardHalI2c(bus_handle_);
|
||||
base_board_control_.Init(hal_i2c);
|
||||
ESP_LOGI(HW_INIT_TAG, "Base board control initialized with I2C handle");
|
||||
} else {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize base board control: I2C bus is null");
|
||||
}
|
||||
|
||||
// 6. 可选外设(根据具体应用需求)
|
||||
// BaseBoardControlUartInit(); // 底座控制串口(demo5需要)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized");
|
||||
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
StepperMotorInit();
|
||||
|
||||
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,执行相应的功耗优化策略:
|
||||
* - IDLE模式:关闭非必要外设,保持快速响应
|
||||
* - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电
|
||||
* - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低
|
||||
*/
|
||||
esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode);
|
||||
|
||||
if (mode == current_power_mode_) {
|
||||
ESP_LOGW(POWER_TAG, "Already in power mode %d", mode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 保存当前模式,以便恢复
|
||||
power_mode_t previous_mode = current_power_mode_;
|
||||
|
||||
switch (mode) {
|
||||
case POWER_MODE_NORMAL:
|
||||
// 正常模式,不需要特殊处理
|
||||
break;
|
||||
|
||||
case POWER_MODE_IDLE:
|
||||
// 空闲模式:关闭非必要外设
|
||||
ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals");
|
||||
|
||||
// 关闭SD卡(如果正在使用,需要先卸载)
|
||||
if (is_sdcard_initialized_) {
|
||||
// 注意:这里只是示例,实际应用中需要确保没有文件操作
|
||||
ESP_LOGW(POWER_TAG, "SD card still active in idle mode");
|
||||
}
|
||||
|
||||
// 关闭显示背光
|
||||
// 关闭非必要GPIO的上拉/下拉
|
||||
// 降低I2C时钟频率
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep");
|
||||
|
||||
// 设置唤醒源(需要根据具体需求配置)
|
||||
// esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒
|
||||
// esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒
|
||||
|
||||
// 进入轻度睡眠
|
||||
// ret = esp_light_sleep_start();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret));
|
||||
current_power_mode_ = previous_mode;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up");
|
||||
|
||||
// 保存必要的RTC数据
|
||||
// rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO
|
||||
|
||||
// 设置深度睡眠唤醒源
|
||||
// esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒
|
||||
|
||||
// 进入深度睡眠
|
||||
// esp_deep_sleep_start();
|
||||
// 注意:深度睡眠后系统会重启,不会返回
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
current_power_mode_ = mode;
|
||||
ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。
|
||||
*/
|
||||
esp_err_t BoardSweekar::ExitLowPowerMode(void) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Exiting low power mode");
|
||||
|
||||
if (current_power_mode_ == POWER_MODE_NORMAL) {
|
||||
ESP_LOGW(POWER_TAG, "Already in normal mode");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 根据之前的功耗模式执行相应的恢复操作
|
||||
switch (current_power_mode_) {
|
||||
case POWER_MODE_IDLE:
|
||||
// 恢复空闲模式
|
||||
ESP_LOGI(POWER_TAG, "Restoring from idle mode");
|
||||
|
||||
// 重新初始化必要的外设
|
||||
// 恢复I2C时钟频率
|
||||
// 重新开启显示背光
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠唤醒后会自动继续执行
|
||||
ESP_LOGI(POWER_TAG, "Woken up from light sleep");
|
||||
|
||||
// 重新配置时钟(如果需要)
|
||||
// 重新初始化外设
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠后系统会重启,不会执行到这里
|
||||
ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 恢复到正常模式
|
||||
current_power_mode_ = POWER_MODE_NORMAL;
|
||||
ESP_LOGI(POWER_TAG, "Successfully exited low power mode");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。
|
||||
*/
|
||||
esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) {
|
||||
static const char *POWER_TAG = "POWER_MODULE";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module);
|
||||
|
||||
// 更新电源状态位图
|
||||
if (enable) {
|
||||
power_state_flags_ |= (1 << module);
|
||||
} else {
|
||||
power_state_flags_ &= ~(1 << module);
|
||||
}
|
||||
|
||||
switch (module) {
|
||||
case HW_MODULE_I2C:
|
||||
if (!enable && bus_handle_) {
|
||||
// 注意:I2C总线通常不建议完全关闭,可能影响多个设备
|
||||
ESP_LOGW(POWER_TAG, "I2C bus power control not recommended");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_SDCARD:
|
||||
if (enable && !is_sdcard_initialized_) {
|
||||
ret = InitializeSdcard();
|
||||
} else if (!enable && is_sdcard_initialized_) {
|
||||
// 卸载SD卡文件系统
|
||||
// 注意:需要确保没有打开的文件
|
||||
ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_LCD:
|
||||
// LCD背光控制
|
||||
// LCD电源引脚控制(如果有)
|
||||
break;
|
||||
|
||||
case HW_MODULE_AUDIO:
|
||||
// 音频编解码器电源控制
|
||||
// 需要与AudioPlayer协调
|
||||
break;
|
||||
|
||||
case HW_MODULE_MOTOR:
|
||||
// 步进电机驱动器电源控制
|
||||
// 电机睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_GYROSCOPE:
|
||||
// 陀螺仪电源控制
|
||||
// 设置陀螺仪为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_TOUCH:
|
||||
// 触摸传感器电源控制
|
||||
// 设置触摸传感器为睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_RADAR:
|
||||
// 毫米波雷达电源控制
|
||||
// 设置雷达为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_IO_EXPAND:
|
||||
// IO扩展板电源控制
|
||||
// 设置扩展板为低功耗模式
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled");
|
||||
} else {
|
||||
ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "stepper_motor.h"
|
||||
#include "stepper_driver.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "gyroscope.h"
|
||||
#include "touch_sensor.h"
|
||||
#include "base_board_control.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗模式枚举
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用
|
||||
POWER_MODE_IDLE, // 空闲模式,关闭非必要外设
|
||||
POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒
|
||||
POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行
|
||||
} power_mode_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件模块枚举,用于精细化电源管理
|
||||
*/
|
||||
typedef enum {
|
||||
HW_MODULE_I2C, // I2C总线
|
||||
HW_MODULE_SDCARD, // SD卡
|
||||
HW_MODULE_LCD, // LCD显示
|
||||
HW_MODULE_AUDIO, // 音频编解码器
|
||||
HW_MODULE_MOTOR, // 步进电机
|
||||
HW_MODULE_GYROSCOPE, // 陀螺仪
|
||||
HW_MODULE_TOUCH, // 触摸传感器
|
||||
HW_MODULE_RADAR, // 毫米波雷达
|
||||
HW_MODULE_IO_EXPAND, // IO扩展板
|
||||
} hardware_module_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件板级管理器
|
||||
*
|
||||
* 采用高内聚低耦合设计原则,统一管理所有硬件资源。
|
||||
* 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。
|
||||
*/
|
||||
class BoardSweekar
|
||||
{
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄
|
||||
esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄
|
||||
bool is_sdcard_initialized_ = false; // SD卡初始化状态
|
||||
power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式
|
||||
uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启)
|
||||
|
||||
public:
|
||||
BoardSweekar();
|
||||
~BoardSweekar();
|
||||
|
||||
static BoardSweekar* GetInstance();
|
||||
|
||||
// --- 语义化的高层 API:音频与功放控制 ---
|
||||
// 开启或关闭外放功放 (PA),供上层 AudioActor/AudioPlayer 调用,屏蔽底层引脚实现
|
||||
void SetAudioAmplifier(bool enable);
|
||||
|
||||
IOExpansionBoard io_expansion_; // IO扩展板对象
|
||||
Gyroscope gyroscope_; // 陀螺仪对象
|
||||
TouchSensor touch_sensor_; // 触摸传感器对象
|
||||
BaseBoardControl base_board_control_; // 底座控制对象
|
||||
StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象
|
||||
|
||||
StepperDriver* GetStepperDriver() const { return stepper_driver_; }
|
||||
|
||||
// 初始化步进电机
|
||||
void StepperMotorInit(void);
|
||||
|
||||
// 初始化LCD IO引脚(消除与步进电机的耦合)
|
||||
void LcdIoInit(void);
|
||||
|
||||
// 初始化串口
|
||||
void MillimeterWaveRadarUartInit(void);
|
||||
|
||||
//初始化毫米波雷达的中断引脚
|
||||
void MillimeterWaveRadarGpioInit(void);
|
||||
|
||||
/**
|
||||
* @brief 执行系统关机
|
||||
* 内部拉高/拉低 SHUTDOWN_CTRL_PIN 引脚切断电源
|
||||
*/
|
||||
void SystemShutdown(void);
|
||||
|
||||
// 初始化I2C总线
|
||||
esp_err_t I2CMasterInit(void);
|
||||
|
||||
// 初始化VBAT toVBAT_5V引脚
|
||||
void VbatToVbat5vInit(void);
|
||||
|
||||
// 初始化底座控制串口
|
||||
void BaseBoardControlInit(void);
|
||||
|
||||
// 初始化SD卡(推荐使用统一的硬件初始化)
|
||||
esp_err_t InitializeSdcard(void);
|
||||
|
||||
// 获取SD卡初始化状态
|
||||
bool IsSdcardInitialized() const { return is_sdcard_initialized_; }
|
||||
|
||||
// 获取外设管理句柄(供需要访问SD卡的模块使用)
|
||||
esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; }
|
||||
|
||||
// 获取I2C总线句柄
|
||||
i2c_bus_handle_t GetBusHandle() const { return bus_handle_; }
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。
|
||||
* 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardware(void);
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为复杂应用优化)
|
||||
*
|
||||
* 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。
|
||||
* 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardwareComplete(void);
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置,优化启动流程。
|
||||
*
|
||||
* @param app_type 应用类型(demo5、音频播放器、显示应用等)
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeHardwareForApplication(int app_type);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、
|
||||
* 调整时钟频率等。支持多种功耗模式以适应不同应用场景。
|
||||
*
|
||||
* @param mode 功耗模式
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t EnterLowPowerMode(power_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复,重新初始化必要的硬件资源。
|
||||
*
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ExitLowPowerMode(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前功耗模式
|
||||
*
|
||||
* @return power_mode_t 当前功耗模式
|
||||
*/
|
||||
power_mode_t GetPowerMode(void) const { return current_power_mode_; }
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。
|
||||
*
|
||||
* @param module 硬件模块
|
||||
* @param enable true为开启,false为关闭
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetModulePower(hardware_module_t module, bool enable);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* @file board_sweekar_complete_init.cc
|
||||
* @brief 完整的统一硬件初始化实现
|
||||
*
|
||||
* 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。
|
||||
* 专为demo5等复杂应用场景设计。
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为demo5优化)
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备依赖)
|
||||
* 2. IO扩展板(控制其他外设)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. LCD IO引脚(显示相关)
|
||||
* 5. 底座控制串口(通信)
|
||||
* 6. 底座控制模块(业务逻辑)
|
||||
* 7. 其他外设(根据应用需求)
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardwareComplete(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT_COMPLETE";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础,其他设备依赖)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚(显示相关)
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化底座控制串口(demo5需要)
|
||||
BaseBoardControlUartInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized");
|
||||
|
||||
// 6. 初始化底座控制模块
|
||||
base_board_control_.Init();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized");
|
||||
|
||||
// 7. 设置IO扩展板的PA控制模式(demo5需要)
|
||||
io_expansion_.SetPaCtrlMode(true);
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set");
|
||||
|
||||
// 8. 可选外设(根据具体应用需求启用)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals...");
|
||||
//
|
||||
// // 毫米波雷达(如需要)
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized");
|
||||
//
|
||||
// // VBAT升压(如需要)
|
||||
// VbatToVbat5vInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized");
|
||||
//
|
||||
// // 步进电机(如需要)
|
||||
// StepperMotorInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized");
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ===");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) {
|
||||
static const char *APP_INIT_TAG = "APP_HW_INIT";
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type);
|
||||
|
||||
// 基础硬件初始化(所有应用都需要)
|
||||
esp_err_t ret = InitializeAllHardwareComplete();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (app_type) {
|
||||
case APP_TYPE_DEMO5: // 宠物游戏demo
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)...");
|
||||
|
||||
// Demo5需要的额外初始化
|
||||
// 触摸传感器、陀螺仪、RGB LED等会在应用层初始化
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_AUDIO_PLAYER: // 音频播放器
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player...");
|
||||
|
||||
// 音频应用需要确保音频编解码器正确初始化
|
||||
// 这部分通常在AudioPlayer类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_DISPLAY_ONLY: // 纯显示应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only...");
|
||||
|
||||
// 显示应用需要确保LCD相关硬件正确配置
|
||||
// 这部分通常在Display类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_MINIMAL: // 最小化应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application...");
|
||||
|
||||
// 最小化配置,只保留最基本的功能
|
||||
// 关闭非必要外设以节省功耗
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete");
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration");
|
||||
break;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 硬件初始化状态报告
|
||||
*
|
||||
* 提供详细的硬件初始化状态报告,便于调试和问题排查
|
||||
*/
|
||||
void BoardSweekar::ReportHardwareStatus(void) {
|
||||
static const char *STATUS_TAG = "HW_STATUS";
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ===");
|
||||
|
||||
// I2C总线状态
|
||||
ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// SD卡状态
|
||||
ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized");
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available");
|
||||
}
|
||||
|
||||
// IO扩展板状态
|
||||
ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured");
|
||||
|
||||
// 底座控制状态
|
||||
ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// 功耗管理状态
|
||||
ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode");
|
||||
ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_);
|
||||
ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_);
|
||||
|
||||
// 内存状态
|
||||
ESP_LOGI(STATUS_TAG, "Memory Status:");
|
||||
ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ===");
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/* 定义引脚分配 */
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @brief 定义了引脚的分配。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h" // 用于 esp_rom_delay_us
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "linear_motor.h"
|
||||
#include "gyroscope.h"
|
||||
|
||||
#define TAG_BOARD "SWEEKAR_ESP32"
|
||||
/*I2C总线引脚定义*/
|
||||
#define I2C0_MASTER_PORT I2C_NUM_0
|
||||
#define I2C0_MASTER_SDA_IO GPIO_NUM_2
|
||||
#define I2C0_MASTER_SCL_IO GPIO_NUM_3
|
||||
|
||||
/* 步进电机配置 */
|
||||
#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚
|
||||
#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进)
|
||||
|
||||
/* 定义屏幕驱动控制引脚 */
|
||||
#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚
|
||||
#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL
|
||||
#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚
|
||||
#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚
|
||||
#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚
|
||||
#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚
|
||||
#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS)
|
||||
|
||||
#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数)
|
||||
#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数)
|
||||
|
||||
/* 毫米波雷达配置参数 */
|
||||
/* 定义毫米波雷达的中断引脚 */
|
||||
#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35
|
||||
// UART 配置参数
|
||||
#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1
|
||||
#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整)
|
||||
#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX
|
||||
#define RADAR_BAUD_RATE 9600 // 雷达波特率
|
||||
#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小
|
||||
|
||||
/* IO扩展硬件配置常量 */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000)
|
||||
#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚
|
||||
#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/* 定义线性马达的I2C从机配置常量 */
|
||||
#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址
|
||||
|
||||
/* 定义陀螺仪的I2C从机配置常量 */
|
||||
#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址
|
||||
#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚
|
||||
|
||||
/* AW触摸芯片配置 */
|
||||
#define AW_TOUCH_IRQ_PIN GPIO_NUM_11 // AW触摸芯片中断引脚
|
||||
#define NFC_RST_PIN GPIO_NUM_12 // NFC复位引脚
|
||||
#define SHUTDOWN_CTRL_PIN GPIO_NUM_13 // 关机控制引脚
|
||||
|
||||
/* 原生触摸引脚配置 (v1.1.17已改为上述功能,保留定义需谨慎) */
|
||||
// 触摸按键数量配置
|
||||
#define TOUCH_BUTTON_NUM 3
|
||||
// 触摸通道定义 - 注意:v1.1.17如果不使用ESP32原生触摸,这些定义可能不再适用
|
||||
// 但为了兼容编译,可以保留或注释
|
||||
#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 (Now AW_IRQ)
|
||||
#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 (Now NFC_RST)
|
||||
#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 (Now SHUTDOWN)
|
||||
|
||||
/* ES8311音频编解码器配置 (ESP-ADF兼容) */
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
/* I2S GPIO定义 */
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
/* PA引脚定义 */
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
|
||||
/* I2C配置 */
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3
|
||||
#define AUDIO_CODEC_ES8311_ADDR 0x18
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x40
|
||||
|
||||
/* WS2812 RGB LED配置 */
|
||||
#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚
|
||||
#define WS2812_NUM_LEDS 2 // WS2812 LED数量
|
||||
|
||||
/* 创建VBAT to VBAT_5V */
|
||||
#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚
|
||||
|
||||
/* 定义按键的中断引脚 */
|
||||
#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚
|
||||
#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚
|
||||
|
||||
/* 底座控制命令串口配置 */
|
||||
#define BASE_BOARD_CTL_UART_PORT UART_NUM_0
|
||||
#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43
|
||||
#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44
|
||||
#define BASE_BOARD_CTL_UART_BAUDRATE 115200
|
||||
#define BASE_BOARD_CTL_UART_BUF_SIZE 256
|
||||
|
||||
/* 背光控制引脚配置 */
|
||||
#define BL_PIN GPIO_NUM_45
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,432 @@
|
||||
#ifndef IO_EXPANSION_BOARD_H
|
||||
#define IO_EXPANSION_BOARD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <functional>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
class MillimeterWaveRadar;
|
||||
class PhotoInterrupter;
|
||||
class AdcBatteryMonitor;
|
||||
|
||||
// 回调函数类型定义
|
||||
typedef std::function<void()> RadarCallback;
|
||||
typedef std::function<void()> PhotoInterrupterStartCallback;
|
||||
typedef std::function<void()> PhotoInterrupterEndCallback;
|
||||
typedef std::function<void()> BatteryChargingCallback;
|
||||
typedef std::function<void()> BatteryFullCallback;
|
||||
typedef std::function<void()> BatteryNotChargingCallback;
|
||||
|
||||
/* 寄存器地址 */
|
||||
#define INPUT_PORT0 0x00 // 输入端口0寄存器
|
||||
#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取)
|
||||
#define OUTPUT_PORT0 0x02 // 输出端口0寄存器
|
||||
#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平
|
||||
#define CONFIG_PORT0 0x04 // 配置端口0寄存器
|
||||
#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式
|
||||
#define INT_PORT0 0x06 // 中断端口0寄存器
|
||||
#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的)
|
||||
#define CTL 0x11 // 全局控制寄存器
|
||||
#define ID 0x23 // 芯片ID寄存器(0x23)
|
||||
|
||||
/***********************************IO扩展板电机引脚配置参数*************************************/
|
||||
/* 设置步进电机方向 */
|
||||
#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转
|
||||
#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转
|
||||
#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4
|
||||
#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4
|
||||
|
||||
/* 设置步进电机细分模式 */
|
||||
#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5
|
||||
#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5
|
||||
|
||||
#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4
|
||||
#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4
|
||||
|
||||
/* 设置步进电机睡眠引脚 */
|
||||
#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式
|
||||
#define STEPPER_MOTOR_WORK true //步进电机进入工作模式
|
||||
#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
/* 设置电机的使能引脚 */
|
||||
#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平
|
||||
#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平
|
||||
|
||||
/* 设置毫米波雷达对应IO扩展板的中断引脚 */
|
||||
#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7
|
||||
#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口
|
||||
#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1
|
||||
#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态
|
||||
#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态
|
||||
/* 任务配置常量 */
|
||||
#define WRITE_BUF_SIZE 2 // I2C单次写入字节数
|
||||
#define READ_BUF_SIZE 2 // I2C单次读取字节数
|
||||
#define I2C_TASK_PRIORITY 2 // 任务优先级(中等)
|
||||
#define I2C_TASK_STACK 4096 // 任务栈大小(4KB)
|
||||
|
||||
// 光学传感器引脚定义
|
||||
#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2)
|
||||
#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3)
|
||||
#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
/***********************************IO扩展板LCD引脚配置参数*************************************/
|
||||
// /* 设置LCD的BL引脚 */
|
||||
// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6
|
||||
// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6
|
||||
// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平
|
||||
// #define LCD_BL_LOW false //LCD背光引脚状态为低电平
|
||||
|
||||
/* 设置LED_EN (LCD背光/LED控制)引脚, PMOS高侧驱动 */
|
||||
#define LED_EN_PIN 1 //LED_EN对应IO扩展板引脚P0_1
|
||||
#define LED_EN_PORT OUTPUT_PORT0 //挂载在输出端口OUTPUT_PORT0
|
||||
#define LED_EN_CONFIG CONFIG_PORT0 //配置在P0_1
|
||||
#define LED_EN_OFF true //高电平关(PMOS)
|
||||
#define LED_EN_ON false //低电平开(PMOS)
|
||||
|
||||
/* 设置LCD的RST引脚 */
|
||||
#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1
|
||||
#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1
|
||||
#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_RST_HIGH true //LCD复位引脚状态为高电平
|
||||
#define LCD_RST_LOW false //LCD复位引脚状态为低电平
|
||||
|
||||
/* 设置PA控制引脚 */
|
||||
#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2
|
||||
#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2
|
||||
#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define PA_CTRL_HIGH true //PA控制引脚状态为高电平
|
||||
#define PA_CTRL_LOW false //PA控制引脚状态为低电平
|
||||
|
||||
// 电池充电检测引脚定义
|
||||
#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3
|
||||
#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3
|
||||
|
||||
#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5)
|
||||
#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
|
||||
#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签
|
||||
#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签
|
||||
|
||||
// GPIO引脚定义
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚
|
||||
// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/**
|
||||
* @class IOExpansionBoard
|
||||
* @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作
|
||||
*/
|
||||
class IOExpansionBoard
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 设置毫米波雷达指针
|
||||
* @param radar 毫米波雷达对象指针
|
||||
*/
|
||||
void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; };
|
||||
|
||||
/**
|
||||
* @brief 设置限位开关指针
|
||||
* @param photo_interrupter 限位开关对象指针
|
||||
*/
|
||||
void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; };
|
||||
|
||||
/**
|
||||
* @brief 设置电池监控器指针
|
||||
* @param battery_monitor 电池监控器对象指针
|
||||
*/
|
||||
void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; };
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetIoExpand();
|
||||
|
||||
/**
|
||||
* @brief 初始化I2C主机通信
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
// esp_err_t IoExpansionI2cInit();
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void CreateI2cReadTask();
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务(整合初始化和任务创建)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StartTask();
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief 读寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要读出的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口0寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort0(uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口1寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort1(uint8_t *data);
|
||||
|
||||
// /**
|
||||
// * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断
|
||||
// * @param reg_addr 寄存器地址
|
||||
// * @return esp_err_t 操作结果
|
||||
// */
|
||||
// esp_err_t SetInterruptStatus(bool status);
|
||||
|
||||
/**
|
||||
* @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandSetMode();
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
* @param mode 模式:1/2/4/8/16/32/64
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的方向
|
||||
* @param dir 方向
|
||||
* @param OUTPUT_PORT 输出端口
|
||||
* @param pin 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的睡眠模式
|
||||
* @param 是否进入睡眠模式
|
||||
* @param 输出端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能引脚状态
|
||||
* @param 使能状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的BL引脚状态
|
||||
* @param BL状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置 LED_EN 引脚电平(用于控制LCD背光/LED灯电源)
|
||||
* @param mode true:开启(低电平), false:关闭(高电平)
|
||||
*/
|
||||
esp_err_t SetLedEnMode(bool mode);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的RST引脚状态
|
||||
* @param RST状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置PA控制引脚状态
|
||||
* @param mode PA_CTRL状态(true为高电平,false为低电平)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetPaCtrlMode(bool mode);
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断引脚
|
||||
* @param 毫米波雷达的中断引脚模式
|
||||
* @param 输入端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin);
|
||||
|
||||
/**
|
||||
* @brief 计算Port0的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort0();
|
||||
|
||||
/**
|
||||
* @brief 计算Port1的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort1();
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断回调函数
|
||||
* @param callback 雷达中断回调函数
|
||||
*/
|
||||
void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器开始中断回调函数
|
||||
* @param callback 光学传感器开始中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器结束中断回调函数
|
||||
* @param callback 光学传感器结束中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充电中断回调函数
|
||||
* @param callback 电池充电中断回调函数
|
||||
*/
|
||||
void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充满中断回调函数
|
||||
* @param callback 电池充满中断回调函数
|
||||
*/
|
||||
void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池非充电中断回调函数
|
||||
* @param callback 电池非充电中断回调函数
|
||||
*/
|
||||
void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; }
|
||||
|
||||
// 公共成员变量
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
uint8_t device_addr_; // I2C设备地址
|
||||
|
||||
private:
|
||||
// 静态成员函数
|
||||
MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调
|
||||
PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调
|
||||
AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调
|
||||
static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数
|
||||
|
||||
// 成员变量用于状态跟踪
|
||||
uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态
|
||||
uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态
|
||||
bool radar_last_state_ = false; // 雷达引脚上一次的状态
|
||||
bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态
|
||||
bool battery_full_last_state_ = false; // 电池充满状态上一次的状态
|
||||
|
||||
// 回调函数成员变量
|
||||
RadarCallback radar_callback_ = nullptr;
|
||||
PhotoInterrupterStartCallback photo_start_callback_ = nullptr;
|
||||
PhotoInterrupterEndCallback photo_end_callback_ = nullptr;
|
||||
BatteryChargingCallback battery_charging_callback_ = nullptr;
|
||||
BatteryFullCallback battery_full_callback_ = nullptr;
|
||||
BatteryNotChargingCallback battery_not_charging_callback_ = nullptr;
|
||||
|
||||
// PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调
|
||||
// /**
|
||||
// * @brief 分配静态任务所需的内存
|
||||
// * @return bool 分配是否成功
|
||||
// */
|
||||
// bool AllocateStaticTaskMemory();
|
||||
|
||||
// /**
|
||||
// * @brief 释放静态任务分配的内存
|
||||
// */
|
||||
// void FreeStaticTaskMemory();
|
||||
|
||||
// 实例成员变量
|
||||
EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组
|
||||
TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄
|
||||
bool is_initialized_ = false; // 初始化状态标记(新增)
|
||||
gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚
|
||||
gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚
|
||||
|
||||
// StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM)
|
||||
// StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @file power_management_config.h
|
||||
* @brief 功耗管理配置和策略定义
|
||||
* @author Embedded Software Expert
|
||||
* @date 2025年1月
|
||||
*
|
||||
* 这个文件定义了功耗管理的配置参数、策略和优化建议,
|
||||
* 为系统提供灵活的功耗管理方案。
|
||||
*/
|
||||
|
||||
#ifndef POWER_MANAGEMENT_CONFIG_H
|
||||
#define POWER_MANAGEMENT_CONFIG_H
|
||||
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗管理配置结构体
|
||||
*/
|
||||
typedef struct {
|
||||
// 睡眠模式配置
|
||||
uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒)
|
||||
uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒)
|
||||
|
||||
// 唤醒源配置
|
||||
bool enable_timer_wakeup; // 启用定时器唤醒
|
||||
bool enable_gpio_wakeup; // 启用GPIO唤醒
|
||||
bool enable_touch_wakeup; // 启用触摸唤醒
|
||||
gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号
|
||||
int wakeup_level; // 唤醒电平(0或1)
|
||||
|
||||
// 功耗优化配置
|
||||
bool disable_bt_in_sleep; // 睡眠时关闭蓝牙
|
||||
bool disable_wifi_in_sleep; // 睡眠时关闭WiFi
|
||||
bool reduce_cpu_frequency; // 降低CPU频率
|
||||
uint32_t cpu_frequency_hz; // CPU频率(Hz)
|
||||
|
||||
// 外设功耗配置
|
||||
bool power_down_sdcard; // 睡眠时关闭SD卡电源
|
||||
bool power_down_display; // 睡眠时关闭显示电源
|
||||
bool power_down_audio; // 睡眠时关闭音频电源
|
||||
bool power_down_motor; // 睡眠时关闭电机电源
|
||||
|
||||
// RTC内存配置
|
||||
bool preserve_rtc_memory; // 保留RTC内存
|
||||
size_t rtc_memory_size; // RTC内存大小
|
||||
} power_management_config_t;
|
||||
|
||||
/**
|
||||
* @brief 默认功耗管理配置
|
||||
*/
|
||||
#define DEFAULT_POWER_CONFIG { \
|
||||
.light_sleep_duration_us = 1000000, /* 1秒 */ \
|
||||
.deep_sleep_duration_us = 30000000, /* 30秒 */ \
|
||||
.enable_timer_wakeup = true, /* 启用定时器唤醒 */ \
|
||||
.enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \
|
||||
.enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \
|
||||
.wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \
|
||||
.wakeup_level = 0, /* 低电平唤醒 */ \
|
||||
.disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \
|
||||
.disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \
|
||||
.reduce_cpu_frequency = true, /* 降低CPU频率 */ \
|
||||
.cpu_frequency_hz = 80000000, /* 80MHz */ \
|
||||
.power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \
|
||||
.power_down_display = true, /* 睡眠时关闭显示 */ \
|
||||
.power_down_audio = true, /* 睡眠时关闭音频 */ \
|
||||
.power_down_motor = true, /* 睡眠时关闭电机 */ \
|
||||
.preserve_rtc_memory = true, /* 保留RTC内存 */ \
|
||||
.rtc_memory_size = 4096, /* 4KB RTC内存 */ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 各功耗模式的详细配置
|
||||
*/
|
||||
static const power_management_config_t idle_mode_config = {
|
||||
.light_sleep_duration_us = 500000, // 500ms轻度睡眠
|
||||
.deep_sleep_duration_us = 0, // 不使用深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = false, // 保持蓝牙连接
|
||||
.disable_wifi_in_sleep = false, // 保持WiFi连接
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000, // 40MHz
|
||||
.power_down_sdcard = false, // 保持SD卡(可能有后台任务)
|
||||
.power_down_display = true, // 关闭显示背光
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 2048,
|
||||
};
|
||||
|
||||
static const power_management_config_t light_sleep_config = {
|
||||
.light_sleep_duration_us = 0, // 直接进入轻度睡眠
|
||||
.deep_sleep_duration_us = 0,
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000,
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 4096,
|
||||
};
|
||||
|
||||
static const power_management_config_t deep_sleep_config = {
|
||||
.light_sleep_duration_us = 0,
|
||||
.deep_sleep_duration_us = 60000000, // 60秒深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 10000000, // 10MHz
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 8192,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 功耗统计和监控结构体
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t total_sleep_time_us; // 总睡眠时间
|
||||
uint64_t total_wake_time_us; // 总唤醒时间
|
||||
uint32_t sleep_count; // 睡眠次数
|
||||
uint32_t wake_count; // 唤醒次数
|
||||
uint32_t average_sleep_duration_us; // 平均睡眠时长
|
||||
uint32_t average_wake_duration_us; // 平均唤醒时长
|
||||
float estimated_power_saving_percent; // 估计的功耗节省百分比
|
||||
} power_statistics_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗优化建议
|
||||
*
|
||||
* 基于硬件特性和使用模式,提供功耗优化建议
|
||||
*/
|
||||
typedef enum {
|
||||
OPTIMIZATION_NONE = 0,
|
||||
OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率
|
||||
OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设
|
||||
OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠
|
||||
OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠
|
||||
OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态
|
||||
OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存
|
||||
OPTIMIZATION_BATCH_OPERATIONS, // 批量操作
|
||||
} power_optimization_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件回调
|
||||
*/
|
||||
typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_EVENT_MODE_CHANGE, // 功耗模式改变
|
||||
POWER_EVENT_SLEEP_START, // 睡眠开始
|
||||
POWER_EVENT_SLEEP_END, // 睡眠结束
|
||||
POWER_EVENT_WAKEUP, // 系统唤醒
|
||||
POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发
|
||||
} power_event_t;
|
||||
|
||||
#endif // POWER_MANAGEMENT_CONFIG_H
|
||||
@@ -0,0 +1,778 @@
|
||||
/**
|
||||
* @file board.cc
|
||||
* @brief 板级外设初始化类,包含步进电机、毫米波雷达、I2C总线等外设的初始化函数。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "esp_check.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
}
|
||||
|
||||
#include "board_sweekar.h"
|
||||
#include "config.h"
|
||||
#include "board.h" // 添加board.h以获取audio_board_sdcard_init函数声明
|
||||
#include "drv8428.h"
|
||||
#include "aw8646.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "audio_mem.h"
|
||||
#include "esp_timer.h"
|
||||
#include "base_board_hal_i2c.h"
|
||||
|
||||
#define TAG "board_sweekar"
|
||||
|
||||
static BoardSweekar* s_board_instance = nullptr;
|
||||
|
||||
BoardSweekar* BoardSweekar::GetInstance()
|
||||
{
|
||||
if (s_board_instance == nullptr) {
|
||||
static BoardSweekar global_board;
|
||||
s_board_instance = &global_board;
|
||||
}
|
||||
return s_board_instance;
|
||||
}
|
||||
|
||||
BoardSweekar::BoardSweekar()
|
||||
{
|
||||
#ifdef CONFIG_STEPPER_DRIVER_AW8646
|
||||
stepper_driver_ = new Aw8646Driver(io_expansion_);
|
||||
#else
|
||||
stepper_driver_ = new Drv8428Driver(io_expansion_);
|
||||
#endif
|
||||
}
|
||||
|
||||
BoardSweekar::~BoardSweekar()
|
||||
{
|
||||
if (stepper_driver_) {
|
||||
delete stepper_driver_;
|
||||
stepper_driver_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BoardSweekar::SetAudioAmplifier(bool enable) {
|
||||
// AUD_CTRL 是 codec 侧控制脚,不参与 PA 开关;PA 仍由 IO 扩展板控制。
|
||||
io_expansion_.SetPaCtrlMode(enable);
|
||||
ESP_LOGI(TAG, "Audio Amplifier (via IO Expansion) %s", enable ? "ENABLED" : "DISABLED");
|
||||
}
|
||||
|
||||
/*========================== 步进电机相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 步进电机初始化函数
|
||||
* 配置步进电机所需的GPIO引脚模式,通过IO扩展板设置步进驱动芯片的工作模式
|
||||
* 在 stepper_motor.cc 中完成 GPTimer + GPIO 翻转 STEP 脉冲的初始化
|
||||
*/
|
||||
void BoardSweekar::StepperMotorInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) STEP 引脚改为普通 GPIO(不再用 LEDC)
|
||||
gpio_config_t io_cfg;
|
||||
io_cfg.pin_bit_mask = 1ULL << STEPPER_STEP_IO;
|
||||
io_cfg.mode = GPIO_MODE_OUTPUT;
|
||||
io_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_cfg.intr_type = GPIO_INTR_DISABLE;
|
||||
err = gpio_config(&io_cfg);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "步进电机 STEP GPIO 配置失败, 错误码: 0x%x", err);
|
||||
}
|
||||
|
||||
// 初始电平拉低,保证上电不乱跳
|
||||
gpio_set_level(STEPPER_STEP_IO, 0);
|
||||
|
||||
// 2) 检查 I2C 总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) 初始化驱动对象并初始化
|
||||
if (stepper_driver_) {
|
||||
err = stepper_driver_->Init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动初始化失败, 错误码: 0x%x", err);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG_BOARD, "步进电机驱动创建失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCD IO引脚初始化函数(消除与步进电机的耦合)
|
||||
*
|
||||
* 配置LCD所需的IO扩展板寄存器,确保LCD复位引脚正常工作
|
||||
* 此函数独立于步进电机初始化,专门处理LCD相关的IO配置
|
||||
*/
|
||||
void BoardSweekar::LcdIoInit(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1) 检查I2C总线是否已初始化
|
||||
if (bus_handle_ == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "I2C总线未初始化,请先调用I2CMasterInit()");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) 执行硬件复位,确保IO扩展板处于已知状态
|
||||
err = io_expansion_.ResetIoExpand();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板硬件复位失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板硬件复位成功");
|
||||
}
|
||||
|
||||
// 3) 配置IO扩展板模式(端口方向等)
|
||||
err = io_expansion_.IoexpandSetMode();
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "IO扩展板模式配置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "IO扩展板模式配置成功");
|
||||
}
|
||||
|
||||
// 4) 初始化LCD复位引脚:设置为高电平
|
||||
err = io_expansion_.SetLcdResetMode(LCD_RST_HIGH, LCD_RST_PORT, LCD_RST_PIN);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "LCD复位引脚高电平设置失败, 错误码: 0x%x", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "LCD复位引脚高电平设置成功");
|
||||
}
|
||||
|
||||
// 5) 初始化LED_EN电源为关闭状态 (PMOS高电平关)
|
||||
// 只有在需要亮灯时,由ActuatorActor主动开启,避免平静状态下常亮
|
||||
err = io_expansion_.SetLedEnMode(false);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_BOARD, "初始化LED_EN电源(关闭)失败, 错误码: 0x%x", err);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_BOARD, "初始化LED_EN电源(关闭)成功");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行系统关机
|
||||
* 内部拉高 SHUTDOWN_CTRL_PIN 引脚切断电源
|
||||
*/
|
||||
void BoardSweekar::SystemShutdown(void)
|
||||
{
|
||||
#ifdef SHUTDOWN_CTRL_PIN
|
||||
ESP_LOGI(TAG, "Executing System Shutdown... Pulling SHUTDOWN_CTRL_PIN (%d) HIGH", SHUTDOWN_CTRL_PIN);
|
||||
// 用户指定:拉高可以完成关机动作
|
||||
gpio_set_level(SHUTDOWN_CTRL_PIN, 1);
|
||||
|
||||
// 给一点时间让电源完全断开
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
#else
|
||||
ESP_LOGW(TAG, "SHUTDOWN_CTRL_PIN is not defined. Cannot execute hardware shutdown.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================== 毫米波雷达相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达串口初始化函数
|
||||
*
|
||||
* 配置毫米波雷达所使用的串口参数(波特率、数据位、校验位、停止位等),设置串口引脚,
|
||||
* 并安装串口驱动。采用较大的RX/TX FIFO深度以处理突发数据,禁用驱动自带事件队列以避免
|
||||
* 与自定义中断冲突。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarUartInit(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = RADAR_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(RADAR_UART_NUM, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(RADAR_UART_NUM, UART_TX_PIN, UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动(禁用驱动自带事件队列,避免与自定义中断冲突)
|
||||
// 增加 RX/TX FIFO 深度以处理突发数据
|
||||
ESP_ERROR_CHECK(uart_driver_install(RADAR_UART_NUM, RADAR_BUF_SIZE * 4, RADAR_BUF_SIZE * 4,
|
||||
0, NULL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫米波雷达中断引脚初始化函数
|
||||
*
|
||||
* 配置毫米波雷达中断引脚为输入模式,禁用上拉电阻,使能下拉电阻,初始禁用中断功能
|
||||
* (如需使用中断需单独进行配置)。
|
||||
*/
|
||||
void BoardSweekar::MillimeterWaveRadarGpioInit(void)
|
||||
{
|
||||
// GPIO配置结构体
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << MILLIMETER_WAVE_RADAR_PIN), // 选择GPIO引脚
|
||||
.mode = GPIO_MODE_INPUT, // 设置为输入模式
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 使能下拉
|
||||
.intr_type = GPIO_INTR_DISABLE // 禁用中断(如需中断需单独配置)
|
||||
};
|
||||
|
||||
// 配置GPIO
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
/*========================== I2C总线及挂载的从设备相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief I2C总线及从机设备初始化函数
|
||||
*
|
||||
* 首先配置并创建I2C主机总线,然后依次添加IO扩展板和线性马达作为I2C从机设备到总线上。
|
||||
* 若总线创建或设备添加失败,会输出错误信息并进行相应的资源清理(删除已创建的总线)。
|
||||
* 初始化成功后,会通过ESP_LOGI输出IO扩展板和线性马达的从机地址信息。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示相应的失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::I2CMasterInit(void)
|
||||
{
|
||||
static const char *I2C_INIT = "I2C_INIT";
|
||||
|
||||
// 初始化IO扩展板复位引脚
|
||||
gpio_config_t reset_io_conf = {
|
||||
.pin_bit_mask = (1ULL << IO_EXPAND_RSTN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE, // 使能上拉
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&reset_io_conf);
|
||||
|
||||
// 执行复位时序:先拉低100ms,再拉高并等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 0); // 拉低复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
|
||||
gpio_set_level(IO_EXPAND_RSTN, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板复位完成");
|
||||
|
||||
// 创建统一的I2C总线(使用ESP-ADF的i2c_bus)
|
||||
i2c_config_t i2c_cfg = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C0_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C0_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = {
|
||||
.clk_speed = 100000,
|
||||
},
|
||||
};
|
||||
|
||||
// 创建I2C总线(ESP-ADF的audio_board_init会复用这个总线)
|
||||
bus_handle_ = i2c_bus_create(I2C0_MASTER_PORT, &i2c_cfg);
|
||||
if (bus_handle_ == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create I2C bus");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待设备启动
|
||||
// ESP-ADF的i2c_bus不需要单独添加设备,直接通过总线句柄和设备地址进行通信
|
||||
|
||||
// 验证线性马达设备是否存在
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, LINEAR_MOTOR_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "线性马达设备未找到(地址:0x%02X),错误码: 0x%x", LINEAR_MOTOR_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "线性马达设备检测成功(地址:0x%02X)", LINEAR_MOTOR_I2C_SLAVE_ADDR);
|
||||
}
|
||||
// 验证IO扩展板设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, I2C_IO_EXPAND_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "IO扩展板设备未找到(地址:0x%02X),错误码: 0x%x", I2C_IO_EXPAND_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化其他设备
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "IO扩展板设备检测成功(地址:0x%02X)", I2C_IO_EXPAND_SLAVE_ADDR);
|
||||
}
|
||||
// 验证陀螺仪设备是否存在
|
||||
err = i2c_bus_probe_addr(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(I2C_INIT, "陀螺仪设备未找到(地址:0x%02X),错误码: 0x%x", GYROSCOPE_I2C_SLAVE_ADDR, err);
|
||||
// 不返回错误,继续初始化
|
||||
} else {
|
||||
ESP_LOGI(I2C_INIT, "陀螺仪设备检测成功(地址:0x%02X)", GYROSCOPE_I2C_SLAVE_ADDR);
|
||||
}
|
||||
|
||||
// 为IO扩展板设置总线句柄和设备地址(使用7位地址)
|
||||
io_expansion_.bus_handle_ = bus_handle_;
|
||||
io_expansion_.device_addr_ = I2C_IO_EXPAND_SLAVE_ADDR << 1;
|
||||
|
||||
// 线性马达的初始化已移至 InitializeAllHardware 中统一调用 Init 方法
|
||||
// linear_motor_ 的参数传递将在那里完成,不再此处直接赋值,提高内聚性
|
||||
|
||||
ESP_LOGI(I2C_INIT, "I2C总线初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*========================== VBAT to VBAT_5V相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 开启VBAT to VBAT_5V
|
||||
*
|
||||
* 创建开启升压的电源管理单元
|
||||
*
|
||||
*/
|
||||
void BoardSweekar::VbatToVbat5vInit(void)
|
||||
{
|
||||
// 配置VBAT_5V引脚为输出模式
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << VBAT_5V_PIN),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
// 使能VBAT_5V
|
||||
gpio_set_level(VBAT_5V_PIN, 1);
|
||||
}
|
||||
|
||||
/*========================== 底座控制串口相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief 底座控制命令串口初始化函数
|
||||
*/
|
||||
// 根据配置选择通信方式的HAL头文件
|
||||
#ifdef CONFIG_BASE_BOARD_COMM_I2C
|
||||
#include "base_board_hal_i2c.h"
|
||||
#else
|
||||
#include "base_board_hal_uart.h"
|
||||
#endif
|
||||
|
||||
void BoardSweekar::BaseBoardControlInit(void)
|
||||
{
|
||||
#ifdef CONFIG_BASE_BOARD_COMM_I2C
|
||||
// I2C Mode
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "I2C bus not initialized before BaseBoardControlInit");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建 I2C HAL 实例
|
||||
BaseBoardHalI2c *hal = new BaseBoardHalI2c(bus_handle_);
|
||||
base_board_control_.Init(hal);
|
||||
ESP_LOGI(TAG, "BaseBoardControl I2C initialized");
|
||||
#else
|
||||
// UART Mode
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BASE_BOARD_CTL_UART_BAUDRATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
.flags = {
|
||||
.allow_pd = 0,
|
||||
.backup_before_sleep = 0,
|
||||
},
|
||||
};
|
||||
|
||||
// 1. 设置串口参数
|
||||
ESP_ERROR_CHECK(uart_param_config(BASE_BOARD_CTL_UART_PORT, &uart_config));
|
||||
|
||||
// 2. 设置 UART 引脚
|
||||
ESP_ERROR_CHECK(uart_set_pin(BASE_BOARD_CTL_UART_PORT, BASE_BOARD_CTL_UART_TX_PIN, BASE_BOARD_CTL_UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// 3. 安装 UART 驱动
|
||||
ESP_ERROR_CHECK(uart_driver_install(BASE_BOARD_CTL_UART_PORT,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
BASE_BOARD_CTL_UART_BUF_SIZE,
|
||||
0, NULL, 0));
|
||||
|
||||
BaseBoardHalUart *hal = new BaseBoardHalUart(BASE_BOARD_CTL_UART_PORT);
|
||||
base_board_control_.Init(hal);
|
||||
ESP_LOGI(TAG, "BaseBoardControl UART initialized");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================== SD卡相关驱动 ==========================*/
|
||||
|
||||
/**
|
||||
* @brief SD卡初始化函数
|
||||
*
|
||||
* 初始化SD卡外设,使用1线模式进行通信。该函数负责初始化外设管理器
|
||||
* 并配置SD卡,为后续的文件系统操作做准备。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示成功,其他错误码表示失败原因
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeSdcard(void)
|
||||
{
|
||||
static const char *SDCARD_TAG = "SDCARD_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(SDCARD_TAG, "Initializing SD card");
|
||||
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGW(SDCARD_TAG, "SD card already initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 初始化外设管理
|
||||
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
|
||||
periph_cfg.extern_stack = true; // 将任务栈分配到 PSRAM 以节省 Internal SRAM
|
||||
periph_set_ = esp_periph_set_init(&periph_cfg);
|
||||
if (!periph_set_) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize peripheral set");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// 初始化SD卡外设
|
||||
ret = audio_board_sdcard_init(periph_set_, SD_MODE_1_LINE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(SDCARD_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
is_sdcard_initialized_ = true;
|
||||
ESP_LOGI(SDCARD_TAG, "SD card initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口实现
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备可能依赖)
|
||||
* 2. IO扩展板(可能影响其他设备)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. 其他外设
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardware(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting unified hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化底座控制
|
||||
if (bus_handle_ != nullptr) {
|
||||
BaseBoardHalI2c *hal_i2c = new BaseBoardHalI2c(bus_handle_);
|
||||
base_board_control_.Init(hal_i2c);
|
||||
ESP_LOGI(HW_INIT_TAG, "Base board control initialized with I2C handle");
|
||||
} else {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize base board control: I2C bus is null");
|
||||
}
|
||||
|
||||
// 6. AUD_CTRL 为 codec 控制脚,板级初始化后保持拉高,不参与 PA 开关。
|
||||
#ifdef AUD_CTRL_PIN
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << AUD_CTRL_PIN);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(AUD_CTRL_PIN, 1);
|
||||
ESP_LOGI(HW_INIT_TAG, "AUD_CTRL pin initialized to HIGH");
|
||||
#endif
|
||||
|
||||
// 7. 可选外设(根据具体应用需求)
|
||||
// BaseBoardControlUartInit(); // 底座控制串口(demo5需要)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Base board control UART initialized");
|
||||
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
StepperMotorInit();
|
||||
|
||||
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Unified hardware initialization completed successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,执行相应的功耗优化策略:
|
||||
* - IDLE模式:关闭非必要外设,保持快速响应
|
||||
* - LIGHT_SLEEP模式:进入轻度睡眠,CPU暂停,外设断电
|
||||
* - DEEP_SLEEP模式:深度睡眠,仅RTC运行,功耗最低
|
||||
*/
|
||||
esp_err_t BoardSweekar::EnterLowPowerMode(power_mode_t mode) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Entering power mode: %d", mode);
|
||||
|
||||
if (mode == current_power_mode_) {
|
||||
ESP_LOGW(POWER_TAG, "Already in power mode %d", mode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 保存当前模式,以便恢复
|
||||
power_mode_t previous_mode = current_power_mode_;
|
||||
|
||||
switch (mode) {
|
||||
case POWER_MODE_NORMAL:
|
||||
// 正常模式,不需要特殊处理
|
||||
break;
|
||||
|
||||
case POWER_MODE_IDLE:
|
||||
// 空闲模式:关闭非必要外设
|
||||
ESP_LOGI(POWER_TAG, "Idle mode: disabling non-essential peripherals");
|
||||
|
||||
// 关闭SD卡(如果正在使用,需要先卸载)
|
||||
if (is_sdcard_initialized_) {
|
||||
// 注意:这里只是示例,实际应用中需要确保没有文件操作
|
||||
ESP_LOGW(POWER_TAG, "SD card still active in idle mode");
|
||||
}
|
||||
|
||||
// 关闭显示背光
|
||||
// 关闭非必要GPIO的上拉/下拉
|
||||
// 降低I2C时钟频率
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Light sleep mode: preparing for sleep");
|
||||
|
||||
// 设置唤醒源(需要根据具体需求配置)
|
||||
// esp_sleep_enable_timer_wakeup(1000000); // 1秒后唤醒
|
||||
// esp_sleep_enable_ext0_wakeup(GPIO_NUM_XX, 0); // 外部中断唤醒
|
||||
|
||||
// 进入轻度睡眠
|
||||
// ret = esp_light_sleep_start();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(POWER_TAG, "Failed to enter light sleep: %s", esp_err_to_name(ret));
|
||||
current_power_mode_ = previous_mode;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠
|
||||
ESP_LOGI(POWER_TAG, "Deep sleep mode: system will restart after wake-up");
|
||||
|
||||
// 保存必要的RTC数据
|
||||
// rtc_gpio_isolate(GPIO_NUM_XX); // 隔离GPIO
|
||||
|
||||
// 设置深度睡眠唤醒源
|
||||
// esp_sleep_enable_timer_wakeup(60000000); // 60秒后唤醒
|
||||
|
||||
// 进入深度睡眠
|
||||
// esp_deep_sleep_start();
|
||||
// 注意:深度睡眠后系统会重启,不会返回
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Invalid power mode: %d", mode);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
current_power_mode_ = mode;
|
||||
ESP_LOGI(POWER_TAG, "Successfully entered power mode: %d", mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复到正常运行模式,重新初始化必要的硬件资源。
|
||||
*/
|
||||
esp_err_t BoardSweekar::ExitLowPowerMode(void) {
|
||||
static const char *POWER_TAG = "POWER_MGMT";
|
||||
|
||||
ESP_LOGI(POWER_TAG, "Exiting low power mode");
|
||||
|
||||
if (current_power_mode_ == POWER_MODE_NORMAL) {
|
||||
ESP_LOGW(POWER_TAG, "Already in normal mode");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 根据之前的功耗模式执行相应的恢复操作
|
||||
switch (current_power_mode_) {
|
||||
case POWER_MODE_IDLE:
|
||||
// 恢复空闲模式
|
||||
ESP_LOGI(POWER_TAG, "Restoring from idle mode");
|
||||
|
||||
// 重新初始化必要的外设
|
||||
// 恢复I2C时钟频率
|
||||
// 重新开启显示背光
|
||||
break;
|
||||
|
||||
case POWER_MODE_LIGHT_SLEEP:
|
||||
// 轻度睡眠唤醒后会自动继续执行
|
||||
ESP_LOGI(POWER_TAG, "Woken up from light sleep");
|
||||
|
||||
// 重新配置时钟(如果需要)
|
||||
// 重新初始化外设
|
||||
break;
|
||||
|
||||
case POWER_MODE_DEEP_SLEEP:
|
||||
// 深度睡眠后系统会重启,不会执行到这里
|
||||
ESP_LOGW(POWER_TAG, "Deep sleep recovery should not reach here");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 恢复到正常模式
|
||||
current_power_mode_ = POWER_MODE_NORMAL;
|
||||
ESP_LOGI(POWER_TAG, "Successfully exited low power mode");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 提供精细化的电源管理,可以单独控制各个硬件模块的电源状态。
|
||||
*/
|
||||
esp_err_t BoardSweekar::SetModulePower(hardware_module_t module, bool enable) {
|
||||
static const char *POWER_TAG = "POWER_MODULE";
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(POWER_TAG, "%s module %d", enable ? "Enabling" : "Disabling", module);
|
||||
|
||||
// 更新电源状态位图
|
||||
if (enable) {
|
||||
power_state_flags_ |= (1 << module);
|
||||
} else {
|
||||
power_state_flags_ &= ~(1 << module);
|
||||
}
|
||||
|
||||
switch (module) {
|
||||
case HW_MODULE_I2C:
|
||||
if (!enable && bus_handle_) {
|
||||
// 注意:I2C总线通常不建议完全关闭,可能影响多个设备
|
||||
ESP_LOGW(POWER_TAG, "I2C bus power control not recommended");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_SDCARD:
|
||||
if (enable && !is_sdcard_initialized_) {
|
||||
ret = InitializeSdcard();
|
||||
} else if (!enable && is_sdcard_initialized_) {
|
||||
// 卸载SD卡文件系统
|
||||
// 注意:需要确保没有打开的文件
|
||||
ESP_LOGW(POWER_TAG, "SD card power down requires file system cleanup");
|
||||
}
|
||||
break;
|
||||
|
||||
case HW_MODULE_LCD:
|
||||
// LCD背光控制
|
||||
// LCD电源引脚控制(如果有)
|
||||
break;
|
||||
|
||||
case HW_MODULE_AUDIO:
|
||||
// 音频编解码器电源控制
|
||||
// 需要与AudioPlayer协调
|
||||
break;
|
||||
|
||||
case HW_MODULE_MOTOR:
|
||||
// 步进电机驱动器电源控制
|
||||
// 电机睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_GYROSCOPE:
|
||||
// 陀螺仪电源控制
|
||||
// 设置陀螺仪为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_TOUCH:
|
||||
// 触摸传感器电源控制
|
||||
// 设置触摸传感器为睡眠模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_RADAR:
|
||||
// 毫米波雷达电源控制
|
||||
// 设置雷达为低功耗模式
|
||||
break;
|
||||
|
||||
case HW_MODULE_IO_EXPAND:
|
||||
// IO扩展板电源控制
|
||||
// 设置扩展板为低功耗模式
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(POWER_TAG, "Unknown hardware module: %d", module);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(POWER_TAG, "Module %d power %s successfully", module, enable ? "enabled" : "disabled");
|
||||
} else {
|
||||
ESP_LOGE(POWER_TAG, "Failed to %s module %d: %s", enable ? "enable" : "disable", module, esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
#ifndef __BOARD_H__
|
||||
#define __BOARD_H__
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "stepper_motor.h"
|
||||
#include "stepper_driver.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "gyroscope.h"
|
||||
#include "touch_sensor.h"
|
||||
#include "base_board_control.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "periph_sdcard.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗模式枚举
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_MODE_NORMAL, // 正常运行模式,所有硬件可用
|
||||
POWER_MODE_IDLE, // 空闲模式,关闭非必要外设
|
||||
POWER_MODE_LIGHT_SLEEP, // 轻度睡眠,快速唤醒
|
||||
POWER_MODE_DEEP_SLEEP, // 深度睡眠,仅RTC运行
|
||||
} power_mode_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件模块枚举,用于精细化电源管理
|
||||
*/
|
||||
typedef enum {
|
||||
HW_MODULE_I2C, // I2C总线
|
||||
HW_MODULE_SDCARD, // SD卡
|
||||
HW_MODULE_LCD, // LCD显示
|
||||
HW_MODULE_AUDIO, // 音频编解码器
|
||||
HW_MODULE_MOTOR, // 步进电机
|
||||
HW_MODULE_GYROSCOPE, // 陀螺仪
|
||||
HW_MODULE_TOUCH, // 触摸传感器
|
||||
HW_MODULE_RADAR, // 毫米波雷达
|
||||
HW_MODULE_IO_EXPAND, // IO扩展板
|
||||
} hardware_module_t;
|
||||
|
||||
/**
|
||||
* @brief 硬件板级管理器
|
||||
*
|
||||
* 采用高内聚低耦合设计原则,统一管理所有硬件资源。
|
||||
* 提供统一的硬件初始化接口和资源访问,避免各模块重复初始化。
|
||||
*/
|
||||
class BoardSweekar
|
||||
{
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // 使用ESP-ADF的I2C总线句柄
|
||||
esp_periph_set_handle_t periph_set_ = nullptr; // 外设管理句柄
|
||||
bool is_sdcard_initialized_ = false; // SD卡初始化状态
|
||||
power_mode_t current_power_mode_ = POWER_MODE_NORMAL; // 当前功耗模式
|
||||
uint32_t power_state_flags_ = 0xFFFFFFFF; // 各模块电源状态位图(1为开启)
|
||||
|
||||
public:
|
||||
BoardSweekar();
|
||||
~BoardSweekar();
|
||||
|
||||
static BoardSweekar* GetInstance();
|
||||
|
||||
// --- 语义化的高层 API:音频与功放控制 ---
|
||||
// 开启或关闭外放功放 (PA),供上层 AudioActor/AudioPlayer 调用,屏蔽底层引脚实现
|
||||
void SetAudioAmplifier(bool enable);
|
||||
|
||||
IOExpansionBoard io_expansion_; // IO扩展板对象
|
||||
Gyroscope gyroscope_; // 陀螺仪对象
|
||||
TouchSensor touch_sensor_; // 触摸传感器对象
|
||||
BaseBoardControl base_board_control_; // 底座控制对象
|
||||
StepperDriver* stepper_driver_ = nullptr; // 步进电机驱动对象
|
||||
|
||||
StepperDriver* GetStepperDriver() const { return stepper_driver_; }
|
||||
|
||||
// 初始化步进电机
|
||||
void StepperMotorInit(void);
|
||||
|
||||
// 初始化LCD IO引脚(消除与步进电机的耦合)
|
||||
void LcdIoInit(void);
|
||||
|
||||
// 初始化串口
|
||||
void MillimeterWaveRadarUartInit(void);
|
||||
|
||||
//初始化毫米波雷达的中断引脚
|
||||
void MillimeterWaveRadarGpioInit(void);
|
||||
|
||||
/**
|
||||
* @brief 执行系统关机
|
||||
* 内部拉高/拉低 SHUTDOWN_CTRL_PIN 引脚切断电源
|
||||
*/
|
||||
void SystemShutdown(void);
|
||||
|
||||
// 初始化I2C总线
|
||||
esp_err_t I2CMasterInit(void);
|
||||
|
||||
// 初始化VBAT toVBAT_5V引脚
|
||||
void VbatToVbat5vInit(void);
|
||||
|
||||
// 初始化底座控制串口
|
||||
void BaseBoardControlInit(void);
|
||||
|
||||
// 初始化SD卡(推荐使用统一的硬件初始化)
|
||||
esp_err_t InitializeSdcard(void);
|
||||
|
||||
// 获取SD卡初始化状态
|
||||
bool IsSdcardInitialized() const { return is_sdcard_initialized_; }
|
||||
|
||||
// 获取外设管理句柄(供需要访问SD卡的模块使用)
|
||||
esp_periph_set_handle_t GetPeriphSet() const { return periph_set_; }
|
||||
|
||||
// 获取I2C总线句柄
|
||||
i2c_bus_handle_t GetBusHandle() const { return bus_handle_; }
|
||||
|
||||
/**
|
||||
* @brief 统一的硬件初始化接口
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源,确保各模块可以安全使用。
|
||||
* 推荐在主程序启动时调用此函数,而不是分别调用各个初始化函数。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardware(void);
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为复杂应用优化)
|
||||
*
|
||||
* 包含所有必要外设的完整初始化,适用于demo5等复杂应用场景。
|
||||
* 这个函数会初始化:I2C总线、IO扩展板、SD卡、LCD IO、底座控制等。
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeAllHardwareComplete(void);
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置,优化启动流程。
|
||||
*
|
||||
* @param app_type 应用类型(demo5、音频播放器、显示应用等)
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t InitializeHardwareForApplication(int app_type);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 进入低功耗模式
|
||||
*
|
||||
* 根据指定的功耗模式,关闭非必要硬件、设置GPIO为低功耗状态、
|
||||
* 调整时钟频率等。支持多种功耗模式以适应不同应用场景。
|
||||
*
|
||||
* @param mode 功耗模式
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t EnterLowPowerMode(power_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理接口 - 退出低功耗模式
|
||||
*
|
||||
* 从低功耗模式恢复,重新初始化必要的硬件资源。
|
||||
*
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ExitLowPowerMode(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前功耗模式
|
||||
*
|
||||
* @return power_mode_t 当前功耗模式
|
||||
*/
|
||||
power_mode_t GetPowerMode(void) const { return current_power_mode_; }
|
||||
|
||||
/**
|
||||
* @brief 设置硬件模块电源状态
|
||||
*
|
||||
* 单独控制某个硬件模块的电源状态,用于精细化的功耗管理。
|
||||
*
|
||||
* @param module 硬件模块
|
||||
* @param enable true为开启,false为关闭
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetModulePower(hardware_module_t module, bool enable);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* @file board_sweekar_complete_init.cc
|
||||
* @brief 完整的统一硬件初始化实现
|
||||
*
|
||||
* 这个文件提供了完整的统一硬件初始化函数,包含所有必要的硬件初始化步骤。
|
||||
* 专为demo5等复杂应用场景设计。
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 完整的统一硬件初始化接口(专为demo5优化)
|
||||
*
|
||||
* 按照依赖关系顺序初始化所有硬件资源:
|
||||
* 1. I2C总线(最基础,其他设备依赖)
|
||||
* 2. IO扩展板(控制其他外设)
|
||||
* 3. SD卡(文件系统,供显示和音频使用)
|
||||
* 4. LCD IO引脚(显示相关)
|
||||
* 5. 底座控制串口(通信)
|
||||
* 6. 底座控制模块(业务逻辑)
|
||||
* 7. 其他外设(根据应用需求)
|
||||
*
|
||||
* @return esp_err_t 初始化结果,ESP_OK表示全部成功
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeAllHardwareComplete(void)
|
||||
{
|
||||
static const char *HW_INIT_TAG = "HW_INIT_COMPLETE";
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "Starting complete hardware initialization...");
|
||||
|
||||
// 1. 初始化I2C总线(最基础,其他设备依赖)
|
||||
ret = I2CMasterInit();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize I2C master: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C master initialized");
|
||||
|
||||
// 2. 创建I2C读任务(IO扩展板需要)
|
||||
io_expansion_.CreateI2cReadTask();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ I2C read task created");
|
||||
|
||||
// 3. 初始化SD卡(文件系统,供显示和音频使用)
|
||||
ret = InitializeSdcard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(HW_INIT_TAG, "Failed to initialize SD card: %s", esp_err_to_name(ret));
|
||||
// SD卡失败不是致命错误,继续初始化其他硬件
|
||||
ESP_LOGW(HW_INIT_TAG, "⚠ SD card initialization failed, but continuing with other hardware");
|
||||
} else {
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ SD card initialized");
|
||||
}
|
||||
|
||||
// 4. 初始化LCD IO引脚(显示相关)
|
||||
LcdIoInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ LCD IO pins initialized");
|
||||
|
||||
// 5. 初始化底座控制串口(demo5需要)
|
||||
BaseBoardControlUartInit();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control UART initialized");
|
||||
|
||||
// 6. 初始化底座控制模块
|
||||
base_board_control_.Init();
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ Base board control initialized");
|
||||
|
||||
// 7. 设置IO扩展板的PA控制模式(demo5需要)
|
||||
io_expansion_.SetPaCtrlMode(true);
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ IO expansion PA control mode set");
|
||||
|
||||
// 8. 初始化 AUD_CTRL 引脚(如果定义了的话)
|
||||
#ifdef AUD_CTRL_PIN
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << AUD_CTRL_PIN);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
// 拉高开机
|
||||
gpio_set_level(AUD_CTRL_PIN, 1);
|
||||
ESP_LOGI(HW_INIT_TAG, "✓ AUD_CTRL pin initialized to HIGH");
|
||||
#endif
|
||||
|
||||
// 9. 可选外设(根据具体应用需求启用)
|
||||
// ESP_LOGI(HW_INIT_TAG, "Initializing optional peripherals...");
|
||||
//
|
||||
// // 毫米波雷达(如需要)
|
||||
// MillimeterWaveRadarUartInit();
|
||||
// MillimeterWaveRadarGpioInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Millimeter wave radar initialized");
|
||||
//
|
||||
// // VBAT升压(如需要)
|
||||
// VbatToVbat5vInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ VBAT to 5V booster initialized");
|
||||
//
|
||||
// // 步进电机(如需要)
|
||||
// StepperMotorInit();
|
||||
// ESP_LOGI(HW_INIT_TAG, "✓ Stepper motor initialized");
|
||||
|
||||
ESP_LOGI(HW_INIT_TAG, "=== Complete hardware initialization finished successfully ===");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 针对特定应用的硬件初始化配置
|
||||
*
|
||||
* 为不同类型的应用提供专门的初始化配置
|
||||
*/
|
||||
esp_err_t BoardSweekar::InitializeHardwareForApplication(application_type_t app_type) {
|
||||
static const char *APP_INIT_TAG = "APP_HW_INIT";
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "Initializing hardware for application type: %d", app_type);
|
||||
|
||||
// 基础硬件初始化(所有应用都需要)
|
||||
esp_err_t ret = InitializeAllHardwareComplete();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(APP_INIT_TAG, "Basic hardware initialization failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (app_type) {
|
||||
case APP_TYPE_DEMO5: // 宠物游戏demo
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Demo5 (Pet Game)...");
|
||||
|
||||
// Demo5需要的额外初始化
|
||||
// 触摸传感器、陀螺仪、RGB LED等会在应用层初始化
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Demo5 hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_AUDIO_PLAYER: // 音频播放器
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Audio Player...");
|
||||
|
||||
// 音频应用需要确保音频编解码器正确初始化
|
||||
// 这部分通常在AudioPlayer类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Audio player hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_DISPLAY_ONLY: // 纯显示应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Display Only...");
|
||||
|
||||
// 显示应用需要确保LCD相关硬件正确配置
|
||||
// 这部分通常在Display类中处理
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Display-only hardware configuration complete");
|
||||
break;
|
||||
|
||||
case APP_TYPE_MINIMAL: // 最小化应用
|
||||
ESP_LOGI(APP_INIT_TAG, "Configuring for Minimal Application...");
|
||||
|
||||
// 最小化配置,只保留最基本的功能
|
||||
// 关闭非必要外设以节省功耗
|
||||
|
||||
ESP_LOGI(APP_INIT_TAG, "✓ Minimal hardware configuration complete");
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(APP_INIT_TAG, "Unknown application type, using default configuration");
|
||||
break;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 硬件初始化状态报告
|
||||
*
|
||||
* 提供详细的硬件初始化状态报告,便于调试和问题排查
|
||||
*/
|
||||
void BoardSweekar::ReportHardwareStatus(void) {
|
||||
static const char *STATUS_TAG = "HW_STATUS";
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== Hardware Initialization Status Report ===");
|
||||
|
||||
// I2C总线状态
|
||||
ESP_LOGI(STATUS_TAG, "I2C Bus: %s", (bus_handle_ != nullptr) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// SD卡状态
|
||||
ESP_LOGI(STATUS_TAG, "SD Card: %s", (is_sdcard_initialized_) ? "✓ Initialized" : "✗ Not initialized");
|
||||
if (is_sdcard_initialized_) {
|
||||
ESP_LOGI(STATUS_TAG, " Peripheral Set: %s", (periph_set_ != nullptr) ? "✓ Available" : "✗ Not available");
|
||||
}
|
||||
|
||||
// IO扩展板状态
|
||||
ESP_LOGI(STATUS_TAG, "IO Expansion Board: %s", (io_expansion_.bus_handle_ != nullptr) ? "✓ Configured" : "✗ Not configured");
|
||||
|
||||
// 底座控制状态
|
||||
ESP_LOGI(STATUS_TAG, "Base Board Control: %s", (base_board_control_.GetUartPort() != 0) ? "✓ Initialized" : "✗ Not initialized");
|
||||
|
||||
// 功耗管理状态
|
||||
ESP_LOGI(STATUS_TAG, "Power Management: %s", (current_power_mode_ == POWER_MODE_NORMAL) ? "✓ Normal mode" : "⚠ Low power mode");
|
||||
ESP_LOGI(STATUS_TAG, " Current Mode: %d", current_power_mode_);
|
||||
ESP_LOGI(STATUS_TAG, " Module Power States: 0x%08X", power_state_flags_);
|
||||
|
||||
// 内存状态
|
||||
ESP_LOGI(STATUS_TAG, "Memory Status:");
|
||||
ESP_LOGI(STATUS_TAG, " Internal RAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
|
||||
ESP_LOGI(STATUS_TAG, " PSRAM Free: %d bytes", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
|
||||
|
||||
ESP_LOGI(STATUS_TAG, "=== End of Hardware Status Report ===");
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/* 定义引脚分配 */
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @brief 定义了引脚的分配。
|
||||
* @author zouyuhua
|
||||
* @date 2025年8月7日
|
||||
*
|
||||
*/
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h" // 用于 esp_rom_delay_us
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "linear_motor.h"
|
||||
#include "gyroscope.h"
|
||||
|
||||
#define TAG_BOARD "SWEEKAR_ESP32"
|
||||
/*I2C总线引脚定义*/
|
||||
#define I2C0_MASTER_PORT I2C_NUM_0
|
||||
#define I2C0_MASTER_SDA_IO GPIO_NUM_2
|
||||
#define I2C0_MASTER_SCL_IO GPIO_NUM_3
|
||||
|
||||
/* 步进电机配置 */
|
||||
#define STEPPER_STEP_IO GPIO_NUM_42 // 步进电机脉冲输入引脚
|
||||
#define STEPPER_TIMER_RES_HZ 1000000 // 步进电机定时器分辨率 1 MHz(1 us 步进)
|
||||
|
||||
/* 定义屏幕驱动控制引脚 */
|
||||
#define ST7789_PIN_CLK GPIO_NUM_48 // SPI时钟引脚
|
||||
#define ST7789_PIN_DC GPIO_NUM_38 // 数据/命令选择引脚RSEL
|
||||
#define ST7789_PIN_MOSI GPIO_NUM_47 // SPI数据输出引脚
|
||||
#define ST7789_PIN_CS GPIO_NUM_46 // SPI片选引脚
|
||||
#define ST7789_PIN_BL GPIO_NUM_45 // 背光引脚
|
||||
#define ST7789_PIN_RST GPIO_NUM_NC // 复位引脚
|
||||
#define LCD_BL_ACTIVE_LEVEL 0 // 背光有效电平:1=高电平有效(NMOS),0=低电平有效(PMOS)
|
||||
|
||||
#define LCD_WIDTH 172 // 屏幕宽度(水平方向像素数)
|
||||
#define LCD_HEIGHT 320 // 屏幕高度(垂直方向像素数)
|
||||
|
||||
/* 毫米波雷达配置参数 */
|
||||
/* 定义毫米波雷达的中断引脚 */
|
||||
#define MILLIMETER_WAVE_RADAR_PIN GPIO_NUM_35
|
||||
// UART 配置参数
|
||||
#define RADAR_UART_NUM UART_NUM_1 // 使用 UART1
|
||||
#define UART_TX_PIN GPIO_NUM_40 // GPIO40 作为 TX(根据实际硬件连接调整)
|
||||
#define UART_RX_PIN GPIO_NUM_39 // GPIO39 作为 RX
|
||||
#define RADAR_BAUD_RATE 9600 // 雷达波特率
|
||||
#define RADAR_BUF_SIZE 100 // 雷达接收缓冲区大小
|
||||
|
||||
/* IO扩展硬件配置常量 */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C通信频率(100kHz)(可更改至400000)
|
||||
#define I2C_IO_EXPAND_SLAVE_ADDR 0x58 // AW9523BTQR器件地址,v1_1_13的addr1和addr0是0
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // 中断检测引脚
|
||||
#define ESP_INTR_FLAG_DEFAULT 0 // 中断标志默认值
|
||||
#define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/* 定义线性马达的I2C从机配置常量 */
|
||||
#define LINEAR_MOTOR_I2C_SLAVE_ADDR 0x5A // 线性马达的I2C从机地址
|
||||
|
||||
/* 定义陀螺仪的I2C从机配置常量 */
|
||||
#define GYROSCOPE_I2C_SLAVE_ADDR 0x6A // 陀螺仪的I2C从机地址
|
||||
#define GYROSCOPE_INPUT_PIN_SEL GPIO_NUM_21 // 陀螺仪中断引脚
|
||||
|
||||
/* AW触摸芯片配置 */
|
||||
#define AW_TOUCH_IRQ_PIN GPIO_NUM_11 // AW触摸芯片中断引脚
|
||||
#define NFC_RST_PIN GPIO_NUM_12 // NFC复位引脚
|
||||
#define AUD_CTRL_PIN GPIO_NUM_13 // AUD_CTRL引脚
|
||||
|
||||
/* 原生触摸引脚配置 (v1.1.18已改为上述功能,保留定义需谨慎) */
|
||||
// 触摸按键数量配置
|
||||
#define TOUCH_BUTTON_NUM 3
|
||||
// 触摸通道定义 - 注意:v1.1.18如果不使用ESP32原生触摸,这些定义可能不再适用
|
||||
// 但为了兼容编译,可以保留或注释
|
||||
#define TOUCH_PAD_CHANNEL_1 TOUCH_PAD_NUM11 // GPIO11 (Now AW_IRQ)
|
||||
#define TOUCH_PAD_CHANNEL_2 TOUCH_PAD_NUM12 // GPIO12 (Now NFC_RST)
|
||||
#define TOUCH_PAD_CHANNEL_3 TOUCH_PAD_NUM13 // GPIO13 (Now AUD_CTRL)
|
||||
|
||||
/* ES8311音频编解码器配置 (ESP-ADF兼容) */
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
|
||||
/* I2S GPIO定义 */
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
/* PA引脚定义 */
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
|
||||
/* I2C配置 */
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_2
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_3
|
||||
#define AUDIO_CODEC_ES8311_ADDR 0x18
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x40
|
||||
|
||||
/* WS2812 RGB LED配置 */
|
||||
#define WS2812_PIN GPIO_NUM_41 // WS2812数据引脚
|
||||
#define WS2812_NUM_LEDS 2 // WS2812 LED数量
|
||||
|
||||
/* 创建VBAT to VBAT_5V */
|
||||
#define VBAT_5V_PIN GPIO_NUM_NC // VBAT_5V引脚
|
||||
|
||||
/* 定义按键的中断引脚 */
|
||||
#define BUTTON_PIN GPIO_NUM_0 // 按键中断引脚
|
||||
#define RIGHT_BUTTON_PIN GPIO_NUM_8 // 按键中断引脚
|
||||
|
||||
/* 底座控制命令串口配置 */
|
||||
#define BASE_BOARD_CTL_UART_PORT UART_NUM_0
|
||||
#define BASE_BOARD_CTL_UART_TX_PIN GPIO_NUM_43
|
||||
#define BASE_BOARD_CTL_UART_RX_PIN GPIO_NUM_44
|
||||
#define BASE_BOARD_CTL_UART_BAUDRATE 115200
|
||||
#define BASE_BOARD_CTL_UART_BUF_SIZE 256
|
||||
|
||||
/* 背光控制引脚配置 */
|
||||
#define BL_PIN GPIO_NUM_45
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,432 @@
|
||||
#ifndef IO_EXPANSION_BOARD_H
|
||||
#define IO_EXPANSION_BOARD_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <functional>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
class MillimeterWaveRadar;
|
||||
class PhotoInterrupter;
|
||||
class AdcBatteryMonitor;
|
||||
|
||||
// 回调函数类型定义
|
||||
typedef std::function<void()> RadarCallback;
|
||||
typedef std::function<void()> PhotoInterrupterStartCallback;
|
||||
typedef std::function<void()> PhotoInterrupterEndCallback;
|
||||
typedef std::function<void()> BatteryChargingCallback;
|
||||
typedef std::function<void()> BatteryFullCallback;
|
||||
typedef std::function<void()> BatteryNotChargingCallback;
|
||||
|
||||
/* 寄存器地址 */
|
||||
#define INPUT_PORT0 0x00 // 输入端口0寄存器
|
||||
#define INPUT_PORT1 0x01 // 输入端口1寄存器 0为低电平(仅支持读取)
|
||||
#define OUTPUT_PORT0 0x02 // 输出端口0寄存器
|
||||
#define OUTPUT_PORT1 0x03 // 输出端口1寄存器 0为低电平
|
||||
#define CONFIG_PORT0 0x04 // 配置端口0寄存器
|
||||
#define CONFIG_PORT1 0x05 // 配置端口1寄存器 0为输出模式
|
||||
#define INT_PORT0 0x06 // 中断端口0寄存器
|
||||
#define INT_PORT1 0x07 // 中断端口1寄存器 0为使能中断(根据手册默认是使能的)
|
||||
#define CTL 0x11 // 全局控制寄存器
|
||||
#define ID 0x23 // 芯片ID寄存器(0x23)
|
||||
|
||||
/***********************************IO扩展板电机引脚配置参数*************************************/
|
||||
/* 设置步进电机方向 */
|
||||
#define STEPPER_MOTOR_LEFT false //步进电机的方向为左转
|
||||
#define STEPPER_MOTOR_RIGHT true //步进电机的方向为右转
|
||||
#define STEPPER_MOTOR_DIR_PORT OUTPUT_PORT0 //步进电机方向引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_DIR_PIN 4 //步进电机方向引脚对应的IO扩展板引脚P0_4
|
||||
#define STEPPER_MOTOR_DIR_CONFIG CONFIG_PORT0 //步进电机方向引脚配置在P0_4
|
||||
|
||||
/* 设置步进电机细分模式 */
|
||||
#define STEPPER_MOTOR_M0_PIN 5 //步进电机细分模式选择引脚对应IO扩展板引脚P1_5
|
||||
#define STEPPER_MOTOR_M0_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M0_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_5
|
||||
|
||||
#define STEPPER_MOTOR_M1_PIN 4 //步进电机细分模式选择引脚对应IO扩展板引脚P1_4
|
||||
#define STEPPER_MOTOR_M1_MADE_PORT OUTPUT_PORT1 //步进电机模式选择引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define STEPPER_MOTOR_M1_CONFIG CONFIG_PORT1 //步进电机细分模式选择引脚配置在P1_4
|
||||
|
||||
/* 设置步进电机睡眠引脚 */
|
||||
#define STEPPER_MOTOR_SLEEP false //步进电机进入睡眠模式
|
||||
#define STEPPER_MOTOR_WORK true //步进电机进入工作模式
|
||||
#define STEPPER_MOTOR_SLEEP_PIN 6 //步进电机睡眠引脚对应IO扩展板引脚P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_CONFIG CONFIG_PORT1 //步进电机睡眠引脚配置在P1_6
|
||||
#define STEPPER_MOTOR_SLEEP_PORT OUTPUT_PORT1 //步进电机睡眠引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
|
||||
/* 设置电机的使能引脚 */
|
||||
#define STEPPER_MOTOR_ENABLE_PIN 7 //电机使能引脚对应IO扩展板引脚P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_PORT OUTPUT_PORT0 //电机使能引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
#define STEPPER_MOTOR_ENABLE_CONFIG CONFIG_PORT0 //电机使能引脚配置在P0_7
|
||||
#define STEPPER_MOTOR_ENABLE_ENABLE true //电机使能引脚状态为高电平
|
||||
#define STEPPER_MOTOR_ENABLE_DISABLE false //电机使能引脚状态为低电平
|
||||
|
||||
/* 设置毫米波雷达对应IO扩展板的中断引脚 */
|
||||
#define RADAR_INTERRUPT_PIN 7 //毫米波雷达中断引脚对应IO扩展板引脚P1_7
|
||||
#define RADAR_INTERRUPT_CONFIG CONFIG_PORT1 //毫米波雷达中断引脚挂载在IO扩展板的输入端口
|
||||
#define RADAR_INTERRUPT_INPUT INPUT_PORT1 //毫米波雷达中断引脚输入状态检测在INPUT_PORT1
|
||||
#define RADAR_INTERRUPT_ENABLE true //毫米波雷达中断引脚状态为输入状态
|
||||
#define RADAR_INTERRUPT_DISABLE false //毫米波雷达中断引脚状态为输出状态
|
||||
/* 任务配置常量 */
|
||||
#define WRITE_BUF_SIZE 2 // I2C单次写入字节数
|
||||
#define READ_BUF_SIZE 2 // I2C单次读取字节数
|
||||
#define I2C_TASK_PRIORITY 2 // 任务优先级(中等)
|
||||
#define I2C_TASK_STACK 4096 // 任务栈大小(4KB)
|
||||
|
||||
// 光学传感器引脚定义
|
||||
#define START_PHOTO_INTERRUPTER_PIN 2 // 光学传感器引脚(P0_2)
|
||||
#define START_PHOTO_INTERRUPTER_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define START_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define START_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define START_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
#define END_PHOTO_INTERRUPTER_PIN 3 // 光学传感器引脚(P0_3)
|
||||
#define END_PHOTO_INTERRUPTER_PORT_CONFIG CONFIG_PORT0 // 光学传感器引脚挂载在IO扩展板的输入端口
|
||||
#define END_PHOTO_INTERRUPTER_INPUT INPUT_PORT0 // 光学传感器引脚输入状态检测在INPUT_PORT0
|
||||
#define END_PHOTO_INTERRUPTER_HIGH true // 光学传感器引脚状态为高电平
|
||||
#define END_PHOTO_INTERRUPTER_LOW false // 光学传感器引脚状态为低电平
|
||||
|
||||
/***********************************IO扩展板LCD引脚配置参数*************************************/
|
||||
// /* 设置LCD的BL引脚 */
|
||||
// #define LCD_BL_PIN 6 //LCD背光引脚对应IO扩展板引脚P0_6
|
||||
// #define LCD_BL_PORT OUTPUT_PORT0 //LCD背光引脚挂载在IO扩展板的输出端口OUTPUT_PORT0
|
||||
// #define LCD_BL_CONFIG CONFIG_PORT0 //LCD背光引脚配置在P0_6
|
||||
// #define LCD_BL_HIGH true //LCD背光引脚状态为高电平
|
||||
// #define LCD_BL_LOW false //LCD背光引脚状态为低电平
|
||||
|
||||
/* 设置LED_EN (LCD背光/LED控制)引脚, PMOS高侧驱动 */
|
||||
#define LED_EN_PIN 1 //LED_EN对应IO扩展板引脚P0_1
|
||||
#define LED_EN_PORT OUTPUT_PORT0 //挂载在输出端口OUTPUT_PORT0
|
||||
#define LED_EN_CONFIG CONFIG_PORT0 //配置在P0_1
|
||||
#define LED_EN_OFF true //高电平关(PMOS)
|
||||
#define LED_EN_ON false //低电平开(PMOS)
|
||||
|
||||
/* 设置LCD的RST引脚 */
|
||||
#define LCD_RST_PIN 1 //LCD复位引脚对应IO扩展板引脚P1_1
|
||||
#define LCD_RST_CONFIG CONFIG_PORT1 //LCD复位引脚配置在P1_1
|
||||
#define LCD_RST_PORT OUTPUT_PORT1 //LCD复位引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define LCD_RST_HIGH true //LCD复位引脚状态为高电平
|
||||
#define LCD_RST_LOW false //LCD复位引脚状态为低电平
|
||||
|
||||
/* 设置PA控制引脚 */
|
||||
#define PA_CTRL_PIN 2 //PA控制引脚对应IO扩展板引脚P1_2
|
||||
#define PA_CTRL_CONFIG CONFIG_PORT1 //PA控制引脚配置在P1_2
|
||||
#define PA_CTRL_PORT OUTPUT_PORT1 //PA控制引脚挂载在IO扩展板的输出端口OUTPUT_PORT1
|
||||
#define PA_CTRL_HIGH true //PA控制引脚状态为高电平
|
||||
#define PA_CTRL_LOW false //PA控制引脚状态为低电平
|
||||
|
||||
// 电池充电检测引脚定义
|
||||
#define BATTERY_FULL_INPUT INPUT_PORT1 // 电池充满检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_FULL_PIN 3 // 电池充满检测引脚对应IO扩展板引脚P1_3
|
||||
#define BATTERY_FULL_CONFIG CONFIG_PORT1 // 电池充满检测引脚配置在P1_3
|
||||
|
||||
#define BATTERY_CHRG_INPUT INPUT_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
#define BATTERY_CHRG_PIN 5 // 充电检测引脚(P0_5)
|
||||
#define BATTERY_CHRG_CONFIG CONFIG_PORT0 // 充电检测引脚挂载在IO扩展板的输入端口
|
||||
|
||||
#define TAG_GPIO_IO_EXPAND_DETECT "GPIO_IO_EXPAND_DETECT" // GPIO中断检测日志标签
|
||||
#define TAG_I2C_IO_EXPAND_TASK "I2C_IO_EXPAND_TASK" // I2CIO扩展板任务日志标签
|
||||
|
||||
// GPIO引脚定义
|
||||
#define GPIO_INPUT_PIN_SEL GPIO_NUM_10 // IO扩展板中断检测引脚
|
||||
// #define IO_EXPAND_RSTN GPIO_NUM_14 // IO扩展板复位引脚
|
||||
|
||||
/**
|
||||
* @class IOExpansionBoard
|
||||
* @brief I/O扩展板驱动类,封装AW9523BTQR芯片操作
|
||||
*/
|
||||
class IOExpansionBoard
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 设置毫米波雷达指针
|
||||
* @param radar 毫米波雷达对象指针
|
||||
*/
|
||||
void SetRadar(MillimeterWaveRadar* radar) { radar_ = radar; };
|
||||
|
||||
/**
|
||||
* @brief 设置限位开关指针
|
||||
* @param photo_interrupter 限位开关对象指针
|
||||
*/
|
||||
void setPhotoInterrupter(PhotoInterrupter* photo_interrupter) { photo_interrupter_ = photo_interrupter; };
|
||||
|
||||
/**
|
||||
* @brief 设置电池监控器指针
|
||||
* @param battery_monitor 电池监控器对象指针
|
||||
*/
|
||||
void setBatteryMonitor(AdcBatteryMonitor* battery_monitor) { battery_monitor_ = battery_monitor; };
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~IOExpansionBoard();
|
||||
|
||||
/**
|
||||
* @brief 初始化GPIO中断检测
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化IO扩展板复位引脚
|
||||
* @param gpio_num 复位引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t ResetIoExpand();
|
||||
|
||||
/**
|
||||
* @brief 初始化I2C主机通信
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
// esp_err_t IoExpansionI2cInit();
|
||||
|
||||
/**
|
||||
* @brief 创建I2C数据读取任务
|
||||
*/
|
||||
void CreateI2cReadTask();
|
||||
|
||||
/**
|
||||
* @brief 启动I2C任务(整合初始化和任务创建)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StartTask();
|
||||
|
||||
/**
|
||||
* @brief 写寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandWriteReg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief 读寄存器数据
|
||||
* @param reg_addr 寄存器地址
|
||||
* @param data 要读出的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandReadReg(uint8_t reg_addr, uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口0寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort0(uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief 读取输入端口1寄存器数据
|
||||
* @param data 输出参数,用于存储读取到的数据
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t ReadInputPort1(uint8_t *data);
|
||||
|
||||
// /**
|
||||
// * @brief 设置IO扩展板GPIO中断状态 通过读取Input_Port0 和 Input_Port1 寄存器可以清除中断
|
||||
// * @param reg_addr 寄存器地址
|
||||
// * @return esp_err_t 操作结果
|
||||
// */
|
||||
// esp_err_t SetInterruptStatus(bool status);
|
||||
|
||||
/**
|
||||
* @brief 配置IO扩展版上的IO口为输出还是输入,并且设置初始为高电平
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t IoexpandSetMode();
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的细分模式
|
||||
* @param mode 模式:1/2/4/8/16/32/64
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
void SetStepperMicrostepMode(uint8_t mode, uint8_t OUTPUT_PORT_m0, uint8_t m0_pin, uint8_t OUTPUT_PORT_m1, uint8_t m1_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的方向
|
||||
* @param dir 方向
|
||||
* @param OUTPUT_PORT 输出端口
|
||||
* @param pin 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t StepperMotorSetDir(bool dir, uint8_t OUTPUT_PORT, uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的睡眠模式
|
||||
* @param 是否进入睡眠模式
|
||||
* @param 输出端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorSleepMode(bool mode, uint8_t OUTPUT_PORT, uint8_t nsleep_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置步进电机的使能引脚状态
|
||||
* @param 使能状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetMotorEnableMode(bool enable, uint8_t OUTPUT_PORT, uint8_t enable_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的BL引脚状态
|
||||
* @param BL状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdBlMode(bool mode, uint8_t OUTPUT_PORT, uint8_t bl_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置 LED_EN 引脚电平(用于控制LCD背光/LED灯电源)
|
||||
* @param mode true:开启(低电平), false:关闭(高电平)
|
||||
*/
|
||||
esp_err_t SetLedEnMode(bool mode);
|
||||
|
||||
/**
|
||||
* @brief 设置LCD的RST引脚状态
|
||||
* @param RST状态
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetLcdResetMode(bool mode, uint8_t OUTPUT_PORT, uint8_t rst_pin);
|
||||
|
||||
/**
|
||||
* @brief 设置PA控制引脚状态
|
||||
* @param mode PA_CTRL状态(true为高电平,false为低电平)
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetPaCtrlMode(bool mode);
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断引脚
|
||||
* @param 毫米波雷达的中断引脚模式
|
||||
* @param 输入端口
|
||||
* @param 引脚号
|
||||
* @return esp_err_t 操作结果
|
||||
*/
|
||||
esp_err_t SetRadarInterruptPin(bool mode, uint8_t INPUT_PORT, uint8_t interrupt_pin);
|
||||
|
||||
/**
|
||||
* @brief 计算Port0的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort0();
|
||||
|
||||
/**
|
||||
* @brief 计算Port1的字节值
|
||||
* @return uint8_t 操作结果
|
||||
*/
|
||||
uint8_t ByteCalculatePort1();
|
||||
|
||||
/**
|
||||
* @brief 设置雷达中断回调函数
|
||||
* @param callback 雷达中断回调函数
|
||||
*/
|
||||
void SetRadarCallback(RadarCallback callback) { radar_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器开始中断回调函数
|
||||
* @param callback 光学传感器开始中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterStartCallback(PhotoInterrupterStartCallback callback) { photo_start_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置光学传感器结束中断回调函数
|
||||
* @param callback 光学传感器结束中断回调函数
|
||||
*/
|
||||
void SetPhotoInterrupterEndCallback(PhotoInterrupterEndCallback callback) { photo_end_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充电中断回调函数
|
||||
* @param callback 电池充电中断回调函数
|
||||
*/
|
||||
void SetBatteryChargingCallback(BatteryChargingCallback callback) { battery_charging_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池充满中断回调函数
|
||||
* @param callback 电池充满中断回调函数
|
||||
*/
|
||||
void SetBatteryFullCallback(BatteryFullCallback callback) { battery_full_callback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 设置电池非充电中断回调函数
|
||||
* @param callback 电池非充电中断回调函数
|
||||
*/
|
||||
void SetBatteryNotChargingCallback(BatteryNotChargingCallback callback) { battery_not_charging_callback_ = callback; }
|
||||
|
||||
// 公共成员变量
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
uint8_t device_addr_; // I2C设备地址
|
||||
|
||||
private:
|
||||
// 静态成员函数
|
||||
MillimeterWaveRadar* radar_ = nullptr; // 毫米波雷达指针,用于触发回调
|
||||
PhotoInterrupter* photo_interrupter_ = nullptr; // 限位开关指针,用于触发回调
|
||||
AdcBatteryMonitor* battery_monitor_ = nullptr; // 电池监控器指针,用于触发回调
|
||||
static void IRAM_ATTR GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void I2cReadTask(void* pvParameters); // I2C数据读取任务函数
|
||||
|
||||
// 成员变量用于状态跟踪
|
||||
uint8_t last_port0_state_ = 0; // 上次检测到的Port0状态
|
||||
uint8_t last_port1_state_ = 0; // 上次检测到的Port1状态
|
||||
bool radar_last_state_ = false; // 雷达引脚上一次的状态
|
||||
bool battery_charging_last_state_ = false; // 电池充电状态上一次的状态
|
||||
bool battery_full_last_state_ = false; // 电池充满状态上一次的状态
|
||||
|
||||
// 回调函数成员变量
|
||||
RadarCallback radar_callback_ = nullptr;
|
||||
PhotoInterrupterStartCallback photo_start_callback_ = nullptr;
|
||||
PhotoInterrupterEndCallback photo_end_callback_ = nullptr;
|
||||
BatteryChargingCallback battery_charging_callback_ = nullptr;
|
||||
BatteryFullCallback battery_full_callback_ = nullptr;
|
||||
BatteryNotChargingCallback battery_not_charging_callback_ = nullptr;
|
||||
|
||||
// PhotoInterrupter* photo_interrupter_ = nullptr; // 光学传感器指针,用于触发回调
|
||||
// /**
|
||||
// * @brief 分配静态任务所需的内存
|
||||
// * @return bool 分配是否成功
|
||||
// */
|
||||
// bool AllocateStaticTaskMemory();
|
||||
|
||||
// /**
|
||||
// * @brief 释放静态任务分配的内存
|
||||
// */
|
||||
// void FreeStaticTaskMemory();
|
||||
|
||||
// 实例成员变量
|
||||
EventGroupHandle_t i2c_task_event_group_ = nullptr; // 事件组
|
||||
TaskHandle_t xI2CReadTaskHandle_ = nullptr; // 任务句柄
|
||||
bool is_initialized_ = false; // 初始化状态标记(新增)
|
||||
gpio_num_t interrupt_gpio_ = GPIO_NUM_NC; // 中断引脚
|
||||
gpio_num_t reset_gpio_ = GPIO_NUM_NC; // 复位引脚
|
||||
|
||||
// StackType_t* pI2CReadTaskStackBuffer = nullptr; // 任务栈指针(PSRAM)
|
||||
// StaticTask_t* pxI2CReadTaskBuffer = nullptr; // 任务控制块指针(内部RAM)
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @file power_management_config.h
|
||||
* @brief 功耗管理配置和策略定义
|
||||
* @author Embedded Software Expert
|
||||
* @date 2025年1月
|
||||
*
|
||||
* 这个文件定义了功耗管理的配置参数、策略和优化建议,
|
||||
* 为系统提供灵活的功耗管理方案。
|
||||
*/
|
||||
|
||||
#ifndef POWER_MANAGEMENT_CONFIG_H
|
||||
#define POWER_MANAGEMENT_CONFIG_H
|
||||
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
|
||||
/**
|
||||
* @brief 功耗管理配置结构体
|
||||
*/
|
||||
typedef struct {
|
||||
// 睡眠模式配置
|
||||
uint64_t light_sleep_duration_us; // 轻度睡眠持续时间(微秒)
|
||||
uint64_t deep_sleep_duration_us; // 深度睡眠持续时间(微秒)
|
||||
|
||||
// 唤醒源配置
|
||||
bool enable_timer_wakeup; // 启用定时器唤醒
|
||||
bool enable_gpio_wakeup; // 启用GPIO唤醒
|
||||
bool enable_touch_wakeup; // 启用触摸唤醒
|
||||
gpio_num_t wakeup_gpio_num; // 唤醒GPIO编号
|
||||
int wakeup_level; // 唤醒电平(0或1)
|
||||
|
||||
// 功耗优化配置
|
||||
bool disable_bt_in_sleep; // 睡眠时关闭蓝牙
|
||||
bool disable_wifi_in_sleep; // 睡眠时关闭WiFi
|
||||
bool reduce_cpu_frequency; // 降低CPU频率
|
||||
uint32_t cpu_frequency_hz; // CPU频率(Hz)
|
||||
|
||||
// 外设功耗配置
|
||||
bool power_down_sdcard; // 睡眠时关闭SD卡电源
|
||||
bool power_down_display; // 睡眠时关闭显示电源
|
||||
bool power_down_audio; // 睡眠时关闭音频电源
|
||||
bool power_down_motor; // 睡眠时关闭电机电源
|
||||
|
||||
// RTC内存配置
|
||||
bool preserve_rtc_memory; // 保留RTC内存
|
||||
size_t rtc_memory_size; // RTC内存大小
|
||||
} power_management_config_t;
|
||||
|
||||
/**
|
||||
* @brief 默认功耗管理配置
|
||||
*/
|
||||
#define DEFAULT_POWER_CONFIG { \
|
||||
.light_sleep_duration_us = 1000000, /* 1秒 */ \
|
||||
.deep_sleep_duration_us = 30000000, /* 30秒 */ \
|
||||
.enable_timer_wakeup = true, /* 启用定时器唤醒 */ \
|
||||
.enable_gpio_wakeup = false, /* 不启用GPIO唤醒 */ \
|
||||
.enable_touch_wakeup = false, /* 不启用触摸唤醒 */ \
|
||||
.wakeup_gpio_num = GPIO_NUM_NC, /* 无GPIO唤醒 */ \
|
||||
.wakeup_level = 0, /* 低电平唤醒 */ \
|
||||
.disable_bt_in_sleep = true, /* 睡眠时关闭蓝牙 */ \
|
||||
.disable_wifi_in_sleep = true, /* 睡眠时关闭WiFi */ \
|
||||
.reduce_cpu_frequency = true, /* 降低CPU频率 */ \
|
||||
.cpu_frequency_hz = 80000000, /* 80MHz */ \
|
||||
.power_down_sdcard = true, /* 睡眠时关闭SD卡 */ \
|
||||
.power_down_display = true, /* 睡眠时关闭显示 */ \
|
||||
.power_down_audio = true, /* 睡眠时关闭音频 */ \
|
||||
.power_down_motor = true, /* 睡眠时关闭电机 */ \
|
||||
.preserve_rtc_memory = true, /* 保留RTC内存 */ \
|
||||
.rtc_memory_size = 4096, /* 4KB RTC内存 */ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 各功耗模式的详细配置
|
||||
*/
|
||||
static const power_management_config_t idle_mode_config = {
|
||||
.light_sleep_duration_us = 500000, // 500ms轻度睡眠
|
||||
.deep_sleep_duration_us = 0, // 不使用深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0, // 按键唤醒
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = false, // 保持蓝牙连接
|
||||
.disable_wifi_in_sleep = false, // 保持WiFi连接
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000, // 40MHz
|
||||
.power_down_sdcard = false, // 保持SD卡(可能有后台任务)
|
||||
.power_down_display = true, // 关闭显示背光
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 2048,
|
||||
};
|
||||
|
||||
static const power_management_config_t light_sleep_config = {
|
||||
.light_sleep_duration_us = 0, // 直接进入轻度睡眠
|
||||
.deep_sleep_duration_us = 0,
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 40000000,
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 4096,
|
||||
};
|
||||
|
||||
static const power_management_config_t deep_sleep_config = {
|
||||
.light_sleep_duration_us = 0,
|
||||
.deep_sleep_duration_us = 60000000, // 60秒深度睡眠
|
||||
.enable_timer_wakeup = true,
|
||||
.enable_gpio_wakeup = true,
|
||||
.wakeup_gpio_num = GPIO_NUM_0,
|
||||
.wakeup_level = 0,
|
||||
.disable_bt_in_sleep = true, // 关闭蓝牙
|
||||
.disable_wifi_in_sleep = true, // 关闭WiFi
|
||||
.reduce_cpu_frequency = true,
|
||||
.cpu_frequency_hz = 10000000, // 10MHz
|
||||
.power_down_sdcard = true, // 关闭SD卡
|
||||
.power_down_display = true, // 关闭显示
|
||||
.power_down_audio = true, // 关闭音频
|
||||
.power_down_motor = true, // 关闭电机
|
||||
.preserve_rtc_memory = true,
|
||||
.rtc_memory_size = 8192,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 功耗统计和监控结构体
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t total_sleep_time_us; // 总睡眠时间
|
||||
uint64_t total_wake_time_us; // 总唤醒时间
|
||||
uint32_t sleep_count; // 睡眠次数
|
||||
uint32_t wake_count; // 唤醒次数
|
||||
uint32_t average_sleep_duration_us; // 平均睡眠时长
|
||||
uint32_t average_wake_duration_us; // 平均唤醒时长
|
||||
float estimated_power_saving_percent; // 估计的功耗节省百分比
|
||||
} power_statistics_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗优化建议
|
||||
*
|
||||
* 基于硬件特性和使用模式,提供功耗优化建议
|
||||
*/
|
||||
typedef enum {
|
||||
OPTIMIZATION_NONE = 0,
|
||||
OPTIMIZATION_REDUCE_CPU_FREQ, // 降低CPU频率
|
||||
OPTIMIZATION_DISABLE_UNUSED_PERIPHERALS, // 关闭未使用的外设
|
||||
OPTIMIZATION_USE_LIGHT_SLEEP, // 使用轻度睡眠
|
||||
OPTIMIZATION_USE_DEEP_SLEEP, // 使用深度睡眠
|
||||
OPTIMIZATION_OPTIMIZE_GPIO_STATES, // 优化GPIO状态
|
||||
OPTIMIZATION_USE_RTC_MEMORY, // 使用RTC内存
|
||||
OPTIMIZATION_BATCH_OPERATIONS, // 批量操作
|
||||
} power_optimization_t;
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件回调
|
||||
*/
|
||||
typedef void (*power_event_callback_t)(power_mode_t old_mode, power_mode_t new_mode, void* user_data);
|
||||
|
||||
/**
|
||||
* @brief 功耗管理事件
|
||||
*/
|
||||
typedef enum {
|
||||
POWER_EVENT_MODE_CHANGE, // 功耗模式改变
|
||||
POWER_EVENT_SLEEP_START, // 睡眠开始
|
||||
POWER_EVENT_SLEEP_END, // 睡眠结束
|
||||
POWER_EVENT_WAKEUP, // 系统唤醒
|
||||
POWER_EVENT_OPTIMIZATION_TRIGGER, // 功耗优化触发
|
||||
} power_event_t;
|
||||
|
||||
#endif // POWER_MANAGEMENT_CONFIG_H
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef BOARD_CONFIG_H
|
||||
#define BOARD_CONFIG_H
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// 根据menuconfig的配置选择不同版本的config.h文件
|
||||
#ifdef CONFIG_BOARD_VERSION_V1_1_11
|
||||
#include "boards/board_v1_1_11/config.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_12)
|
||||
#include "boards/board_v1_1_12/config.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_13)
|
||||
#include "boards/board_v1_1_13/config.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_14)
|
||||
#include "boards/board_v1_1_14/config.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_16)
|
||||
#include "boards/board_v1_1_16/config.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_17)
|
||||
#include "boards/board_v1_1_17/config.h"
|
||||
#elif defined(CONFIG_BOARD_VERSION_V1_1_18)
|
||||
#include "boards/board_v1_1_18/config.h"
|
||||
#else
|
||||
// 默认使用v1.1.11版本,避免编译错误
|
||||
#include "boards/board_v1_1_13/config.h"
|
||||
#endif
|
||||
|
||||
#endif // BOARD_CONFIG_H
|
||||
@@ -0,0 +1,35 @@
|
||||
# 根据 menuconfig 中选择的板卡配置,自动匹配 boards/board_v* 目录
|
||||
# 这样新增板卡时,只要:
|
||||
# 1. 增加对应的 Kconfig 项,例如 CONFIG_BOARD_VERSION_V1_1_18
|
||||
# 2. 新增目录 02_physical/boards/board_v1_1_18/
|
||||
# 就不需要再修改 main/CMakeLists.txt
|
||||
|
||||
set(BOARD_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}")
|
||||
set(MAIN_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../..")
|
||||
set(SELECTED_BOARD_DIR "")
|
||||
|
||||
file(GLOB BOARD_CANDIDATE_DIRS RELATIVE "${BOARD_ROOT_DIR}" "${BOARD_ROOT_DIR}/board_v*")
|
||||
|
||||
foreach(board_dir ${BOARD_CANDIDATE_DIRS})
|
||||
if(IS_DIRECTORY "${BOARD_ROOT_DIR}/${board_dir}")
|
||||
string(REGEX REPLACE "^board_" "" board_suffix "${board_dir}")
|
||||
string(TOUPPER "${board_suffix}" board_suffix_upper)
|
||||
set(board_config_var "CONFIG_BOARD_VERSION_${board_suffix_upper}")
|
||||
|
||||
if(DEFINED ${board_config_var} AND ${board_config_var})
|
||||
set(SELECTED_BOARD_DIR "02_physical/boards/${board_dir}")
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT SELECTED_BOARD_DIR)
|
||||
message(FATAL_ERROR "Please select a board version in menuconfig")
|
||||
endif()
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${SELECTED_BOARD_DIR}/board_sweekar.cc")
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${SELECTED_BOARD_DIR}/io_expansion_board.cc")
|
||||
target_include_directories(${COMPONENT_LIB} PRIVATE "${SELECTED_BOARD_DIR}")
|
||||
|
||||
# 添加到 main 目录,使类似 "boards/config.h" 的包含路径保持兼容
|
||||
target_include_directories(${COMPONENT_LIB} PRIVATE "${MAIN_ROOT_DIR}")
|
||||
@@ -0,0 +1,247 @@
|
||||
#include "audio_codec.h"
|
||||
#include "esp_log.h"
|
||||
#include "es7210.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "AudioCodec";
|
||||
|
||||
// 静态成员初始化
|
||||
AudioCodec* AudioCodec::instance_ = nullptr;
|
||||
SemaphoreHandle_t AudioCodec::mutex_ = nullptr;
|
||||
|
||||
AudioCodec::AudioCodec()
|
||||
: board_handle_(nullptr),
|
||||
is_initialized_(false),
|
||||
current_mode_(AUDIO_CODEC_MODE_DECODE),
|
||||
current_volume_(100)
|
||||
{
|
||||
}
|
||||
|
||||
AudioCodec::~AudioCodec() {
|
||||
Deinitialize();
|
||||
}
|
||||
|
||||
AudioCodec* AudioCodec::GetInstance() {
|
||||
// 双重检查锁定模式确保线程安全
|
||||
if (instance_ == nullptr) {
|
||||
if (mutex_ == nullptr) {
|
||||
mutex_ = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(mutex_, portMAX_DELAY) == pdTRUE) {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new AudioCodec();
|
||||
}
|
||||
xSemaphoreGive(mutex_);
|
||||
}
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::Initialize() {
|
||||
if (is_initialized_) {
|
||||
ESP_LOGW(TAG, "AudioCodec already initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Initializing AudioCodec");
|
||||
|
||||
esp_err_t ret = InitializeBoard();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio board: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 先设置初始化标志,然后启动编解码器
|
||||
is_initialized_ = true;
|
||||
|
||||
// 默认启用双向模式,同时支持播放和录音
|
||||
ret = StartCodec(AUDIO_CODEC_MODE_BOTH);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start codec in both mode: %s", esp_err_to_name(ret));
|
||||
is_initialized_ = false; // 如果启动失败,重置标志
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "AudioCodec initialized successfully with both encode and decode enabled");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::InitializeBoard() {
|
||||
// 初始化音频板
|
||||
board_handle_ = audio_board_init();
|
||||
if (board_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio board");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Audio board initialized successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::StartCodec(audio_codec_mode_t mode) {
|
||||
// 检查音频板是否已初始化,而不是检查整体初始化状态
|
||||
if (board_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Audio board not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
switch (mode) {
|
||||
case AUDIO_CODEC_MODE_DECODE:
|
||||
ESP_LOGI(TAG, "Starting codec in decode mode");
|
||||
ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START);
|
||||
break;
|
||||
|
||||
case AUDIO_CODEC_MODE_ENCODE:
|
||||
ESP_LOGI(TAG, "Starting codec in encode mode");
|
||||
ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_ENCODE, AUDIO_HAL_CTRL_START);
|
||||
if (ret == ESP_OK) {
|
||||
// 设置ADC音量
|
||||
ret = audio_hal_set_volume(board_handle_->adc_hal, 100);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
// 设置ES7210麦克风增益
|
||||
ret = es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to set ES7210 gain: %s", esp_err_to_name(ret));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ES7210 gain set to 37.5dB");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_CODEC_MODE_BOTH:
|
||||
ESP_LOGI(TAG, "Starting codec in both modes");
|
||||
ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
|
||||
if (ret == ESP_OK) {
|
||||
// 同时设置播放和录音参数
|
||||
audio_hal_set_volume(board_handle_->adc_hal, 100);
|
||||
es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid codec mode: %d", mode);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start codec: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
current_mode_ = mode;
|
||||
|
||||
// 设置初始音量(仅在播放模式下)
|
||||
if (mode == AUDIO_CODEC_MODE_DECODE || mode == AUDIO_CODEC_MODE_BOTH) {
|
||||
SetVolume(current_volume_);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Codec started successfully in mode %d", mode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::StopCodec() {
|
||||
if (!is_initialized_) {
|
||||
ESP_LOGW(TAG, "AudioCodec not initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Stopping codec");
|
||||
// 修复:直接使用audio_hal_codec_mode_t类型
|
||||
esp_err_t ret = audio_hal_ctrl_codec(board_handle_->audio_hal, (audio_hal_codec_mode_t)current_mode_, AUDIO_HAL_CTRL_STOP);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to stop codec: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::SetVolume(uint8_t volume) {
|
||||
if (!is_initialized_) {
|
||||
ESP_LOGE(TAG, "AudioCodec not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (volume > 100) {
|
||||
ESP_LOGW(TAG, "Volume %d exceeds maximum, setting to 100", volume);
|
||||
volume = 100;
|
||||
}
|
||||
|
||||
// 转换为HAL音量范围 (0-63)
|
||||
int hal_volume = (volume * 63) / 100;
|
||||
esp_err_t ret = audio_hal_set_volume(board_handle_->audio_hal, hal_volume);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set volume: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
current_volume_ = volume;
|
||||
ESP_LOGI(TAG, "Volume set to %d%% (HAL volume: %d)", volume, hal_volume);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::GetVolume(uint8_t* volume) {
|
||||
if (!volume) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*volume = current_volume_;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::SetAdcVolume(uint8_t volume) {
|
||||
if (!is_initialized_) {
|
||||
ESP_LOGE(TAG, "AudioCodec not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
|
||||
esp_err_t ret = audio_hal_set_volume(board_handle_->adc_hal, volume);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "ADC volume set to %d", volume);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
audio_board_handle_t AudioCodec::GetBoardHandle() {
|
||||
return board_handle_;
|
||||
}
|
||||
|
||||
bool AudioCodec::IsInitialized() {
|
||||
return is_initialized_;
|
||||
}
|
||||
|
||||
esp_err_t AudioCodec::Deinitialize() {
|
||||
if (!is_initialized_) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Deinitializing AudioCodec");
|
||||
|
||||
StopCodec();
|
||||
Cleanup();
|
||||
|
||||
is_initialized_ = false;
|
||||
ESP_LOGI(TAG, "AudioCodec deinitialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void AudioCodec::Cleanup() {
|
||||
if (board_handle_) {
|
||||
audio_board_deinit(board_handle_);
|
||||
board_handle_ = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef AUDIO_CODEC_H
|
||||
#define AUDIO_CODEC_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "audio_hal.h"
|
||||
#include "board.h"
|
||||
#include "esp_peripherals.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 使用audio_hal中已定义的模式类型,避免重复定义
|
||||
typedef audio_hal_codec_mode_t audio_codec_mode_t;
|
||||
|
||||
// 为了代码可读性,定义别名
|
||||
#define AUDIO_CODEC_MODE_DECODE AUDIO_HAL_CODEC_MODE_DECODE
|
||||
#define AUDIO_CODEC_MODE_ENCODE AUDIO_HAL_CODEC_MODE_ENCODE
|
||||
#define AUDIO_CODEC_MODE_BOTH AUDIO_HAL_CODEC_MODE_BOTH
|
||||
|
||||
class AudioCodec {
|
||||
public:
|
||||
// 获取单例实例
|
||||
static AudioCodec* GetInstance();
|
||||
|
||||
// 初始化音频编解码器(默认启用双向模式)
|
||||
esp_err_t Initialize();
|
||||
|
||||
// 音量控制
|
||||
esp_err_t SetVolume(uint8_t volume);
|
||||
esp_err_t GetVolume(uint8_t* volume);
|
||||
|
||||
// ADC音量控制(录音)
|
||||
esp_err_t SetAdcVolume(uint8_t volume);
|
||||
|
||||
// 获取音频板句柄
|
||||
audio_board_handle_t GetBoardHandle();
|
||||
|
||||
// 检查是否已初始化
|
||||
bool IsInitialized();
|
||||
|
||||
// 反初始化
|
||||
esp_err_t Deinitialize();
|
||||
|
||||
private:
|
||||
AudioCodec(); // 私有构造函数
|
||||
~AudioCodec();
|
||||
|
||||
// 禁止拷贝构造和赋值
|
||||
AudioCodec(const AudioCodec&) = delete;
|
||||
AudioCodec& operator=(const AudioCodec&) = delete;
|
||||
|
||||
static AudioCodec* instance_;
|
||||
static SemaphoreHandle_t mutex_;
|
||||
|
||||
audio_board_handle_t board_handle_;
|
||||
bool is_initialized_;
|
||||
audio_codec_mode_t current_mode_;
|
||||
uint8_t current_volume_;
|
||||
|
||||
esp_err_t InitializeBoard();
|
||||
void Cleanup();
|
||||
esp_err_t StartCodec(audio_codec_mode_t mode);
|
||||
esp_err_t StopCodec();
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // AUDIO_CODEC_H
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/04_hal/audio_codec/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_HAL_AUDIO_CODEC AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] audio_codec module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"04_hal/audio_codec/audio_codec.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"04_hal/audio_codec"
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Base Board Hardware Abstraction Layer
|
||||
* Abstracts the communication transport (UART vs I2C) and sensor reading.
|
||||
*/
|
||||
class BaseBoardHal
|
||||
{
|
||||
public:
|
||||
virtual ~BaseBoardHal() = default;
|
||||
|
||||
/**
|
||||
* @brief Initialize the hardware interface
|
||||
*/
|
||||
virtual esp_err_t Init() = 0;
|
||||
|
||||
/**
|
||||
* @brief Send raw data to the base board
|
||||
* @param data Pointer to data buffer
|
||||
* @param len Length of data
|
||||
*/
|
||||
virtual esp_err_t Send(const uint8_t *data, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* @brief Read raw data from the base board
|
||||
* @param data Pointer to data buffer
|
||||
* @param len Length of data to read
|
||||
*/
|
||||
virtual esp_err_t Read(uint8_t *data, size_t len) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the current angle from Hall sensor (or via query)
|
||||
* @param[out] angle Output angle in degrees (0.0 - 360.0)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t GetAngle(float *angle) = 0;
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_board_hal.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
class BaseBoardHalI2c : public BaseBoardHal
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kBaseSlaveAddr = 0x22;
|
||||
// TMAG5273 default address often 0x35 or defined by config
|
||||
static constexpr uint8_t kHallSensorAddr = 0x35;
|
||||
|
||||
BaseBoardHalI2c(i2c_bus_handle_t bus_handle)
|
||||
: bus_handle_(bus_handle) {}
|
||||
|
||||
virtual ~BaseBoardHalI2c()
|
||||
{
|
||||
// i2c_bus handles device management internally if used via i2c_bus_create
|
||||
// But here we just use the bus handle directly.
|
||||
}
|
||||
|
||||
virtual esp_err_t Init() override
|
||||
{
|
||||
if (!bus_handle_) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
// Check if device is alive
|
||||
esp_err_t err = i2c_bus_probe_addr(bus_handle_, kBaseSlaveAddr << 1);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW("BaseBoardHalI2c", "Base board not found at 0x%02X", kBaseSlaveAddr);
|
||||
// Don't fail init, maybe it's sleeping
|
||||
} else {
|
||||
ESP_LOGI("BaseBoardHalI2c", "Base board found at 0x%02X", kBaseSlaveAddr);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
virtual esp_err_t Send(const uint8_t *data, size_t len) override
|
||||
{
|
||||
if (!bus_handle_) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
// i2c_bus_write_bytes expects: bus, addr, reg_addr, reg_len, data, datalen
|
||||
// The data pointer in i2c_bus_write_bytes is (uint8_t *), not (const uint8_t *)
|
||||
// This is a common issue in legacy C APIs. We have to cast away constness.
|
||||
|
||||
return i2c_bus_write_bytes(bus_handle_, kBaseSlaveAddr << 1, NULL, 0, (uint8_t*)data, len);
|
||||
}
|
||||
|
||||
virtual esp_err_t Read(uint8_t *data, size_t len) override
|
||||
{
|
||||
if (!bus_handle_) return ESP_ERR_INVALID_STATE;
|
||||
|
||||
return i2c_bus_read_bytes(bus_handle_, kBaseSlaveAddr << 1, NULL, 0, data, len);
|
||||
}
|
||||
|
||||
virtual esp_err_t GetAngle(float *angle) override
|
||||
{
|
||||
// TODO: Implement TMAG5273 read logic using i2c_bus_read_bytes
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
private:
|
||||
i2c_bus_handle_t bus_handle_;
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_board_hal.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
class BaseBoardHalUart : public BaseBoardHal
|
||||
{
|
||||
public:
|
||||
BaseBoardHalUart(uart_port_t port) : port_(port) {}
|
||||
virtual ~BaseBoardHalUart() = default;
|
||||
|
||||
virtual esp_err_t Init() override
|
||||
{
|
||||
// Assuming UART is already initialized by board.cc or similar
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
virtual esp_err_t Send(const uint8_t *data, size_t len) override
|
||||
{
|
||||
if (port_ >= UART_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
int written = uart_write_bytes(port_, (const char *)data, len);
|
||||
return (written == (int)len) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
virtual esp_err_t Read(uint8_t *data, size_t len) override
|
||||
{
|
||||
if (port_ >= UART_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
int read = uart_read_bytes(port_, data, len, pdMS_TO_TICKS(100));
|
||||
return (read == (int)len) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
virtual esp_err_t GetAngle(float *angle) override
|
||||
{
|
||||
// TODO: Implement angle reading via UART (query command or report parsing)
|
||||
// For now, return not supported or cached value if we had one
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
private:
|
||||
uart_port_t port_;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
# main/04_hal/base_board_hal/module.cmake
|
||||
|
||||
# 注意:此文件夹可能没有 cpp 源文件,仅有头文件。如果有源文件,请追加到 MODULE_SRCS。
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_HAL_BASE_BOARD_HAL AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] base_board_hal module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"04_hal/base_board_hal"
|
||||
)
|
||||
@@ -0,0 +1,213 @@
|
||||
#include "aw8646.h"
|
||||
#include "config.h"
|
||||
#include "esp_log.h"
|
||||
#include "io_expansion_board.h"
|
||||
|
||||
// Define AW8646 specific pins for Board v1.1.16
|
||||
// P0_0 -> DRV_T0
|
||||
// P0_6 -> DRV_T1
|
||||
// Only if NFC_RST_PIN is defined (implying it's moved to GPIO, freeing up P0_0)
|
||||
#ifdef NFC_RST_PIN
|
||||
#define AW8646_USE_CURRENT_CONTROL
|
||||
#define AW8646_T0_PIN 0
|
||||
#define AW8646_T0_PORT OUTPUT_PORT0
|
||||
#define AW8646_T1_PIN 6
|
||||
#define AW8646_T1_PORT OUTPUT_PORT0
|
||||
#endif
|
||||
|
||||
Aw8646Driver::Aw8646Driver(IOExpansionBoard &ioExp) : io_expansion_(ioExp)
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::Init()
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1. 默认处于休眠和禁用状态,防止发热!
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_SLEEP,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set sleep mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 2. Disable Enable Pin (High = Disable for AW8646)
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
true, // High -> Disable
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set enable mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef AW8646_USE_CURRENT_CONTROL
|
||||
// 3. Initialize T0 and T1 pins for Current Control
|
||||
// Default to Low (0, 0) for now.
|
||||
uint8_t output0_val = 0;
|
||||
err = io_expansion_.IoexpandReadReg(OUTPUT_PORT0, &output0_val);
|
||||
if (err == ESP_OK) {
|
||||
output0_val &= ~(1 << AW8646_T0_PIN); // Set T0 Low
|
||||
output0_val &= ~(1 << AW8646_T1_PIN); // Set T1 Low
|
||||
err = io_expansion_.IoexpandWriteReg(OUTPUT_PORT0, output0_val);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set T0/T1: 0x%x", err);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to read port 0: 0x%x", err);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 4. Set Microsteps (Default to 1/8 step)
|
||||
err = SetMicrosteps(8);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set microsteps: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 5. Set Default Direction
|
||||
err = SetDirection(true);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set direction: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "AW8646 Driver Initialized (EN Logic Inverted, T0/T1 Configured)");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::Enable(bool enable)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (enable)
|
||||
{
|
||||
ESP_LOGD(TAG, "Enabling AW8646 (sleep + enable=Low)");
|
||||
|
||||
// Ensure Sleep is High (Work)
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_WORK,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Enable Pin: Low to Enable
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
false, // Low -> Enable
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, "Disabling AW8646 (disable=High + sleep)");
|
||||
|
||||
// Enable Pin: High to Disable
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
true, // High -> Disable
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Sleep Pin: Low to Sleep
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_SLEEP,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::SetDirection(bool dir)
|
||||
{
|
||||
uint8_t mode = dir ? STEPPER_MOTOR_RIGHT : STEPPER_MOTOR_LEFT;
|
||||
|
||||
return io_expansion_.StepperMotorSetDir(
|
||||
mode,
|
||||
STEPPER_MOTOR_DIR_PORT,
|
||||
STEPPER_MOTOR_DIR_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::Sleep(bool sleep)
|
||||
{
|
||||
uint8_t mode = sleep ? STEPPER_MOTOR_SLEEP : STEPPER_MOTOR_WORK;
|
||||
return io_expansion_.SetMotorSleepMode(
|
||||
mode,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::SetTriLevelPin(uint8_t port_reg, uint8_t config_reg, uint8_t pin, int state)
|
||||
{
|
||||
uint8_t val;
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
if (state == 2) { // Hi-Z -> Input
|
||||
// Set as Input
|
||||
err = io_expansion_.IoexpandReadReg(config_reg, &val);
|
||||
if (err != ESP_OK) return err;
|
||||
val |= (1 << pin); // Set Input
|
||||
err = io_expansion_.IoexpandWriteReg(config_reg, val);
|
||||
} else { // 0 or 1 -> Output
|
||||
// Set as Output
|
||||
err = io_expansion_.IoexpandReadReg(config_reg, &val);
|
||||
if (err != ESP_OK) return err;
|
||||
val &= ~(1 << pin); // Set Output
|
||||
err = io_expansion_.IoexpandWriteReg(config_reg, val);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Set Level
|
||||
err = io_expansion_.IoexpandReadReg(port_reg, &val);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
if (state == 1) val |= (1 << pin);
|
||||
else val &= ~(1 << pin);
|
||||
|
||||
err = io_expansion_.IoexpandWriteReg(port_reg, val);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t Aw8646Driver::SetMicrosteps(int microsteps)
|
||||
{
|
||||
// AW8646 Microstep Table (Rising Edge Only)
|
||||
// 1 (Full): MODE1=0, MODE0=0
|
||||
// 2 (1/2): MODE1=0, MODE0=Z (Hi-Z)
|
||||
// 4 (1/4): MODE1=0, MODE0=1
|
||||
// 8 (1/8): MODE1=Z, MODE0=0
|
||||
// 16 (1/16): MODE1=Z, MODE0=1
|
||||
// 32 (1/32): MODE1=1, MODE0=Z
|
||||
|
||||
int m1 = 0;
|
||||
int m0 = 0;
|
||||
|
||||
switch(microsteps) {
|
||||
case 1: m1 = 0; m0 = 0; break;
|
||||
case 2: m1 = 0; m0 = 2; break; // Z
|
||||
case 4: m1 = 0; m0 = 1; break;
|
||||
case 8: m1 = 2; m0 = 0; break; // Z
|
||||
case 16: m1 = 2; m0 = 1; break; // Z
|
||||
case 32: m1 = 1; m0 = 2; break; // Z
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unsupported microsteps: %d, defaulting to 1/8", microsteps);
|
||||
m1 = 2; m0 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Setting Microsteps to 1/%d (M1=%d, M0=%d)", microsteps, m1, m0);
|
||||
|
||||
esp_err_t err;
|
||||
err = SetTriLevelPin(STEPPER_MOTOR_M1_MADE_PORT, STEPPER_MOTOR_M1_CONFIG, STEPPER_MOTOR_M1_PIN, m1);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
err = SetTriLevelPin(STEPPER_MOTOR_M0_MADE_PORT, STEPPER_MOTOR_M0_CONFIG, STEPPER_MOTOR_M0_PIN, m0);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef AW8646_DRIVER_H
|
||||
#define AW8646_DRIVER_H
|
||||
|
||||
#include "stepper_driver.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
class Aw8646Driver : public StepperDriver
|
||||
{
|
||||
public:
|
||||
explicit Aw8646Driver(IOExpansionBoard &ioExp);
|
||||
virtual ~Aw8646Driver() = default;
|
||||
|
||||
esp_err_t Init() override;
|
||||
esp_err_t Enable(bool enable) override;
|
||||
esp_err_t SetDirection(bool dir) override;
|
||||
esp_err_t Sleep(bool sleep) override;
|
||||
esp_err_t SetMicrosteps(int microsteps) override;
|
||||
|
||||
private:
|
||||
esp_err_t SetTriLevelPin(uint8_t port_reg, uint8_t config_reg, uint8_t pin, int state);
|
||||
|
||||
IOExpansionBoard &io_expansion_;
|
||||
const char* TAG = "Aw8646Driver";
|
||||
};
|
||||
|
||||
#endif // AW8646_DRIVER_H
|
||||
Binary file not shown.
@@ -0,0 +1,147 @@
|
||||
#include "drv8428.h"
|
||||
#include "config.h"
|
||||
|
||||
Drv8428Driver::Drv8428Driver(IOExpansionBoard &ioExp) : io_expansion_(ioExp)
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::Init()
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// 1. Set Sleep Mode to WORK (wake up initially to configure?)
|
||||
// Actually BoardSweekar::StepperMotorInit sets it to WORK then ENABLE_DISABLE.
|
||||
// Let's follow that.
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_WORK,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set sleep mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 2. Disable Enable Pin
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
STEPPER_MOTOR_ENABLE_DISABLE,
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set enable mode: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 3. Set Microsteps (Defaulting to 1/8 as per original code which passed 4? need to verify)
|
||||
// BoardSweekar passed 4.
|
||||
// "io_expansion_.SetStepperMicrostepMode(4, ...)"
|
||||
// Let's assume 4 maps to 1/8 or whatever.
|
||||
err = SetMicrosteps(4);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set microsteps: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 4. Set Default Direction
|
||||
err = SetDirection(true); // Default to "UP" or whatever true means
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set direction: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "DRV8428 Driver Initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::Enable(bool enable)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (enable)
|
||||
{
|
||||
ESP_LOGD(TAG, "Enabling stepper motor (sleep + enable)");
|
||||
|
||||
// 1. Set sleep mode to WORK
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_WORK,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 2. Set enable mode to ENABLE
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
STEPPER_MOTOR_ENABLE_ENABLE,
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGD(TAG, "Disabling stepper motor (disable + sleep)");
|
||||
|
||||
// 1. Disable enable pin
|
||||
err = io_expansion_.SetMotorEnableMode(
|
||||
STEPPER_MOTOR_ENABLE_DISABLE,
|
||||
STEPPER_MOTOR_ENABLE_PORT,
|
||||
STEPPER_MOTOR_ENABLE_PIN
|
||||
);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 2. Set sleep mode to SLEEP
|
||||
err = io_expansion_.SetMotorSleepMode(
|
||||
STEPPER_MOTOR_SLEEP,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::SetDirection(bool dir)
|
||||
{
|
||||
// dir: true=UP, false=DOWN (based on original StepperMotor::SetDir logic)
|
||||
// Original: dir ? STEPPER_MOTOR_RIGHT : STEPPER_MOTOR_LEFT
|
||||
// Wait, StepperMotor::SetDir used STEPPER_MOTOR_RIGHT for true.
|
||||
// STEPPER_MOTOR_RIGHT is a macro, likely 1 or 0.
|
||||
|
||||
uint8_t mode = dir ? STEPPER_MOTOR_RIGHT : STEPPER_MOTOR_LEFT;
|
||||
|
||||
return io_expansion_.StepperMotorSetDir(
|
||||
mode,
|
||||
STEPPER_MOTOR_DIR_PORT,
|
||||
STEPPER_MOTOR_DIR_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::Sleep(bool sleep)
|
||||
{
|
||||
// This is explicitly setting sleep mode, might be redundant with Enable(false)
|
||||
// but useful if we want to sleep without disabling or vice versa if supported.
|
||||
// For DRV8428, Enable(false) sets Sleep to SLEEP.
|
||||
|
||||
uint8_t mode = sleep ? STEPPER_MOTOR_SLEEP : STEPPER_MOTOR_WORK;
|
||||
return io_expansion_.SetMotorSleepMode(
|
||||
mode,
|
||||
STEPPER_MOTOR_SLEEP_PORT,
|
||||
STEPPER_MOTOR_SLEEP_PIN
|
||||
);
|
||||
}
|
||||
|
||||
esp_err_t Drv8428Driver::SetMicrosteps(int microsteps)
|
||||
{
|
||||
// Original code used hardcoded ports for microsteps.
|
||||
// io_expansion_.SetStepperMicrostepMode(4, STEPPER_MOTOR_M0_MADE_PORT, STEPPER_MOTOR_M0_PIN,
|
||||
// STEPPER_MOTOR_M1_MADE_PORT, STEPPER_MOTOR_M1_PIN);
|
||||
|
||||
// We can just pass the value 'microsteps' if it corresponds to the index expected by SetStepperMicrostepMode.
|
||||
// Or we might need a mapping.
|
||||
// Assuming 'microsteps' passed here is the raw value/index for now.
|
||||
|
||||
io_expansion_.SetStepperMicrostepMode(
|
||||
(uint8_t)microsteps,
|
||||
STEPPER_MOTOR_M0_MADE_PORT, STEPPER_MOTOR_M0_PIN,
|
||||
STEPPER_MOTOR_M1_MADE_PORT, STEPPER_MOTOR_M1_PIN
|
||||
);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef DRV8428_DRIVER_H
|
||||
#define DRV8428_DRIVER_H
|
||||
|
||||
#include "stepper_driver.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
class Drv8428Driver : public StepperDriver
|
||||
{
|
||||
public:
|
||||
explicit Drv8428Driver(IOExpansionBoard &ioExp);
|
||||
virtual ~Drv8428Driver() = default;
|
||||
|
||||
esp_err_t Init() override;
|
||||
esp_err_t Enable(bool enable) override;
|
||||
esp_err_t SetDirection(bool dir) override;
|
||||
esp_err_t Sleep(bool sleep) override;
|
||||
esp_err_t SetMicrosteps(int microsteps) override;
|
||||
|
||||
private:
|
||||
IOExpansionBoard &io_expansion_;
|
||||
const char* TAG = "Drv8428Driver";
|
||||
};
|
||||
|
||||
#endif // DRV8428_DRIVER_H
|
||||
@@ -0,0 +1,17 @@
|
||||
# main/04_hal/stepper_driver/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_HAL_STEPPER_DRIVER AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] stepper_driver module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"04_hal/stepper_driver/drv8428.cc"
|
||||
"04_hal/stepper_driver/aw8646.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"04_hal/stepper_driver"
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef STEPPER_DRIVER_H
|
||||
#define STEPPER_DRIVER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Abstract base class for stepper motor driver chips.
|
||||
*
|
||||
* This interface abstracts the low-level control of the stepper motor driver,
|
||||
* such as enabling/disabling, setting direction, sleep mode, and microstepping configuration.
|
||||
* It does NOT handle step generation (that is handled by the StepperMotor class using GPTimer).
|
||||
*/
|
||||
class StepperDriver
|
||||
{
|
||||
public:
|
||||
virtual ~StepperDriver() = default;
|
||||
|
||||
/**
|
||||
* @brief Initialize the driver hardware (GPIOs, IO Expander, etc.)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t Init() = 0;
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the motor driver output.
|
||||
* @param enable true to enable, false to disable
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t Enable(bool enable) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the motor direction.
|
||||
* @param dir true for one direction (e.g. UP/CW), false for the other (e.g. DOWN/CCW)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t SetDirection(bool dir) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the motor driver to sleep mode to save power.
|
||||
* @param sleep true to sleep, false to wake up
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t Sleep(bool sleep) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set microstepping mode.
|
||||
* @param microsteps Microstepping value (e.g., 1, 2, 4, 8, 16, 32, etc.)
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
virtual esp_err_t SetMicrosteps(int microsteps) = 0;
|
||||
};
|
||||
|
||||
#endif // STEPPER_DRIVER_H
|
||||
@@ -0,0 +1,167 @@
|
||||
#include "adc_battery_monitor.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "AdcBatteryMonitor" ///< 日志标签,用于ESP-IDF日志系统
|
||||
|
||||
AdcBatteryMonitor::AdcBatteryMonitor(BoardSweekar& board, adc_unit_t adc_unit, adc_channel_t adc_channel, float upper_resistor, float lower_resistor)
|
||||
: board_(board) {
|
||||
|
||||
// Initialize ADC battery estimation
|
||||
adc_battery_estimation_t adc_cfg = {
|
||||
.internal = {
|
||||
.adc_unit = adc_unit,
|
||||
.adc_bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.adc_atten = ADC_ATTEN_DB_12,
|
||||
},
|
||||
.adc_channel = adc_channel,
|
||||
.upper_resistor = upper_resistor,
|
||||
.lower_resistor = lower_resistor
|
||||
};
|
||||
adc_cfg.charging_detect_cb = [](void *user_data) -> bool {
|
||||
AdcBatteryMonitor *self = (AdcBatteryMonitor *)user_data;
|
||||
return self->IsCharging();
|
||||
};
|
||||
adc_cfg.charging_detect_user_data = this;
|
||||
adc_battery_estimation_handle_ = adc_battery_estimation_create(&adc_cfg);
|
||||
|
||||
// Initialize timer
|
||||
esp_timer_create_args_t timer_cfg = {
|
||||
.callback = [](void *arg) {
|
||||
AdcBatteryMonitor *self = (AdcBatteryMonitor *)arg;
|
||||
self->CheckBatteryStatus();
|
||||
},
|
||||
.arg = this,
|
||||
.name = "adc_battery_monitor",
|
||||
.skip_unhandled_events = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(&timer_cfg, &timer_handle_));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handle_, 1000000));
|
||||
}
|
||||
|
||||
// 注册ADC电池回调函数
|
||||
void AdcBatteryMonitor::AdcBatteryMonitor_Init(void) {
|
||||
ESP_LOGI(TAG, "注册ADC电池回调函数");
|
||||
// 设置默认的电池状态回调函数
|
||||
OnNotCharging([]() {
|
||||
ESP_LOGI(TAG, "电池未充电状态回调 - 默认处理");
|
||||
});
|
||||
|
||||
OnFull([]() {
|
||||
ESP_LOGI(TAG, "电池充满电状态回调 - 默认处理");
|
||||
});
|
||||
|
||||
OnCharging([]() {
|
||||
ESP_LOGI(TAG, "电池充电中状态回调 - 默认处理");
|
||||
});
|
||||
}
|
||||
|
||||
AdcBatteryMonitor::~AdcBatteryMonitor() {
|
||||
if (adc_battery_estimation_handle_) {
|
||||
ESP_ERROR_CHECK(adc_battery_estimation_destroy(adc_battery_estimation_handle_));
|
||||
}
|
||||
|
||||
if (timer_handle_) {
|
||||
esp_timer_stop(timer_handle_);
|
||||
esp_timer_delete(timer_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
bool AdcBatteryMonitor::IsCharging() {
|
||||
// 通过IO扩展板读取充电检测引脚状态
|
||||
// BATTERY_CHRG_PIN连接到P0_5,对应INPUT_PORT0
|
||||
uint8_t port0_data = 0;
|
||||
esp_err_t err = board_.io_expansion_.ReadInputPort0(&port0_data);
|
||||
|
||||
// 如果读取失败,返回false
|
||||
if (err != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查BATTERY_CHRG_PIN位状态
|
||||
// 当引脚为低电平时表示正在充电
|
||||
return (port0_data & (1 << BATTERY_CHRG_PIN)) == 0;
|
||||
}
|
||||
|
||||
bool AdcBatteryMonitor::IsDischarging() {
|
||||
return !IsCharging();
|
||||
}
|
||||
|
||||
uint8_t AdcBatteryMonitor::GetBatteryLevel() {
|
||||
// 如果句柄无效,返回默认值
|
||||
if (adc_battery_estimation_handle_ == nullptr) {
|
||||
printf("adc_battery_estimation_handle_ 为空!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
float capacity = 0;
|
||||
esp_err_t err = adc_battery_estimation_get_capacity(adc_battery_estimation_handle_, &capacity);
|
||||
if (err != ESP_OK) {
|
||||
printf("返回值出错!\n");
|
||||
return 0; // 出错时返回默认值
|
||||
}
|
||||
return (uint8_t)capacity;
|
||||
}
|
||||
|
||||
void AdcBatteryMonitor::OnChargingStatusChanged(std::function<void(bool)> callback) {
|
||||
on_charging_status_changed_ = callback;
|
||||
}
|
||||
|
||||
void AdcBatteryMonitor::CheckBatteryStatus() {
|
||||
bool new_charging_status = IsCharging();
|
||||
if (new_charging_status != is_charging_) {
|
||||
is_charging_ = new_charging_status;
|
||||
if (on_charging_status_changed_) {
|
||||
on_charging_status_changed_(is_charging_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 三个电池状态回调函数的实现
|
||||
void AdcBatteryMonitor::TriggerNotChrgCallback() {
|
||||
if (on_not_charging_callback_) {
|
||||
on_not_charging_callback_();
|
||||
}
|
||||
}
|
||||
|
||||
void AdcBatteryMonitor::TriggerFullCallback() {
|
||||
if (on_full_callback_) {
|
||||
on_full_callback_();
|
||||
}
|
||||
}
|
||||
|
||||
void AdcBatteryMonitor::TriggerChrgCallback() {
|
||||
if (on_charging_callback_) {
|
||||
on_charging_callback_();
|
||||
}
|
||||
}
|
||||
|
||||
// 注册电池状态回调函数的实现
|
||||
void AdcBatteryMonitor::OnNotCharging(std::function<void()> callback) {
|
||||
on_not_charging_callback_ = callback;
|
||||
}
|
||||
|
||||
void AdcBatteryMonitor::OnFull(std::function<void()> callback) {
|
||||
on_full_callback_ = callback;
|
||||
}
|
||||
|
||||
void AdcBatteryMonitor::OnCharging(std::function<void()> callback) {
|
||||
on_charging_callback_ = callback;
|
||||
}
|
||||
|
||||
//CHRG引脚充电前为高电平 充电中为低电平 充满电为高电平
|
||||
//FULL未充满为高电平 充满电为低电平
|
||||
bool AdcBatteryMonitor::IsFull() {
|
||||
// 通过IO扩展板读取电池充满检测引脚状态
|
||||
// BATTERY_FULL_PIN连接到P1_3,对应INPUT_PORT1
|
||||
uint8_t port1_data = 0;
|
||||
esp_err_t err = board_.io_expansion_.ReadInputPort1(&port1_data);
|
||||
|
||||
// 如果读取失败,返回false
|
||||
if (err != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查BATTERY_FULL_PIN位状态
|
||||
// 当引脚为低电平时表示电池已充满
|
||||
return (port1_data & (1 << BATTERY_FULL_PIN)) == 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef ADC_BATTERY_MONITOR_H
|
||||
#define ADC_BATTERY_MONITOR_H
|
||||
|
||||
#include <functional>
|
||||
#include <driver/gpio.h>
|
||||
#include <adc_battery_estimation.h>
|
||||
#include <esp_timer.h>
|
||||
#include "02_physical/boards/board_sweekar.h"
|
||||
|
||||
class AdcBatteryMonitor {
|
||||
public:
|
||||
AdcBatteryMonitor(BoardSweekar& board, adc_unit_t adc_unit, adc_channel_t adc_channel, float upper_resistor, float lower_resistor);
|
||||
~AdcBatteryMonitor();
|
||||
|
||||
bool IsCharging();
|
||||
bool IsDischarging();
|
||||
bool IsFull(); // 电池充满检测函数
|
||||
uint8_t GetBatteryLevel();
|
||||
|
||||
// 注册电池状态回调函数
|
||||
void AdcBatteryMonitor_Init(void);
|
||||
// 三个电池状态回调函数
|
||||
void TriggerNotChrgCallback(); // 触发未充电回调
|
||||
void TriggerFullCallback(); // 触发充满电回调
|
||||
void TriggerChrgCallback(); // 触发充电中回调
|
||||
|
||||
// 注册电池状态回调函数
|
||||
void OnNotCharging(std::function<void()> callback); // 注册未充电回调
|
||||
void OnFull(std::function<void()> callback); // 注册充满电回调
|
||||
void OnCharging(std::function<void()> callback); // 注册充电中回调
|
||||
|
||||
void OnChargingStatusChanged(std::function<void(bool)> callback);
|
||||
|
||||
private:
|
||||
BoardSweekar& board_; // 添加对BoardSweekar的引用
|
||||
adc_battery_estimation_handle_t adc_battery_estimation_handle_ = nullptr;
|
||||
esp_timer_handle_t timer_handle_ = nullptr;
|
||||
bool is_charging_ = false;
|
||||
std::function<void(bool)> on_charging_status_changed_;
|
||||
std::function<void()> on_not_charging_callback_; // 未充电回调函数
|
||||
std::function<void()> on_full_callback_; // 充满电回调函数
|
||||
std::function<void()> on_charging_callback_; // 充电中回调函数
|
||||
|
||||
void CheckBatteryStatus();
|
||||
};
|
||||
|
||||
#endif // ADC_BATTERY_MONITOR_H
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/05_executors/adc_battery_monitor/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_EXEC_ADC_BATTERY_MONITOR AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] adc_battery_monitor module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"05_executors/adc_battery_monitor/adc_battery_monitor.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"05_executors/adc_battery_monitor"
|
||||
)
|
||||
@@ -0,0 +1,257 @@
|
||||
#include "base_board_control.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "BaseBoardCtrl";
|
||||
|
||||
esp_err_t BaseBoardControl::Init(BaseBoardHal *hal)
|
||||
{
|
||||
if (hal == nullptr)
|
||||
{
|
||||
ESP_LOGE(TAG, "Init: hal is null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
hal_ = hal;
|
||||
return hal_->Init();
|
||||
}
|
||||
|
||||
esp_err_t BaseBoardControl::GetAngle(float *angle)
|
||||
{
|
||||
if (hal_ == nullptr)
|
||||
{
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return hal_->GetAngle(angle);
|
||||
}
|
||||
|
||||
esp_err_t BaseBoardControl::SendSetAngleAbs(uint16_t angle_deg,
|
||||
uint8_t speed_percent,
|
||||
uint8_t flags)
|
||||
{
|
||||
if (hal_ == nullptr)
|
||||
{
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// 角度限制在 0~359 之间
|
||||
if (angle_deg > 359)
|
||||
{
|
||||
angle_deg = static_cast<uint16_t>(angle_deg % 360);
|
||||
}
|
||||
|
||||
// 速度百分比限制在 0~100
|
||||
if (speed_percent > 100)
|
||||
{
|
||||
speed_percent = 100;
|
||||
}
|
||||
|
||||
uint8_t payload[4];
|
||||
|
||||
payload[0] = static_cast<uint8_t>(angle_deg & 0xFF); // LSB
|
||||
payload[1] = static_cast<uint8_t>((angle_deg >> 8) & 0xFF); // MSB
|
||||
payload[2] = speed_percent;
|
||||
payload[3] = flags; // 预留/扩展位
|
||||
|
||||
return SendFrame(0x01, payload, sizeof(payload));
|
||||
}
|
||||
|
||||
esp_err_t BaseBoardControl::SendSetAngleRel(int16_t delta_deg,
|
||||
uint8_t speed_percent,
|
||||
uint8_t flags)
|
||||
{
|
||||
if (hal_ == nullptr)
|
||||
{
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (speed_percent > 100)
|
||||
{
|
||||
speed_percent = 100;
|
||||
}
|
||||
|
||||
uint8_t payload[4];
|
||||
|
||||
// int16_t 直接按补码低字节在前的顺序发
|
||||
uint16_t delta_u = static_cast<uint16_t>(delta_deg);
|
||||
|
||||
payload[0] = static_cast<uint8_t>(delta_u & 0xFF); // LSB
|
||||
payload[1] = static_cast<uint8_t>((delta_u >> 8) & 0xFF); // MSB
|
||||
payload[2] = speed_percent;
|
||||
payload[3] = flags; // 预留/扩展位
|
||||
|
||||
return SendFrame(0x02, payload, sizeof(payload));
|
||||
}
|
||||
|
||||
esp_err_t BaseBoardControl::SendSetMotorMove(MotorMode mode, uint8_t speed_percent, uint16_t duration_ms)
|
||||
{
|
||||
if (hal_ == nullptr)
|
||||
{
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (speed_percent > 100) {
|
||||
speed_percent = 100;
|
||||
}
|
||||
|
||||
uint8_t payload[4];
|
||||
|
||||
payload[0] = mode;
|
||||
payload[1] = speed_percent;
|
||||
payload[2] = static_cast<uint8_t>(duration_ms & 0xFF);
|
||||
payload[3] = static_cast<uint8_t>((duration_ms >> 8) & 0xFF);
|
||||
|
||||
return SendFrame(0x03, payload, sizeof(payload));
|
||||
}
|
||||
|
||||
esp_err_t BaseBoardControl::SendSetLedRgb(uint8_t mode,
|
||||
uint8_t target_mask,
|
||||
uint8_t r,
|
||||
uint8_t g,
|
||||
uint8_t b,
|
||||
uint8_t speed)
|
||||
{
|
||||
if (hal_ == nullptr)
|
||||
{
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (speed > 100)
|
||||
{
|
||||
speed = 100;
|
||||
}
|
||||
|
||||
uint8_t payload[7];
|
||||
|
||||
payload[0] = mode; // 灯效模式
|
||||
payload[1] = target_mask; // 位掩码,指示哪些 LED 生效
|
||||
payload[2] = r;
|
||||
payload[3] = g;
|
||||
payload[4] = b;
|
||||
payload[5] = speed; // 呼吸/渐变速度
|
||||
payload[6] = 0; // Reserved,写死为 0
|
||||
|
||||
return SendFrame(0x10, payload, sizeof(payload));
|
||||
}
|
||||
|
||||
esp_err_t BaseBoardControl::SendFrame(uint8_t cmd,
|
||||
const uint8_t *payload,
|
||||
uint8_t payload_len)
|
||||
{
|
||||
if (hal_ == nullptr)
|
||||
{
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// LEN = CMD(1) + payload_len
|
||||
uint8_t len = static_cast<uint8_t>(1u + payload_len);
|
||||
|
||||
// 总长度 = HEAD1 + HEAD2 + LEN + (CMD + payload_len) + CRC = 3 + len + 1
|
||||
size_t frame_len = static_cast<size_t>(3u + len + 1u);
|
||||
if (frame_len > kMaxFrameLen)
|
||||
{
|
||||
ESP_LOGE(TAG, "SendFrame: frame too long, len=%u", static_cast<unsigned>(frame_len));
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
uint8_t frame[kMaxFrameLen];
|
||||
|
||||
// 帧头
|
||||
frame[0] = 0xAA;
|
||||
frame[1] = 0x55;
|
||||
|
||||
// LEN 字段:从 CMD 开始计数
|
||||
frame[2] = len;
|
||||
|
||||
// CMD
|
||||
frame[3] = cmd;
|
||||
|
||||
// payload
|
||||
for (uint8_t i = 0; i < payload_len; ++i)
|
||||
{
|
||||
frame[4u + i] = payload[i];
|
||||
}
|
||||
|
||||
uint8_t crc = CRC8(&frame[2], len + 1); // 从 LEN 开始算起
|
||||
|
||||
// CRC 放在数据之后
|
||||
frame[3u + len] = crc;
|
||||
|
||||
const int kMaxRetries = 5;
|
||||
const int kRetryDelayMs = 50;
|
||||
|
||||
for (int i = 0; i < kMaxRetries; i++)
|
||||
{
|
||||
esp_err_t err = hal_->Send(frame, frame_len);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
// 等待从机处理并准备好 ACK
|
||||
// 增加延时以确保从机有足够时间写入 I2C 缓冲
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
|
||||
uint8_t ack_buf[kAckFrameLen] = {0};
|
||||
err = hal_->Read(ack_buf, kAckFrameLen);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
// 校验 ACK
|
||||
if (ack_buf[0] == 0xAA && ack_buf[1] == 0x55 &&
|
||||
ack_buf[2] == 0x01 && ack_buf[3] == 0xFF)
|
||||
{
|
||||
uint8_t crc = CRC8(&ack_buf[2], 2);
|
||||
if (crc == ack_buf[4])
|
||||
{
|
||||
return ESP_OK; // 握手成功
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "ACK CRC Fail: Recv=0x%02X Calc=0x%02X", ack_buf[4], crc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Invalid ACK: %02X %02X %02X %02X",
|
||||
ack_buf[0], ack_buf[1], ack_buf[2], ack_buf[3]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Read ACK Failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Send Failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// 重试前等待
|
||||
vTaskDelay(pdMS_TO_TICKS(kRetryDelayMs));
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "SendFrame Failed after %d retries", kMaxRetries);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
uint8_t BaseBoardControl::CRC8(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint8_t crc = 0x00;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
crc ^= data[i];
|
||||
|
||||
for (int b = 0; b < 8; ++b)
|
||||
{
|
||||
if (crc & 0x80)
|
||||
{
|
||||
crc = static_cast<uint8_t>((crc << 1) ^ 0x07);
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = static_cast<uint8_t>(crc << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// base_board_control.h
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "esp_err.h"
|
||||
#include "base_board_hal.h"
|
||||
|
||||
class BaseBoardControl
|
||||
{
|
||||
public:
|
||||
/** 帧最大长度,按你的协议冗余留一点空间 */
|
||||
static constexpr size_t kMaxFrameLen = 16;
|
||||
/** ACK 帧长度: HEAD(2) + LEN(1) + CMD(1) + CRC(1) = 5 */
|
||||
static constexpr size_t kAckFrameLen = 5;
|
||||
|
||||
BaseBoardControl() = default;
|
||||
~BaseBoardControl() = default;
|
||||
|
||||
esp_err_t Init(BaseBoardHal *hal);
|
||||
|
||||
/** 发送绝对角度命令 CMD=0x01 */
|
||||
esp_err_t SendSetAngleAbs(uint16_t angle_deg,
|
||||
uint8_t speed_percent,
|
||||
uint8_t flags = 0);
|
||||
|
||||
/** 发送相对角度命令 CMD=0x02 */
|
||||
esp_err_t SendSetAngleRel(int16_t delta_deg,
|
||||
uint8_t speed_percent,
|
||||
uint8_t flags = 0);
|
||||
|
||||
/** 电机工作模式枚举 */
|
||||
enum MotorMode
|
||||
{
|
||||
MotorOff = 0,
|
||||
MotorForward = 1,
|
||||
MotorBackward = 2
|
||||
};
|
||||
|
||||
/** 发送电机开环控制命令 CMD=0x03 */
|
||||
esp_err_t SendSetMotorMove(MotorMode mode, uint8_t speed_percent, uint16_t duration_ms);
|
||||
|
||||
/** 发送 RGB 命令 CMD=0x10 */
|
||||
esp_err_t SendSetLedRgb(uint8_t mode,
|
||||
uint8_t target_mask,
|
||||
uint8_t r,
|
||||
uint8_t g,
|
||||
uint8_t b,
|
||||
uint8_t speed);
|
||||
|
||||
/** 获取当前角度 */
|
||||
esp_err_t GetAngle(float *angle);
|
||||
|
||||
private:
|
||||
BaseBoardHal *hal_ = nullptr;
|
||||
|
||||
/** 通用打包 + 发送接口:传 CMD 和 payload,内部加头、LEN、CRC */
|
||||
esp_err_t SendFrame(uint8_t cmd,
|
||||
const uint8_t *payload,
|
||||
uint8_t payload_len);
|
||||
|
||||
/** CRC8 工具函数 */
|
||||
static uint8_t CRC8(const uint8_t *data, size_t len);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/05_executors/base_board_control/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_EXEC_BASE_BOARD_CONTROL AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] base_board_control module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"05_executors/base_board_control/base_board_control.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"05_executors/base_board_control"
|
||||
)
|
||||
@@ -0,0 +1,625 @@
|
||||
#include "gyroscope.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
|
||||
Gyroscope::Gyroscope()
|
||||
{
|
||||
bus_handle_ = nullptr;
|
||||
on_shake_callback_ = nullptr; // 初始化回调函数
|
||||
on_pickup_callback_ = nullptr; // 初始化拿起回调函数
|
||||
on_putdown_callback_ = nullptr; // 初始化放置回调函数
|
||||
on_tilt_callback_ = nullptr; // 初始化倾斜回调函数
|
||||
timer_handle_ = nullptr; // 初始化定时器句柄
|
||||
pGyroscopeTaskStackBuffer_ = nullptr;
|
||||
pxGyroscopeTaskBuffer_ = nullptr;
|
||||
|
||||
// 初始化滤波相关变量
|
||||
last_filtered_x_ = 0;
|
||||
last_filtered_y_ = 0;
|
||||
last_filtered_z_ = 0;
|
||||
is_first_sample_ = true;
|
||||
}
|
||||
|
||||
Gyroscope::~Gyroscope()
|
||||
{
|
||||
// 删除定时器
|
||||
DeleteTimer();
|
||||
|
||||
if (pGyroscopeTaskStackBuffer_) {
|
||||
free(pGyroscopeTaskStackBuffer_);
|
||||
pGyroscopeTaskStackBuffer_ = nullptr;
|
||||
}
|
||||
if (pxGyroscopeTaskBuffer_) {
|
||||
vPortFree(pxGyroscopeTaskBuffer_);
|
||||
pxGyroscopeTaskBuffer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建500ms周期定时器
|
||||
* @return esp_err_t 创建结果
|
||||
*/
|
||||
esp_err_t Gyroscope::CreateTimer()
|
||||
{
|
||||
if (timer_handle_ != nullptr) {
|
||||
ESP_LOGW(TAG_GYROSCOPE, "定时器已存在");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 配置定时器参数
|
||||
esp_timer_create_args_t timer_args = {};
|
||||
timer_args.callback = &TimerCallback; // 静态回调函数
|
||||
timer_args.arg = this; // 传入实例指针
|
||||
timer_args.name = "gyro_timer"; // 定时器名称
|
||||
timer_args.dispatch_method = ESP_TIMER_TASK; // 使用任务调度
|
||||
timer_args.skip_unhandled_events = false; // 不跳过未处理事件
|
||||
|
||||
// 创建定时器
|
||||
esp_err_t err = esp_timer_create(&timer_args, &timer_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "创建定时器失败: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 启动定时器,500ms周期重复
|
||||
err = esp_timer_start_periodic(timer_handle_, 50000); // 50000微秒 = 50ms 20hz
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "启动定时器失败: 0x%x", err);
|
||||
esp_timer_delete(timer_handle_);
|
||||
timer_handle_ = nullptr;
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "50ms周期定时器创建并启动成功");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 停止并删除定时器
|
||||
*/
|
||||
void Gyroscope::DeleteTimer()
|
||||
{
|
||||
if (timer_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 停止定时器
|
||||
esp_err_t err = esp_timer_stop(timer_handle_);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "停止定时器失败: 0x%x", err);
|
||||
}
|
||||
|
||||
// 删除定时器
|
||||
err = esp_timer_delete(timer_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "删除定时器失败: 0x%x", err);
|
||||
}
|
||||
|
||||
timer_handle_ = nullptr;
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器已删除");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 静态定时器回调函数
|
||||
* @param arg 传入的Gyroscope实例指针
|
||||
*/
|
||||
void Gyroscope::TimerCallback(void* arg)
|
||||
{
|
||||
Gyroscope* gyroscope = static_cast<Gyroscope*>(arg);
|
||||
if (gyroscope) {
|
||||
gyroscope->TimerInterruptHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定时器中断处理函数
|
||||
* 每50ms调用一次,可以在这里执行周期性任务
|
||||
*/
|
||||
void Gyroscope::TimerInterruptHandler()
|
||||
{
|
||||
// 在这里添加定时器中断处理逻辑
|
||||
// 例如:读取传感器数据、检测动作、发送状态等
|
||||
AccelerationData accel_data_ = {0};
|
||||
|
||||
esp_err_t err = GetAcceleration(&accel_data_);
|
||||
if (err == ESP_OK) {
|
||||
// 根据实际安装方式重新定义姿态判断
|
||||
// 平放状态:Y轴接近±1g(因为Y轴垂直于桌面),X和Z轴接近0
|
||||
bool is_flat = (fabs(accel_data_.y) > 0.85 && fabs(accel_data_.y) < 1.15) &&
|
||||
(fabs(accel_data_.x) < 0.15 && fabs(accel_data_.z) < 0.15);
|
||||
|
||||
// 手持状态:Y轴接近0,X和Z轴中至少有一个有明显值
|
||||
bool is_held = (fabs(accel_data_.y) < 0.7) &&
|
||||
(fabs(accel_data_.x) > 0.15 || fabs(accel_data_.z) > 0.15);
|
||||
|
||||
// 计算合成加速度(总加速度大小)
|
||||
float total_accel = sqrt(accel_data_.x * accel_data_.x +
|
||||
accel_data_.y * accel_data_.y +
|
||||
accel_data_.z * accel_data_.z);
|
||||
|
||||
// 计算与上次合成加速度的差值(加速度变化量)
|
||||
float total_accel_diff = fabs(total_accel - total_accel_last_);
|
||||
|
||||
// 计算Y轴加速度变化
|
||||
float y_diff = accel_data_.y - accel_data_y_last_;
|
||||
|
||||
// 检测是否处于平放稳定状态
|
||||
if(is_flat) {
|
||||
stable_count_++;
|
||||
if(stable_count_ >= 8) { // 连续8次检测到平放状态(400ms),减少误判
|
||||
stable_count_ = 8; // 防止溢出
|
||||
if(!is_stable_) {
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到稳定平放状态 (x:%.2f, y:%.2f, z:%.2f, total:%.2f)",
|
||||
accel_data_.x, accel_data_.y, accel_data_.z, total_accel);
|
||||
is_stable_ = true;
|
||||
is_lifted_ = false; // 重置拿起状态
|
||||
putdown_count_ = 0; // 重置放置计数器
|
||||
lift_count_ = 0; // 重置拿起计数器
|
||||
|
||||
// 调用放置回调
|
||||
if (on_putdown_callback_) {
|
||||
on_putdown_callback_();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
stable_count_ = 0; // 不在范围内则重置稳定计数器
|
||||
|
||||
// 如果之前是稳定状态,检测是否有拿起动作
|
||||
if(is_stable_) {
|
||||
// 检测拿起动作的多种特征:
|
||||
// 1. Y轴从接近1g变为接近0g(位置变化)
|
||||
// 2. 合成加速度有显著变化(表示有加速度)
|
||||
bool y_change_indicates_lift = fabs(y_diff) > 0.25;
|
||||
bool total_accel_change_indicates_lift = total_accel_diff > 0.3; // 检测加速度突变
|
||||
|
||||
if(y_change_indicates_lift || total_accel_change_indicates_lift) {
|
||||
lift_count_++;
|
||||
if(lift_count_ >= 1) { // 降低拿起检测阈值,提高灵敏度
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到拿起动作 (x:%.2f, y:%.2f, z:%.2f, total:%.2f, y_diff:%.2f, accel_diff:%.2f)",
|
||||
accel_data_.x, accel_data_.y, accel_data_.z, total_accel, y_diff, total_accel_diff);
|
||||
is_stable_ = false; // 重置状态
|
||||
is_lifted_ = true; // 设置拿起状态
|
||||
lift_count_ = 0;
|
||||
stable_count_ = 0;
|
||||
|
||||
// 调用拿起回调
|
||||
if (on_pickup_callback_) {
|
||||
on_pickup_callback_();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lift_count_ = 0; // 变化不符合预期,重置拿起计数器
|
||||
}
|
||||
}
|
||||
// 如果之前是被拿起状态,检测是否有放置动作
|
||||
else if(is_lifted_) {
|
||||
// 检测从手持到平放的变化 - Y轴从接近0g变为接近1g
|
||||
bool y_change_indicates_putdown = (y_diff > 0.25 && y_diff < 0.80);
|
||||
|
||||
if(y_change_indicates_putdown) {
|
||||
putdown_count_++;
|
||||
if(putdown_count_ >= 3) { // 连续3次检测到缓慢变化
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到缓慢放置动作 (x:%.2f, y:%.2f, z:%.2f, total:%.2f, y_diff:%.2f)",
|
||||
accel_data_.x, accel_data_.y, accel_data_.z, total_accel, y_diff);
|
||||
is_lifted_ = false; // 重置拿起状态
|
||||
putdown_count_ = 0;
|
||||
|
||||
// 调用放置回调
|
||||
if (on_putdown_callback_) {
|
||||
on_putdown_callback_();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
putdown_count_ = 0; // 变化不符合预期,重置放置计数器
|
||||
}
|
||||
}
|
||||
|
||||
// 检测倾斜动作 - 仅当手持时才触发倾斜
|
||||
if (is_held && (fabs(accel_data_.x) > 0.3f || fabs(accel_data_.z) > 0.3f)) {
|
||||
// 检测到倾斜,调用倾斜回调
|
||||
if (on_tilt_callback_) {
|
||||
on_tilt_callback_();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 保存当前值作为下一次的上一次值
|
||||
accel_data_y_last_ = accel_data_.y;
|
||||
total_accel_last_ = total_accel;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief 注册摇晃检测回调函数
|
||||
*
|
||||
* @param callback 当检测到摇晃时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnShake(std::function<void()> callback)
|
||||
{
|
||||
on_shake_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册拿起检测回调函数
|
||||
*
|
||||
* @param callback 当检测到设备被拿起时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnPickUp(std::function<void()> callback)
|
||||
{
|
||||
on_pickup_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册放置检测回调函数
|
||||
*
|
||||
* @param callback 当检测到设备被放置时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnPutDown(std::function<void()> callback)
|
||||
{
|
||||
on_putdown_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册倾斜检测回调函数
|
||||
*
|
||||
* @param callback 当检测到设备倾斜时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnTilt(std::function<void()> callback)
|
||||
{
|
||||
on_tilt_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 静态中断处理函数
|
||||
*
|
||||
* @param arg 传入的Gyroscope实例指针
|
||||
*/
|
||||
void IRAM_ATTR Gyroscope::GpioIsrHandler(void* arg)
|
||||
{
|
||||
Gyroscope* gyroscope = static_cast<Gyroscope*>(arg);
|
||||
if (gyroscope) {
|
||||
gyroscope->interrupt_flag_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向陀螺仪寄存器写入数据
|
||||
*
|
||||
* @param reg 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::WriteRegister(uint8_t reg, uint8_t data)
|
||||
{
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "I2C总线未初始化");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return i2c_bus_write_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, &data, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从陀螺仪寄存器读取数据
|
||||
*
|
||||
* @param reg 寄存器地址
|
||||
* @param data 读取到的数据指针
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::ReadRegister(uint8_t reg, uint8_t* data)
|
||||
{
|
||||
if (bus_handle_ == nullptr || data == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "参数错误或I2C总线未初始化");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return i2c_bus_read_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, data, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 批量读取陀螺仪寄存器数据
|
||||
*
|
||||
* @param reg 起始寄存器地址
|
||||
* @param data 读取到的数据指针
|
||||
* @param length 要读取的字节数
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::ReadRegisters(uint8_t reg, uint8_t* data, size_t length)
|
||||
{
|
||||
if (bus_handle_ == nullptr || data == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "参数错误或I2C总线未初始化");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return i2c_bus_read_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, data, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化陀螺仪中断GPIO
|
||||
*
|
||||
* @param gpio_num 要初始化的GPIO引脚号
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::InterruptGpioInit(gpio_num_t gpio_num)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_POSEDGE; // 上升沿触发
|
||||
io_conf.pin_bit_mask = (1ULL<<gpio_num);
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; // 禁用上拉,因为INT1已经是推挽输出
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; // 启用下拉
|
||||
|
||||
esp_err_t err = gpio_config(&io_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "GPIO配置失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 配置中断服务
|
||||
err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3 | ESP_INTR_FLAG_IRAM);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "GPIO中断服务安装失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 注册中断处理函数
|
||||
err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "GPIO中断处理函数添加失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 清除任何待处理的中断
|
||||
gpio_intr_disable(gpio_num);
|
||||
gpio_intr_enable(gpio_num);
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "GPIO%d中断初始化完成", gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清除中断标志
|
||||
*
|
||||
* 该函数会读取唤醒源寄存器和功能源寄存器来清除中断标志
|
||||
*
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::ClearInterruptFlags()
|
||||
{
|
||||
esp_err_t err;
|
||||
uint8_t wake_up_src = 0;
|
||||
uint8_t func_src1 = 0;
|
||||
// 读取唤醒源寄存器和功能源寄存器来清除中断
|
||||
err = ReadRegister(WAKE_UP_SRC, &wake_up_src);
|
||||
if (err != ESP_OK) return err;
|
||||
err = ReadRegister(FUNC_SRC1, &func_src1);
|
||||
if (err != ESP_OK) return err;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化陀螺仪
|
||||
*
|
||||
* @param bus_handle I2C总线句柄
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::Init(i2c_bus_handle_t bus_handle)
|
||||
{
|
||||
bus_handle_ = bus_handle;
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "I2C总线句柄为空");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "开始初始化陀螺仪...");
|
||||
|
||||
// 1. 验证设备连接和通信
|
||||
uint8_t who_am_i = 0;
|
||||
esp_err_t err = ReadRegister(0x0F, &who_am_i); // WHO_AM_I寄存器
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "无法读取陀螺仪ID: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (who_am_i != 0x6A) { // LSM6DS3TR-C的WHO_AM_I值
|
||||
ESP_LOGE(TAG_GYROSCOPE, "设备ID不匹配,期望0x6A,实际0x%02X", who_am_i);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG_GYROSCOPE, "陀螺仪设备ID验证成功: 0x%02X", who_am_i);
|
||||
|
||||
// 2. 初始化中断引脚
|
||||
err = InterruptGpioInit(GYROSCOPE_INPUT_PIN_SEL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "中断引脚初始化失败: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
ESP_LOGI(TAG_GYROSCOPE, "开始配置唤醒中断...");
|
||||
|
||||
// 1. 软件复位陀螺仪
|
||||
err = WriteRegister(CTRL3_C, 0x01); // SW_RESET
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待复位完成
|
||||
|
||||
// 3. 配置加速度计: 104Hz ODR, ±2g满量程
|
||||
err = WriteRegister(CTRL1_XL, 0x50); // 0b01010000 - 104Hz ODR, ±2g
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 4. 配置陀螺仪: 104Hz ODR, ±125dps满量程
|
||||
err = WriteRegister(CTRL2_G, 0x50); // 0b01010000
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 5. 配置控制寄存器3: 高电平有效,推挽输出
|
||||
err = WriteRegister(CTRL3_C, 0x44); // 0b01000100
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 6. 禁用陀螺仪低功耗模式
|
||||
err = WriteRegister(CTRL7_G, 0x00); // 禁用低功耗模式
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 7. 配置唤醒功能: 启用X轴的唤醒检测
|
||||
err = WriteRegister(TAP_CFG, 0x81); // 0b10000000 - 仅启用高通滤波器
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 8. 配置唤醒阈值: 非常灵敏的设置
|
||||
err = WriteRegister(WAKE_UP_THS, 0x3F); // 31.25mg - 最灵敏的阈值
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 9. 配置唤醒持续时间: 6个ODR周期
|
||||
err = WriteRegister(WAKE_UP_DUR, 0x06);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 10. 配置中断1路由: 将唤醒中断路由到INT1
|
||||
err = WriteRegister(MD1_CFG, 0x20); // 0b00100000 - 仅唤醒中断到INT1
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 11. 配置中断2路由: 禁用所有中断
|
||||
err = WriteRegister(MD2_CFG, 0x00);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 12. 配置INT1_CTRL: 启用唤醒中断到INT1
|
||||
err = WriteRegister(INT1_CTRL, 0x20); // 0b00100000
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 13. 启用嵌入式功能
|
||||
err = WriteRegister(CTRL10_C, 0x3C); // 0b00111000
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 14. 等待配置生效
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
CreateTimer();
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "陀螺仪唤醒中断配置完成");
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "陀螺仪初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建陀螺仪读取任务
|
||||
*
|
||||
* 该任务会周期性读取陀螺仪数据并处理中断
|
||||
*/
|
||||
void Gyroscope::CreateGyroReadTask()
|
||||
{
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "I2C总线未初始化,无法启动陀螺仪任务");
|
||||
return;
|
||||
}
|
||||
|
||||
xTaskCreateWithCaps(
|
||||
GyroReadTask,
|
||||
"gyro_read_task",
|
||||
4096,
|
||||
this,
|
||||
5, // Reduced priority to allow other tasks to run
|
||||
&xGyroscopeTaskHandle_,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
|
||||
);
|
||||
|
||||
if (xGyroscopeTaskHandle_ == NULL) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "Failed to create static gyro read task");
|
||||
} else {
|
||||
ESP_LOGI(TAG_GYROSCOPE, "Static gyro read task created successfully");
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t Gyroscope::ReadRawAcceleration(int16_t* x, int16_t* y, int16_t* z) {
|
||||
// 1. 参数合法性检查
|
||||
if (x == nullptr || y == nullptr || z == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "参数为空指针");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// 2. 读取原始加速度数据(6字节:X_L/X_H/Y_L/Y_H/Z_L/Z_H)
|
||||
uint8_t accel_data_[6] = {0};
|
||||
esp_err_t err = ReadRegisters(ACCEL_X_L, accel_data_, 6);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "读取加速度寄存器失败: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 3. 组合高低字节为int16_t(二进制补码,适配传感器输出)
|
||||
int16_t current_raw_x = (int16_t)((accel_data_[1] << 8) | accel_data_[0]);
|
||||
int16_t current_raw_y = (int16_t)((accel_data_[3] << 8) | accel_data_[2]);
|
||||
int16_t current_raw_z = (int16_t)((accel_data_[5] << 8) | accel_data_[4]);
|
||||
|
||||
// 4. 一阶α滤波(整数版,无浮点运算,避免精度丢失)
|
||||
int16_t filtered_x, filtered_y, filtered_z;
|
||||
if (is_first_sample_) {
|
||||
// 首次采样:直接初始化滤波值为原始值
|
||||
filtered_x = current_raw_x;
|
||||
filtered_y = current_raw_y;
|
||||
filtered_z = current_raw_z;
|
||||
is_first_sample_ = false; // 标记首次采样完成
|
||||
} else {
|
||||
// 核心滤波公式(整数版):α*原始值 + (1-α)*上一次滤波值
|
||||
// WEIGHTFACTOR=0.9; (1-WEIGHTFACTOR)=0.1
|
||||
const int32_t weight_scaled = (int32_t)(WEIGHTFACTOR * 10); // 9
|
||||
const int32_t inv_weight_scaled = 10 - weight_scaled; // 1
|
||||
|
||||
filtered_x = (weight_scaled * (int32_t)current_raw_x +
|
||||
inv_weight_scaled * last_filtered_x_) / 10;
|
||||
filtered_y = (weight_scaled * (int32_t)current_raw_y +
|
||||
inv_weight_scaled * last_filtered_y_) / 10;
|
||||
filtered_z = (weight_scaled * (int32_t)current_raw_z +
|
||||
inv_weight_scaled * last_filtered_z_) / 10;
|
||||
}
|
||||
|
||||
// 5. 转换为int16_t输出(filtered_x/y/z是int32_t,范围仍在int16_t内)
|
||||
*x = (int16_t)filtered_x;
|
||||
*y = (int16_t)filtered_y;
|
||||
*z = (int16_t)filtered_z;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Gyroscope::GetAcceleration(AccelerationData* data) {
|
||||
if (data == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "数据指针为空");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
int16_t raw_x, raw_y, raw_z;
|
||||
esp_err_t err = ReadRawAcceleration(&raw_x, &raw_y, &raw_z);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// 转换公式:加速度(g) = 原始值 × 灵敏度(mg/LSB) × 10^-3
|
||||
data->x = raw_x * ACCEL_SENSITIVITY_2G / 1000.0f;
|
||||
data->y = raw_y * ACCEL_SENSITIVITY_2G / 1000.0f;
|
||||
data->z = raw_z * ACCEL_SENSITIVITY_2G / 1000.0f;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 陀螺仪读取任务
|
||||
* Y轴立起 Z轴躺下
|
||||
* 该任务会周期性读取陀螺仪数据并处理中断
|
||||
*/
|
||||
void IRAM_ATTR Gyroscope::GyroReadTask(void* pvParameters)
|
||||
{
|
||||
Gyroscope* gyroscope = static_cast<Gyroscope*>(pvParameters);
|
||||
uint32_t interrupt_count = 0;
|
||||
while (1) {
|
||||
if (gyroscope->interrupt_flag_) {
|
||||
interrupt_count++;
|
||||
gyroscope->ClearInterruptFlags();
|
||||
gyroscope->interrupt_flag_ = false;
|
||||
|
||||
// 调用用户注册的回调函数
|
||||
if (gyroscope->on_shake_callback_) {
|
||||
gyroscope->on_shake_callback_();
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "累计中断次数: %lu", interrupt_count);
|
||||
if(interrupt_count >= 2){
|
||||
interrupt_count = 0;
|
||||
ESP_LOGI(TAG_GYROSCOPE, "检测到摇晃>>>>>>>>>>");
|
||||
}
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); // 50ms检查一次,更快的响应
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
#ifndef GYROSCOPE_H
|
||||
#define GYROSCOPE_H
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include <functional>
|
||||
#include "esp_timer.h"
|
||||
|
||||
// 加速度数据结构体
|
||||
typedef struct {
|
||||
float x; // X轴加速度 (g)
|
||||
float y; // Y轴加速度 (g)
|
||||
float z; // Z轴加速度 (g)
|
||||
} AccelerationData;
|
||||
|
||||
// 一阶滤波系数
|
||||
#define WEIGHTFACTOR 0.93f
|
||||
|
||||
/* 陀螺仪寄存器定义 */
|
||||
#define CTRL1_XL 0x10 // 加速度计控制寄存器1
|
||||
#define CTRL2_G 0x11 // 陀螺仪控制寄存器2
|
||||
#define CTRL3_C 0x12 // 控制寄存器3
|
||||
#define CTRL4_C 0x13 // 控制寄存器4
|
||||
#define CTRL5_C 0x14 // 控制寄存器5
|
||||
#define CTRL6_C 0x15 // 控制寄存器6
|
||||
#define CTRL7_G 0x16 // 陀螺仪控制寄存器7
|
||||
#define CTRL8_XL 0x17 // 加速度计控制寄存器8
|
||||
#define CTRL9_XL 0x18 // 加速度计控制寄存器9
|
||||
#define CTRL10_C 0x19 // 控制寄存器10
|
||||
#define INT1_CTRL 0x0D // 中断1控制寄存器
|
||||
#define WAKE_UP_DUR 0x5B // 唤醒持续时间寄存器
|
||||
#define WAKE_UP_THS 0x5C // 唤醒阈值寄存器
|
||||
#define TAP_CFG 0x58 // 敲击配置寄存器
|
||||
#define TAP_THS_6D 0x59 // 6D方向阈值寄存器
|
||||
#define INT_DUR2 0x5A // 中断持续时间寄存器
|
||||
#define MD1_CFG 0x5E // 中断1配置寄存器
|
||||
#define MD2_CFG 0x5F // 中断2配置寄存器
|
||||
#define FUNC_SRC1 0x53 // 功能源寄存器1
|
||||
#define WAKE_UP_SRC 0x1B // 唤醒源寄存器
|
||||
|
||||
#define ACCEL_X_L 0x28 // OUTX_L_XL
|
||||
#define ACCEL_X_H 0x29 // OUTX_H_XL
|
||||
#define ACCEL_Y_L 0x2A // OUTY_L_XL
|
||||
#define ACCEL_Y_H 0x2B // OUTY_H_XL
|
||||
#define ACCEL_Z_L 0x2C // OUTZ_L_XL
|
||||
#define ACCEL_Z_H 0x2D // OUTZ_H_XL
|
||||
|
||||
#define ACCEL_SENSITIVITY_2G 0.061f // 2g 灵敏度 (g/LSB)
|
||||
|
||||
#define I2C_MASTER_TIMEOUT_MS 1000 // I2C主设备超时时间(毫秒)
|
||||
|
||||
/**
|
||||
* @class Gyroscope
|
||||
* @brief 陀螺仪驱动类,封装芯片操作
|
||||
*/
|
||||
#define TAG_GYROSCOPE "Gyroscope"
|
||||
class Gyroscope
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
Gyroscope();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~Gyroscope();
|
||||
|
||||
/**
|
||||
* @brief 初始化中断引脚
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 创建陀螺仪读取任务
|
||||
*/
|
||||
void CreateGyroReadTask();
|
||||
|
||||
/**
|
||||
* @brief 初始化陀螺仪
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t Init(i2c_bus_handle_t bus_handle);
|
||||
|
||||
/**
|
||||
* @brief 清除中断标志
|
||||
* @return esp_err_t 清除结果
|
||||
*/
|
||||
esp_err_t ClearInterruptFlags();
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取当前加速度数据
|
||||
* @param data 指向AccelerationData结构体的指针,用于存储读取到的加速度数据
|
||||
* @return esp_err_t 获取结果
|
||||
*/
|
||||
esp_err_t GetAcceleration(AccelerationData* data);
|
||||
|
||||
/**
|
||||
* @brief 创建500ms周期定时器
|
||||
* @return esp_err_t 创建结果
|
||||
*/
|
||||
esp_err_t CreateTimer();
|
||||
|
||||
/**
|
||||
* @brief 停止并删除定时器
|
||||
*/
|
||||
void DeleteTimer();
|
||||
|
||||
/**
|
||||
* @brief 注册摇晃检测回调函数
|
||||
* @param callback 当检测到摇晃时调用的回调函数
|
||||
*/
|
||||
void OnShake(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 注册拿起检测回调函数
|
||||
* @param callback 当检测到设备被拿起时调用的回调函数
|
||||
*/
|
||||
void OnPickUp(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 注册放置检测回调函数
|
||||
* @param callback 当检测到设备被放置时调用的回调函数
|
||||
*/
|
||||
void OnPutDown(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 注册倾斜检测回调函数
|
||||
* @param callback 当检测到设备倾斜时调用的回调函数
|
||||
*/
|
||||
void OnTilt(std::function<void()> callback);
|
||||
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
volatile uint8_t interrupt_count_ = 0; // 中断计数
|
||||
volatile bool interrupt_flag_ = false; // 中断标志位)(判断是否需要处理)
|
||||
|
||||
private:
|
||||
static void GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void GyroReadTask(void* pvParameters);
|
||||
static void TimerCallback(void* arg); // 定时器回调函数
|
||||
|
||||
void TimerInterruptHandler(); // 定时器中断处理函数
|
||||
|
||||
esp_err_t WriteRegister(uint8_t reg, uint8_t data);
|
||||
esp_err_t ReadRegister(uint8_t reg, uint8_t* data);
|
||||
esp_err_t ReadRegisters(uint8_t reg, uint8_t* data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief 读取原始加速度数据
|
||||
* @param x 指向X轴加速度存储的指针
|
||||
* @param y 指向Y轴加速度存储的指针
|
||||
* @param z 指向Z轴加速度存储的指针
|
||||
* @return esp_err_t 读取结果
|
||||
*/
|
||||
esp_err_t ReadRawAcceleration(int16_t* x, int16_t* y, int16_t* z);
|
||||
|
||||
std::function<void()> on_shake_callback_; // 摇晃回调函数
|
||||
std::function<void()> on_pickup_callback_; // 拿起回调函数
|
||||
std::function<void()> on_putdown_callback_; // 放置回调函数
|
||||
std::function<void()> on_tilt_callback_; // 倾斜回调函数
|
||||
|
||||
esp_timer_handle_t timer_handle_ = nullptr; // 定时器句柄
|
||||
|
||||
/**
|
||||
* @brief 分配静态任务所需的内存
|
||||
* @return bool 分配是否成功
|
||||
*/
|
||||
bool AllocateStaticTaskMemory();
|
||||
|
||||
/**
|
||||
* @brief 释放静态任务分配的内存
|
||||
*/
|
||||
void FreeStaticTaskMemory();
|
||||
|
||||
TaskHandle_t xGyroscopeTaskHandle_ = nullptr;
|
||||
StackType_t* pGyroscopeTaskStackBuffer_ = nullptr; // 任务栈指针(PSRAM)
|
||||
StaticTask_t* pxGyroscopeTaskBuffer_ = nullptr; // 任务控制块指针(内部RAM)
|
||||
|
||||
// 滤波相关成员变量
|
||||
int16_t last_filtered_x_ = 0; // 上一次滤波后的X轴值
|
||||
int16_t last_filtered_y_ = 0; // 上一次滤波后的Y轴值
|
||||
int16_t last_filtered_z_ = 0; // 上一次滤波后的Z轴值
|
||||
bool is_first_sample_ = true; // 是否为第一次采样标志
|
||||
|
||||
// 状态检测相关成员变量
|
||||
float accel_data_y_last_ = 0.0f; // 保存上一次Y轴数据
|
||||
float total_accel_last_ = 1.0f; // 保存上一次合成加速度值,初始值为1g(平放时的典型值)
|
||||
uint8_t stable_count_ = 0; // 稳定状态计数器
|
||||
uint8_t lift_count_ = 0; // 拿起动作计数器
|
||||
uint8_t putdown_count_ = 0; // 放置动作计数器
|
||||
bool is_stable_ = false; // 是否处于稳定平放状态
|
||||
bool is_lifted_ = false; // 是否处于被拿起状态
|
||||
};
|
||||
|
||||
#endif // GYROSCOPE_H
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/05_executors/gyroscope/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_EXEC_GYROSCOPE AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] gyroscope module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"05_executors/gyroscope/gyroscope.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"05_executors/gyroscope"
|
||||
)
|
||||
@@ -0,0 +1,202 @@
|
||||
#include "millimeter_wave_radar.h"
|
||||
#include <cstring>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
static const char *TAG = "MillimeterWaveRadar";
|
||||
|
||||
bool MillimeterWaveRadar::Init() {
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = MillimeterWaveRadar::BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(UART_NUM, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
ESP_ERROR_CHECK(uart_driver_install(UART_NUM, 256, 0, 0, NULL, 0));
|
||||
|
||||
// 清空缓冲区
|
||||
uart_flush(UART_NUM);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t MillimeterWaveRadar::CalculateChecksum(uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4) {
|
||||
return d1 ^ d2 ^ d3 ^ d4;
|
||||
}
|
||||
|
||||
// 通过查看最高位是0还是1来判断是否是写命令。但是查询感应模式时最高位不是1(5A 11 00 00 00 11 FE),输入的是0x11,所以仅对此条不适用。
|
||||
bool MillimeterWaveRadar::IsWriteCommand(uint8_t cmd) {
|
||||
if (cmd == 0x11) {
|
||||
return false;
|
||||
}
|
||||
return (cmd & 0x80) == 0x00; // 写命令高位为0
|
||||
}
|
||||
|
||||
bool MillimeterWaveRadar::SendFrame(const uint8_t *frame, size_t len) {
|
||||
int written = uart_write_bytes(UART_NUM, frame, len);
|
||||
uart_wait_tx_done(UART_NUM, pdMS_TO_TICKS(10));
|
||||
return written == (int)len;
|
||||
}
|
||||
|
||||
MillimeterWaveRadar::Result MillimeterWaveRadar::ReceiveFrame(uint8_t *buffer, size_t maxSize, size_t &receivedLen) {
|
||||
TickType_t start = xTaskGetTickCount();
|
||||
size_t total = 0;
|
||||
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(TIMEOUT_MS)) {
|
||||
size_t available;
|
||||
uart_get_buffered_data_len(UART_NUM, &available);
|
||||
if (available >= 7) {
|
||||
int read = uart_read_bytes(UART_NUM, buffer, 7, pdMS_TO_TICKS(10));
|
||||
if (read == 7) {
|
||||
receivedLen = 7;
|
||||
// 校验帧头尾
|
||||
if (buffer[0] != 0x5A || buffer[6] != 0xFE) {
|
||||
ESP_LOGW(TAG, "Invalid frame header/tail");
|
||||
return Result::CHECKSUM_ERROR;
|
||||
}
|
||||
// 校验 checksum
|
||||
uint8_t expected = CalculateChecksum(buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
if (expected != buffer[5]) {
|
||||
ESP_LOGW(TAG, "Checksum mismatch");
|
||||
return Result::CHECKSUM_ERROR;
|
||||
}
|
||||
return Result::OK;
|
||||
}
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
return Result::TIMEOUT;
|
||||
}
|
||||
|
||||
MillimeterWaveRadar::Result MillimeterWaveRadar::SetParameter(uint8_t paramId, uint32_t value) {
|
||||
if (!IsWriteCommand(paramId)) {
|
||||
return Result::INVALID_PARAM;
|
||||
}
|
||||
|
||||
uint8_t frame[7];
|
||||
frame[0] = 0x5A;
|
||||
frame[1] = paramId;
|
||||
|
||||
switch (paramId) {
|
||||
case SET_RADAR_DISTANCE_THRESHOLD:
|
||||
if (value < 100 || value > 65000) return Result::INVALID_PARAM;
|
||||
frame[2] = 0x00;
|
||||
frame[3] = (value >> 8) & 0xFF;
|
||||
frame[4] = value & 0xFF;
|
||||
ESP_LOGI(TAG, "Setting distance threshold to %d", static_cast<int>(value));
|
||||
break;
|
||||
case SET_RADAR_DELAY_TIME:
|
||||
if (value > 0xFFFFFF) return Result::INVALID_PARAM;
|
||||
frame[2] = (value >> 16) & 0xFF;
|
||||
frame[3] = (value >> 8) & 0xFF;
|
||||
frame[4] = value & 0xFF;
|
||||
ESP_LOGI(TAG, "Setting delay time to %d", static_cast<int>(value));
|
||||
break;
|
||||
case SET_RADAR_LOCKOUT_TIME:
|
||||
if (value > 0xFFFFFF) return Result::INVALID_PARAM;
|
||||
frame[2] = (value >> 16) & 0xFF;
|
||||
frame[3] = (value >> 8) & 0xFF;
|
||||
frame[4] = value & 0xFF;
|
||||
ESP_LOGI(TAG, "Setting lockout time to %d", static_cast<int>(value));
|
||||
break;
|
||||
case SET_RADAR_LIGHT_SENSOR_ENABLE:
|
||||
case SET_RADAR_OUTPUT_LEVEL:
|
||||
case SET_RADAR_POWER_MODE:
|
||||
case SET_RADAR_TRIGGER_MODE:
|
||||
case SET_RADAR_TX_POWER_LEVEL:
|
||||
case SET_RADAR_PWM_ENABLE:
|
||||
case SET_RADAR_PULSE_WIDTH:
|
||||
case SET_RADAR_SENSING_MODE:
|
||||
case SET_RADAR_SENSING_RESULT:
|
||||
if (value > 0xFF) return Result::INVALID_PARAM;
|
||||
frame[2] = 0x00;
|
||||
frame[3] = 0x00;
|
||||
frame[4] = value & 0xFF;
|
||||
break;
|
||||
case SET_RADAR_LIGHT_THRESHOLD:
|
||||
if (value > 0xFF) return Result::INVALID_PARAM;
|
||||
frame[2] = 0x00;
|
||||
frame[3] = 0x00;
|
||||
frame[4] = value & 0xFF;
|
||||
break;
|
||||
case SET_RADAR_PWM_DUTY:
|
||||
if (value > 3500) return Result::INVALID_PARAM;
|
||||
frame[2] = 0x00;
|
||||
frame[3] = (value >> 8) & 0xFF;
|
||||
frame[4] = value & 0xFF;
|
||||
break;
|
||||
default:
|
||||
return Result::INVALID_PARAM;
|
||||
}
|
||||
|
||||
frame[5] = CalculateChecksum(frame[1], frame[2], frame[3], frame[4]);
|
||||
frame[6] = 0xFE;
|
||||
|
||||
if (!SendFrame(frame, 7)) {
|
||||
return Result::UART_ERROR;
|
||||
}
|
||||
|
||||
uint8_t reply[7];
|
||||
size_t len;
|
||||
Result res = ReceiveFrame(reply, sizeof(reply), len);
|
||||
ESP_LOGW(TAG, "Received raw reply frame: %02X %02X %02X %02X %02X %02X %02X",
|
||||
reply[0], reply[1], reply[2], reply[3], reply[4], reply[5], reply[6]);
|
||||
if (res != Result::OK) return res;
|
||||
|
||||
// 发送保存指令
|
||||
uint8_t saveFrame[7] = {0x5A, 0x20, 0x00, 0x00, 0x01, 0x21, 0xFE};
|
||||
SendFrame(saveFrame, 7);
|
||||
// 等待保存回复(协议注释1:约100ms)
|
||||
vTaskDelay(pdMS_TO_TICKS(110)); // 稍微多等一点
|
||||
uart_flush(UART_NUM); // 清除可能的残留
|
||||
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
void MillimeterWaveRadar::OnRadarDetect(RadarDetectCallback callback) {
|
||||
ESP_LOGI(TAG, "Registering radar detection callback");
|
||||
radar_detect_callback_ = callback;
|
||||
}
|
||||
|
||||
void MillimeterWaveRadar::TriggerRadarDetectCallback() {
|
||||
ESP_LOGI(TAG, "Triggering radar detection callback");
|
||||
if (radar_detect_callback_) {
|
||||
radar_detect_callback_();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MillimeterWaveRadar::Result MillimeterWaveRadar::QueryParameter(uint8_t paramId, uint32_t &outputValue) {
|
||||
if (IsWriteCommand(paramId)) {
|
||||
ESP_LOGE(TAG, "Attempted to query with a write command ID: 0x%02X", paramId);
|
||||
return Result::INVALID_PARAM;
|
||||
}
|
||||
|
||||
uint8_t frame[7] = {0x5A, paramId, 0x00, 0x00, 0x00, paramId, 0xFE};
|
||||
ESP_LOGI(TAG, "Sending query frame for param 0x%02X: %02X %02X %02X %02X %02X %02X %02X",
|
||||
paramId, frame[0], frame[1], frame[2], frame[3], frame[4], frame[5], frame[6]);
|
||||
|
||||
if (!SendFrame(frame, 7)) {
|
||||
ESP_LOGE(TAG, "UART send failed");
|
||||
return Result::UART_ERROR;
|
||||
}
|
||||
|
||||
uint8_t reply[7];
|
||||
size_t len;
|
||||
Result res = ReceiveFrame(reply, sizeof(reply), len);
|
||||
if (res != Result::OK) {
|
||||
ESP_LOGW(TAG, "Failed to receive reply for param 0x%02X, error code: %d", paramId, static_cast<int>(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
// 打印原始回复帧(新增功能)
|
||||
ESP_LOGW(TAG, "Received raw reply frame: %02X %02X %02X %02X %02X %02X %02X",
|
||||
reply[0], reply[1], reply[2], reply[3], reply[4], reply[5], reply[6]);
|
||||
|
||||
return Result::OK;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <driver/uart.h>
|
||||
#include <functional>
|
||||
|
||||
// 参数名称宏定义(对应协议中的命令)
|
||||
#define SET_RADAR_DISTANCE_THRESHOLD 0x01 // 设置感应距离门限值。Data3、Data4 为感应距离门限值,取值范围为 100 ~ 65000【值越大,感应距离越近】
|
||||
#define SET_RADAR_DELAY_TIME 0x02 // 设置输出延时时间。取值范围为 0X00~ 0XFFFFFF
|
||||
#define SET_RADAR_LIGHT_SENSOR_ENABLE 0x03 // 开关光感。Data4 为 0x01 时开启光感,为 0x00 时关闭光感。
|
||||
#define SET_RADAR_LOCKOUT_TIME 0x04 // 设置封锁时间。取值范围为 0X00~ 0XFFFFFF
|
||||
#define SET_RADAR_OUTPUT_LEVEL 0x05 // 设置有效电平。Data4 为 0x01 时高电平有效,为 0x00 时低电平有效
|
||||
#define SET_RADAR_POWER_MODE 0x06 // 设置功耗模式。Data4 为 0x00 时超低功耗模式(50/60uA),为 0x01 时常规功耗模式(13mA 档位)
|
||||
#define SET_RADAR_SENSING_RESULT 0x07 // 设置触发状态。Data4 为 0x00 时触发状态为未触发感应,为 0x01 时触发状态为已触发感应。
|
||||
#define SET_RADAR_TRIGGER_MODE 0x0A // 设置触发模式。Data4 为 0x00 时触发模式为连续触发,为 0x01 时触发模式为单次触发。
|
||||
#define SET_RADAR_TX_POWER_LEVEL 0x0B // 设置发射功率档位。Data4 取值范围为 0~ 7,总共 8 档发射功率可调,值越大,功率越小,=7 时最小,相当于关闭发射功率。发射功率档位值越小,实际发射功率越大,距离越远,抗干扰性越好。
|
||||
#define SET_RADAR_LIGHT_THRESHOLD 0x0C // 设置光感门限值。取值范围为 0X00~ 0XFFFFFF。
|
||||
#define SET_RADAR_PWM_ENABLE 0x0D // 开关 PWM 功能
|
||||
#define SET_RADAR_PWM_DUTY 0x0E // 设置 PWM 占空比
|
||||
#define SET_RADAR_PULSE_WIDTH 0x0F // 设置供电脉冲宽度
|
||||
#define SET_RADAR_SENSING_MODE 0x10 // 选择感应模式。Data4 为 0x00 时为移动感应模式,为 0x01 时为手扫感应模式。
|
||||
|
||||
// 参数名称宏定义(对应协议中的命令)
|
||||
#define QUERY_RADAR_DISTANCE_THRESHOLD 0x81 // 查询感应距离门限值
|
||||
#define QUERY_RADAR_DELAY_TIME 0x82 // 查询输出延时时间
|
||||
#define QUERY_RADAR_LIGHT_SENSOR_ENABLE 0x83 // 查询开关光感
|
||||
#define QUERY_RADAR_LOCKOUT_TIME 0x84 // 查询封锁时间
|
||||
#define QUERY_RADAR_OUTPUT_LEVEL 0x85 // 查询有效电平
|
||||
#define QUERY_RADAR_POWER_MODE 0x86 // 查询功耗模式
|
||||
#define QUERY_RADAR_SENSING_RESULT 0x87 // 查询触发状态
|
||||
#define QUERY_RADAR_TRIGGER_MODE 0x8A // 查询触发模式
|
||||
#define QUERY_RADAR_TX_POWER_LEVEL 0x8B // 查询发射功率档位
|
||||
#define QUERY_RADAR_LIGHT_THRESHOLD 0x8C // 查询光感门限值
|
||||
#define QUERY_RADAR_PWM_ENABLE 0x8D // 查询开关 PWM 功能
|
||||
#define QUERY_RADAR_PWM_DUTY 0x8E // 查询 PWM 占空比
|
||||
#define QUERY_RADAR_PULSE_WIDTH 0x8F // 查询供电脉冲宽度
|
||||
#define QUERY_RADAR_SENSING_MODE 0x11 // 查询感应模式
|
||||
|
||||
class MillimeterWaveRadar {
|
||||
public:
|
||||
// 雷达检测回调函数类型定义
|
||||
typedef std::function<void(void)> RadarDetectCallback;
|
||||
enum class Result {
|
||||
OK,
|
||||
TIMEOUT,
|
||||
CHECKSUM_ERROR,
|
||||
INVALID_PARAM,
|
||||
UART_ERROR
|
||||
};
|
||||
|
||||
// 初始化 UART(使用 UART1, TX=GPIO39, RX=GPIO40)
|
||||
bool Init();
|
||||
|
||||
// 设置参数(自动保存)
|
||||
Result SetParameter(uint8_t paramId, uint32_t value);
|
||||
|
||||
// 查询参数(返回值通过 outputValue 返回)
|
||||
Result QueryParameter(uint8_t paramId, uint32_t &outputValue);
|
||||
|
||||
Result QueryRawResponse(uint8_t paramId);
|
||||
|
||||
// 注册雷达检测回调函数
|
||||
void OnRadarDetect(RadarDetectCallback callback);
|
||||
|
||||
// 触发雷达检测回调函数(供IO扩展板调用)
|
||||
void TriggerRadarDetectCallback();
|
||||
|
||||
private:
|
||||
static constexpr uart_port_t UART_NUM = UART_NUM_1;
|
||||
static constexpr int TX_PIN = 39;
|
||||
static constexpr int RX_PIN = 40;
|
||||
static constexpr uint32_t BAUD_RATE = 9600;
|
||||
static constexpr uint32_t TIMEOUT_MS = 100;
|
||||
|
||||
// 雷达检测回调函数
|
||||
RadarDetectCallback radar_detect_callback_ = nullptr;
|
||||
|
||||
bool SendFrame(const uint8_t *frame, size_t len);
|
||||
Result ReceiveFrame(uint8_t *buffer, size_t maxSize, size_t &receivedLen);
|
||||
uint8_t CalculateChecksum(uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4);
|
||||
bool IsWriteCommand(uint8_t cmd);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/05_executors/millimeter_wave_radar/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_EXEC_MILLIMETER_WAVE_RADAR AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] millimeter_wave_radar module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"05_executors/millimeter_wave_radar/millimeter_wave_radar.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"05_executors/millimeter_wave_radar"
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/05_executors/photo_interrupter/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_EXEC_PHOTO_INTERRUPTER AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] photo_interrupter module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"05_executors/photo_interrupter/photo_interrupter.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"05_executors/photo_interrupter"
|
||||
)
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @file photo_interrupter.cc
|
||||
* @brief 光电限位开关类实现文件
|
||||
*
|
||||
* 该类实现了光电限位开关的完整功能,包括初始化、中断处理、
|
||||
* 回调函数管理等。支持起始位置和结束位置两个限位开关的检测。
|
||||
*/
|
||||
|
||||
#include "photo_interrupter.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "PhotoInterrupter" ///< 日志标签,用于ESP-IDF日志系统
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*
|
||||
* 初始化PhotoInterrupter对象,设置默认状态
|
||||
* 目前构造函数为空,所有初始化操作在Init()方法中完成
|
||||
*/
|
||||
PhotoInterrupter::PhotoInterrupter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*
|
||||
* 清理资源,释放分配的内存
|
||||
* 目前析构函数为空,没有需要特殊清理的资源
|
||||
*/
|
||||
PhotoInterrupter::~PhotoInterrupter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化限位开关
|
||||
*
|
||||
* 执行限位开关的初始化操作,包括:
|
||||
* 1. 输出初始化日志
|
||||
* 2. 设置默认的起始限位开关回调函数
|
||||
* 3. 设置默认的结束限位开关回调函数
|
||||
*
|
||||
* 默认回调函数仅输出触发日志,用户可以通过OnStartTrigger()和OnEndTrigger()
|
||||
* 方法覆盖这些默认回调函数
|
||||
*/
|
||||
void PhotoInterrupter::Init()
|
||||
{
|
||||
ESP_LOGI(TAG, "限位开关初始化");
|
||||
|
||||
// 设置默认回调函数 - 起始限位开关触发时输出日志
|
||||
OnStartTrigger([]() {
|
||||
ESP_LOGI(TAG, "起始限位开关触发 - 默认回调");
|
||||
});
|
||||
|
||||
// 设置默认回调函数 - 结束限位开关触发时输出日志
|
||||
OnEndTrigger([]() {
|
||||
ESP_LOGI(TAG, "结束限位开关触发 - 默认回调");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理限位开关中断
|
||||
*
|
||||
* 当限位开关被触发时调用的中断处理函数
|
||||
* 目前仅输出中断触发日志,可以根据需要扩展更多处理逻辑
|
||||
*/
|
||||
void PhotoInterrupter::Interrupt()
|
||||
{
|
||||
ESP_LOGI(TAG, "限位开关中断触发");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置起始限位开关触发回调函数
|
||||
* @param callback 回调函数对象,当起始限位开关被触发时执行
|
||||
*
|
||||
* 允许用户自定义起始限位开关被触发时的处理逻辑。
|
||||
* 该函数会保存传入的回调函数,并输出注册日志。
|
||||
*/
|
||||
void PhotoInterrupter::OnStartTrigger(std::function<void()> callback)
|
||||
{
|
||||
on_start_trigger_ = callback;
|
||||
ESP_LOGI(TAG, "注册起始限位开关回调函数");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置结束限位开关触发回调函数
|
||||
* @param callback 回调函数对象,当结束限位开关被触发时执行
|
||||
*
|
||||
* 允许用户自定义结束限位开关被触发时的处理逻辑。
|
||||
* 该函数会保存传入的回调函数,并输出注册日志。
|
||||
*/
|
||||
void PhotoInterrupter::OnEndTrigger(std::function<void()> callback)
|
||||
{
|
||||
on_end_trigger_ = callback;
|
||||
ESP_LOGI(TAG, "注册结束限位开关回调函数");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 触发起始限位开关回调
|
||||
*
|
||||
* 当检测到起始限位开关被触发时,执行注册的回调函数。
|
||||
* 如果回调函数已设置(不为nullptr),则执行回调并输出触发日志。
|
||||
*
|
||||
* 该函数通常由IO扩展板在检测到起始限位开关中断时调用。
|
||||
*/
|
||||
void PhotoInterrupter::TriggerStartCallback()
|
||||
{
|
||||
if (on_start_trigger_) {
|
||||
ESP_LOGI(TAG, "触发起始限位开关回调");
|
||||
on_start_trigger_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 触发结束限位开关回调
|
||||
*
|
||||
* 当检测到结束限位开关被触发时,执行注册的回调函数。
|
||||
* 如果回调函数已设置(不为nullptr),则执行回调并输出触发日志。
|
||||
*
|
||||
* 该函数通常由IO扩展板在检测到结束限位开关中断时调用。
|
||||
*/
|
||||
void PhotoInterrupter::TriggerEndCallback()
|
||||
{
|
||||
if (on_end_trigger_) {
|
||||
ESP_LOGI(TAG, "触发结束限位开关回调");
|
||||
on_end_trigger_();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file photo_interrupter.h
|
||||
* @brief 光电限位开关类头文件
|
||||
*
|
||||
* 该类用于处理光电限位开关的触发事件,支持起始位置和结束位置的检测。
|
||||
* 通过回调函数机制,当限位开关被触发时执行相应的处理逻辑。
|
||||
*/
|
||||
|
||||
#ifndef PHOTO_INTERRUPTER_H
|
||||
#define PHOTO_INTERRUPTER_H
|
||||
|
||||
#include "io_expansion_board.h"
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* @class PhotoInterrupter
|
||||
* @brief 光电限位开关类
|
||||
*
|
||||
* 提供限位开关的初始化、中断处理和回调函数管理功能。
|
||||
* 支持起始位置和结束位置两个限位开关的检测。
|
||||
*/
|
||||
class PhotoInterrupter {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*
|
||||
* 初始化PhotoInterrupter对象,设置默认状态
|
||||
*/
|
||||
PhotoInterrupter();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*
|
||||
* 清理资源,释放分配的内存
|
||||
*/
|
||||
~PhotoInterrupter();
|
||||
|
||||
/**
|
||||
* @brief 初始化限位开关
|
||||
*
|
||||
* 执行限位开关的初始化操作,包括设置默认回调函数
|
||||
*/
|
||||
void Init();
|
||||
|
||||
/**
|
||||
* @brief 处理限位开关中断
|
||||
*
|
||||
* 当限位开关被触发时调用的中断处理函数
|
||||
*/
|
||||
void Interrupt();
|
||||
|
||||
/**
|
||||
* @brief 设置起始限位开关触发回调函数
|
||||
* @param callback 回调函数对象,当起始限位开关被触发时执行
|
||||
*
|
||||
* 允许用户自定义起始限位开关被触发时的处理逻辑
|
||||
*/
|
||||
void OnStartTrigger(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 设置结束限位开关触发回调函数
|
||||
* @param callback 回调函数对象,当结束限位开关被触发时执行
|
||||
*
|
||||
* 允许用户自定义结束限位开关被触发时的处理逻辑
|
||||
*/
|
||||
void OnEndTrigger(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 触发起始限位开关回调
|
||||
*
|
||||
* 当检测到起始限位开关被触发时,执行注册的回调函数
|
||||
*/
|
||||
void TriggerStartCallback();
|
||||
|
||||
/**
|
||||
* @brief 触发结束限位开关回调
|
||||
*
|
||||
* 当检测到结束限位开关被触发时,执行注册的回调函数
|
||||
*/
|
||||
void TriggerEndCallback();
|
||||
|
||||
private:
|
||||
std::function<void()> on_start_trigger_; ///< 起始限位开关回调函数
|
||||
std::function<void()> on_end_trigger_; ///< 结束限位开关回调函数
|
||||
};
|
||||
|
||||
#endif // PHOTO_INTERRUPTER_H
|
||||
@@ -0,0 +1,150 @@
|
||||
# 获取当前选择的 demo 配置
|
||||
if(CONFIG_SWEEKAR_DEMO_1)
|
||||
set(ACTIVE_DEMO "sweekar_demo1")
|
||||
elseif(CONFIG_SWEEKAR_DEMO_2)
|
||||
set(ACTIVE_DEMO "sweekar_demo2")
|
||||
elseif(CONFIG_SWEEKAR_DEMO_3)
|
||||
set(ACTIVE_DEMO "sweekar_demo3")
|
||||
elseif(CONFIG_SWEEKAR_DEMO_4)
|
||||
set(ACTIVE_DEMO "sweekar_demo4")
|
||||
elseif(CONFIG_SWEEKAR_DEMO_5)
|
||||
set(ACTIVE_DEMO "sweekar_demo5")
|
||||
elseif(CONFIG_SWEEKAR_DEMO_6)
|
||||
set(ACTIVE_DEMO "sweekar_demo6")
|
||||
elseif(CONFIG_SWEEKAR_DEMO_7)
|
||||
set(ACTIVE_DEMO "sweekar_demo7")
|
||||
endif()
|
||||
|
||||
# 初始化全局变量,用于收集各模块的信息
|
||||
set(MODULE_SRCS)
|
||||
set(MODULE_INCLUDE_DIRS)
|
||||
set(MODULE_REQUIRES)
|
||||
set(MODULE_PRIV_REQUIRES)
|
||||
set(MODULE_EMBED_TXTFILES)
|
||||
|
||||
if(NOT DEFINED CONFIG_SWEEKAR_DEMO_SELECTION)
|
||||
set(EARLY_EXPANSION TRUE)
|
||||
message(STATUS "Early expansion pass: loading all module requirements")
|
||||
else()
|
||||
set(EARLY_EXPANSION FALSE)
|
||||
endif()
|
||||
|
||||
# ===================================================================
|
||||
# 执行 Kconfig 自动组装脚本 (在配置阶段自动生成 Kconfig.modules)
|
||||
# ===================================================================
|
||||
execute_process(
|
||||
COMMAND python3 ${CMAKE_CURRENT_LIST_DIR}/generate_kconfig_modules.py
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
RESULT_VARIABLE generate_kconfig_result
|
||||
)
|
||||
if(NOT generate_kconfig_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to generate Kconfig.modules")
|
||||
endif()
|
||||
|
||||
# ==================== 模块注册区 ====================
|
||||
# 定义需要扫描的架构层级目录
|
||||
set(SUBSYSTEM_DIRS
|
||||
"04_hal"
|
||||
"05_executors"
|
||||
"05_service"
|
||||
"06_behaviors"
|
||||
"tests"
|
||||
)
|
||||
|
||||
# 扫描并加载所有启用的子模块(依赖各个模块中的 module.cmake)
|
||||
foreach(dir ${SUBSYSTEM_DIRS})
|
||||
file(GLOB MODULE_FILES "${CMAKE_CURRENT_LIST_DIR}/${dir}/*/module.cmake")
|
||||
foreach(mod_file ${MODULE_FILES})
|
||||
include(${mod_file})
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# sweekar_demos 模块 (单独加载)
|
||||
# include(${CMAKE_CURRENT_LIST_DIR}/sweekar_demos/module.cmake)
|
||||
|
||||
# ===================================================================
|
||||
|
||||
if(MODULE_REQUIRES)
|
||||
list(REMOVE_DUPLICATES MODULE_REQUIRES)
|
||||
endif()
|
||||
if(MODULE_PRIV_REQUIRES)
|
||||
list(REMOVE_DUPLICATES MODULE_PRIV_REQUIRES)
|
||||
endif()
|
||||
|
||||
message(STATUS "==== DEBUG ====")
|
||||
message(STATUS "MODULE_REQUIRES: ${MODULE_REQUIRES}")
|
||||
message(STATUS "MODULE_SRCS: ${MODULE_SRCS}")
|
||||
message(STATUS "===============")
|
||||
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"main.cc"
|
||||
# "tests/test.cc"
|
||||
# "tests/korvo_port/korvo_port_runner.cc"
|
||||
# "tests/korvo_port/ai_agent.c"
|
||||
# "tests/korvo_port/audio_proc.c"
|
||||
# "tests/korvo_port/rtc_proc.c"
|
||||
# "../managed_components/espressif__zlib/zlib/contrib/minizip/unzip.c"
|
||||
# "../managed_components/espressif__zlib/zlib/contrib/minizip/ioapi.c"
|
||||
${MODULE_SRCS}
|
||||
INCLUDE_DIRS
|
||||
"."
|
||||
# "../managed_components/espressif__zlib/zlib/contrib/minizip"
|
||||
# "05_executors/touch_sensor"
|
||||
# "05_executors/aw_touch_sensor"
|
||||
${MODULE_INCLUDE_DIRS}
|
||||
|
||||
REQUIRES
|
||||
# lvgl
|
||||
# esp_timer
|
||||
# driver
|
||||
# esp_driver_i2c
|
||||
# esp_driver_i2s
|
||||
# esp_event
|
||||
# nvs_flash
|
||||
# spi_flash
|
||||
# esp_driver_gpio
|
||||
# spiffs
|
||||
# vfs
|
||||
# esp_http_server
|
||||
# log
|
||||
# fatfs
|
||||
# bt
|
||||
# mbedtls
|
||||
# audio_pipeline
|
||||
# audio_hal
|
||||
# audio_board
|
||||
# esp_peripherals
|
||||
# audio_stream
|
||||
# audio_sal
|
||||
# esp-adf-libs
|
||||
# espressif__zlib
|
||||
${MODULE_REQUIRES}
|
||||
PRIV_REQUIRES
|
||||
# esp-qcloud
|
||||
${MODULE_PRIV_REQUIRES}
|
||||
EMBED_TXTFILES
|
||||
${MODULE_EMBED_TXTFILES}
|
||||
)
|
||||
# 添加 C++ 标准库支持
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# 自动创建SPIFFS分区镜像
|
||||
# 这会在构建时自动生成audio.bin并在烧录时一并烧录
|
||||
# spiffs_create_partition_image(audio ../spiffs FLASH_IN_PROJECT)
|
||||
|
||||
# 添加编译选项来忽略字符串常量转换警告
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-write-strings)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE -DUSE_FILE32API)
|
||||
|
||||
|
||||
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
|
||||
|
||||
# 根据 boards 目录内部模块自动匹配当前选择的板卡
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/02_physical/boards/module.cmake)
|
||||
|
||||
if (CONFIG_VOLC_RTC_MODE)
|
||||
set(COMPONENT_SRCS ${COMPONENT_SRCS} RtcBotUtils.c)
|
||||
endif()
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE IOAPI_NO_64)
|
||||
@@ -0,0 +1,52 @@
|
||||
menu "Sweekar Subsystems Configuration"
|
||||
|
||||
menu "04 Hal Modules"
|
||||
config ENABLE_HAL_AUDIO_CODEC
|
||||
bool "Enable Audio Codec"
|
||||
default y
|
||||
help
|
||||
Enable the audio_codec module in 04_hal.
|
||||
config ENABLE_HAL_BASE_BOARD_HAL
|
||||
bool "Enable Base Board Hal"
|
||||
default y
|
||||
help
|
||||
Enable the base_board_hal module in 04_hal.
|
||||
config ENABLE_HAL_STEPPER_DRIVER
|
||||
bool "Enable Stepper Driver"
|
||||
default y
|
||||
help
|
||||
Enable the stepper_driver module in 04_hal.
|
||||
endmenu
|
||||
|
||||
menu "05 Executors Modules"
|
||||
config ENABLE_EXEC_ADC_BATTERY_MONITOR
|
||||
bool "Enable Adc Battery Monitor"
|
||||
default y
|
||||
help
|
||||
Enable the adc_battery_monitor module in 05_executors.
|
||||
config ENABLE_EXEC_BASE_BOARD_CONTROL
|
||||
bool "Enable Base Board Control"
|
||||
default y
|
||||
help
|
||||
Enable the base_board_control module in 05_executors.
|
||||
config ENABLE_EXEC_GYROSCOPE
|
||||
bool "Enable Gyroscope"
|
||||
default y
|
||||
help
|
||||
Enable the gyroscope module in 05_executors.
|
||||
config ENABLE_EXEC_MILLIMETER_WAVE_RADAR
|
||||
bool "Enable Millimeter Wave Radar"
|
||||
default y
|
||||
help
|
||||
Enable the millimeter_wave_radar module in 05_executors.
|
||||
config ENABLE_EXEC_PHOTO_INTERRUPTER
|
||||
bool "Enable Photo Interrupter"
|
||||
default y
|
||||
help
|
||||
Enable the photo_interrupter module in 05_executors.
|
||||
endmenu
|
||||
|
||||
menu "tests Modules"
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,544 @@
|
||||
menu "Sweekar Application Configuration"
|
||||
|
||||
# ==============================================================
|
||||
# 模块化配置自动扫描引入点
|
||||
# 这里会自动加载 main/Kconfig.modules 文件
|
||||
# ==============================================================
|
||||
rsource "Kconfig.modules"
|
||||
|
||||
choice BOARD_VERSION_SELECTION
|
||||
prompt "Select Board Version"
|
||||
default BOARD_VERSION_V1_1_11
|
||||
help
|
||||
Select the hardware board version to use.
|
||||
|
||||
config BOARD_VERSION_V1_1_11
|
||||
bool "Board v1.1.11"
|
||||
help
|
||||
Use board version v1.1.11
|
||||
|
||||
config BOARD_VERSION_V1_1_12
|
||||
bool "Board v1.1.12"
|
||||
help
|
||||
Use board version v1.1.12
|
||||
|
||||
config BOARD_VERSION_V1_1_13
|
||||
bool "Board v1.1.13"
|
||||
help
|
||||
Use board version v1.1.13
|
||||
|
||||
config BOARD_VERSION_V1_1_14
|
||||
bool "Board v1.1.14"
|
||||
help
|
||||
Use board version v1.1.14
|
||||
|
||||
config BOARD_VERSION_V1_1_16
|
||||
bool "Board v1.1.16"
|
||||
help
|
||||
Use board version v1.1.16
|
||||
|
||||
config BOARD_VERSION_V1_1_17
|
||||
bool "Board v1.1.17"
|
||||
help
|
||||
Use board version v1.1.17
|
||||
|
||||
config BOARD_VERSION_V1_1_18
|
||||
bool "Board v1.1.18"
|
||||
help
|
||||
Use board version v1.1.18
|
||||
|
||||
endchoice
|
||||
|
||||
choice STEPPER_DRIVER_IMPL
|
||||
prompt "Stepper Driver Implementation"
|
||||
default STEPPER_DRIVER_DRV8428
|
||||
help
|
||||
Select the stepper motor driver chip.
|
||||
|
||||
config STEPPER_DRIVER_DRV8428
|
||||
bool "TI DRV8428"
|
||||
help
|
||||
Use TI DRV8428 stepper motor driver.
|
||||
|
||||
config STEPPER_DRIVER_AW8646
|
||||
bool "Awinic AW8646"
|
||||
help
|
||||
Use Awinic AW8646 stepper motor driver.
|
||||
|
||||
endchoice
|
||||
|
||||
choice LINEAR_MOTOR_TYPE
|
||||
prompt "Linear Motor Type"
|
||||
default LINEAR_MOTOR_LD0832
|
||||
help
|
||||
Select the linear motor type.
|
||||
|
||||
config LINEAR_MOTOR_LD0832
|
||||
bool "LD0832 (1.8V, 235Hz, 21 ohm)"
|
||||
help
|
||||
Use LD0832 linear motor.
|
||||
|
||||
config LINEAR_MOTOR_LD0625
|
||||
bool "LD0625 (0.7V, 260Hz, 8 ohm)"
|
||||
help
|
||||
Use LD0625 linear motor.
|
||||
|
||||
endchoice
|
||||
|
||||
choice AUDIO_DECODER_SUPPORT
|
||||
prompt "Audio Decoder"
|
||||
default AUDIO_SUPPORT_OPUS_DECODER
|
||||
|
||||
config AUDIO_SUPPORT_G711A_DECODER
|
||||
bool "AUDIUO-G711-DECODER"
|
||||
|
||||
config AUDIO_SUPPORT_OPUS_DECODER
|
||||
bool "AUDIO-OPUS-DECODER"
|
||||
|
||||
config AUDIO_SUPPORT_AAC_DECODER
|
||||
bool "AUDIO-AAC-DECODER"
|
||||
|
||||
endchoice
|
||||
|
||||
choice AUDIO_CONVERSATION_MODE_SUPPORT
|
||||
prompt "Conversion Mode"
|
||||
default CONTINUOUS_CONVERSATION_MODE
|
||||
|
||||
config LANGUAGE_WAKEUP_MODE
|
||||
select USE_WAKENET
|
||||
select SR_WN_WN9_HILEXIN
|
||||
bool "LANGUAGE-WAKEUP-MODE"
|
||||
|
||||
config CONTINUOUS_CONVERSATION_MODE
|
||||
bool "CONTINUOUS-CONVERSATION-MODE"
|
||||
|
||||
endchoice
|
||||
|
||||
choice RTC_MODE_CHOICE
|
||||
prompt "rtc mode choice"
|
||||
default COZE_REQUEST
|
||||
help
|
||||
Select rtc request mode
|
||||
|
||||
config COZE_REQUEST
|
||||
bool "enable coze request"
|
||||
|
||||
config RTC_TOKEN_REQUEST
|
||||
bool "enable rtc token request"
|
||||
endchoice
|
||||
|
||||
choice RTC_BACKEND_PROVIDER
|
||||
prompt "RTC backend provider"
|
||||
default RTC_BACKEND_VOLC
|
||||
help
|
||||
Select the RTC SDK backend used by the AI RTC service.
|
||||
|
||||
config RTC_BACKEND_VOLC
|
||||
bool "VolcEngine RTC (current default)"
|
||||
|
||||
config RTC_BACKEND_AGORA
|
||||
bool "Agora RTC (migration target)"
|
||||
endchoice
|
||||
|
||||
menu "Agora RTC Configuration"
|
||||
depends on RTC_BACKEND_AGORA
|
||||
|
||||
config AGORA_SDK_ENABLED
|
||||
bool "Agora SDK integrated"
|
||||
default n
|
||||
help
|
||||
Enable this option after adding Agora RTC SDK headers/libs.
|
||||
|
||||
config AGORA_APP_ID
|
||||
string "Agora App ID"
|
||||
default ""
|
||||
|
||||
config AGORA_TOKEN
|
||||
string "Agora RTC Token"
|
||||
default ""
|
||||
|
||||
config AGORA_CHANNEL
|
||||
string "Agora Channel Name"
|
||||
default "default"
|
||||
|
||||
config AGORA_UID
|
||||
int "Agora Local UID"
|
||||
default 0
|
||||
endmenu
|
||||
|
||||
choice TOUCH_SENSOR_IMPL
|
||||
prompt "Touch Sensor Implementation"
|
||||
default TOUCH_SENSOR_IMPL_ESP
|
||||
|
||||
config TOUCH_SENSOR_IMPL_ESP
|
||||
bool "ESP32 Touch Pad"
|
||||
help
|
||||
Use ESP32 internal touch sensor (via touch_pad).
|
||||
|
||||
config TOUCH_SENSOR_IMPL_AW
|
||||
bool "Awinic Touch Sensor"
|
||||
help
|
||||
Use Awinic AW933xx touch sensor.
|
||||
|
||||
endchoice
|
||||
|
||||
choice BASE_BOARD_COMM_INTERFACE
|
||||
prompt "Base Board Communication Interface"
|
||||
default BASE_BOARD_COMM_UART
|
||||
help
|
||||
Select the communication interface for the base board.
|
||||
|
||||
config BASE_BOARD_COMM_UART
|
||||
bool "UART (Legacy)"
|
||||
help
|
||||
Use UART for base board communication.
|
||||
|
||||
config BASE_BOARD_COMM_I2C
|
||||
bool "I2C (v1.1.16+)"
|
||||
help
|
||||
Use I2C for base board communication.
|
||||
endchoice
|
||||
|
||||
|
||||
config COZE_URL
|
||||
string "COZE-URL"
|
||||
default "http://115.190.92.216:8899/startvoicechat"
|
||||
depends on COZE_REQUEST
|
||||
|
||||
config COZE_AUTHORIZATION
|
||||
string "COZE-AUTHORIZATION"
|
||||
default "af78e3067582ac8c04ba20174410bd1"
|
||||
depends on COZE_REQUEST
|
||||
|
||||
config COZE_BOTID
|
||||
string "COZE-BOTID"
|
||||
default "ep-20241104163951-sdmjc"
|
||||
depends on COZE_REQUEST
|
||||
|
||||
|
||||
config RTC_TOKEN
|
||||
depends on RTC_TOKEN_REQUEST
|
||||
config APPID
|
||||
string "appid"
|
||||
depends on RTC_TOKEN_REQUEST
|
||||
|
||||
config ROOMID
|
||||
string "roomid"
|
||||
depends on RTC_TOKEN_REQUEST
|
||||
|
||||
config UID
|
||||
string "userid"
|
||||
depends on RTC_TOKEN_REQUEST
|
||||
|
||||
config TOKEN
|
||||
string "token"
|
||||
depends on RTC_TOKEN_REQUEST
|
||||
|
||||
config ENABLE_RECORDER_DEBUG
|
||||
bool "enable recorder debug save to sdcard"
|
||||
default "n"
|
||||
help
|
||||
Save the data processed by AEC to the SD card. The saved file name is "rec.pcm", and by default, 30 seconds' worth of data will be saved.
|
||||
|
||||
config ENABLE_OTA_UPDATE
|
||||
bool "Enable OTA Update"
|
||||
default y
|
||||
help
|
||||
Enable or disable OTA
|
||||
|
||||
choice OTA_UPDATE_STRATEGY
|
||||
prompt "OTA Update Strategy"
|
||||
default OTA_MODE_NOTIFY
|
||||
depends on ENABLE_OTA_UPDATE
|
||||
help
|
||||
Select the OTA update strategy
|
||||
|
||||
config OTA_MODE_AUTO
|
||||
bool "Auto Update (Immediate)"
|
||||
help
|
||||
Automatically download and install updates immediately
|
||||
|
||||
config OTA_MODE_NOTIFY
|
||||
bool "Notify Update (Wait for Confirmation)"
|
||||
help
|
||||
Wait for user confirmation before starting the OTA update process.
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
menu "QCloud COS Download Configuration"
|
||||
|
||||
config QCLOUD_COS_QUEUE_SIZE
|
||||
int "COS download queue size"
|
||||
default 20
|
||||
range 1 100
|
||||
help
|
||||
Number of pending COS download messages that can be buffered.
|
||||
|
||||
config QCLOUD_COS_WORKER_COUNT
|
||||
int "COS worker thread count"
|
||||
default 1
|
||||
range 1 4
|
||||
help
|
||||
Number of worker threads for COS download processing.
|
||||
|
||||
config QCLOUD_COS_WORKER_STACK_SIZE
|
||||
int "COS worker stack size (bytes)"
|
||||
default 16384
|
||||
range 4096 65536
|
||||
help
|
||||
Stack size in bytes for each COS worker thread.
|
||||
|
||||
config QCLOUD_COS_HTTP_BUFFER_SIZE
|
||||
int "COS HTTP download buffer size (bytes)"
|
||||
default 32768
|
||||
range 4096 131072
|
||||
help
|
||||
Buffer size used by HTTP read and esp_http_client internal buffer.
|
||||
|
||||
config QCLOUD_COS_ZIP_UNZIP_BUFFER_SIZE
|
||||
int "COS ZIP unzip read buffer size (bytes)"
|
||||
default 32768
|
||||
range 4096 131072
|
||||
help
|
||||
Buffer size used when reading compressed data from ZIP entries.
|
||||
|
||||
config QCLOUD_COS_SD_WRITE_BUFFER_SIZE
|
||||
int "COS SD write buffer size (bytes)"
|
||||
default 32768
|
||||
range 4096 131072
|
||||
help
|
||||
stdio write buffer size for HTTP download and ZIP extraction output.
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
menu "WiFi Configuration"
|
||||
config ENABLE_HARDCODED_WIFI
|
||||
bool "Enable Hardcoded WiFi Credentials"
|
||||
default n
|
||||
help
|
||||
If enabled, the device will first attempt to connect to the specified WiFi network.
|
||||
If disabled or connection fails, it will fall back to SmartConfig/QCloud provisioning.
|
||||
|
||||
config HARDCODED_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
depends on ENABLE_HARDCODED_WIFI
|
||||
default ""
|
||||
help
|
||||
The SSID of the WiFi network to connect to.
|
||||
Leave empty to fallback to SmartConfig/QCloud provisioning.
|
||||
|
||||
config HARDCODED_WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
depends on ENABLE_HARDCODED_WIFI
|
||||
default ""
|
||||
help
|
||||
The password of the WiFi network to connect to.
|
||||
endmenu
|
||||
|
||||
# Sweekar Demo Selection
|
||||
menu "Sweekar Demo Selection"
|
||||
|
||||
choice SWEEKAR_DEMO_SELECTION
|
||||
prompt "Select Active Demo"
|
||||
default SWEEKAR_DEMO_3
|
||||
help
|
||||
Select which demo to build and run. Only one demo can be active at a time.
|
||||
|
||||
config SWEEKAR_DEMO_2
|
||||
bool "Demo 2"
|
||||
|
||||
config SWEEKAR_DEMO_3
|
||||
bool "Demo 3 - Basic Pet Game"
|
||||
|
||||
config SWEEKAR_DEMO_5
|
||||
bool "Demo 5"
|
||||
|
||||
config SWEEKAR_DEMO_6
|
||||
bool "Demo 6 - Layered Architecture"
|
||||
|
||||
config SWEEKAR_DEMO_7
|
||||
bool "Demo 7 - Microkernel Architecture"
|
||||
|
||||
endchoice
|
||||
|
||||
config ACTIVE_DEMO_NAME
|
||||
string
|
||||
default "sweekar_demo2" if SWEEKAR_DEMO_2
|
||||
default "sweekar_demo3" if SWEEKAR_DEMO_3
|
||||
default "sweekar_demo5" if SWEEKAR_DEMO_5
|
||||
default "sweekar_demo6" if SWEEKAR_DEMO_6
|
||||
default "sweekar_demo7" if SWEEKAR_DEMO_7
|
||||
|
||||
config SWEEKAR_DEMO6_HATCHING5_TVC
|
||||
bool "Use TVC version for Hatching 5"
|
||||
depends on SWEEKAR_DEMO_6
|
||||
default n
|
||||
help
|
||||
If enabled, plays EGG_EMORAISING_HATCHING5_TVC instead of EGG_EMORAISING_HATCHING5_NORMAL during the final hatching stage.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "ESP QCloud Example Configuration"
|
||||
menu "Light development board selection "
|
||||
choice LIGHTBULB_DEMO_DRIVER_SELECT
|
||||
bool "Demo select"
|
||||
default LIGHTBULB_DEMO_DRIVER_SELECT_WS2812 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32H2
|
||||
default LIGHTBULB_DEMO_DRIVER_SELECT_PWM
|
||||
help
|
||||
Select the driver type you want to demonstrate
|
||||
|
||||
config LIGHTBULB_DEMO_DRIVER_SELECT_SM2135E
|
||||
bool "Demo SM2135E"
|
||||
config LIGHTBULB_DEMO_DRIVER_SELECT_WS2812
|
||||
bool "Demo WS2812"
|
||||
config LIGHTBULB_DEMO_DRIVER_SELECT_PWM
|
||||
bool "Demo PWM"
|
||||
endchoice
|
||||
|
||||
config WS2812_LED_GPIO
|
||||
int "WS2812 LED GPIO"
|
||||
default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32H2
|
||||
default 18 if IDF_TARGET_ESP32S2
|
||||
default 48 if IDF_TARGET_ESP32S3
|
||||
default 4 if IDF_TARGET_ESP32C2
|
||||
default 18
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_WS2812
|
||||
help
|
||||
Set the WS2812 RGB LED GPIO.
|
||||
|
||||
config WS2812_LED_NUM
|
||||
int "WS2812 LED NUM"
|
||||
default 1
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_WS2812
|
||||
help
|
||||
Set the WS2812 LED NUM.
|
||||
|
||||
config PWM_FREQ_HZ
|
||||
int "PWM Frequency (hz)"
|
||||
default 4000
|
||||
range 2000 5000
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
|
||||
help
|
||||
Set the PWM Frequency (hz).
|
||||
|
||||
config PWM_RED_GPIO
|
||||
int "PWM Red GPIO"
|
||||
default 10 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2
|
||||
default 15 if IDF_TARGET_ESP32S3
|
||||
default 0 if IDF_TARGET_ESP32C2
|
||||
default 23 if IDF_TARGET_ESP32H2
|
||||
default 25
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
|
||||
help
|
||||
Set the PWM Red LED GPIO.
|
||||
|
||||
config PWM_GREEN_GPIO
|
||||
int "PWM Green GPIO"
|
||||
default 6 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2
|
||||
default 16 if IDF_TARGET_ESP32S3
|
||||
default 1 if IDF_TARGET_ESP32C2
|
||||
default 24 if IDF_TARGET_ESP32H2
|
||||
default 26
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
|
||||
help
|
||||
Set the PWM Green LED GPIO.
|
||||
|
||||
config PWM_BLUE_GPIO
|
||||
int "PWM Blue GPIO"
|
||||
default 7 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2
|
||||
default 17 if IDF_TARGET_ESP32S3
|
||||
default 8 if IDF_TARGET_ESP32C2
|
||||
default 25 if IDF_TARGET_ESP32H2
|
||||
default 27
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_PWM
|
||||
help
|
||||
Set the PWM Blue LED GPIO.
|
||||
|
||||
config SM2135E_IIC_CLK_GPIO
|
||||
int "SM2135E IIC CLK GPIO"
|
||||
default 4
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_SM2135E
|
||||
help
|
||||
Set the SM2135E CLK GPIO.
|
||||
|
||||
config SM2135E_IIC_SDA_GPIO
|
||||
int "SM2135E IIC SDA GPIO"
|
||||
default 5
|
||||
depends on LIGHTBULB_DEMO_DRIVER_SELECT_SM2135E
|
||||
help
|
||||
Set the SM2135E SDA GPIO.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
endmenu
|
||||
menu "Light provisioning network selection"
|
||||
config LIGHT_PROVISIONING_SMARTCONFIG
|
||||
bool "Enable SmartConfig's smart network configuration method"
|
||||
default n
|
||||
help
|
||||
Enable SmartConfig's smart network configuration method
|
||||
|
||||
config LIGHT_PROVISIONING_SOFTAPCONFIG
|
||||
bool "Enable SoftAP's network configuration method"
|
||||
default y
|
||||
help
|
||||
"Enable SoftAP's network configuration method"
|
||||
|
||||
config LIGHT_PROVISIONING_BLECONFIG
|
||||
depends on QCLOUD_ENABLE_BLECONFIG
|
||||
bool "Enable BLE's network configuration method"
|
||||
default y
|
||||
help
|
||||
"Enable BLE's network configuration method"
|
||||
|
||||
config LIGHT_PROVISIONING_SOFTAPCONFIG_SSID
|
||||
depends on LIGHT_PROVISIONING_SOFTAPCONFIG
|
||||
string "SoftAP ssid"
|
||||
default "tcloud_XXX"
|
||||
help
|
||||
SSID (network name) for the phone to connect to.
|
||||
|
||||
config LIGHT_PROVISIONING_BLECONFIG_NAME
|
||||
depends on LIGHT_PROVISIONING_BLECONFIG
|
||||
string "BLE name"
|
||||
default "Qcloud"
|
||||
help
|
||||
BLE for the phone to connect to.
|
||||
endmenu
|
||||
|
||||
config LIGHT_REBOOT_UNBROKEN_COUNT_RESET
|
||||
int "More than this number of continuous uninterrupted restarts triggers a reset of the device"
|
||||
range 3 15
|
||||
default 5
|
||||
help
|
||||
Devices without buttons trigger a device reset through continuous restart.
|
||||
|
||||
config LIGHT_DEBUG
|
||||
bool "The device will be in debug mode"
|
||||
default n
|
||||
help
|
||||
Debug mode device performance is only used during development.
|
||||
|
||||
|
||||
|
||||
choice QCLOUD_WIFI_CONFIG_METHOD
|
||||
prompt "WiFi Provisioning Method"
|
||||
default QCLOUD_WIFI_SMARTCONFIG
|
||||
help
|
||||
Select how the device should connect to WiFi.
|
||||
|
||||
config QCLOUD_WIFI_PROVISIONING
|
||||
bool "WeChat Mini-Program (connectWiFi)"
|
||||
|
||||
config QCLOUD_WIFI_SMARTCONFIG
|
||||
bool "ESP-Touch / SmartConfig (connectWiFi_smartconfig)"
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
# Sweekar-ESP32 模块化开发与构建系统指南
|
||||
|
||||
为了支持多人无冲突协作,并保持系统代码的高内聚、低耦合,Sweekar-ESP32 的 CMake 构建系统采用 **“透明化脚手架 (Transparent Scaffolding) + Kconfig 自动组装”** 架构。
|
||||
|
||||
在这套架构下,开发者在添加新的底层硬件驱动、业务服务或测试代码时,**完全不需要修改任何顶层文件(包括 `main/CMakeLists.txt` 和 `main/Kconfig.projbuild`)**,构建系统会自动帮你生成必要的模板文件,而后续的修改则完全交由你掌控,没有任何“黑魔法”。
|
||||
|
||||
以下是添加新模块的标准流程和机制说明。
|
||||
|
||||
---
|
||||
|
||||
## 1. 确定模块归属的目录分类
|
||||
系统顶层会自动扫描以下目录下的子文件夹:
|
||||
- `04_hal/` : 硬件抽象层代码(如 Codec 驱动、马达驱动等)
|
||||
- `05_executors/` : 执行器组件(如 AudioPlayer, Display, 传感器读取等)
|
||||
- `05_service/` : 后台服务组件(如 AI RTC、QCloud、WiFi 连接等)
|
||||
- `06_behaviors/` : 行为逻辑组件
|
||||
- `tests/` : 各种测试模块(如麦克风测试、扬声器测试等)
|
||||
- `sweekar_demos/` : 各种组装好的 Demo 入口
|
||||
|
||||
*假设我们要添加一个专门测试麦克风的模块,名为 `test_mic`,它显然应该归属于 `tests/` 目录。*
|
||||
|
||||
## 2. 新建模块与文件 (自动化部分)
|
||||
在对应的分类下新建文件夹,并将你的源码和头文件放进去:
|
||||
```bash
|
||||
mkdir -p main/tests/test_mic
|
||||
touch main/tests/test_mic/test_mic.cc
|
||||
touch main/tests/test_mic/test_mic.h
|
||||
```
|
||||
|
||||
**【核心自动化机制】**
|
||||
此时,你**不需要**手动去写 CMake 文件。你只需要在终端执行一次:
|
||||
```bash
|
||||
idf.py reconfigure
|
||||
```
|
||||
(或者 `idf.py build` 如果这是你第一次编译该工程)。
|
||||
|
||||
构建系统中的 Python 脚本 (`generate_kconfig_modules.py`) 会在配置阶段自动扫描目录。当它发现 `tests/test_mic` 目录下有源码但**没有** `module.cmake` 时,它会**自动为你生成一个 `module.cmake` 脚手架文件**。
|
||||
|
||||
自动生成的文件内容类似于:
|
||||
```cmake
|
||||
# main/tests/test_mic/module.cmake
|
||||
# 自动生成的模块脚手架,可直接手工修改。
|
||||
# 如果后续添加了新文件,可以手工在此处添加,或者删除本文件让脚本重新生成。
|
||||
|
||||
if(NOT CONFIG_ENABLE_TEST_TEST_MIC AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] test_mic module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"tests/test_mic/test_mic.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"tests/test_mic"
|
||||
)
|
||||
|
||||
# 需要公开依赖时,在这里手工补充。例如:
|
||||
# list(APPEND MODULE_REQUIRES
|
||||
# esp_timer
|
||||
# driver
|
||||
# )
|
||||
```
|
||||
|
||||
## 3. 后续维护与修改 (手工部分)
|
||||
|
||||
**“透明化”原则**:一旦 `module.cmake` 被生成,Python 脚本就**再也不会覆盖或修改它**。它现在完全属于你。
|
||||
|
||||
### 3.1 当你新增/删除源文件时
|
||||
你有两种选择:
|
||||
1. **手动修改(推荐)**:直接打开 `module.cmake`,在 `list(APPEND MODULE_SRCS ...)` 中手动添加或删除文件路径。所见即所得,非常直观。
|
||||
2. **重新生成(偷懒大法)**:如果你一口气加了十几个文件,不想手写路径,你可以**直接删除**这个 `module.cmake` 文件,然后运行 `idf.py reconfigure`,脚本会重新帮你扫描并生成一份包含所有最新文件的脚手架。
|
||||
|
||||
### 3.2 当你需要依赖其他库时
|
||||
直接在 `module.cmake` 底部,取消注释并填入你需要的 ESP-IDF 组件名(如 `esp_adc`, `audio_pipeline` 等):
|
||||
```cmake
|
||||
list(APPEND MODULE_REQUIRES
|
||||
audio_pipeline
|
||||
driver
|
||||
)
|
||||
```
|
||||
|
||||
## 4. 编写模块内部的 `Kconfig` (可选)
|
||||
系统会自动为你的模块生成一个默认的配置开关(例如 `CONFIG_ENABLE_TEST_TEST_MIC`)。
|
||||
- `tests/` 目录下的默认开关为关闭(`default n`)。
|
||||
- 其他目录默认开启(`default y`)。
|
||||
|
||||
如果你需要为你的模块定义更复杂的配置选项(比如定义默认开启、依赖其他模块、或者包含子菜单),你可以在模块目录(`main/tests/test_mic/`)下建立一个名为 `Kconfig` 的文件:
|
||||
|
||||
```kconfig
|
||||
# main/tests/test_mic/Kconfig
|
||||
config ENABLE_TEST_MIC
|
||||
bool "Enable Microphone Test Module"
|
||||
default n
|
||||
help
|
||||
Enable this to compile the microphone testing routines.
|
||||
```
|
||||
> 系统如果扫描到模块自带 `Kconfig`,就会使用你写的,而不再自动生成默认开关。
|
||||
|
||||
## 5. 编译与配置
|
||||
1. 运行 `idf.py menuconfig`。
|
||||
2. 导航到 `Sweekar Subsystems Configuration` -> 对应的目录(如 `Tests Modules`)。
|
||||
3. 找到你刚刚添加的 `Enable test_mic`(或你自己定义的开关名字),按空格键勾选 `[*]`。
|
||||
4. 保存退出后,运行 `idf.py build` 即可!
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 常见问题与注意事项
|
||||
|
||||
### Q: 为什么我新建了一个文件夹或者删除了 `module.cmake`,运行 `idf.py build` 没有反应?
|
||||
这是 CMake 的缓存机制导致的。如果你只是增删了目录或文件,但没有修改任何现有的 `CMakeLists.txt` 内容,CMake 会跳过配置阶段直接去编译,导致 Python 扫描脚本没有运行。
|
||||
**解决办法**:遇到这种情况,请明确告诉 IDF 重新配置:
|
||||
```bash
|
||||
idf.py reconfigure
|
||||
```
|
||||
然后再运行 `idf.py build`。
|
||||
|
||||
### Q: 为什么要加 `NOT EARLY_EXPANSION`?
|
||||
ESP-IDF 的构建系统分为两步:
|
||||
1. **依赖解析阶段 (Early Expansion)**:此时 CMake 快速扫描所有组件收集 `REQUIRES`,但此时 `menuconfig` 的配置尚未加载,所有的 `CONFIG_xxx` 都是空值!
|
||||
2. **实际构建阶段 (Build Pass)**:此时配置加载完毕,开始真实编译。
|
||||
|
||||
如果在 `module.cmake` 顶部仅仅写 `if(NOT CONFIG_ENABLE_XXX) return()`,会导致在依赖解析阶段该模块就被错误地跳过了,从而丢失其依赖声明,引发“找不到头文件”的编译灾难。
|
||||
加入 `AND NOT EARLY_EXPANSION` 后,能保证所有启用的组件依赖都被正确收集到构建树中,实现完美解耦。
|
||||
@@ -0,0 +1,247 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
# The directories to scan for Kconfig files
|
||||
SUBSYSTEM_DIRS = ["04_hal", "05_executors", "05_service", "06_behaviors", "tests"]
|
||||
TEMPLATE_SCAN_DIRS = SUBSYSTEM_DIRS + ["sweekar_demos"]
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
OUTPUT_FILE = os.path.join(BASE_DIR, "Kconfig.modules")
|
||||
|
||||
SOURCE_EXTENSIONS = (".c", ".cc", ".cpp")
|
||||
HEADER_EXTENSIONS = (".h", ".hpp")
|
||||
SKIP_DIR_NAMES = {"build", "__pycache__"}
|
||||
|
||||
|
||||
def iter_child_dirs(parent_dir):
|
||||
if not os.path.exists(parent_dir):
|
||||
return []
|
||||
return sorted(
|
||||
[
|
||||
name
|
||||
for name in os.listdir(parent_dir)
|
||||
if os.path.isdir(os.path.join(parent_dir, name)) and not name.startswith(".")
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def compute_default_config_name(subsystem_dir, module_name):
|
||||
if subsystem_dir == "tests":
|
||||
prefix = "TEST"
|
||||
else:
|
||||
prefix = subsystem_dir.split("_")[1].upper()
|
||||
if prefix == "EXECUTORS":
|
||||
prefix = "EXEC"
|
||||
elif prefix == "BEHAVIORS":
|
||||
prefix = "BEHAV"
|
||||
elif prefix == "SERVICE":
|
||||
prefix = "SVC"
|
||||
return f"CONFIG_ENABLE_{prefix}_{module_name.upper()}"
|
||||
|
||||
|
||||
def contains_module_files(module_dir):
|
||||
for _, _, files in os.walk(module_dir):
|
||||
for filename in files:
|
||||
if filename.endswith(SOURCE_EXTENSIONS) or filename.endswith(HEADER_EXTENSIONS):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def collect_existing_module_cmake_files():
|
||||
module_files = []
|
||||
for root, _, files in os.walk(BASE_DIR):
|
||||
if "module.cmake" in files:
|
||||
module_files.append(os.path.join(root, "module.cmake"))
|
||||
return sorted(module_files)
|
||||
|
||||
|
||||
def collect_module_files(module_dir):
|
||||
srcs = []
|
||||
include_dirs = {"."}
|
||||
|
||||
for root, dirs, files in os.walk(module_dir):
|
||||
dirs[:] = [
|
||||
d for d in dirs
|
||||
if d not in SKIP_DIR_NAMES and not d.startswith(".")
|
||||
]
|
||||
|
||||
rel_root = os.path.relpath(root, module_dir).replace(os.sep, "/")
|
||||
rel_root = "." if rel_root == "." else rel_root
|
||||
|
||||
has_header = False
|
||||
for filename in files:
|
||||
if filename.endswith(SOURCE_EXTENSIONS):
|
||||
rel_path = os.path.normpath(os.path.join(rel_root, filename)).replace(os.sep, "/")
|
||||
if rel_path.startswith("./"):
|
||||
rel_path = rel_path[2:]
|
||||
srcs.append(rel_path)
|
||||
elif filename.endswith(HEADER_EXTENSIONS):
|
||||
has_header = True
|
||||
|
||||
if has_header:
|
||||
include_dirs.add(rel_root)
|
||||
|
||||
srcs = sorted(set(srcs))
|
||||
include_dirs = sorted(set(include_dirs))
|
||||
return srcs, include_dirs
|
||||
|
||||
|
||||
def is_already_aggregated(rel_module_dir, existing_module_files):
|
||||
rel_module_prefix = f'"{rel_module_dir}/'
|
||||
for module_file in existing_module_files:
|
||||
try:
|
||||
with open(module_file, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
if rel_module_prefix in content:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def render_module_template(subsystem_dir, module_name, module_dir):
|
||||
srcs, include_dirs = collect_module_files(module_dir)
|
||||
rel_module_dir = os.path.relpath(module_dir, BASE_DIR).replace(os.sep, "/")
|
||||
|
||||
lines = [
|
||||
f"# main/{subsystem_dir}/{module_name}/module.cmake",
|
||||
"# 自动生成的模块脚手架,可直接手工修改。",
|
||||
"# 如果后续添加了新文件,可以手工在此处添加,或者删除本文件让脚本重新生成。",
|
||||
"",
|
||||
]
|
||||
|
||||
if subsystem_dir != "sweekar_demos":
|
||||
config_name = compute_default_config_name(subsystem_dir, module_name)
|
||||
lines.extend(
|
||||
[
|
||||
f"if(NOT {config_name} AND NOT EARLY_EXPANSION)",
|
||||
f' message(STATUS " [Skip] {module_name} module disabled by menuconfig.")',
|
||||
" return()",
|
||||
"endif()",
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
lines.append("list(APPEND MODULE_SRCS")
|
||||
for src in srcs:
|
||||
lines.append(f' "{rel_module_dir}/{src}"')
|
||||
lines.append(")")
|
||||
lines.append("")
|
||||
|
||||
lines.append("list(APPEND MODULE_INCLUDE_DIRS")
|
||||
for inc in include_dirs:
|
||||
if inc == ".":
|
||||
lines.append(f' "{rel_module_dir}"')
|
||||
else:
|
||||
lines.append(f' "{rel_module_dir}/{inc}"')
|
||||
lines.append(")")
|
||||
lines.append("")
|
||||
|
||||
lines.extend(
|
||||
[
|
||||
"# 需要公开依赖时,在这里手工补充。例如:",
|
||||
"# list(APPEND MODULE_REQUIRES",
|
||||
"# esp_timer",
|
||||
"# driver",
|
||||
"# )",
|
||||
"",
|
||||
"# 需要私有依赖时,在这里手工补充。例如:",
|
||||
"# list(APPEND MODULE_PRIV_REQUIRES",
|
||||
"# nvs_flash",
|
||||
"# )",
|
||||
"",
|
||||
]
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def ensure_module_templates():
|
||||
created_files = []
|
||||
existing_module_files = collect_existing_module_cmake_files()
|
||||
|
||||
for subsystem_dir in TEMPLATE_SCAN_DIRS:
|
||||
dir_path = os.path.join(BASE_DIR, subsystem_dir)
|
||||
if not os.path.exists(dir_path):
|
||||
continue
|
||||
|
||||
for module_name in iter_child_dirs(dir_path):
|
||||
if subsystem_dir == "sweekar_demos" and not module_name.startswith("sweekar_demo"):
|
||||
continue
|
||||
|
||||
module_dir = os.path.join(dir_path, module_name)
|
||||
module_cmake = os.path.join(module_dir, "module.cmake")
|
||||
if os.path.exists(module_cmake):
|
||||
continue
|
||||
|
||||
if not contains_module_files(module_dir):
|
||||
continue
|
||||
|
||||
rel_module_dir = os.path.relpath(module_dir, BASE_DIR).replace(os.sep, "/")
|
||||
if subsystem_dir != "sweekar_demos" and is_already_aggregated(rel_module_dir, existing_module_files):
|
||||
continue
|
||||
|
||||
template_content = render_module_template(subsystem_dir, module_name, module_dir)
|
||||
with open(module_cmake, "w", encoding="utf-8") as f:
|
||||
f.write(template_content)
|
||||
created_files.append(module_cmake)
|
||||
|
||||
return created_files
|
||||
|
||||
def generate_kconfig_modules():
|
||||
created_templates = ensure_module_templates()
|
||||
kconfig_content = 'menu "Sweekar Subsystems Configuration"\n\n'
|
||||
|
||||
for d in SUBSYSTEM_DIRS:
|
||||
dir_path = os.path.join(BASE_DIR, d)
|
||||
if not os.path.exists(dir_path):
|
||||
continue
|
||||
|
||||
# Create a pretty menu name from the directory name
|
||||
# e.g., "05_executors" -> "05 Executors Modules"
|
||||
parts = d.split('_')
|
||||
menu_name = parts[0] + " " + " ".join([p.capitalize() for p in parts[1:]]) + " Modules"
|
||||
|
||||
kconfig_content += f' menu "{menu_name}"\n'
|
||||
|
||||
# Sort subdirectories to ensure consistent ordering
|
||||
subdirs = iter_child_dirs(dir_path)
|
||||
|
||||
for module_name in subdirs:
|
||||
module_dir = os.path.join(dir_path, module_name)
|
||||
kconfig_file = os.path.join(module_dir, "Kconfig")
|
||||
|
||||
if os.path.exists(kconfig_file):
|
||||
# If the module has its own Kconfig, just source it
|
||||
# Make sure the source path is relative to the project root or uses proper env vars
|
||||
# Since Kconfig.projbuild is processed relative to project root usually
|
||||
rel_path = os.path.join("main", d, module_name, "Kconfig")
|
||||
kconfig_content += f' source "{rel_path}"\n'
|
||||
else:
|
||||
# If no Kconfig exists, generate a default toggle for it
|
||||
config_name = compute_default_config_name(d, module_name)
|
||||
pretty_name = " ".join([word.capitalize() for word in module_name.split('_')])
|
||||
|
||||
# Default to 'n' for tests, 'y' for everything else
|
||||
default_val = 'n' if d == 'tests' else 'y'
|
||||
|
||||
kconfig_content += f''' config {config_name.replace("CONFIG_", "")}
|
||||
bool "Enable {pretty_name}"
|
||||
default {default_val}
|
||||
help
|
||||
Enable the {module_name} module in {d}.
|
||||
'''
|
||||
kconfig_content += ' endmenu\n\n'
|
||||
|
||||
kconfig_content += 'endmenu\n'
|
||||
|
||||
with open(OUTPUT_FILE, 'w') as f:
|
||||
f.write(kconfig_content)
|
||||
|
||||
print(f"Generated {OUTPUT_FILE} successfully.")
|
||||
if created_templates:
|
||||
print("Generated module.cmake templates:")
|
||||
for path in created_templates:
|
||||
print(f" - {path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_kconfig_modules()
|
||||
@@ -0,0 +1,19 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf:
|
||||
version: '>=5.0.0'
|
||||
|
||||
# lvgl/lvgl: ^8.*
|
||||
# 添加button组件依赖
|
||||
# espressif/button: ~4.1.3
|
||||
|
||||
# 78/esp-wifi-connect: ~2.4.3
|
||||
|
||||
espressif/adc_battery_estimation: ^0.2.0
|
||||
|
||||
# lightbulb_driver: ^0.0.9
|
||||
# espressif/touch_slider_sensor: ^0.2.0
|
||||
|
||||
# espressif/touch_button_sensor: ^0.2.0
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
extern "C" void app_main() {
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user