int fputc(int ch, FILE *f)
{while ((USART1->SR & 0X40) == 0); /* 等待上一个字符发送完成 */USART1->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */return ch;
}int fputc(int ch, FILE *f)
{ unsigned char temp[1]={ch};HAL_UART_Transmit(&huart1,temp,1,0xffff); return ch;
}
可以看到上述两个fputc函数,其中第一个不可以使用在freertos系统中,因为多任务同时输出会导致输出错误。
这两个fputc
函数的实现都是为了将字符通过STM32的串口(UART)发送出去,以支持通过printf
等标准I/O函数将输出重定向到串口。然而,它们使用了不同的方法来达到这个目的,具体区别如下:
第一个fputc
实现
c复制代码
int fputc(int ch, FILE *f) | |
{ | |
while ((USART1->SR & 0X40) == 0); /* 等待上一个字符发送完成 */ | |
USART1->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */ | |
return ch; | |
} |
- 直接操作硬件寄存器:这个实现直接操作STM32的USART1的硬件寄存器。
USART1->SR
是状态寄存器,0X40
(即USART_FLAG_TXE
)表示发送数据寄存器空标志位,用于检查发送缓冲区是否为空。如果为空,表示可以发送新的数据。USART1->DR
是数据寄存器,用于存放要发送的数据。 - 阻塞等待:该实现使用了一个
while
循环来阻塞等待,直到发送缓冲区为空(即上一个字符发送完成)。这种方式简单直接,但可能会在某些情况下导致程序响应变慢,尤其是当串口通信速度较慢或通信频繁时。 - 效率:直接操作寄存器通常具有较高的效率,因为没有函数调用和中断处理的开销。
第二个fputc
实现
c复制代码
int fputc(int ch, FILE *f) | |
{ | |
unsigned char temp[1]={ch}; | |
HAL_UART_Transmit(&huart1,temp,1,0xffff); | |
return ch; | |
} |
- 使用HAL库:这个实现使用了STM32的硬件抽象层(HAL)库函数
HAL_UART_Transmit
来发送数据。HAL_UART_Transmit
是一个非阻塞或可配置为超时阻塞的函数,用于通过指定的UART接口发送一定数量的数据字节。 - 配置灵活:使用HAL库函数可以提供更多的配置选项,比如可以设置超时时间(在这个例子中为
0xffff
,即几乎无限等待),从而避免完全阻塞等待。 - 代码可读性和可移植性:使用HAL库函数可以提高代码的可读性和可移植性,因为库函数封装了底层硬件操作的细节。
- 开销:使用HAL库函数相比直接操作寄存器可能会有一定的性能开销,因为库函数内部可能包含额外的检查和错误处理逻辑。
总结
两个实现的主要区别在于它们如何与STM32的UART硬件接口交互:一个是直接操作硬件寄存器,另一个是通过STM32 HAL库提供的函数。选择哪种方法取决于具体的应用场景和需求,比如对性能的要求、代码的可读性和可维护性等。