整理了main 函数
This commit is contained in:
+64
-33
@@ -14,27 +14,10 @@
|
||||
|
||||
#include "rs485.h"
|
||||
|
||||
/* ======================== 内部辅助函数 ======================== */
|
||||
/* ======================== 全局实例 ======================== */
|
||||
|
||||
/*
|
||||
* 函数功能:DWT 微秒级延时
|
||||
* 入口参数:us - 延时微秒数 uint32_t 1 - N
|
||||
* 返回值:无
|
||||
* 限定条件:无(首次调用自动初始化 DWT CYCCNT)
|
||||
* 函数说明:利用 Cortex-M4 DWT CYCCNT 实现精确微秒延时,168MHz 下 1us = 168 计数。
|
||||
* 首次调用时自动使能 DWT 和 CYCCNT,后续只读 CYCCNT 寄存器,不影响其他模块。
|
||||
*/
|
||||
static void delay_us(uint32_t us)
|
||||
{
|
||||
if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CYCCNT = 0;
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
}
|
||||
uint32_t start = DWT->CYCCNT;
|
||||
uint32_t ticks = us * (SystemCoreClock / 1000000uL);
|
||||
while ((DWT->CYCCNT - start) < ticks) { ; }
|
||||
}
|
||||
/* RS-485 全局实例(接收缓冲内聚于句柄的 rx_buf 字段) */
|
||||
rs485_handle_t g_rs485;
|
||||
|
||||
/* ======================== 方向控制宏 ======================== */
|
||||
|
||||
@@ -51,7 +34,8 @@ static void delay_us(uint32_t us)
|
||||
* dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0) uint16_t
|
||||
* 返回值:无
|
||||
* 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化
|
||||
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低)
|
||||
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低),
|
||||
* 并自动启动 IDLE 中断接收,无需再手动调用 rs485_receive_start。
|
||||
*/
|
||||
void rs485_init(rs485_handle_t *p_handle,
|
||||
UART_HandleTypeDef *p_huart,
|
||||
@@ -64,6 +48,9 @@ void rs485_init(rs485_handle_t *p_handle,
|
||||
p_handle->rx_size = 0;
|
||||
|
||||
RS485_DIR_RX(p_handle);
|
||||
|
||||
/* 自动开启 IDLE 中断接收(后续在回调中重新开启) */
|
||||
(void)rs485_receive_start(p_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -76,14 +63,15 @@ void rs485_init(rs485_handle_t *p_handle,
|
||||
* HAL_TIMEOUT - 发送超时
|
||||
* HAL_ERROR - 发送错误
|
||||
* 限定条件:须在主循环或 FreeRTOS 任务中调用,不可在 UART 中断中调用
|
||||
* 函数说明:发送前拉高 DE,等待 50us 确保 RS485 收发器驱动使能稳定后再启动 UART 发送。
|
||||
* 函数说明:发送前拉高 DE,等待 HAL 时基延时确保 RS485 收发器驱动使能稳定后再启动
|
||||
* UART 发送(HAL 时基最小粒度 1ms,此处延时 1ms,远大于 50us 的 DE 建立时间)。
|
||||
* HAL_UART_Transmit 内部等待 TC(发送完成)标志,确保最后一字节完全移出后
|
||||
* 再拉低 DE 切回接收状态。
|
||||
*/
|
||||
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
|
||||
const uint8_t *p_data,
|
||||
uint16_t len,
|
||||
uint32_t timeout)
|
||||
const uint8_t *p_data,
|
||||
uint16_t len,
|
||||
uint32_t timeout)
|
||||
{
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
|
||||
@@ -93,7 +81,8 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
|
||||
|
||||
RS485_DIR_TX(p_handle);
|
||||
|
||||
delay_us(50);
|
||||
/* DE 建立延时:HAL 时基为 1ms 粒度,1ms 已充分覆盖收发器驱动使能稳定时间 */
|
||||
HAL_Delay(1);
|
||||
|
||||
status = HAL_UART_Transmit(p_handle->huart,
|
||||
(uint8_t *)p_data,
|
||||
@@ -108,22 +97,19 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
|
||||
/*
|
||||
* 函数功能:启动中断方式接收(IDLE 空闲帧检测)
|
||||
* 入口参数:p_handle - RS-485 句柄指针 rs485_handle_t*(非空)
|
||||
* p_buf - 接收缓冲区 uint8_t*(非空)
|
||||
* buf_size - 缓冲区大小 uint16_t
|
||||
* 返回值:HAL_OK - 启动成功 HAL_StatusTypeDef
|
||||
* HAL_ERROR - 启动失败
|
||||
* 限定条件:UART 须已开启全局中断(NVIC 使能)
|
||||
* 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收。
|
||||
* 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收,
|
||||
* 接收缓冲固定使用句柄内部的 rx_buf(RS485_RX_BUF_SIZE)。
|
||||
* 当 UART 总线空闲超过 1 个字符时间后硬件触发 IDLE 中断,
|
||||
* HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。
|
||||
* 用户须在回调中重新调用本函数重新开启接收。
|
||||
*/
|
||||
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle,
|
||||
uint8_t *p_buf,
|
||||
uint16_t buf_size)
|
||||
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle)
|
||||
{
|
||||
p_handle->rx_size = 0;
|
||||
return HAL_UARTEx_ReceiveToIdle_IT(p_handle->huart, p_buf, buf_size);
|
||||
return HAL_UARTEx_ReceiveToIdle_IT(p_handle->huart, p_handle->rx_buf, RS485_RX_BUF_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,3 +136,48 @@ uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle)
|
||||
{
|
||||
return p_handle->rx_size;
|
||||
}
|
||||
|
||||
/* ======================== HAL 回调(UART5 / RS-485 专属) ======================== */
|
||||
|
||||
/*
|
||||
* 应用层接收钩子默认实现(弱符号,可被应用重定义)。
|
||||
* 在中断上下文调用,仅做占位,业务解析由应用提供。
|
||||
*/
|
||||
__weak void rs485_on_rx(uint8_t *buf, uint16_t size)
|
||||
{
|
||||
(void)buf;
|
||||
(void)size;
|
||||
}
|
||||
|
||||
/*
|
||||
* HAL UART 扩展接收回调(IDLE 空闲帧中断触发)。
|
||||
* 当 RS-485 总线空闲超过 1 个字符时间后触发,由 HAL 自动调用。
|
||||
* 注意:回调按实例分发,仅处理本驱动绑定的 UART,不写死 UART5。
|
||||
*/
|
||||
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
|
||||
{
|
||||
if (huart == g_rs485.huart) {
|
||||
rs485_rx_set_size(&g_rs485, Size);
|
||||
|
||||
/* 通知应用处理本次接收(中断上下文,应尽快返回) */
|
||||
rs485_on_rx(g_rs485.rx_buf, Size);
|
||||
|
||||
/* 重新开启接收 */
|
||||
rs485_receive_start(&g_rs485);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* HAL UART 错误回调(ORE/NE/FE/PE 等)。
|
||||
* 读 SR + DR 清除错误标志后重新开启接收,避免中断锁死。
|
||||
*/
|
||||
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart == g_rs485.huart) {
|
||||
/* STM32F4 通过读 SR + DR 清除 ORE/NE/FE/PE 错误标志 */
|
||||
(void)huart->Instance->SR;
|
||||
(void)huart->Instance->DR;
|
||||
/* 重新开启接收 */
|
||||
rs485_receive_start(&g_rs485);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ extern "C" {
|
||||
* 常量定义
|
||||
*/
|
||||
#define RS485_TIMEOUT_DEFAULT 1000U /* 默认发送超时(ms) */
|
||||
#define RS485_RX_BUF_SIZE 256U /* 接收缓冲区大小 */
|
||||
|
||||
/*
|
||||
* RS-485 句柄结构体
|
||||
@@ -34,6 +35,7 @@ typedef struct {
|
||||
GPIO_TypeDef *dir_port; /* 方向控制 GPIO 端口 */
|
||||
uint16_t dir_pin; /* 方向控制 GPIO 引脚号 */
|
||||
volatile uint16_t rx_size; /* 最近一次接收的字节数 */
|
||||
uint8_t rx_buf[RS485_RX_BUF_SIZE]; /* 接收缓冲区 */
|
||||
} rs485_handle_t;
|
||||
|
||||
/*
|
||||
@@ -48,7 +50,8 @@ typedef struct {
|
||||
* dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0)
|
||||
* 返回值:无
|
||||
* 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化
|
||||
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低)
|
||||
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低),并自动启动 IDLE
|
||||
* 中断接收,无需再手动调用 rs485_receive_start。
|
||||
*/
|
||||
void rs485_init(rs485_handle_t *p_handle,
|
||||
UART_HandleTypeDef *p_huart,
|
||||
@@ -73,18 +76,16 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
|
||||
|
||||
/*
|
||||
* 函数功能:启动中断方式接收(IDLE 空闲帧检测)
|
||||
* 入口参数:handle - RS-485 句柄指针
|
||||
* buf - 接收缓冲区
|
||||
* buf_size - 缓冲区大小
|
||||
* 入口参数:handle - RS-485 句柄指针
|
||||
* 返回值:HAL_OK / HAL_ERROR
|
||||
* 限定条件:UART 须已开启全局中断,NVIC 中须使能对应 UART 中断
|
||||
* 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收,
|
||||
* 收到完整帧后在 RxEventCallback 中通知用户。
|
||||
* 用户须在回调中重新调用本函数重新开启接收
|
||||
* 接收缓冲固定使用句柄内部的 rx_buf(RS485_RX_BUF_SIZE)。
|
||||
* 当 UART 总线空闲超过 1 个字符时间后硬件触发 IDLE 中断,
|
||||
* HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。
|
||||
* 用户须在回调中重新调用本函数重新开启接收。
|
||||
*/
|
||||
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle,
|
||||
uint8_t *p_buf,
|
||||
uint16_t buf_size);
|
||||
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle);
|
||||
|
||||
/*
|
||||
* 函数功能:将 RS-485 句柄与 HAL 回调关联
|
||||
@@ -103,6 +104,21 @@ void rs485_rx_set_size(rs485_handle_t *p_handle, uint16_t size);
|
||||
*/
|
||||
uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle);
|
||||
|
||||
/*
|
||||
* 全局 RS-485 实例(由 rs485.c 定义,应用层通过 extern 引用)。
|
||||
* 接收缓冲已内聚到 rs485_handle_t 的 rx_buf 字段,随实例统一管理。
|
||||
*/
|
||||
extern rs485_handle_t g_rs485;
|
||||
|
||||
/*
|
||||
* 应用层接收钩子:RS-485 收到完整帧(IDLE 空闲帧)后由驱动回调调用,
|
||||
* 传入本次接收缓冲区与有效字节数。默认弱实现为空,应用可重定义此函数
|
||||
* 处理业务数据。
|
||||
* 注意:此函数在 UART 中断上下文执行,应尽快拷贝数据后返回,不要在内部
|
||||
* 调用阻塞式 API(如 rs485_transmit 会切换 DE 并等待 TC)。
|
||||
*/
|
||||
void rs485_on_rx(uint8_t *buf, uint16_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user