高级会员

- 积分
- 500
- 金钱
- 500
- 注册时间
- 2026-1-29
- 在线时间
- 31 小时
|
针对 STM32F103 的串口程序问题,以下是逐步分析和解决方案:
一、核心问题定位
根据你的描述和代码,最可能的原因是波特率计算错误。你在 serial_begin 函数中通过浮点运算生成波特率寄存器值的方式存在精度损失风险,且不符合 STM32 官方库的标准做法。
二、关键代码修正
1. 波特率计算错误
// 错误代码示例:
speed /= 7.5; // 非常规计算方式,易引入误差
tmp1 = (unsigned int)speed; // 整数部分
speed -= tmp1; // 小数部分
tmp2 = (unsigned int)(speed * 16); // 尝试生成小数部分
USART1_BR = (tmp1 << 4) + tmp2; // 最终结果可能不准确
正确方法:
应使用整数运算计算 USART_BRR 寄存器值,公式为:
=
(
×
16
)
USARTDIV=
(波特率×16)
APB2时钟频率
​
然后将整数部分和小数部分分别写入 USART_BRR。
修正后的代码:
#include "stm32f10x.h" // 确保包含头文件
void serial_begin(uint32_t baudrate) {
// 开启USART1时钟
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
// 计算波特率寄存器值
uint32_t apb2_clock = RCC->APB2ENR & RCC_APB2ENR_USART1EN ? SystemCoreClock : SystemCoreClock / 2;
uint32_t usartdiv = apb2_clock / (16 * baudrate);
USART1->BRR = usartdiv; // 直接赋值给BRR寄存器
// 配置控制寄存器
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 8位数据位,无校验,1停止位
}
2. 缺少必要的GPIO配置
STM32 的串口引脚(PA9/TX, PA10/RX)需配置为复用推挽输出和输入模式。
修正代码:
void gpio_config(void) {
// 开启GPIOA时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 配置PA9为复用推挽输出 (TX)
GPIOA->CRH &= ~(0xF << 4); // 清除原有配置
GPIOA->CRH |= (0x8 << 4); // MODE9: 0b10 (50MHz), CNF9: 0b00 (复用推挽)
// 配置PA10为浮空输入 (RX)
GPIOA->CRH &= ~(0xF << 8); // 清除原有配置
GPIOA->CRH |= (0x4 << 8); // CNF10: 0b01 (浮空输入)
}
在 main() 中调用:
int main(void) {
SystemInit(); // 确保系统时钟已初始化
gpio_config();
serial_begin(115200); // 示例:设置波特率为115200
while (1) {
serial_write('A'); // 测试发送
for (volatile int i = 0; i < 1000000; i++); // 简单延时
}
}
三、其他潜在问题排查
硬件连接检查:
确认 USB-TTL 模块的 TX/RX 与开发板的 RX/TX 交叉连接。
检查接线是否松动或虚焊。
终端工具配置:
确保上位机端(如串口助手)的波特率、数据位、停止位与代码一致(如 115200-8N1)。
调试技巧:
用示波器测量 PA9 引脚,观察是否有波形输出。
尝试降低波特率(如 9600)以提高容错性。
四、完整代码模板
#include "stm32f10x.h"
void gpio_config(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRH = (GPIOA->CRH & ~((0xF << 4) | (0xF << 8))) | (0x8 << 4) | (0x4 << 8);
}
void serial_begin(uint32_t baudrate) {
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
uint32_t usartdiv = SystemCoreClock / (16 * baudrate);
USART1->BRR = usartdiv;
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}
void serial_write(char data) {
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = data;
}
int main(void) {
SystemInit();
gpio_config();
serial_begin(115200);
while (1) {
serial_write('H');
serial_write('e');
serial_write('l');
serial_write('l');
serial_write('o');
serial_write('\r');
serial_write('\n');
for (volatile int i = 0; i < 1000000; i++);
}
}
五、总结
优先修复波特率计算:使用整数运算替代浮点运算。
务必配置GPIO引脚:确保 TX/RX 引脚正确设置为复用功能。
简化测试:先用固定字符串发送测试,排除复杂逻辑干扰。 |
|