# bsp_usart

neozng1@hnu.edu.cn

> TODO: 增加发送队列以解决短时间内调用`USARTSend()`发生丢包的问题,目前仅支持DMA。还需要提供阻塞和IT模式以供选择,参考bspiic和spi进行实现。 > 可以直接在发送函数的参数列表添加发送模式选择,或增加instance成员变量,并提供设置模式接口,两者各有优劣 ## 使用说明 若你需要构建新的基于串口的module,首先需要拥有一个`usart_instance`的指针用于操作串口对象。 需要在串口实例下设定接收的数据包的长度,实例对应的串口硬件(通过`UART_HandleTypeDef`指定,如`&huart1`),解析接收数据对应的回调函数这三个参数。然后,调用`USARTRegister()`并传入配置好的`usart_instance`指针即可。 若要发送数据,调用`USARTSend()`。注意buffsize务必小于你创建的buff的大小,否则造成指针越界后果未知。 串口硬件收到数据时,会将其存入`usart_instance.recv_buff[]`中,当收到完整一包数据,会调用设定的回调函数`module_callback`(即你注册时提供的解析函数)。在此函数中,你可以通过`usart_instance.recv_buff[]`访问串口收到的数据。 ## 代码结构 .h文件内包括了外部接口和类型定义,以及模块对应的宏。c文件内为私有函数和外部接口的定义。 ## 类型定义 ```c #define DEVICE_USART_CNT 3 // C板至多分配3个串口 #define USART_RXBUFF_LIMIT 128 // if your protocol needs bigger buff, modify here typedef void (*usart_module_callback)(); /* usart_instance struct,each app would have one instance */ typedef struct { uint8_t recv_buff[USART_RXBUFF_LIMIT]; // 预先定义的最大buff大小,如果太小请修改USART_RXBUFF_LIMIT uint8_t recv_buff_size; // 模块接收一包数据的大小 UART_HandleTypeDef *usart_handle; // 实例对应的usart_handle usart_module_callback module_callback; // 解析收到的数据的回调函数 } usart_instance; ``` - `DEVICE_USART_CNT`是开发板上可用的串口数量。 - `USART_RXBUFF_LIMIT`是串口单次接收的数据长度上限,暂时设为128,如果需要更大的buffer容量,修改该值。 - `usart_module_callback()`是模块提供给串口接收中断回调函数使用的协议解析函数指针。对于每个需要串口的模块,需要定义一个这样的函数用于解包数据。 - 每定义一个`usart_instance`,就代表一个串口的**实例**(对象)。一个串口实例内有接收buffer,单个数据包的大小,该串口对应的`HAL handle`(代表其使用的串口硬件具体是哪一个)以及用于解包数据的回调函数。 ## 外部接口 ```c void USARTRegister(usart_instance *_instance); void USARTSend(usart_instance *_instance, uint8_t *send_buf, uint16_t send_size); ``` - `USARTRegister`是用于初始化串口对象的接口,module层的模块对象(也应当为一个结构体)内要包含一个`usart_instance`。 **在调用该函数之前,需要先对其成员变量`*usart_handle`,`module_callback()`以及`recv_buff_size`进行赋值。** - `USARTSend()`是通过模块通过其拥有的串口对象发送数据的接口,调用时传入的参数为串口实例指针,发送缓存以及此次要发送的数据长度(8-bit\*n)。 ## 私有函数和变量 在.c文件内设为static的函数和变量 ```c static usart_instance *instance[DEVICE_USART_CNT]; ``` 这是bsp层管理所有串口实例的入口。 ```c static void USARTServiceInit(usart_instance *_instance) void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) ``` - `USARTServiceInit()`会被`USARTRegister()`调用,开启接收中断 - `HAL_UARTEx_RxEventCallback()`和`HAL_UART_ErrorCallback()`都是对HAL的回调函数的重定义(原本的callback是`__week`修饰的弱定义),前者在发生**IDLE中断**或**单次DMA传输中断**后会被调用(说明收到了完整的一包数据),随后在里面根据中断来源,调用拥有产生了该中断的模块的协议解析函数进行数据解包;后者在串口传输出错的时候会被调用,重新开启接收。