步进电机速度控制验证通过
This commit is contained in:
commit
230ad1254a
11 files changed
+501
No files matched your search
+78
@@ -0,0 +1,78 @@
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Directory metadata
|
||||
.directory
|
||||
|
||||
# Temporary files
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Build artifacts and directories
|
||||
**/build/
|
||||
build/
|
||||
*.o
|
||||
*.a
|
||||
*.out
|
||||
*.exe # For any host-side utilities compiled on Windows
|
||||
|
||||
# ESP-IDF specific build outputs
|
||||
*.bin
|
||||
*.elf
|
||||
*.map
|
||||
flasher_args.json # Generated in build directory
|
||||
sdkconfig.old
|
||||
sdkconfig
|
||||
|
||||
# ESP-IDF dependencies
|
||||
# For older versions or manual component management
|
||||
/components/.idf/
|
||||
**/components/.idf/
|
||||
# For modern ESP-IDF component manager
|
||||
managed_components/
|
||||
# If ESP-IDF tools are installed/referenced locally to the project
|
||||
.espressif/
|
||||
|
||||
# CMake generated files
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
CTestTestfile.cmake
|
||||
|
||||
# Python environment files
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
__pycache__/
|
||||
*.egg-info/
|
||||
dist/
|
||||
|
||||
# Virtual environment folders
|
||||
venv/
|
||||
.venv/
|
||||
env/
|
||||
|
||||
# Language Servers
|
||||
.clangd/
|
||||
.ccls-cache/
|
||||
compile_commands.json
|
||||
|
||||
# Windows specific
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# User-specific configuration files
|
||||
*.user
|
||||
*.workspace # General workspace files, can be from various tools
|
||||
*.suo # Visual Studio Solution User Options
|
||||
*.sln.docstates # Visual Studio
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "C:\\Espressif\\tools\\xtensa-esp-elf\\esp-15.2.0_20251204\\xtensa-esp-elf\\bin\\xtensa-esp32-elf-gcc.exe",
|
||||
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
|
||||
"intelliSenseMode": "gcc-x86",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "gdbtarget",
|
||||
"request": "attach",
|
||||
"name": "Eclipse CDT GDB Adapter"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"C_Cpp.intelliSenseEngine": "default",
|
||||
"idf.extensionActivationMode": "always",
|
||||
"idf.openOcdConfigs": [
|
||||
"board/esp32c5-builtin.cfg"
|
||||
],
|
||||
"idf.currentSetup": "C:\\esp\\v6.0.2\\esp-idf",
|
||||
"idf.customExtraVars": {
|
||||
"IDF_TARGET": "esp32c5"
|
||||
},
|
||||
"clangd.path": "C:\\Espressif\\tools\\esp-clang\\esp-20.1.1_20250829\\esp-clang\\bin\\clangd.exe",
|
||||
"clangd.arguments": [
|
||||
"--background-index",
|
||||
"--query-driver=**",
|
||||
"--compile-commands-dir=c:\\Users\\Kirl\\Desktop\\EDC\\edc-mcu\\build"
|
||||
],
|
||||
"idf.portWin": "COM4"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(edc-mcu)
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "emm_v5.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_driver_uart esp_driver_gpio driver esp_timer)
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @file emm_v5.c
|
||||
* @brief Emm_V5.0 步进闭环电机驱动器 - ESP-IDF 实现
|
||||
*/
|
||||
|
||||
#include "emm_v5.h"
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
static const char *TAG = "EMM_V5";
|
||||
|
||||
/* 运行时配置 (由 Emm_V5_Init 设置) */
|
||||
static uart_port_t s_uart_port;
|
||||
|
||||
/* ============================================================
|
||||
* 初始化
|
||||
* ============================================================ */
|
||||
|
||||
void Emm_V5_Init(uart_port_t port, int tx_pin, int rx_pin)
|
||||
{
|
||||
s_uart_port = port;
|
||||
|
||||
uart_config_t uart_cfg = {
|
||||
.baud_rate = EMM_V5_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,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(s_uart_port,
|
||||
EMM_V5_UART_BUF_SIZE * 2,
|
||||
EMM_V5_UART_BUF_SIZE * 2,
|
||||
0, NULL, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(s_uart_port, &uart_cfg));
|
||||
ESP_ERROR_CHECK(uart_set_pin(s_uart_port,
|
||||
tx_pin,
|
||||
rx_pin,
|
||||
UART_PIN_NO_CHANGE,
|
||||
UART_PIN_NO_CHANGE));
|
||||
|
||||
gpio_reset_pin(EMM_V5_LED_GPIO);
|
||||
gpio_set_direction(EMM_V5_LED_GPIO, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(EMM_V5_LED_GPIO, 0);
|
||||
|
||||
ESP_LOGI(TAG, "初始化完成 (UART%d, TX=%d, RX=%d, LED=GPIO%d)",
|
||||
s_uart_port, tx_pin, rx_pin, EMM_V5_LED_GPIO);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 内部辅助
|
||||
* ============================================================ */
|
||||
|
||||
static inline void Emm_V5_Send(const uint8_t *cmd, uint8_t len)
|
||||
{
|
||||
uart_write_bytes(s_uart_port, (const char *)cmd, len);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 接收数据
|
||||
* ============================================================ */
|
||||
|
||||
uint8_t Emm_V5_Receive_Data(uint8_t *rxCmd, uint8_t maxLen)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
int64_t last_time, now;
|
||||
|
||||
last_time = esp_timer_get_time();
|
||||
|
||||
while (1) {
|
||||
int len = uart_read_bytes(s_uart_port, &rxCmd[count], 1,
|
||||
pdMS_TO_TICKS(10));
|
||||
if (len > 0) {
|
||||
count++;
|
||||
if (count >= maxLen) break;
|
||||
last_time = esp_timer_get_time();
|
||||
} else {
|
||||
now = esp_timer_get_time();
|
||||
if ((now - last_time) > (EMM_V5_RX_TIMEOUT_MS * 1000)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 控制命令 (协议与 Arduino 版本完全一致)
|
||||
* ============================================================ */
|
||||
|
||||
void Emm_V5_Reset_CurPos_To_Zero(uint8_t addr)
|
||||
{
|
||||
uint8_t cmd[4] = {addr, 0x0A, 0x6D, 0x6B};
|
||||
Emm_V5_Send(cmd, 4);
|
||||
}
|
||||
|
||||
void Emm_V5_Reset_Clog_Pro(uint8_t addr)
|
||||
{
|
||||
uint8_t cmd[4] = {addr, 0x0E, 0x52, 0x6B};
|
||||
Emm_V5_Send(cmd, 4);
|
||||
}
|
||||
|
||||
void Emm_V5_Read_Sys_Params(uint8_t addr, EmmSysParams_t s)
|
||||
{
|
||||
uint8_t cmd[8] = {0};
|
||||
uint8_t i = 0;
|
||||
|
||||
cmd[i++] = addr;
|
||||
switch (s) {
|
||||
case S_VER: cmd[i++] = 0x1F; break;
|
||||
case S_RL: cmd[i++] = 0x20; break;
|
||||
case S_PID: cmd[i++] = 0x21; break;
|
||||
case S_VBUS: cmd[i++] = 0x24; break;
|
||||
case S_CPHA: cmd[i++] = 0x27; break;
|
||||
case S_ENCL: cmd[i++] = 0x31; break;
|
||||
case S_TPOS: cmd[i++] = 0x33; break;
|
||||
case S_VEL: cmd[i++] = 0x35; break;
|
||||
case S_CPOS: cmd[i++] = 0x36; break;
|
||||
case S_PERR: cmd[i++] = 0x37; break;
|
||||
case S_FLAG: cmd[i++] = 0x3A; break;
|
||||
case S_ORG: cmd[i++] = 0x3B; break;
|
||||
case S_Conf: cmd[i++] = 0x42; cmd[i++] = 0x6C; break;
|
||||
case S_State: cmd[i++] = 0x43; cmd[i++] = 0x7A; break;
|
||||
default: break;
|
||||
}
|
||||
cmd[i++] = 0x6B;
|
||||
Emm_V5_Send(cmd, i);
|
||||
}
|
||||
|
||||
void Emm_V5_Modify_Ctrl_Mode(uint8_t addr, bool svF, uint8_t ctrl_mode)
|
||||
{
|
||||
uint8_t cmd[6] = {addr, 0x46, 0x69, (uint8_t)svF, ctrl_mode, 0x6B};
|
||||
Emm_V5_Send(cmd, 6);
|
||||
}
|
||||
|
||||
void Emm_V5_En_Control(uint8_t addr, bool state, bool snF)
|
||||
{
|
||||
uint8_t cmd[6] = {addr, 0xF3, 0xAB, (uint8_t)state, (uint8_t)snF, 0x6B};
|
||||
Emm_V5_Send(cmd, 6);
|
||||
}
|
||||
|
||||
void Emm_V5_Vel_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, bool snF)
|
||||
{
|
||||
uint8_t cmd[8] = {
|
||||
addr, 0xF6, dir,
|
||||
(uint8_t)(vel >> 8), (uint8_t)(vel >> 0),
|
||||
acc, (uint8_t)snF, 0x6B
|
||||
};
|
||||
Emm_V5_Send(cmd, 8);
|
||||
}
|
||||
|
||||
void Emm_V5_Pos_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc,
|
||||
uint32_t clk, bool raF, bool snF)
|
||||
{
|
||||
uint8_t cmd[13] = {
|
||||
addr, 0xFD, dir,
|
||||
(uint8_t)(vel >> 8), (uint8_t)(vel >> 0), acc,
|
||||
(uint8_t)(clk >> 24), (uint8_t)(clk >> 16),
|
||||
(uint8_t)(clk >> 8), (uint8_t)(clk >> 0),
|
||||
(uint8_t)raF, (uint8_t)snF, 0x6B
|
||||
};
|
||||
Emm_V5_Send(cmd, 13);
|
||||
}
|
||||
|
||||
void Emm_V5_Stop_Now(uint8_t addr, bool snF)
|
||||
{
|
||||
uint8_t cmd[5] = {addr, 0xFE, 0x98, (uint8_t)snF, 0x6B};
|
||||
Emm_V5_Send(cmd, 5);
|
||||
}
|
||||
|
||||
void Emm_V5_Synchronous_motion(uint8_t addr)
|
||||
{
|
||||
uint8_t cmd[4] = {addr, 0xFF, 0x66, 0x6B};
|
||||
Emm_V5_Send(cmd, 4);
|
||||
}
|
||||
|
||||
void Emm_V5_Origin_Set_O(uint8_t addr, bool svF)
|
||||
{
|
||||
uint8_t cmd[5] = {addr, 0x93, 0x88, (uint8_t)svF, 0x6B};
|
||||
Emm_V5_Send(cmd, 5);
|
||||
}
|
||||
|
||||
void Emm_V5_Origin_Modify_Params(uint8_t addr, bool svF, uint8_t o_mode,
|
||||
uint8_t o_dir, uint16_t o_vel, uint32_t o_tm,
|
||||
uint16_t sl_vel, uint16_t sl_ma, uint16_t sl_ms, bool potF)
|
||||
{
|
||||
uint8_t cmd[20] = {
|
||||
addr, 0x4C, 0xAE, (uint8_t)svF,
|
||||
o_mode, o_dir,
|
||||
(uint8_t)(o_vel >> 8), (uint8_t)(o_vel >> 0),
|
||||
(uint8_t)(o_tm >> 24), (uint8_t)(o_tm >> 16),
|
||||
(uint8_t)(o_tm >> 8), (uint8_t)(o_tm >> 0),
|
||||
(uint8_t)(sl_vel >> 8), (uint8_t)(sl_vel >> 0),
|
||||
(uint8_t)(sl_ma >> 8), (uint8_t)(sl_ma >> 0),
|
||||
(uint8_t)(sl_ms >> 8), (uint8_t)(sl_ms >> 0),
|
||||
(uint8_t)potF, 0x6B
|
||||
};
|
||||
Emm_V5_Send(cmd, 20);
|
||||
}
|
||||
|
||||
void Emm_V5_Origin_Trigger_Return(uint8_t addr, uint8_t o_mode, bool snF)
|
||||
{
|
||||
uint8_t cmd[5] = {addr, 0x9A, o_mode, (uint8_t)snF, 0x6B};
|
||||
Emm_V5_Send(cmd, 5);
|
||||
}
|
||||
|
||||
void Emm_V5_Origin_Interrupt(uint8_t addr)
|
||||
{
|
||||
uint8_t cmd[4] = {addr, 0x9C, 0x48, 0x6B};
|
||||
Emm_V5_Send(cmd, 4);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file emm_v5.h
|
||||
* @brief Emm_V5.0 步进闭环电机驱动器 - ESP-IDF 组件
|
||||
* @author 移植自 Arduino 版本 (原作者: ZHANGDATOU)
|
||||
*
|
||||
* 通信协议: UART, 115200bps, 8N1
|
||||
* 使用方式:
|
||||
* Emm_V5_Init(UART_NUM_1, GPIO_NUM_6, GPIO_NUM_7);
|
||||
*/
|
||||
|
||||
#ifndef EMM_V5_H
|
||||
#define EMM_V5_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================
|
||||
* 可配置常量
|
||||
* ============================================================ */
|
||||
#define EMM_V5_UART_BAUDRATE 115200
|
||||
#define EMM_V5_UART_BUF_SIZE 256
|
||||
|
||||
/* LED 指示 (GPIO2 为多数 ESP32 板载 LED) */
|
||||
#define EMM_V5_LED_GPIO GPIO_NUM_2
|
||||
|
||||
/* 接收超时时间 (毫秒) */
|
||||
#define EMM_V5_RX_TIMEOUT_MS 100
|
||||
|
||||
/* ============================================================
|
||||
* 系统参数枚举 (与 Arduino 版本一致)
|
||||
* ============================================================ */
|
||||
typedef enum {
|
||||
S_VER = 0, /* 读取固件版本和对应的硬件版本 */
|
||||
S_RL = 1, /* 读取相电阻和相电感 */
|
||||
S_PID = 2, /* 读取PID参数 */
|
||||
S_VBUS = 3, /* 读取总线电压 */
|
||||
S_CPHA = 5, /* 读取相电流 */
|
||||
S_ENCL = 7, /* 读取经过线性化校准后的编码器值 */
|
||||
S_TPOS = 8, /* 读取电机目标位置角度 */
|
||||
S_VEL = 9, /* 读取电机实时转速 */
|
||||
S_CPOS = 10, /* 读取电机实时位置角度 */
|
||||
S_PERR = 11, /* 读取电机位置误差角度 */
|
||||
S_FLAG = 13, /* 读取使能/到位/堵转状态标志位 */
|
||||
S_Conf = 14, /* 读取驱动参数 */
|
||||
S_State = 15, /* 读取系统状态参数 */
|
||||
S_ORG = 16, /* 读取正在回零/回零失败状态标志位 */
|
||||
} EmmSysParams_t;
|
||||
|
||||
/* ============================================================
|
||||
* API 函数声明
|
||||
* ============================================================ */
|
||||
|
||||
/**
|
||||
* @brief 初始化 UART 和 LED GPIO
|
||||
* @param port UART 端口号, 如 UART_NUM_1
|
||||
* @param tx_pin TX 引脚, 如 GPIO_NUM_6
|
||||
* @param rx_pin RX 引脚, 如 GPIO_NUM_7
|
||||
*/
|
||||
void Emm_V5_Init(uart_port_t port, int tx_pin, int rx_pin);
|
||||
void Emm_V5_Reset_CurPos_To_Zero(uint8_t addr);
|
||||
void Emm_V5_Reset_Clog_Pro(uint8_t addr);
|
||||
void Emm_V5_Read_Sys_Params(uint8_t addr, EmmSysParams_t s);
|
||||
void Emm_V5_Modify_Ctrl_Mode(uint8_t addr, bool svF, uint8_t ctrl_mode);
|
||||
void Emm_V5_En_Control(uint8_t addr, bool state, bool snF);
|
||||
void Emm_V5_Vel_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc, bool snF);
|
||||
void Emm_V5_Pos_Control(uint8_t addr, uint8_t dir, uint16_t vel, uint8_t acc,
|
||||
uint32_t clk, bool raF, bool snF);
|
||||
void Emm_V5_Stop_Now(uint8_t addr, bool snF);
|
||||
void Emm_V5_Synchronous_motion(uint8_t addr);
|
||||
void Emm_V5_Origin_Set_O(uint8_t addr, bool svF);
|
||||
void Emm_V5_Origin_Modify_Params(uint8_t addr, bool svF, uint8_t o_mode,
|
||||
uint8_t o_dir, uint16_t o_vel, uint32_t o_tm,
|
||||
uint16_t sl_vel, uint16_t sl_ma, uint16_t sl_ms, bool potF);
|
||||
void Emm_V5_Origin_Trigger_Return(uint8_t addr, uint8_t o_mode, bool snF);
|
||||
void Emm_V5_Origin_Interrupt(uint8_t addr);
|
||||
uint8_t Emm_V5_Receive_Data(uint8_t *rxCmd, uint8_t maxLen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EMM_V5_H */
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES emm_v5)
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file main.c
|
||||
* @brief Emm_V5.0 步进闭环电机驱动演示 (ESP-IDF)
|
||||
*
|
||||
* 硬件接线:
|
||||
* ESP32 TX (GPIO6) -> 电机 RX
|
||||
* ESP32 RX (GPIO7) -> 电机 TX
|
||||
* ESP32 GND -> 电机 GND
|
||||
*/
|
||||
|
||||
#include "emm_v5.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
uint8_t rx_buf[128] = {0};
|
||||
uint8_t rx_len;
|
||||
|
||||
/* 初始化驱动 (UART1, TX=GPIO6, RX=GPIO7, LED=GPIO2) */
|
||||
Emm_V5_Init(UART_NUM_1, GPIO_NUM_6, GPIO_NUM_7);
|
||||
|
||||
/* 上电延时 2 秒, 等待电机闭环初始化完毕 */
|
||||
ESP_LOGI("MAIN", "等待电机初始化...");
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
|
||||
/* ---- 速度模式演示 ---- */
|
||||
ESP_LOGI("MAIN", "发送速度控制命令: 地址1, CW, 1000RPM, 加速度10");
|
||||
Emm_V5_Vel_Control(1, 0, 100, 10, false);
|
||||
|
||||
/* 接收电机返回的数据 */
|
||||
rx_len = Emm_V5_Receive_Data(rx_buf, sizeof(rx_buf));
|
||||
|
||||
/* 验证校验字节 (0x6B), 点亮/熄灭 LED */
|
||||
if (rx_len > 0 && rx_buf[rx_len - 1] == 0x6B) {
|
||||
gpio_set_level(EMM_V5_LED_GPIO, 1);
|
||||
ESP_LOGI("MAIN", "通信正常 (校验通过, LED亮)");
|
||||
} else {
|
||||
gpio_set_level(EMM_V5_LED_GPIO, 0);
|
||||
ESP_LOGW("MAIN", "通信异常 (校验失败, LED灭)");
|
||||
}
|
||||
|
||||
/* 打印返回的原始数据 (调试用, 每个字节+1 避免与电机地址冲突) */
|
||||
ESP_LOGI("MAIN", "返回数据长度: %d", rx_len);
|
||||
if (rx_len > 0) {
|
||||
printf("返回数据(+1偏移): ");
|
||||
for (int i = 0; i < rx_len; i++) {
|
||||
printf("%02X ", rx_buf[i] + 1);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ESP_LOGI("MAIN", "演示完成, 程序挂起");
|
||||
while (1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user