From 511b9809c9d5f50404ed167719659a9bf17cf6a5 Mon Sep 17 00:00:00 2001 From: Robofish <1683502971@qq.com> Date: Sat, 14 Mar 2026 17:24:48 +0800 Subject: [PATCH] fix dr16 --- User/device/dr16.c | 53 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/User/device/dr16.c b/User/device/dr16.c index 120997b..650f748 100644 --- a/User/device/dr16.c +++ b/User/device/dr16.c @@ -41,12 +41,26 @@ static osThreadId_t thread_alert; static bool inited = false; +static DR16_t *dr16_instance = NULL; /* 用于空闲中断回调中访问实例 */ +static uint8_t sync_buf[32]; /* 帧同步时的丢弃缓冲区 */ /* Private function -------------------------------------------------------- */ static void DR16_RxCpltCallback(void) { osThreadFlagsSet(thread_alert, SIGNAL_DR16_RAW_REDY); } +/** + * @brief 空闲中断回调 - 用于帧同步 + * 空闲中断表示一帧传输结束(总线空闲),此时停止当前DMA接收, + * 丢弃不完整的数据,这样下一次 StartDmaRecv 就能从帧头开始。 + */ +static void DR16_IdleCallback(void) { + /* 停止当前DMA接收(无论收了多少字节) */ + HAL_UART_AbortReceive(BSP_UART_GetHandle(BSP_UART_DR16)); + /* 通知任务:可以启动下一次对齐的接收了 */ + osThreadFlagsSet(thread_alert, SIGNAL_DR16_RAW_REDY); +} + static bool DR16_DataCorrupted(const DR16_t *dr16) { if (dr16 == NULL) return DEVICE_ERR_NULL; @@ -79,16 +93,49 @@ int8_t DR16_Init(DR16_t *dr16) { if (inited) return DEVICE_ERR_INITED; if ((thread_alert = osThreadGetId()) == NULL) return DEVICE_ERR_NULL; + dr16_instance = dr16; + + /* 注册 DMA 接收完成回调 */ BSP_UART_RegisterCallback(BSP_UART_DR16, BSP_UART_RX_CPLT_CB, DR16_RxCpltCallback); + /* 注册空闲中断回调并使能空闲中断,用于帧同步 */ + BSP_UART_RegisterCallback(BSP_UART_DR16, BSP_UART_IDLE_LINE_CB, + DR16_IdleCallback); + __HAL_UART_ENABLE_IT(BSP_UART_GetHandle(BSP_UART_DR16), UART_IT_IDLE); + + /* + * 首次帧同步:启动一次丢弃式DMA接收。 + * 如果遥控器已经在发送,DMA会从帧中间开始收,空闲中断到来时 + * IdleCallback 会 Abort 这次接收并通知任务,下一次 StartDmaRecv + * 就能从完整帧头开始。 + */ + HAL_UART_Receive_DMA(BSP_UART_GetHandle(BSP_UART_DR16), + sync_buf, sizeof(sync_buf)); + /* 等待空闲中断完成首次同步(最多50ms,足够等一帧) */ + osThreadFlagsWait(SIGNAL_DR16_RAW_REDY, osFlagsWaitAll, 50); + inited = true; return DEVICE_OK; } int8_t DR16_Restart(void) { - __HAL_UART_DISABLE(BSP_UART_GetHandle(BSP_UART_DR16)); - __HAL_UART_ENABLE(BSP_UART_GetHandle(BSP_UART_DR16)); + UART_HandleTypeDef *huart = BSP_UART_GetHandle(BSP_UART_DR16); + + /* 先终止当前DMA接收 */ + HAL_UART_AbortReceive(huart); + + /* 重置串口 */ + __HAL_UART_DISABLE(huart); + __HAL_UART_ENABLE(huart); + + /* 重新使能空闲中断 */ + __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE); + + /* 重新做帧同步:丢弃式接收,等空闲中断对齐 */ + HAL_UART_Receive_DMA(huart, sync_buf, sizeof(sync_buf)); + osThreadFlagsWait(SIGNAL_DR16_RAW_REDY, osFlagsWaitAll, 50); + return DEVICE_OK; } @@ -109,6 +156,8 @@ int8_t DR16_ParseData(DR16_t *dr16){ if (dr16 == NULL) return DEVICE_ERR_NULL; if (DR16_DataCorrupted(dr16)) { + /* 数据损坏说明帧错位了,重启串口并重新同步 */ + DR16_Restart(); return DEVICE_ERR; }