releasev1.2
This commit is contained in:
1 parent
74010ef611
commit
c296caa328
10 files changed
+693
-267
No files matched your search
@@ -1,3 +1,3 @@
|
||||
idf_component_register(SRCS "emm_v5.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_driver_uart esp_driver_gpio driver esp_timer)
|
||||
REQUIRES esp_driver_uart esp_driver_gpio driver esp_timer freertos)
|
||||
+276
-90
@@ -8,6 +8,9 @@
|
||||
#include <math.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
static const char *TAG = "EMM_V5";
|
||||
@@ -15,6 +18,40 @@ static const char *TAG = "EMM_V5";
|
||||
/* 运行时配置 (由 Emm_V5_Init 设置) */
|
||||
static uart_port_t s_uart_port;
|
||||
|
||||
/* ============================================================
|
||||
* RX 中断/事件驱动状态
|
||||
*
|
||||
* 驱动 Response 菜单设为 Reached/Both/Other 后, 位置模式 (0xFD) 命令
|
||||
* 运动到位会主动回传到位帧: 地址 + FD + 9F + 6B。
|
||||
* UART RX 由内部任务独占读取, 解析出到位帧后置位事件组位
|
||||
* (bit = 电机地址 - 1); 调用方用 Emm_V5_Wait_Arrival 事件等待,
|
||||
* 全部到位即返回 —— 不再轮询 S_TPOS/S_CPOS, 避免"没到位就下一步"。
|
||||
* ============================================================ */
|
||||
|
||||
#define EMM_V5_ARRIVAL_MAX_MOTORS 8
|
||||
|
||||
static EventGroupHandle_t s_arrival_evt = NULL;
|
||||
static QueueHandle_t s_uart_evt_queue = NULL;
|
||||
static TaskHandle_t s_rx_task = NULL;
|
||||
|
||||
/* 请求-响应 (网页手动读参数等) */
|
||||
static SemaphoreHandle_t s_resp_mutex = NULL;
|
||||
static struct {
|
||||
bool active;
|
||||
uint8_t addr;
|
||||
uint8_t func;
|
||||
uint8_t *out;
|
||||
uint8_t max;
|
||||
uint8_t len;
|
||||
SemaphoreHandle_t done;
|
||||
} s_resp;
|
||||
|
||||
/* RX 帧累积缓冲 (0x6B 为帧尾) */
|
||||
static uint8_t s_rx_frame[64];
|
||||
static uint8_t s_rx_frame_len;
|
||||
|
||||
static void emm_v5_rx_task(void *arg); /* 前置声明 (Emm_V5_Init 中创建) */
|
||||
|
||||
/* ============================================================
|
||||
* 初始化
|
||||
* ============================================================ */
|
||||
@@ -32,10 +69,13 @@ void Emm_V5_Init(uart_port_t port, int tx_pin, int rx_pin)
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
/* 事件队列: 中断驱动 RX (到位帧解析); 64 深度防突发丢事件 */
|
||||
s_uart_evt_queue = xQueueCreate(64, sizeof(uart_event_t));
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(s_uart_port,
|
||||
EMM_V5_UART_BUF_SIZE * 2,
|
||||
EMM_V5_UART_BUF_SIZE * 2,
|
||||
0, NULL, 0));
|
||||
16, &s_uart_evt_queue, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(s_uart_port, &uart_cfg));
|
||||
ESP_ERROR_CHECK(uart_set_pin(s_uart_port,
|
||||
tx_pin,
|
||||
@@ -43,7 +83,15 @@ void Emm_V5_Init(uart_port_t port, int tx_pin, int rx_pin)
|
||||
UART_PIN_NO_CHANGE,
|
||||
UART_PIN_NO_CHANGE));
|
||||
|
||||
ESP_LOGI(TAG, "初始化完成 (UART%d, TX=%d, RX=%d)",
|
||||
/* 到位事件组 / 请求-响应信号量 / RX 任务 */
|
||||
if (s_arrival_evt == NULL) s_arrival_evt = xEventGroupCreate();
|
||||
if (s_resp_mutex == NULL) s_resp_mutex = xSemaphoreCreateMutex();
|
||||
if (s_resp.done == NULL) s_resp.done = xSemaphoreCreateBinary();
|
||||
if (s_rx_task == NULL) {
|
||||
xTaskCreate(emm_v5_rx_task, "emm_rx", 3072, NULL, 5, &s_rx_task);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "初始化完成 (UART%d, TX=%d, RX=%d, 到位帧中断已启用)",
|
||||
s_uart_port, tx_pin, rx_pin);
|
||||
}
|
||||
|
||||
@@ -57,31 +105,178 @@ static inline void Emm_V5_Send(const uint8_t *cmd, uint8_t len)
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 接收数据
|
||||
* RX 中断/事件驱动
|
||||
*
|
||||
* 帧格式: 地址 + 功能码 + 数据... + 0x6B (校验字节)
|
||||
* 到位帧: 地址 + FD + 9F + 6B (位置模式命令运动到位后主动回传)
|
||||
* ============================================================ */
|
||||
|
||||
/* 处理一帧完整数据 (以 0x6B 结尾) */
|
||||
static void emm_v5_handle_frame(const uint8_t *f, uint8_t len)
|
||||
{
|
||||
if (len < 4) return;
|
||||
|
||||
/* 到位帧: 地址 + FD + 9F + 6B → 置位事件组 (bit = 地址 - 1) */
|
||||
if (f[1] == 0xFD && f[2] == 0x9F) {
|
||||
uint8_t addr = f[0];
|
||||
if (addr >= 1 && addr <= EMM_V5_ARRIVAL_MAX_MOTORS && s_arrival_evt) {
|
||||
xEventGroupSetBits(s_arrival_evt, (EventBits_t)(1u << (addr - 1)));
|
||||
ESP_LOGI(TAG, "到位帧: 电机%d", addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* 请求-响应匹配 (网页手动读参数等) */
|
||||
if (s_resp_mutex) {
|
||||
xSemaphoreTake(s_resp_mutex, portMAX_DELAY);
|
||||
if (s_resp.active && f[0] == s_resp.addr && f[1] == s_resp.func) {
|
||||
uint8_t n = (len < s_resp.max) ? len : s_resp.max;
|
||||
if (s_resp.out && n) memcpy(s_resp.out, f, n);
|
||||
s_resp.len = n;
|
||||
s_resp.active = false;
|
||||
xSemaphoreGive(s_resp.done);
|
||||
}
|
||||
xSemaphoreGive(s_resp_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/* UART RX 独占任务: 事件队列驱动, 解析帧并分派 */
|
||||
static void emm_v5_rx_task(void *arg)
|
||||
{
|
||||
uart_event_t evt;
|
||||
uint8_t buf[64];
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(s_uart_evt_queue, &evt, portMAX_DELAY) != pdTRUE)
|
||||
continue;
|
||||
|
||||
if (evt.type == UART_DATA || evt.type == UART_FIFO_OVF ||
|
||||
evt.type == UART_BUFFER_FULL) {
|
||||
int len;
|
||||
while ((len = uart_read_bytes(s_uart_port, buf, sizeof(buf), 0)) > 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
s_rx_frame[s_rx_frame_len++] = buf[i];
|
||||
if (s_rx_frame_len >= sizeof(s_rx_frame)) {
|
||||
s_rx_frame_len = 0; /* 缓冲溢出: 重新同步 */
|
||||
}
|
||||
if (buf[i] == 0x6B) { /* 帧尾 */
|
||||
emm_v5_handle_frame(s_rx_frame, s_rx_frame_len);
|
||||
s_rx_frame_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (evt.type == UART_FIFO_OVF || evt.type == UART_BUFFER_FULL) {
|
||||
/* 溢出只说明有部分字节被丢弃: 重置帧累积重新同步即可。
|
||||
不能 uart_flush_input —— 那会把缓冲里仍有效的到位帧一并冲掉,
|
||||
是偶发丢电机2/3/4 到位帧的根因之一 */
|
||||
s_rx_frame_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 内部: 发送命令并等待匹配的响应帧 (地址+功能码), 供读函数复用 */
|
||||
static int emm_v5_request_response(const uint8_t *cmd, uint8_t cmd_len,
|
||||
uint8_t addr, uint8_t func,
|
||||
uint8_t *out, uint8_t max,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
if (!s_resp_mutex || !s_resp.done) return -1;
|
||||
|
||||
xSemaphoreTake(s_resp_mutex, portMAX_DELAY);
|
||||
if (s_resp.active) {
|
||||
xSemaphoreGive(s_resp_mutex);
|
||||
ESP_LOGW(TAG, "请求-响应忙, 放弃 (addr=%u func=0x%02X)", addr, func);
|
||||
return -1;
|
||||
}
|
||||
s_resp.active = true;
|
||||
s_resp.addr = addr;
|
||||
s_resp.func = func;
|
||||
s_resp.out = out;
|
||||
s_resp.max = max;
|
||||
s_resp.len = 0;
|
||||
xSemaphoreGive(s_resp_mutex);
|
||||
|
||||
xSemaphoreTake(s_resp.done, 0); /* 清残留计数 */
|
||||
Emm_V5_Send(cmd, cmd_len);
|
||||
|
||||
if (xSemaphoreTake(s_resp.done, pdMS_TO_TICKS(timeout_ms)) != pdTRUE) {
|
||||
xSemaphoreTake(s_resp_mutex, portMAX_DELAY);
|
||||
s_resp.active = false; /* 放弃等待 */
|
||||
xSemaphoreGive(s_resp_mutex);
|
||||
ESP_LOGW(TAG, "响应超时 (addr=%u func=0x%02X)", addr, func);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreTake(s_resp_mutex, portMAX_DELAY);
|
||||
int n = s_resp.len;
|
||||
xSemaphoreGive(s_resp_mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 到位等待 (事件驱动)
|
||||
*
|
||||
* 注意: Emm_V5_Wait_Arrival 不消费到位位 (便于调用方分段等待时闪烁 LED);
|
||||
* 一段 motion 的等待结束后必须调用 Emm_V5_Arrival_Consume 清除到位位,
|
||||
* 防止残留位污染下一段 motion。
|
||||
* ============================================================ */
|
||||
|
||||
bool Emm_V5_Wait_Arrival(const uint8_t *addrs, uint8_t count, uint32_t timeout_ms)
|
||||
{
|
||||
if (!s_arrival_evt) return false;
|
||||
|
||||
EventBits_t expected = 0;
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
uint8_t a = addrs[i];
|
||||
if (a >= 1 && a <= EMM_V5_ARRIVAL_MAX_MOTORS)
|
||||
expected |= (EventBits_t)(1u << (a - 1));
|
||||
}
|
||||
if (expected == 0) return true;
|
||||
|
||||
EventBits_t got = xEventGroupWaitBits(s_arrival_evt, expected,
|
||||
pdFALSE, pdTRUE,
|
||||
pdMS_TO_TICKS(timeout_ms));
|
||||
return ((got & expected) == expected);
|
||||
}
|
||||
|
||||
void Emm_V5_Arrival_Consume(const uint8_t *addrs, uint8_t count)
|
||||
{
|
||||
if (!s_arrival_evt) return;
|
||||
|
||||
EventBits_t expected = 0;
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
uint8_t a = addrs[i];
|
||||
if (a >= 1 && a <= EMM_V5_ARRIVAL_MAX_MOTORS)
|
||||
expected |= (EventBits_t)(1u << (a - 1));
|
||||
}
|
||||
if (expected)
|
||||
xEventGroupClearBits(s_arrival_evt, expected);
|
||||
}
|
||||
|
||||
void Emm_V5_Arrival_Reset(void)
|
||||
{
|
||||
if (!s_arrival_evt) return;
|
||||
xEventGroupClearBits(s_arrival_evt, 0xFF); /* 清 addr 1~8 对应位 (bit=地址-1) */
|
||||
}
|
||||
|
||||
/* 查询当前已置位的到位位 (调试用): 返回 addr1~8 对应位掩码 */
|
||||
uint32_t Emm_V5_Arrival_Get_Bits(void)
|
||||
{
|
||||
if (!s_arrival_evt) return 0;
|
||||
return xEventGroupGetBits(s_arrival_evt) & 0xFF;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 接收数据 (已废弃)
|
||||
* ============================================================ */
|
||||
|
||||
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;
|
||||
/* 已废弃: UART RX 由内部 RX 任务独占 (中断驱动), 此函数不再直接读 UART;
|
||||
网页手动读参数请改用 Emm_V5_Read_Sys_Params_Resp */
|
||||
(void)rxCmd;
|
||||
(void)maxLen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
@@ -100,33 +295,62 @@ void Emm_V5_Reset_Clog_Pro(uint8_t addr)
|
||||
Emm_V5_Send(cmd, 4);
|
||||
}
|
||||
|
||||
/* 系统参数 → 功能码 (读取响应帧按 地址+功能码 匹配) */
|
||||
static uint8_t emm_v5_sysparam_func(EmmSysParams_t s)
|
||||
{
|
||||
switch (s) {
|
||||
case S_VER: return 0x1F;
|
||||
case S_RL: return 0x20;
|
||||
case S_PID: return 0x21;
|
||||
case S_VBUS: return 0x24;
|
||||
case S_CPHA: return 0x27;
|
||||
case S_ENCL: return 0x31;
|
||||
case S_TPOS: return 0x33;
|
||||
case S_VEL: return 0x35;
|
||||
case S_CPOS: return 0x36;
|
||||
case S_PERR: return 0x37;
|
||||
case S_FLAG: return 0x3A;
|
||||
case S_ORG: return 0x3B;
|
||||
case S_Conf: return 0x42;
|
||||
case S_State: return 0x43;
|
||||
default: return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
void Emm_V5_Read_Sys_Params(uint8_t addr, EmmSysParams_t s)
|
||||
{
|
||||
uint8_t cmd[8] = {0};
|
||||
uint8_t i = 0;
|
||||
uint8_t func = emm_v5_sysparam_func(s);
|
||||
|
||||
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;
|
||||
}
|
||||
if (func) cmd[i++] = func;
|
||||
if (s == S_Conf) cmd[i++] = 0x6C;
|
||||
if (s == S_State) cmd[i++] = 0x7A;
|
||||
cmd[i++] = 0x6B;
|
||||
Emm_V5_Send(cmd, i);
|
||||
}
|
||||
|
||||
uint8_t Emm_V5_Read_Sys_Params_Resp(uint8_t addr, EmmSysParams_t s,
|
||||
uint8_t *rxOut, uint8_t maxLen,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
uint8_t cmd[8] = {0};
|
||||
uint8_t i = 0;
|
||||
uint8_t func = emm_v5_sysparam_func(s);
|
||||
|
||||
cmd[i++] = addr;
|
||||
if (func) cmd[i++] = func;
|
||||
if (s == S_Conf) cmd[i++] = 0x6C;
|
||||
if (s == S_State) cmd[i++] = 0x7A;
|
||||
cmd[i++] = 0x6B;
|
||||
|
||||
int n = emm_v5_request_response(cmd, i, addr, func, rxOut, maxLen,
|
||||
(timeout_ms > 0) ? timeout_ms
|
||||
: EMM_V5_RX_TIMEOUT_MS);
|
||||
return (n > 0) ? (uint8_t)n : 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 读取电机状态标志 (S_FLAG 0x3A) 并解析返回
|
||||
* ============================================================ */
|
||||
@@ -137,29 +361,10 @@ uint8_t Emm_V5_Read_Status_Flag(uint8_t addr, uint32_t timeout_ms)
|
||||
uint8_t cmd[3] = {addr, 0x3A, 0x6B};
|
||||
uint8_t read_to = (timeout_ms > 0) ? timeout_ms : EMM_V5_RX_TIMEOUT_MS;
|
||||
|
||||
/* 清掉历史残留 (运动命令的 ACK/到位帧等), 防止误判 */
|
||||
uart_flush_input(s_uart_port);
|
||||
|
||||
Emm_V5_Send(cmd, 3);
|
||||
|
||||
uint8_t n = 0;
|
||||
int64_t last = esp_timer_get_time();
|
||||
int64_t deadline = last + (int64_t)read_to * 1000;
|
||||
while (esp_timer_get_time() < deadline) {
|
||||
int len = uart_read_bytes(s_uart_port, &rx[n], 1, pdMS_TO_TICKS(5));
|
||||
if (len > 0) {
|
||||
if (n < sizeof(rx) - 1) n++;
|
||||
last = esp_timer_get_time();
|
||||
/* 帧收完整 (地址 + 3A + 状态 + 6B) 立即返回, 不再等空闲超时,
|
||||
把单次轮询从 ~17ms 压到 ~3ms, 减小到位检测抖动 */
|
||||
for (int i = 0; i + 3 < (int)n; i++) {
|
||||
if (rx[i] == addr && rx[i + 1] == 0x3A && rx[i + 3] == 0x6B)
|
||||
return rx[i + 2];
|
||||
}
|
||||
} else if ((esp_timer_get_time() - last) > 5000) {
|
||||
break; /* 5ms 无新字节: 认为帧已收完/无响应 */
|
||||
}
|
||||
}
|
||||
int n = emm_v5_request_response(cmd, sizeof(cmd), addr, 0x3A,
|
||||
rx, sizeof(rx), read_to);
|
||||
if (n >= 4 && rx[0] == addr && rx[1] == 0x3A && rx[3] == 0x6B)
|
||||
return rx[2];
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
@@ -174,34 +379,15 @@ static int32_t Emm_V5_Read_Pos(uint8_t addr, uint8_t func)
|
||||
{
|
||||
uint8_t rx[16] = {0};
|
||||
uint8_t cmd[3] = {addr, func, 0x6B};
|
||||
uint8_t read_to = EMM_V5_RX_TIMEOUT_MS;
|
||||
|
||||
/* 清掉历史残留 (ACK/到位帧等), 防止误判 */
|
||||
uart_flush_input(s_uart_port);
|
||||
|
||||
Emm_V5_Send(cmd, 3);
|
||||
|
||||
uint8_t n = 0;
|
||||
int64_t last = esp_timer_get_time();
|
||||
int64_t deadline = last + (int64_t)read_to * 1000;
|
||||
while (esp_timer_get_time() < deadline) {
|
||||
int len = uart_read_bytes(s_uart_port, &rx[n], 1, pdMS_TO_TICKS(5));
|
||||
if (len > 0) {
|
||||
if (n < sizeof(rx) - 1) n++;
|
||||
last = esp_timer_get_time();
|
||||
/* 帧收完整 (地址+功能码+符号+位置4B+6B) 立即返回 */
|
||||
for (int i = 0; i + 7 < (int)n; i++) {
|
||||
if (rx[i] == addr && rx[i + 1] == func &&
|
||||
(rx[i + 2] == 0 || rx[i + 2] == 1) && rx[i + 7] == 0x6B)
|
||||
return (int32_t)(((uint32_t)rx[i + 3] << 24) |
|
||||
((uint32_t)rx[i + 4] << 16) |
|
||||
((uint32_t)rx[i + 5] << 8) |
|
||||
(uint32_t)rx[i + 6]);
|
||||
}
|
||||
} else if ((esp_timer_get_time() - last) > 5000) {
|
||||
break; /* 5ms 无新字节: 认为帧已收完/无响应 */
|
||||
}
|
||||
}
|
||||
int n = emm_v5_request_response(cmd, sizeof(cmd), addr, func,
|
||||
rx, sizeof(rx), EMM_V5_RX_TIMEOUT_MS);
|
||||
if (n >= 8 && rx[0] == addr && rx[1] == func &&
|
||||
(rx[2] == 0 || rx[2] == 1) && rx[7] == 0x6B)
|
||||
return (int32_t)(((uint32_t)rx[3] << 24) |
|
||||
((uint32_t)rx[4] << 16) |
|
||||
((uint32_t)rx[5] << 8) |
|
||||
(uint32_t)rx[6]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ extern "C" {
|
||||
* 可配置常量
|
||||
* ============================================================ */
|
||||
#define EMM_V5_UART_BAUDRATE 115200
|
||||
#define EMM_V5_UART_BUF_SIZE 256
|
||||
#define EMM_V5_UART_BUF_SIZE 512
|
||||
|
||||
/* 接收超时时间 (毫秒) */
|
||||
#define EMM_V5_RX_TIMEOUT_MS 100
|
||||
@@ -220,10 +220,63 @@ void Emm_V5_Origin_Trigger_Return(uint8_t addr, uint8_t o_mode, bool snF);
|
||||
void Emm_V5_Origin_Interrupt(uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief 接收电机返回数据 (100ms 超时判定帧结束)
|
||||
* @param rxCmd 接收缓冲区
|
||||
* @param maxLen 缓冲区最大长度
|
||||
* @return 实际接收到的字节数
|
||||
* @brief 等待指定电机到位 (事件驱动, 不消费到位位)
|
||||
*
|
||||
* 电机驱动 Response 菜单设为 Reached/Both/Other 后, 位置模式 (0xFD) 命令
|
||||
* 运动到位会主动回传到位帧 (地址 + FD + 9F + 6B)。UART RX 由本组件内部
|
||||
* 任务中断读取并解析, 此处事件等待全部到位, 不再轮询 S_TPOS/S_CPOS。
|
||||
*
|
||||
* @note 本函数不清除到位位, 便于调用方分段等待 (如等待期间闪烁 LED);
|
||||
* 一段 motion 等待结束后必须调用 Emm_V5_Arrival_Consume 清除,
|
||||
* 防止残留位污染下一段 motion。
|
||||
* @param addrs 电机地址数组, 如 {ACTUATOR_ADDR_X}
|
||||
* @param count 数组长度
|
||||
* @param timeout_ms 本次等待超时 (ms); 0 = 立即返回当前状态
|
||||
* @return true=全部到位, false=超时/未到齐
|
||||
*/
|
||||
bool Emm_V5_Wait_Arrival(const uint8_t *addrs, uint8_t count, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief 消费 (清除) 指定电机的到位位
|
||||
* @param addrs 电机地址数组
|
||||
* @param count 数组长度
|
||||
* @note 一段 motion 的到位等待结束后调用 (成功/超时都要调)
|
||||
*/
|
||||
void Emm_V5_Arrival_Consume(const uint8_t *addrs, uint8_t count);
|
||||
|
||||
/**
|
||||
* @brief 清除全部电机到位位 (开始新一段 motion 前调用)
|
||||
* @note 防止上一段 motion 超时后迟到的到位帧 (或 0 脉冲命令仍回传的帧)
|
||||
* 污染新一段 motion 的到位等待
|
||||
*/
|
||||
void Emm_V5_Arrival_Reset(void);
|
||||
|
||||
/**
|
||||
* @brief 查询当前已置位的到位位 (调试用)
|
||||
* @return 位掩码: bit = (电机地址 - 1), 仅低 8 位有效
|
||||
*/
|
||||
uint32_t Emm_V5_Arrival_Get_Bits(void);
|
||||
|
||||
/**
|
||||
* @brief 发送读取系统参数命令并等待响应帧返回 (请求-响应式)
|
||||
* @param addr 电机地址
|
||||
* @param s 系统参数类型 (@see EmmSysParams_t)
|
||||
* @param rxOut 接收缓冲区
|
||||
* @param maxLen 缓冲区最大长度
|
||||
* @param timeout_ms 等待响应超时 (ms)
|
||||
* @return 实际收到的响应字节数 (含 地址/功能码/.../0x6B), 失败返回 0
|
||||
*/
|
||||
uint8_t Emm_V5_Read_Sys_Params_Resp(uint8_t addr, EmmSysParams_t s,
|
||||
uint8_t *rxOut, uint8_t maxLen,
|
||||
uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief 接收电机返回数据
|
||||
* @deprecated UART RX 已由内部 RX 任务独占 (中断驱动), 此函数不再读取 UART;
|
||||
* 网页手动读参数请改用 Emm_V5_Read_Sys_Params_Resp
|
||||
* @param rxCmd 接收缓冲区 (保留, 未使用)
|
||||
* @param maxLen 缓冲区最大长度 (保留, 未使用)
|
||||
* @return 恒为 0
|
||||
*/
|
||||
uint8_t Emm_V5_Receive_Data(uint8_t *rxCmd, uint8_t maxLen);
|
||||
|
||||
|
||||
Reference in new issue
Block a user