/****************************************************************************** * @file rs485.c * @brief RS485 串口驱动 - DMA 与中断接收 * @details 本文件实现 RS485 串口通信驱动,支持两种模式: * 1. DMA 模式:主工作模式,使用 ReceiveToIdle 接收不定长帧 * 2. 中断模式:用于错误恢复或短帧接收,RXNE 逐字节接收 * 收发通过 DE 引脚(PA1)切换:低电平发送,高电平接收。 * @author 阜阳师范大学物电学院 * @version V0.01 * @date 2026.1.24 * @note USART2,TX=PA2,RX=PA3,DE=PA1;波特率 700000 ******************************************************************************/ #include "rs485.h" #include "160160D.h" /* ============================================================================ * USART 与引脚宏定义 * ============================================================================ */ #define RS485_UX USART2 #define RS485_UX_IRQn USART2_IRQn #define RS485_UX_IRQHandler USART2_IRQHandler #define RS485_UX_CLK_ENABLE() do{ __HAL_RCC_USART2_CLK_ENABLE(); }while(0) /**< USART2 时钟使能 */ #define RS485_SEND_ENABLE() do{HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);}while(0) /**< DE 低:发送 */ #define RS485_RECEIVE_ENABLE() do{HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);}while(0) /**< DE 高:接收 */ #define RS485_ENABLE_GPIO_PORT GPIOA #define RS485_ENABLE_GPIO_PIN GPIO_PIN_1 #define RS485_ENABLE_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) #define RS485_TX_GPIO_PORT GPIOA #define RS485_TX_GPIO_PIN GPIO_PIN_2 #define RS485_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) #define RS485_RX_GPIO_PORT GPIOA #define RS485_RX_GPIO_PIN GPIO_PIN_3 #define RS485_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) #define BAUDRATE (700000) /**< 波特率 */ /* ============================================================================ * 全局变量定义 * ============================================================================ */ RS485_REGISTER_TYPE RS485REG = {RESET, {0}, {0}}; /**< RS485 收发寄存器,零初始化 */ UART_HandleTypeDef rs485_handle; /**< HAL UART 句柄 */ DMA_HandleTypeDef hdma_rs485_rx; /**< HAL DMA 接收句柄(DMA1 Channel6) */ /* ============================================================================ * 初始化函数 * ============================================================================ */ /** * @brief RS485 初始化(DMA 接收模式) * @note 配置流程: * 1. 使能 GPIO、USART 时钟 * 2. 配置 TX(PA2)、RX(PA3)、DE(PA1) * 3. 配置 DMA1 Channel6 接收,关联 UART * 4. 使能 DMA、USART 中断 * 5. 初始化 UART(8N1,无流控,波特率 BAUDRATE) * 6. 切换为接收,启动 ReceiveToIdle DMA * USART 时钟源需在 sys_stm32_clock_init 中已配置。 * @retval 无 */ void RS485_DMA_init(void) { /* ======================================================================== * 第一步:使能相关外设时钟 * ======================================================================== * 在 STM32 中,所有外设在使用前必须先使能其时钟,以降低功耗。 * 这里需要使能: * - GPIOA 时钟:用于 TX(PA2)、RX(PA3)、DE(PA1) 引脚 * - USART2 时钟:用于串口通信功能 * - DMA1 时钟:用于 DMA 数据传输功能(必须!) */ RS485_TX_GPIO_CLK_ENABLE(); /* 使能 GPIOA 时钟(TX 引脚 PA2) */ RS485_RX_GPIO_CLK_ENABLE(); /* 使能 GPIOA 时钟(RX 引脚 PA3) */ RS485_ENABLE_GPIO_CLK_ENABLE(); /* 使能 GPIOA 时钟(DE 引脚 PA1) */ RS485_UX_CLK_ENABLE(); /* 使能 USART2 时钟 */ __HAL_RCC_DMA1_CLK_ENABLE(); /* 使能 DMA1 时钟(必须!否则 DMA 无法工作) */ /* ======================================================================== * 第二步:配置 GPIO 引脚功能 * ======================================================================== * RS485 需要三个 GPIO 引脚: * 1. TX 引脚(PA2):发送数据,配置为复用推挽输出 * 2. RX 引脚(PA3):接收数据,配置为复用输入 * 3. DE 引脚(PA1):收发方向控制,配置为普通推挽输出 */ GPIO_InitTypeDef gpio_init_struct = {0}; /* 初始化 GPIO 配置结构体 */ /* 配置 TX 引脚(PA2)为复用推挽输出模式 */ gpio_init_struct.Pin = RS485_TX_GPIO_PIN; /* 选择 PA2 引脚 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出:USART2_TX 功能 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉:提高输出驱动能力,抗干扰 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速:支持高波特率通信 */ HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_init_struct); /* 配置 RX 引脚(PA3)为复用输入模式 */ gpio_init_struct.Pin = RS485_RX_GPIO_PIN; /* 选择 PA3 引脚 */ gpio_init_struct.Mode = GPIO_MODE_AF_INPUT; /* 复用输入:USART2_RX 功能 */ /* 注意:复用输入模式下,Pull 和 Speed 参数通常被忽略,但保持一致性 */ HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_init_struct); /* 配置 DE 引脚(PA1)为普通推挽输出模式 */ gpio_init_struct.Pin = RS485_ENABLE_GPIO_PIN; /* 选择 PA1 引脚 */ gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出:用于控制 RS485 收发方向 */ /* DE 引脚控制逻辑: * - 低电平(RESET):使能发送模式,允许数据从 TX 发送到总线 * - 高电平(SET):使能接收模式,允许从总线接收数据到 RX */ HAL_GPIO_Init(RS485_ENABLE_GPIO_PORT, &gpio_init_struct); /* ======================================================================== * 第三步:配置 DMA 接收通道 * ======================================================================== * DMA(Direct Memory Access)用于在 USART 接收数据时自动将数据从 * 外设寄存器传输到内存缓冲区,无需 CPU 干预,提高效率。 * * STM32F103 中,USART2_RX 对应 DMA1_Channel6 * * 时钟配置分析(系统时钟 72MHz): * - AHB 时钟:72MHz(DMA 在 AHB 总线上) * - APB1 时钟:36MHz(USART2 在 APB1 总线上) * - 波特率:700000 bps * - 每个字节时间:约 14.3 微秒(10 位:1 起始 + 8 数据 + 1 停止) * * DMA 传输速度要求: * - DMA 需要从 APB1 外设(USART2)读取数据到 AHB 内存 * - 需要通过 AHB-APB1 桥,可能有 1-2 个时钟周期延迟 * - 理论上 DMA 时钟 72MHz 足够快,但总线仲裁可能导致延迟 * * 溢出错误可能原因: * 1. 总线竞争:CPU 访问 APB1 外设时与 DMA 竞争总线 * 2. AHB-APB1 桥延迟:DMA 访问 APB1 外设需要经过桥接器 * 3. DMA 优先级:虽然设置为最高,但总线仲裁是轮询的 * 4. 接收速度过快:3208 字节连续接收,DMA 可能来不及处理 */ hdma_rs485_rx.Instance = DMA1_Channel6; /* 使用 DMA1 通道 6 */ hdma_rs485_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; /* 传输方向:外设到内存 */ hdma_rs485_rx.Init.PeriphInc = DMA_PINC_DISABLE; /* 外设地址不递增:USART 数据寄存器地址固定 */ hdma_rs485_rx.Init.MemInc = DMA_MINC_ENABLE; /* 内存地址递增:数据依次存入缓冲区 */ hdma_rs485_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; /* 外设数据宽度:字节(8位) */ hdma_rs485_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; /* 内存数据宽度:字节(8位) */ hdma_rs485_rx.Init.Mode = DMA_NORMAL; /* 普通模式:传输完成后停止,需重新启动 */ hdma_rs485_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH; /* 最高优先级:确保数据及时传输,避免丢失 */ HAL_DMA_Init(&hdma_rs485_rx); /* 初始化 DMA 通道 */ /* 将 DMA 句柄关联到 UART 句柄,使 HAL 库能够自动管理 DMA 传输 */ __HAL_LINKDMA(&rs485_handle, hdmarx, hdma_rs485_rx); /* 使能 DMA 中断,用于接收完成等事件的通知 */ HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn); /* 使能 DMA1_Channel6 中断 */ HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0); /* 设置中断优先级为最高(0,0) */ /* ======================================================================== * 第四步:配置 UART 串口参数 * ======================================================================== * 配置 USART2 的通信参数,包括波特率、数据位、停止位、校验位等 */ rs485_handle.Instance = RS485_UX; /* 使用 USART2 */ rs485_handle.Init.BaudRate = BAUDRATE; /* 波特率:700000 bps(高速通信) */ rs485_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 数据位:8 位 */ rs485_handle.Init.StopBits = UART_STOPBITS_1; /* 停止位:1 位 */ rs485_handle.Init.Parity = UART_PARITY_NONE; /* 校验位:无校验 */ rs485_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 硬件流控:无(RS485 不需要 RTS/CTS) */ rs485_handle.Init.Mode = UART_MODE_TX_RX; /* 工作模式:同时支持发送和接收 */ rs485_handle.Init.OverSampling = UART_OVERSAMPLING_16; /* 过采样:16 倍(STM32F103 仅支持 16 倍过采样) */ HAL_UART_Init(&rs485_handle); /* 初始化 UART,应用上述配置 */ /* 手动精确设置 BRR 寄存器以获得准确的 700000 波特率 * 计算:PCLK1 = 36MHz, 16倍过采样 * USARTDIV = 36000000 / (16 * 700000) = 3.2142857... * BRR = (整数部分 << 4) | 小数部分 */ /* 使能 USART2 中断,用于处理接收完成、错误等事件 */ HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能 USART2 中断 */ HAL_NVIC_SetPriority(RS485_UX_IRQn, 1, 0); /* 设置中断优先级为 1(低于 DMA 中断) */ /* ======================================================================== * 第五步:启动 DMA 接收 * ======================================================================== * 将 RS485 切换到接收模式,并启动 ReceiveToIdle DMA 接收 * * ReceiveToIdle 模式特点: * - 当检测到总线空闲(IDLE)时,自动触发接收完成回调 * - 适用于接收不定长数据帧(如 Modbus 协议) * - 无需预先知道数据长度,总线空闲即表示一帧数据接收完成 */ RS485_RECEIVE_ENABLE(); /* DE 引脚置高,切换到接收模式 */ // HAL_UARTEx_ReceiveToIdle_DMA(&rs485_handle, /* UART 句柄 */ // (uint8_t *)RS485REG.DR, /* 接收缓冲区:RS485REG.DR(3208 字节) */ // UART_RX_LEN); /* 最大接收长度:3208 字节 */ HAL_UARTEx_ReceiveToIdle_IT(&rs485_handle, /* UART 句柄 */ (uint8_t *)RS485REG.DR, /* 接收缓冲区:RS485REG.DR(3208 字节) */ UART_RX_LEN); /* 最大接收长度:3208 字节 */ /* 注意:接收完成后,会在 HAL_UARTEx_RxEventCallback 回调函数中 * 自动重新启动接收,实现连续接收 */ } /** * @brief RS485 反初始化(DMA 接收模式) * @note 按照与初始化相反的顺序清理资源: * 1. 停止 DMA 接收 * 2. 禁用中断 * 3. 反初始化 DMA * 4. 反初始化 UART * 5. 反初始化 GPIO(可选) * 注意:时钟通常不禁用,因为可能被其他外设使用 * @retval 无 */ void RS485_DMA_DeInit(void) { /* ======================================================================== * 第一步:停止 DMA 接收 * ======================================================================== * 必须先停止正在进行的 DMA 传输,避免数据损坏 */ HAL_UART_DMAStop(&rs485_handle); /* 停止 UART DMA 接收 */ /* ======================================================================== * 第二步:禁用中断 * ======================================================================== * 禁用 USART2 和 DMA1_Channel6 的中断,避免在反初始化过程中触发中断 */ HAL_NVIC_DisableIRQ(RS485_UX_IRQn); /* 禁用 USART2 中断 */ HAL_NVIC_DisableIRQ(DMA1_Channel6_IRQn); /* 禁用 DMA1_Channel6 中断 */ /* ======================================================================== * 第三步:反初始化 DMA * ======================================================================== * 断开 DMA 与 UART 的关联,然后反初始化 DMA 通道 * 注意:HAL 库没有提供 __HAL_UNLINK_DMA 宏,需要手动将指针设为 NULL */ rs485_handle.hdmarx = NULL; /* 断开 DMA 与 UART 的关联 */ HAL_DMA_DeInit(&hdma_rs485_rx); /* 反初始化 DMA 通道 */ /* ======================================================================== * 第四步:反初始化 UART * ======================================================================== * 反初始化 USART2,这会调用 HAL_UART_MspDeInit 来清理底层硬件 */ HAL_UART_DeInit(&rs485_handle); /* 反初始化 UART */ /* ======================================================================== * 第五步:反初始化 GPIO(可选) * ======================================================================== * 将 GPIO 引脚恢复为默认状态(模拟输入,高阻态) * 注意:如果这些引脚可能被其他外设使用,可以跳过此步骤 */ HAL_GPIO_DeInit(RS485_TX_GPIO_PORT, RS485_TX_GPIO_PIN); /* 反初始化 TX 引脚(PA2) */ HAL_GPIO_DeInit(RS485_RX_GPIO_PORT, RS485_RX_GPIO_PIN); /* 反初始化 RX 引脚(PA3) */ HAL_GPIO_DeInit(RS485_ENABLE_GPIO_PORT, RS485_ENABLE_GPIO_PIN); /* 反初始化 DE 引脚(PA1) */ /* 注意:时钟通常不禁用,因为: * - GPIOA 时钟可能被其他外设使用 * - USART2 时钟可能被其他功能使用 * - DMA1 时钟可能被其他 DMA 通道使用 * 如果需要完全禁用时钟以节省功耗,可以在确认没有其他外设使用时禁用 */ } /** * @brief RS485 初始化(中断接收模式) * @note 配置 GPIO、UART,使能 RXNE 中断。不启用 DMA。 * 用于错误恢复或接收短帧。USART 时钟源需已配置。 * @retval 无 * * @details 中断接收模式与 DMA 模式的区别: * - 中断模式:每接收一个字节触发一次中断,CPU 需要逐字节处理 * - DMA 模式:自动将数据从 USART 传输到内存,CPU 负担小 * 中断模式适用于: * - DMA 故障时的错误恢复 * - 接收短帧(数据量小,中断开销可接受) * - 调试和测试场景 */ void RS485_init(void) { /* ======================================================================== * 第一步:使能相关外设时钟 * ======================================================================== * 与 DMA 模式相同,需要使能 GPIOA 和 USART2 的时钟 */ RS485_TX_GPIO_CLK_ENABLE(); /* 使能 GPIOA 时钟(TX 引脚 PA2) */ RS485_RX_GPIO_CLK_ENABLE(); /* 使能 GPIOA 时钟(RX 引脚 PA3) */ RS485_ENABLE_GPIO_CLK_ENABLE(); /* 使能 GPIOA 时钟(DE 引脚 PA1) */ RS485_UX_CLK_ENABLE(); /* 使能 USART2 时钟 */ /* ======================================================================== * 第二步:配置 GPIO 引脚功能 * ======================================================================== * GPIO 配置与 DMA 模式完全相同: * - TX(PA2):复用推挽输出,用于发送数据 * - RX(PA3):复用输入,用于接收数据 * - DE(PA1):普通推挽输出,用于控制收发方向 */ GPIO_InitTypeDef gpio_init_struct = {0}; /* 初始化 GPIO 配置结构体 */ /* 配置 TX 引脚(PA2)为复用推挽输出模式 */ gpio_init_struct.Pin = RS485_TX_GPIO_PIN; /* 选择 PA2 引脚 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出:USART2_TX 功能 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉:提高输出驱动能力 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速:支持高波特率 */ HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_init_struct); /* 配置 RX 引脚(PA3)为复用输入模式 */ gpio_init_struct.Pin = RS485_RX_GPIO_PIN; /* 选择 PA3 引脚 */ gpio_init_struct.Mode = GPIO_MODE_AF_INPUT; /* 复用输入:USART2_RX 功能 */ HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_init_struct); /* 配置 DE 引脚(PA1)为普通推挽输出模式 */ gpio_init_struct.Pin = RS485_ENABLE_GPIO_PIN; /* 选择 PA1 引脚 */ gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出:控制 RS485 收发方向 */ HAL_GPIO_Init(RS485_ENABLE_GPIO_PORT, &gpio_init_struct); /* ======================================================================== * 第三步:配置 UART 串口参数 * ======================================================================== * UART 参数配置与 DMA 模式完全相同: * - 波特率:700000 bps * - 数据格式:8 位数据位,1 位停止位,无校验位 * - 无硬件流控 * - 16 倍过采样 */ rs485_handle.Instance = RS485_UX; /* 使用 USART2 */ rs485_handle.Init.BaudRate = BAUDRATE; /* 波特率:700000 bps */ rs485_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 数据位:8 位 */ rs485_handle.Init.StopBits = UART_STOPBITS_1; /* 停止位:1 位 */ rs485_handle.Init.Parity = UART_PARITY_NONE; /* 校验位:无校验 */ rs485_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 硬件流控:无 */ rs485_handle.Init.Mode = UART_MODE_TX_RX; /* 工作模式:发送和接收 */ rs485_handle.Init.OverSampling = UART_OVERSAMPLING_16; /* 过采样:16 倍 */ HAL_UART_Init(&rs485_handle); /* 初始化 UART */ /* ======================================================================== * 第四步:使能接收中断(RXNE) * ======================================================================== * RXNE(Receive Not Empty)中断: * - 当 USART 接收数据寄存器(RDR)中有新数据时触发 * - 每接收一个字节触发一次中断 * - 在中断服务函数中需要手动读取数据并存入缓冲区 * * 注意:此模式不使用 DMA,需要 CPU 在中断中逐字节处理数据 */ __HAL_UART_ENABLE_IT(&rs485_handle, UART_IT_RXNE); /* 使能 RXNE(接收数据寄存器非空)中断 */ HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能 USART2 中断 */ HAL_NVIC_SetPriority(RS485_UX_IRQn, 1, 0); /* 设置中断优先级为 1 */ /* ======================================================================== * 第五步:切换到接收模式 * ======================================================================== * 将 DE 引脚置高,使 RS485 处于接收状态,准备接收数据 */ RS485_RECEIVE_ENABLE(); /* DE 引脚置高,切换到接收模式 */ /* 注意:中断模式下,需要在 USART2_IRQHandler 中断服务函数中 * 手动调用 HAL_UART_IRQHandler,并在回调函数中处理接收到的数据 */ } /* ============================================================================ * 回调与中断服务函数 * ============================================================================ */ /** * @brief UART 接收事件回调(ReceiveToIdle 完成时由 HAL 调用) * @param huart UART 句柄 * @param Size 本帧接收到的字节数 * @note 当为 RS485 所用 UART 时:置位 NewMessageFlag,并重新启动 ReceiveToIdle DMA。 * * @details HAL 库在调用此回调前已经完成以下操作: * - DMA 状态已设置为 READY(在 DMA IRQ 处理中) * - UART 状态已设置为 READY(在 UART_DMAReceiveCplt 中) * - DMA 请求已禁用(清除 DMAR 位) * - 相关中断已禁用 * 因此可以直接调用 HAL_UARTEx_ReceiveToIdle_DMA 重新启动接收。 * * @warning 重要:当接收数据长度 = 缓冲区大小(3208字节)时: * - DMA 传输完成中断触发,而不是 IDLE 中断 * - 如果发生溢出错误(ORE),HAL 库会中止 DMA 并重置 ReceptionType 为 STANDARD * - 这会导致回调函数不会被调用 * - 解决方案:添加错误回调函数来处理这种情况 * * @retval 无 */ void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { if (huart->Instance == RS485_UX) { /* 调试信息:显示接收到的字节数 */ // HZ12AndChar_Printf(0,32, (uint8_t*)"RxEvent:", RESET); // IntValue_Printf(32,32, Size, RESET); /* 设置新消息标志,通知主程序处理数据 */ RS485REG.NewMessageFlag = SET; /* 重新启动 IT 接收*/ HAL_UARTEx_ReceiveToIdle_IT(&rs485_handle, /* UART 句柄 */ (uint8_t *)RS485REG.DR, /* 接收缓冲区:RS485REG.DR(3208 字节) */ UART_RX_LEN); /* 最大接收长度:3208 字节 */ } } /** * @brief UART 错误回调函数 * @param huart UART 句柄 * @note 当发生 UART 错误(如溢出、帧错误等)时,HAL 库会调用此函数 * * @details 重要:当接收3208字节时,如果发生溢出错误(ORE),HAL 库会: * 1. 中止 DMA 传输 * 2. 重置 ReceptionType 为 STANDARD * 3. 调用错误回调函数(而不是 RxEventCallback) * 因此,需要在错误回调中处理这种情况,并重新启动接收 * * @details 错误代码说明: * - HAL_UART_ERROR_NONE (0x00): 无错误 * - HAL_UART_ERROR_PE (0x01): 奇偶校验错误 * - HAL_UART_ERROR_NE (0x02): 噪声错误(信号干扰、波特率不匹配等) * - HAL_UART_ERROR_FE (0x04): 帧错误(停止位检测失败) * - HAL_UART_ERROR_ORE (0x08): 溢出错误(数据接收过快,DMA 来不及处理) * - HAL_UART_ERROR_DMA (0x10): DMA 传输错误 * * @retval 无 */ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if (huart->Instance == RS485_UX) { // /* 调试信息:显示错误代码 */ // HZ12AndChar_Printf(0,64, (uint8_t*)"Error:", RESET); // IntValue_Printf(32,64, huart->ErrorCode, RESET); //HAL_UARTEx_ReceiveToIdle_DMA(&rs485_handle, (uint8_t *)RS485REG.DR, UART_RX_LEN); } } /** * @brief RS485 所用 USART 中断服务函数 * @note 调用 HAL_UART_IRQHandler 处理 UART 及关联 DMA 中断。 * @retval 无 */ void RS485_UX_IRQHandler(void) { HAL_UART_IRQHandler(&rs485_handle); } /** * @brief DMA1 Channel6 中断服务函数(RS485 接收 DMA) * @note 调用 HAL_DMA_IRQHandler,在 ReceiveToIdle 完成等事件时触发。 * @retval 无 */ void DMA1_Channel6_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_rs485_rx); } /* ============================================================================ * 发送接口 * ============================================================================ */ /** * @brief RS485 发送数据 * @param ptr 待发送数据指针 * @param len 待发送字节数 * @note 切换为发送(DE 低)→ 阻塞发送 → 切换回接收(DE 高)。超时 1000ms。 * @retval 无 */ void RS485_SendBuff(uint8_t *ptr, uint32_t len) { RS485_SEND_ENABLE(); HAL_UART_Transmit(&rs485_handle, ptr, len, 1000); RS485_RECEIVE_ENABLE(); }