esp32-servo/lib/uart/uart_handler.c
2025-08-21 14:44:24 +08:00

512 lines
17 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// #include "uart_handler.h"
// #include "pca9685.h"
// #include "driver/uart.h"
// #include "esp_log.h"
// #include "freertos/FreeRTOS.h"
// #include "freertos/task.h"
// #include "freertos/queue.h"
// #include <string.h>
// #include <math.h>
// #define UART_BUF_SIZE 1024
// #define TAG "UART_HANDLER"
// #define MAX_SERVOS 32
// #define MAX_DEVICES 2
// // 设备配置 (在main.c中初始化)
// extern PCA9685_Device devices[MAX_DEVICES];
// // 当前角度状态
// static ServoAngle current_angles[MAX_SERVOS];
// static int angle_count = 0;
// // 舵机控制队列
// static QueueHandle_t servo_queue = NULL;
// // 获取当前角度
// static float get_angle(uint8_t addr, uint8_t channel) {
// for(int i = 0; i < angle_count; i++) {
// if(current_angles[i].addr == addr &&
// current_angles[i].channel == channel) {
// return current_angles[i].angle;
// }
// }
// // 不存在则添加默认值
// if(angle_count < MAX_SERVOS) {
// current_angles[angle_count] = (ServoAngle){addr, channel, 90.0f};
// return current_angles[angle_count++].angle;
// }
// return 90.0f; // 安全默认值
// }
// // 更新角度
// static void update_angle(uint8_t addr, uint8_t channel, float angle) {
// for(int i = 0; i < angle_count; i++) {
// if(current_angles[i].addr == addr &&
// current_angles[i].channel == channel) {
// current_angles[i].angle = angle;
// return;
// }
// }
// // 不存在则添加
// if(angle_count < MAX_SERVOS) {
// current_angles[angle_count++] = (ServoAngle){addr, channel, angle};
// }
// }
// // 线性缓动执行
// static void move_servo_linear(uint8_t addr, uint8_t channel, float from, float to, uint16_t duration_ms) {
// int steps = duration_ms / 20;
// steps = steps < 1 ? 1 : steps;
// for (int i = 0; i <= steps; ++i) {
// float t = (float)i / steps;
// float angle = from + (to - from) * t;
// // 查找设备
// for (int d = 0; d < MAX_DEVICES; d++) {
// if (devices[d].addr == addr) {
// pca9685_set_angle(devices[d].port, addr, channel, angle);
// break;
// }
// }
// vTaskDelay(20 / portTICK_PERIOD_MS);
// }
// update_angle(addr, channel, to);
// }
// // 舵机控制任务
// static void servo_control_task(void *param) {
// ServoCommand cmd;
// while (1) {
// if (xQueueReceive(servo_queue, &cmd, portMAX_DELAY) == pdTRUE) {
// float current = get_angle(cmd.addr, cmd.channel);
// if (cmd.duration <= 1) {
// // 立即设置
// for (int d = 0; d < MAX_DEVICES; d++) {
// if (devices[d].addr == cmd.addr) {
// pca9685_set_angle(devices[d].port, cmd.addr, cmd.channel, cmd.angle);
// break;
// }
// }
// update_angle(cmd.addr, cmd.channel, cmd.angle);
// } else {
// // 缓动控制
// move_servo_linear(cmd.addr, cmd.channel, current, cmd.angle, cmd.duration);
// }
// }
// }
// }
// void uart_handler_init(uart_port_t uart_num) {
// uart_config_t config = {
// .baud_rate = 115200,
// .data_bits = UART_DATA_8_BITS,
// .parity = UART_PARITY_DISABLE,
// .stop_bits = UART_STOP_BITS_1,
// .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
// };
// uart_param_config(uart_num, &config);
// esp_err_t ret = uart_driver_install(uart_num, UART_BUF_SIZE * 4, 0, 0, NULL, 0);
// if (ret != ESP_OK) {
// ESP_LOGE(TAG, "UART driver install failed: 0x%X", ret);
// } else {
// ESP_LOGI(TAG, "UART%d driver installed", uart_num);
// }
// // 创建舵机控制队列
// servo_queue = xQueueCreate(20, sizeof(ServoCommand));
// if (servo_queue == NULL) {
// ESP_LOGE(TAG, "Failed to create servo queue");
// } else {
// ESP_LOGI(TAG, "Servo queue created");
// }
// // 创建舵机控制任务
// BaseType_t task_ret = xTaskCreate(servo_control_task, "servo_ctrl", 4096, (void*)UART_NUM_0, 5, NULL);
// if (task_ret != pdPASS) {
// ESP_LOGE(TAG, "Failed to create servo_control_task");
// } else {
// ESP_LOGI(TAG, "servo_control_task created");
// }
// }
// void uart_handler_task(void *param) {
// uart_port_t uart_num = (uart_port_t)param;
// uint8_t buf[UART_BUF_SIZE];
// while (1) {
// ESP_LOGI(TAG, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// int len = uart_read_bytes(uart_num, buf, UART_BUF_SIZE, 0 / portTICK_PERIOD_MS);
// if (len <= 0) continue;
// ESP_LOGI("UART", "收到 %d 字节数据", len);
// ESP_LOG_BUFFER_HEXDUMP("UART DATA", buf, len, ESP_LOG_INFO);
// ESP_LOGI(TAG, "Received %d bytes", len);
// esp_log_buffer_hex(TAG, buf, len);
// // 寻找帧头 0xAA
// int i = 0;
// while (i < len && buf[i] != 0xAA) ++i;
// if (i >= len - 1) continue;
// int remaining = len - i;
// uint8_t count = buf[i + 1];
// if (remaining < 2 + count * 5) {
// ESP_LOGW(TAG, "Incomplete frame, need %d bytes, have %d", 2+count*5, remaining);
// continue;
// }
// // 计算校验和
// uint8_t calc_checksum = 0;
// for (int j = 0; j < 2 + count * 5; j++) {
// calc_checksum ^= buf[i + j];
// }
// uint8_t packet_checksum = buf[i + 2 + count * 5]; // 最后一个字节
// if (calc_checksum != packet_checksum) {
// ESP_LOGE(TAG, "Checksum error: calc=0x%02X, packet=0x%02X",
// calc_checksum, packet_checksum);
// continue;
// }
// // 解析指令
// for (int j = 0; j < count; ++j) {
// int idx = i + 2 + j * 5;
// ServoCommand cmd = {
// .addr = buf[idx],
// .channel = buf[idx + 1],
// .angle = (float)buf[idx + 2],
// .duration = (uint16_t)(buf[idx + 3] | (buf[idx + 4] << 8))
// };
// // 发送到舵机控制队列
// if (xQueueSend(servo_queue, &cmd, 10 / portTICK_PERIOD_MS) != pdTRUE) {
// ESP_LOGE(TAG, "Failed to send command to queue");
// }
// }
// }
// }
// #include "uart_handler.h"
// #include "pca9685.h"
// #include "driver/uart.h"
// #include "esp_log.h"
// #include "freertos/FreeRTOS.h"
// #include "freertos/task.h"
// #include "freertos/queue.h"
// #include <string.h>
// #include <math.h>
// #define UART_BUF_SIZE 1024
// #define TAG "UART_HANDLER"
// #define MAX_SERVOS 32
// #define MAX_DEVICES 2
// extern PCA9685_Device devices[MAX_DEVICES];
// static ServoAngle current_angles[MAX_SERVOS];
// static int angle_count = 0;
// static QueueHandle_t servo_queue = NULL;
// static float get_angle(uint8_t addr, uint8_t channel) {
// for(int i = 0; i < angle_count; i++) {
// if(current_angles[i].addr == addr && current_angles[i].channel == channel) {
// return current_angles[i].angle;
// }
// }
// if(angle_count < MAX_SERVOS) {
// current_angles[angle_count] = (ServoAngle){addr, channel, 90.0f};
// return current_angles[angle_count++].angle;
// }
// return 90.0f;
// }
// static void update_angle(uint8_t addr, uint8_t channel, float angle) {
// for(int i = 0; i < angle_count; i++) {
// if(current_angles[i].addr == addr && current_angles[i].channel == channel) {
// current_angles[i].angle = angle;
// return;
// }
// }
// if(angle_count < MAX_SERVOS) {
// current_angles[angle_count++] = (ServoAngle){addr, channel, angle};
// }
// }
// static void move_servo_linear(uint8_t addr, uint8_t channel, float from, float to, uint16_t duration_ms) {
// int steps = duration_ms / 20;
// steps = steps < 1 ? 1 : steps;
// for (int i = 0; i <= steps; ++i) {
// float t = (float)i / steps;
// float angle = from + (to - from) * t;
// for (int d = 0; d < MAX_DEVICES; d++) {
// if (devices[d].addr == addr) {
// pca9685_set_angle(devices[d].port, addr, channel, angle);
// break;
// }
// }
// vTaskDelay(20 / portTICK_PERIOD_MS);
// }
// update_angle(addr, channel, to);
// }
// static void servo_control_task(void *param) {
// ServoCommand cmd;
// while (1) {
// if (xQueueReceive(servo_queue, &cmd, portMAX_DELAY) == pdTRUE) {
// float current[MAX_SERVOS];
// int count = 0;
// for (int i = 0; i < MAX_SERVOS; ++i) {
// if (current_angles[i].addr == cmd.addr) {
// current[count++] = current_angles[i].angle;
// }
// }
// if (count > 1) {
// pca9685_set_angles(devices[cmd.addr].port, cmd.addr, 0, count, current);
// } else {
// pca9685_set_angle(devices[cmd.addr].port, cmd.addr, cmd.channel, cmd.angle);
// }
// update_angle(cmd.addr, cmd.channel, cmd.angle);
// }
// }
// }
// void uart_handler_init(uart_port_t uart_num) {
// uart_config_t config = {
// .baud_rate = 115200,
// .data_bits = UART_DATA_8_BITS,
// .parity = UART_PARITY_DISABLE,
// .stop_bits = UART_STOP_BITS_1,
// .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
// };
// uart_param_config(uart_num, &config);
// esp_err_t ret = uart_driver_install(uart_num, UART_BUF_SIZE * 4, 0, 0, NULL, 0);
// if (ret != ESP_OK) {
// ESP_LOGE(TAG, "UART driver install failed: 0x%X", ret);
// } else {
// ESP_LOGI(TAG, "UART%d driver installed", uart_num);
// }
// servo_queue = xQueueCreate(20, sizeof(ServoCommand));
// if (servo_queue == NULL) {
// ESP_LOGE(TAG, "Failed to create servo queue");
// } else {
// ESP_LOGI(TAG, "Servo queue created");
// }
// BaseType_t task_ret = xTaskCreate(servo_control_task, "servo_ctrl", 4096, (void*)UART_NUM_0, 5, NULL);
// if (task_ret != pdPASS) {
// ESP_LOGE(TAG, "Failed to create servo_control_task");
// } else {
// ESP_LOGI(TAG, "servo_control_task created");
// }
// }
// void uart_handler_task(void *param) {
// uart_port_t uart_num = (uart_port_t)param;
// uint8_t buf[UART_BUF_SIZE];
// while (1) {
// int len = uart_read_bytes(uart_num, buf, UART_BUF_SIZE, 0 / portTICK_PERIOD_MS);
// if (len <= 0) continue;
// int i = 0;
// while (i < len && buf[i] != 0xAA) ++i;
// if (i >= len - 1) continue;
// int remaining = len - i;
// uint8_t count = buf[i + 1];
// if (remaining < 2 + count * 5) {
// ESP_LOGW(TAG, "Incomplete frame, need %d bytes, have %d", 2 + count * 5, remaining);
// continue;
// }
// uint8_t calc_checksum = 0;
// for (int j = 0; j < 2 + count * 5; j++) {
// calc_checksum ^= buf[i + j];
// }
// uint8_t packet_checksum = buf[i + 2 + count * 5];
// if (calc_checksum != packet_checksum) {
// ESP_LOGE(TAG, "Checksum error: calc=0x%02X, packet=0x%02X",
// calc_checksum, packet_checksum);
// continue;
// }
// for (int j = 0; j < count; ++j) {
// int idx = i + 2 + j * 5;
// ServoCommand cmd = {
// .addr = buf[idx],
// .channel = buf[idx + 1],
// .angle = (float)buf[idx + 2],
// .duration = (uint16_t)(buf[idx + 3] | (buf[idx + 4] << 8))
// };
// if (xQueueSend(servo_queue, &cmd, 10 / portTICK_PERIOD_MS) != pdTRUE) {
// ESP_LOGE(TAG, "Failed to send command to queue");
// }
// }
// }
// }
#include "uart_handler.h"
#include "pca9685.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include <string.h>
#include <math.h>
#define UART_BUF_SIZE 1024
#define TAG "UART_HANDLER"
#define MAX_SERVOS 32
#define MAX_DEVICES 2
#define MAX_CHANNELS 16 // PCA9685 每个设备最多 16 通道
extern PCA9685_Device devices[MAX_DEVICES];
static QueueHandle_t servo_queue = NULL;
// 设备通道角度缓存
static float device_angles[MAX_DEVICES][MAX_CHANNELS];
// 根据 I2C 地址查设备索引
static int find_device_index(uint8_t addr) {
for (int d = 0; d < MAX_DEVICES; ++d) {
if (devices[d].addr == addr) return d;
}
return -1;
}
// 线性缓动批量更新
static void move_servo_linear(uint8_t addr, uint8_t channel, float from, float to, uint16_t duration_ms) {
int steps = duration_ms / 20;
steps = steps < 1 ? 1 : steps;
int idx = find_device_index(addr);
if (idx < 0) return;
for (int i = 0; i <= steps; ++i) {
float t = (float)i / steps;
float angle = from + (to - from) * t;
device_angles[idx][channel] = angle;
// 一次性批量更新所有通道,保证同步
pca9685_set_angles(devices[idx].port, addr, 0, MAX_CHANNELS, device_angles[idx]);
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
// 舵机控制任务
static void servo_control_task(void *param) {
ServoCommand cmd;
while (1) {
if (xQueueReceive(servo_queue, &cmd, portMAX_DELAY) == pdTRUE) {
int idx = find_device_index(cmd.addr);
if (idx < 0) continue;
float from = device_angles[idx][cmd.channel];
float to = cmd.angle;
if (cmd.duration <= 1) {
// 立即批量更新
device_angles[idx][cmd.channel] = to;
pca9685_set_angles(devices[idx].port, cmd.addr, 0, MAX_CHANNELS, device_angles[idx]);
} else {
// 缓动控制
move_servo_linear(cmd.addr, cmd.channel, from, to, cmd.duration);
// 最终角度已在 move_servo_linear 内更新
}
}
}
}
void uart_handler_init(uart_port_t uart_num) {
uart_config_t config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(uart_num, &config);
esp_err_t ret = uart_driver_install(uart_num, UART_BUF_SIZE * 4, 0, 0, NULL, 0);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "UART driver install failed: 0x%X", ret);
} else {
ESP_LOGI(TAG, "UART%d driver installed", uart_num);
}
// 初始化角度缓存为 90°
for (int d = 0; d < MAX_DEVICES; ++d) {
for (int c = 0; c < MAX_CHANNELS; ++c) {
device_angles[d][c] = 90.0f;
}
}
// 创建舵机控制队列
servo_queue = xQueueCreate(20, sizeof(ServoCommand));
if (!servo_queue) {
ESP_LOGE(TAG, "Failed to create servo queue");
return;
}
ESP_LOGI(TAG, "Servo queue created");
// 启动舵机控制任务
BaseType_t task_ret = xTaskCreate(servo_control_task, "servo_ctrl", 4096,
NULL, configMAX_PRIORITIES - 1, NULL);
if (task_ret != pdPASS) {
ESP_LOGE(TAG, "Failed to create servo_control_task");
} else {
ESP_LOGI(TAG, "servo_control_task created");
}
}
void uart_handler_task(void *param) {
uart_port_t uart_num = (uart_port_t)param;
uint8_t buf[UART_BUF_SIZE];
while (1) {
int len = uart_read_bytes(uart_num, buf, UART_BUF_SIZE, 10 / portTICK_PERIOD_MS);
if (len <= 0) continue;
// 找到帧头 0xAA
int i = 0;
while (i < len && buf[i] != 0xAA) ++i;
if (i >= len - 1) continue;
uint8_t count = buf[i + 1];
int frame_len = 2 + count * 5 + 1;
if (i + frame_len > len) {
ESP_LOGW(TAG, "不完整帧,需要 %d 字节,实际 %d", frame_len, len - i);
continue;
}
// 校验
uint8_t chk = 0;
for (int j = 0; j < frame_len - 1; ++j) chk ^= buf[i + j];
if (chk != buf[i + frame_len - 1]) {
ESP_LOGE(TAG, "校验失败calc=0x%02X, packet=0x%02X", chk, buf[i + frame_len - 1]);
continue;
}
// 解析并发送命令
for (int j = 0; j < count; ++j) {
int idx = i + 2 + j * 5;
ServoCommand cmd = {
.addr = buf[idx],
.channel = buf[idx + 1],
.angle = (float)buf[idx + 2],
.duration = (uint16_t)(buf[idx + 3] | (buf[idx + 4] << 8))
};
if (xQueueSend(servo_queue, &cmd, 10 / portTICK_PERIOD_MS) != pdTRUE) {
ESP_LOGE(TAG, "发送命令到队列失败");
}
}
}
}