本文最后更新于289 天前,其中的信息可能已经过时,如有错误请发送邮件到cishaxiatian@gmail.com
本文章默认安装好VsCode的IDF的环境,如果没有安装好环境,可以看嘉立创的IDF安装环境 1. IDF环境安装 | 立创开发板技术文档中心
1.下载小智AI的源码
Release v2.0.5 · 78/xiaozhi-esp32

2.解压使用vscode的打开文件夹功能打开下载的小智文件夹
2.打开小智AI代码进行自定义配置
3.进入打开的工程文件夹,添加第三方(自己画的,或者是买的)开发板,这里是自己画的,新建文件夹 A-stepper-motor 以及三个文件

A_stepper_motor.cc
文件夹的名字和c++文件的名字可以随意,这里是A_stepper_motor
#include "wifi_board.h"
#include "codecs/no_audio_codec.h"
#include "display/oled_display.h"
#include "system_reset.h"
#include "application.h"
#include "button.h"
#include "config.h"
#include "mcp_server.h"
#include "lamp_controller.h"
#include "led/single_led.h"
#include "assets/lang_config.h"
#include <wifi_station.h>
#include <esp_log.h>
#include <driver/i2c_master.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lcd_panel_vendor.h>
#ifdef SH1106
#include <esp_lcd_panel_sh1106.h>
#endif
#define TAG "A_stepper_motor"
class A_stepper_motor : public WifiBoard {
private:
i2c_master_bus_handle_t display_i2c_bus_;
esp_lcd_panel_io_handle_t panel_io_ = nullptr;
esp_lcd_panel_handle_t panel_ = nullptr;
Display* display_ = nullptr;
Button boot_button_;
Button touch_button_;
Button volume_up_button_;
Button volume_down_button_;
void InitializeDisplayI2c() {
i2c_master_bus_config_t bus_config = {
.i2c_port = (i2c_port_t)0,
.sda_io_num = DISPLAY_SDA_PIN,
.scl_io_num = DISPLAY_SCL_PIN,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.intr_priority = 0,
.trans_queue_depth = 0,
.flags = {
.enable_internal_pullup = 1,
},
};
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &display_i2c_bus_));
}
void InitializeSsd1306Display() {
// SSD1306 config
esp_lcd_panel_io_i2c_config_t io_config = {
.dev_addr = 0x3C,
.on_color_trans_done = nullptr,
.user_ctx = nullptr,
.control_phase_bytes = 1,
.dc_bit_offset = 6,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.flags = {
.dc_low_on_data = 0,
.disable_control_phase = 0,
},
.scl_speed_hz = 400 * 1000,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c_v2(display_i2c_bus_, &io_config, &panel_io_));
ESP_LOGI(TAG, "Install SSD1306 driver");
esp_lcd_panel_dev_config_t panel_config = {};
panel_config.reset_gpio_num = -1;
panel_config.bits_per_pixel = 1;
esp_lcd_panel_ssd1306_config_t ssd1306_config = {
.height = static_cast
<uint8_t>(DISPLAY_HEIGHT),
};
panel_config.vendor_config = &ssd1306_config;
#ifdef SH1106
ESP_ERROR_CHECK(esp_lcd_new_panel_sh1106(panel_io_, &panel_config, &panel_));
#else
ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(panel_io_, &panel_config, &panel_));
#endif
ESP_LOGI(TAG, "SSD1306 driver installed");
// Reset the display
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_));
if (esp_lcd_panel_init(panel_) != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize display");
display_ = new NoDisplay();
return;
}
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_, false));
// Set the display to on
ESP_LOGI(TAG, "Turning display on");
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true));
display_ = new OledDisplay(panel_io_, panel_, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
}
void InitializeButtons() {
boot_button_.OnClick([this]() {
auto& app = Application::GetInstance();
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
ResetWifiConfiguration();
}
app.ToggleChatState();
});
touch_button_.OnPressDown([this]() {
Application::GetInstance().StartListening();
});
touch_button_.OnPressUp([this]() {
Application::GetInstance().StopListening();
});
volume_up_button_.OnClick([this]() {
auto codec = GetAudioCodec();
auto volume = codec->output_volume() + 10;
if (volume > 100) {
volume = 100;
}
codec->SetOutputVolume(volume);
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
});
volume_up_button_.OnLongPress([this]() {
GetAudioCodec()->SetOutputVolume(100);
GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
});
volume_down_button_.OnClick([this]() {
auto codec = GetAudioCodec();
auto volume = codec->output_volume() - 10;
if (volume < 0) {
volume = 0;
}
codec->SetOutputVolume(volume);
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
});
volume_down_button_.OnLongPress([this]() {
GetAudioCodec()->SetOutputVolume(0);
GetDisplay()->ShowNotification(Lang::Strings::MUTED);
});
}
// 物联网初始化,逐步迁移到 MCP 协议
void InitializeTools() {
static LampController lamp(LAMP_GPIO);
}
public:
A_stepper_motor() :
boot_button_(BOOT_BUTTON_GPIO),
touch_button_(TOUCH_BUTTON_GPIO),
volume_up_button_(VOLUME_UP_BUTTON_GPIO),
volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) {
InitializeDisplayI2c();
InitializeSsd1306Display();
InitializeButtons();
InitializeTools();
}
virtual Led* GetLed() override {
static SingleLed led(BUILTIN_LED_GPIO);
return &led;
}
virtual AudioCodec* GetAudioCodec() override {
#ifdef AUDIO_I2S_METHOD_SIMPLEX
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, I2S_STD_SLOT_RIGHT, // 扬声器右声道
AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN, I2S_STD_SLOT_LEFT); // 左声道 麦克风
#else
static NoAudioCodecDuplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN);
#endif
return &audio_codec;
}
virtual Display* GetDisplay() override {
return display_;
}
};
DECLARE_BOARD(A_stepper_motor);
config.h
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
#include <driver/gpio.h>
#define AUDIO_INPUT_SAMPLE_RATE 16000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
// 如果使用 Duplex I2S 模式,请注释下面一行
#define AUDIO_I2S_METHOD_SIMPLEX
#ifdef AUDIO_I2S_METHOD_SIMPLEX
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_40 //必要,修改为自己的
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_42 //必要,修改为自己的
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_41 //必要,修改为自己的
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_21 //必要,修改为自己的
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_47 //必要,修改为自己的
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_48 //必要,修改为自己的
#else
#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 //必要,修改为自己的
#endif
#define BUILTIN_LED_GPIO GPIO_NUM_NC //非必要,没有则使用NC
#define BOOT_BUTTON_GPIO GPIO_NUM_NC
#define TOUCH_BUTTON_GPIO GPIO_NUM_NC
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
#define DISPLAY_SDA_PIN GPIO_NUM_8 //必要,修改为自己的
#define DISPLAY_SCL_PIN GPIO_NUM_9 //必要,修改为自己的
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 32 //这里直接写死
// #if CONFIG_OLED_SSD1306_128X32
// #define DISPLAY_HEIGHT 32
// #elif CONFIG_OLED_SSD1306_128X64
// #define DISPLAY_HEIGHT 64
// #elif CONFIG_OLED_SH1106_128X64
// #define DISPLAY_HEIGHT 64
// #define SH1106
// #else
// #error "未选择 OLED 屏幕类型"
// #endif
#define DISPLAY_MIRROR_X true
#define DISPLAY_MIRROR_Y true
// A MCP Test: Control a lamp
#define LAMP_GPIO GPIO_NUM_18
#endif // _BOARD_CONFIG_H_
config.json
{
"target": "esp32s3",
"builds": [
{
"name": "bread-compact-wifi",
"sdkconfig_append": [
"CONFIG_OLED_SSD1306_128X32=y"
]
},
{
"name": "bread-compact-wifi-128x64",
"sdkconfig_append": [
"CONFIG_OLED_SSD1306_128X64=y"
]
}
]
}
4.修改main文件夹下的CMakeLists.txt,在133行添加板子的信息,使VsCode可以通过cmake连接到
elseif(CONFIG_BOARD_TYPE_A_STEPPER_MOTOR)
set(BOARD_TYPE "A-stepper-motor")
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
set(BUILTIN_ICON_FONT font_awesome_20_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)

5.修改main文件夹下的Kconfig.projbuild,在198行添加板子的信息,使VsCode可以选定开发板型号

6.选择型号

7.打开配置文件进行配置



按下右方向键(->)进入二级菜单

选中刚刚创建的板子

按下回车选中,随后切换到英文输入法后按下shift + s 保存

关闭终端

8.添加自己写的步进电机控制代码和IO定义

让cmake可以找到

进入mcp_server.cc,添加代码
顶端添加路径
#include "Stepper_motor/Little_Rotate.h"
加入代码
/**
* @brief 步进电机MCP接入代码
*
*/
AddTool("设置步进电机角度",
"Rotate the stepper motor to a specific angle.",
PropertyList({
Property("angle", kPropertyTypeInteger, 90, 270), // 角度参数范围
Property("speed", kPropertyTypeInteger, 1, 500), // 转速,你可根据自己的需求调整
Property("direction", kPropertyTypeInteger, 0, 1) // 方向:0 或 1
}),
[this](const PropertyList& properties) -> ReturnValue {
int angle = properties["angle"].value
<int>();
int speed = properties["speed"].value
<int>();
int direction = properties["direction"].value
<int>();
ESP_LOGI(TAG, "步进电机旋转:角度=%d° 速度=%d 方向=%d",
angle, speed, direction);
// 调用你的步进电机函数
Little_stepper_rotate_US(angle, speed, direction);
return true;
});

3.准备成功撒花
连接开发板后选择正确的端口,按下小火苗进行构建,烧录,监视

编译成功

等待进行烧录后设备自动重启,随后可以对话进行步进电机语音控制了





