|
该如何用HAL_UART_Transmit_IT()实现 UART 上的 printf 输出。 下面是阻塞版本,工作正常: void PRINT_MESG_UART(const char format, ... ) { va_list ap; uint8_t buffer [128]; int n; va_start(ap, format); n = vsnprintf ((char)buffer, 128, format, ap); va_end(ap); if(HAL_UART_Transmit(&UartHandle, (uint8_t)buffer, n, 300) != HAL_OK) { Error_Handler(); } } 现在希望改成非阻塞、基于中断发送。我写了下面代码: uint8_t buffer [128]; void PRINT_MESG_UART(const char format, ... ) { va_list ap; int n; while (UartHandle.gState != HAL_UART_STATE_READY); va_start(ap, format); n = vsnprintf ((char)buffer, 128, format, ap); va_end(ap); HAL_UART_Transmit_IT(&UartHandle, (uint8_t)buffer, n); } 可以跑,但缺点明显:UART 处于发送状态时,函数依然会原地阻塞自旋等待,算不上真正非阻塞。 理想方案是传统的软件环形发送缓冲区,逐个字节入环,直接操作 TXE 中断标志: bool u_put_byte(uint8_t data) { bool ok = FALSE; if ((uart_buffer.txin + 1) % S_BUF_SIZE != uart_buffer.txout) { uart_buffer.txbuf[uart_buffer.txin] = data; uart_buffer.txin = (uart_buffer.txin + 1) % S_BUF_SIZE; ok = TRUE; } SET_BIT(UartHandle.Instance->CR1, USART_CR1_TXEIE); return ok; } void PRINT_MESG_UART(const char format, ... ) { va_list ap; uint8_t buffer[S_BUF_SIZE]; int n; va_start(ap, format); n = vsnprintf ((char)buffer, S_BUF_SIZE, format, ap); va_end(ap); int i = 0; while ((buffer[i] != 0) && (i < S_BUF_SIZE) && (i < n)) { while (!u_put_byte(buffer[i])); i++; } } 但是 HAL 库 UART 接口,并不直接支持这种底层环形缓冲区的工作模式。 |
使用 HAL 库通过串口以 ASCII 形式发送整型数据
串口DMA收发出现ORE错误
STM32F103C8T6 上电后无法通过串口发出数据的问题?
HAL_UART_Transmit_DMA 异常
STM32 增加 WiFi + 以太网的低成本方案
在RS485通信中如何有效避免误码,距离5米,速率115200
UART中IDLE 中断与 RTO 接收超时中断有什么区别
I2C 错误代码含义
在 LwIP_HTTP_Server_Netconn_RTOS 工程中添加 USART3 功能时遇到问题
串口+DMA发数据
微信公众号
手机版
你实现的PRINT_MESG_UART基本是正确的,但最后的数据需要放入到一个环形缓存区中。
放入缓存区中后,检查当前串口是否busy,如果是空闲状态,则取出一个字节使用中断模式发送。如果是繁忙状态则不处理函数直接返回。
在串口中断中,从缓存区中取出一个字节再调用HAL_UART_Transmit_IT发送,这样每发送完成一个字节就触发一次中断并触发下一次传输,最终实现连续数据传输。
如果学会了这种做法,还可以尝试配合DMA实现更高效的链式数据传输,效率更高。
可以参考我这个https://shequ.stmicroelectronics.cn/thread-871151-1-1.html