STM32F103C8的USART2发送乱码求助(USART1同配置可正常工作)
我来帮你一步步分析这个问题——既然USART1能正常工作,说明你的基础时钟配置、串口核心逻辑是没问题的,USART2的乱码大概率出在一些容易忽略的细节上,我们来逐个排查:
1. 波特率配置不匹配(最常见原因)
你代码里给USART2和USART1都用了BRR = 0x341,注释里说是基于8MHz晶振计算的,但这里有个关键细节:USART1和USART2挂在不同的总线上,时钟源可能不一样。
STM32F103的默认时钟配置中:
- USART1挂在APB2总线,当系统时钟从8MHz倍频到72MHz时,APB2预分频器是1,所以USART1的时钟就是72MHz
- USART2挂在APB1总线,APB1预分频器默认是2,此时USART2的时钟是APB1时钟的2倍(STM32F1的规则:APB预分频>1时,USART时钟=APB时钟×2),也就是
(72/2)*2=72MHz
如果你的RCC_VidInit()确实把系统时钟倍频到了72MHz,那9600波特率对应的BRR值应该是72000000 / 9600 = 7500,十六进制是0x1D4C,而不是0x341。USART1用0x341能工作可能是巧合(比如终端自动适配了错误的波特率),但USART2对波特率误差更敏感,直接表现为乱码。
2. 发送逻辑的小问题
你现在是轮询TC(发送完成)标志来触发下一次发送,但初始化后TC标志默认是0,所以第一次循环根本不会执行发送操作,只有当第一次发送完成后TC才会置位。USART1能工作可能是初始化后TC被意外置位了,但USART2没这个情况。
建议改成轮询TXE(数据寄存器空)标志,这是更标准的发送逻辑:
while(1){ if( ( GET_BIT( USART2 -> SR , 7 ) ) == 1 ){ // 检查TXE标志(位7) USART2 -> DR = '1' ; /*PUT DATA ON DATA REG*/ for(int i = 0 ; i <= 1000000 ; i++ ); /*JUST BASIC DELAY*/ } }
TXE标志在数据寄存器空的时候就会置位,能保证第一次循环就发送数据,逻辑更可靠。
3. 再核对GPIO配置细节
虽然你的PA2(USART2_TX)配置看起来正确,但再仔细确认一遍:
- PA2属于GPIOA的低8位引脚,对应
GPIOA->CRL的8-11位:- 你设置的
MODE2=10(2MHz输出)、CNF2=10(复用推挽输出)是完全正确的
- 你设置的
- PA3(USART2_RX)的浮空输入配置也没问题
如果硬件上PA2有额外的下拉/上拉电阻,或者焊接不良,也可能导致信号畸变,建议检查一下硬件引脚的连接情况。
4. 确认USART2时钟是否真的使能了
你调用RCC_VidEnablePeripheralClock(APB1_BUS, 17);来开启USART2时钟,这个参数是对的(STM32F1的RCC_APB1ENR寄存器中USART2EN是位17)。但可以在代码里读取RCC_APB1ENR的寄存器值,确认位17确实被置位了,避免RCC_VidEnablePeripheralClock函数内部有隐藏bug。
快速测试方案
先把USART2的BRR改成0x1D4C,同时把轮询标志换成TXE,再测试是否还乱码。如果还是不行,可以尝试把USART2的TX引脚换成其他复用引脚(比如PD5,取决于你的板子布局),排除硬件引脚本身的问题。
内容的提问来源于stack exchange,提问作者Hesham Adel

