Files
DTU-LCD/Drivers/BSP/RS485/rs485.c

475 lines
25 KiB
C
Raw 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.
/******************************************************************************
* @file rs485.c
* @brief RS485 串口驱动 - DMA 与中断接收
* @details 本文件实现 RS485 串口通信驱动,支持两种模式:
* 1. DMA 模式:主工作模式,使用 ReceiveToIdle 接收不定长帧
* 2. 中断模式用于错误恢复或短帧接收RXNE 逐字节接收
* 收发通过 DE 引脚PA1切换低电平发送高电平接收。
* @author 阜阳师范大学物电学院
* @version V0.01
* @date 2026.1.24
* @note USART2TX=PA2RX=PA3DE=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. 初始化 UART8N1无流控波特率 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 接收通道
* ========================================================================
* DMADirect Memory Access用于在 USART 接收数据时自动将数据从
* 外设寄存器传输到内存缓冲区,无需 CPU 干预,提高效率。
*
* STM32F103 中USART2_RX 对应 DMA1_Channel6
*
* 时钟配置分析(系统时钟 72MHz
* - AHB 时钟72MHzDMA 在 AHB 总线上)
* - APB1 时钟36MHzUSART2 在 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.DR3208 字节) */
// UART_RX_LEN); /* 最大接收长度3208 字节 */
HAL_UARTEx_ReceiveToIdle_IT(&rs485_handle, /* UART 句柄 */
(uint8_t *)RS485REG.DR, /* 接收缓冲区RS485REG.DR3208 字节) */
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
* ========================================================================
* RXNEReceive 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 中断
* - 如果发生溢出错误OREHAL 库会中止 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.DR3208 字节) */
UART_RX_LEN); /* 最大接收长度3208 字节 */
}
}
/**
* @brief UART 错误回调函数
* @param huart UART 句柄
* @note 当发生 UART 错误如溢出、帧错误等HAL 库会调用此函数
*
* @details 重要当接收3208字节时如果发生溢出错误OREHAL 库会:
* 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();
}