STM32F3 Discovery采用Rust寄存器级编程时USART1无法发送数据问题
问题描述
以下是我用Rust编写的简单寄存器级程序,参考了多篇C语言相关博客,尝试参照C语言实现方式为Discovery开发板配置寄存器,但运行未达到预期效果。
我需要通过USART1发送单个字符,硬件层面我按照Discovery官方手册的说明连接了FTDI模块,接线如下:
ftdi-----stm32 Rx-------Tx TX-------rx gnd-----gnd
发送数据时FTDI的RX指示灯闪烁,说明有数据传输,预期Mini-com可以接收到发送的数据,但实际FTDI和Mini-com都没有收到任何数据。
问题代码
#![no_std] #![no_main] extern crate cortex_m_semihosting; use cortex_m::asm; use cortex_m_rt::entry; use panic_halt as _; // 不使用HAL库 use stm32f3::stm32f303; use cortex_m_semihosting::hprintln; #[entry] fn main() -> ! { let mut peripherals = &stm32f303::Peripherals::take().unwrap(); let mut rcc = &peripherals.RCC; let gpioa = &peripherals.GPIOA; let usart1 = &peripherals.USART1; // 选择并开启USART1时钟 rcc.cfgr3.write(|w| w.usart1sw().bits(01)); // 选择PCLK作为时钟源(默认值) rcc.apb2enr.write(|w| w.usart1en().set_bit()); // 开启GPIOA时钟 rcc.ahbenr.write(|w| w.iopaen().set_bit()); gpioa.moder.write(|w| w.moder9().bits(10)); // 00=输入,01=输出,10=复用功能 gpioa.otyper.write(|w| w.ot9().clear_bit()); // PA10=RX,PA9=TX gpioa.ospeedr.write(|w| unsafe {w.ospeedr9().bits(01)}); gpioa.moder.write(|w| w.moder10().bits(10)); gpioa.otyper.write(|w| w.ot10().clear_bit()); gpioa.ospeedr.write(|w| unsafe {w.ospeedr10().bits(01)}); gpioa.afrh.write(|w| w.afrh9().af7()); // 选择对应的复用功能 gpioa.afrh.write(|w| w.afrh10().af7()); gpioa.pupdr.write(|w| unsafe {w.pupdr9().bits(00)}); gpioa.pupdr.write(|w| unsafe {w.pupdr10().bits(00)}); // 配置字长 usart1.cr1.write(|w| w.m().bit8()); // 配置USART1波特率 usart1.cr1.write(|w| w.over8().set_bit()); usart1.brr.write(|w| w.brr().bits(0x47)); // 配置停止位数量 usart1.cr2.write(|w| w.stop().bits(00)); // 开启USART1和发送功能 usart1.cr1.write(|w| w .ue().set_bit() .te().set_bit()); // 等待发送数据寄存器为空 while !usart1.isr.read().txe().bit_is_set() {} // 发送数据 usart1.tdr.write(|w| w.tdr().bits(u16::from(b'X'))); loop { while usart1.isr.read().tc().bit_is_clear() {} let txe_status = usart1.isr.read().txe().bits(); let value = usart1.tdr.read().tdr().bits() as u8; hprintln!("tdr value = {} and txe status = {}", value, txe_status); } }
问题排查与修复方案
- 寄存器覆盖写入问题
你对gpioa.moder、usart1.cr1、gpioa.afrh这类寄存器多次调用write()方法,该方法会直接覆盖整个寄存器的所有位,后续写入会清空之前的配置。比如配置完PA9的模式后再配置PA10,会直接把PA9的模式位重置回默认值。应该改用modify()方法仅修改目标位,或者一次性写入所有需要的配置值。 - USART配置被覆盖问题
你在配置字长、OVER8位时就调用了cr1.write(),后续开启UE位的时候又调用了一次cr1.write(),直接清空了之前配置的字长、OVER8位参数,导致USART工作模式完全不符合预期。所有CR1的参数需要在同一次写入操作中完成配置。 - 波特率不匹配问题
你设置OVER8=1时BRR为0x47,对应默认8MHz内部时钟下的波特率约为14084,和常用的115200、9600等波特率不匹配,minicom侧波特率和设备侧波特率不一致时自然无法解析收到的数据。比如要配置9600波特率,8MHz时钟OVER8=1的场景下BRR应设置为0x341。 - 引脚复用配置丢失问题
你对AFRH寄存器分两次写入PA9和PA10的复用功能,第二次写入会直接清空第一次的配置,导致PA9的复用功能配置错误,USART信号无法输出到引脚上。
核心配置修复示例
// GPIO配置改用modify避免覆盖其他位 gpioa.moder.modify(|w| { w.moder9().bits(2); w.moder10().bits(2) }); gpioa.afrh.modify(|w| { w.afrh9().af7(); w.afrh10().af7() }); // USART CR1一次性完成所有配置 usart1.cr1.write(|w| { w.m().bit8(); w.over8().set_bit(); w.ue().set_bit(); w.te().set_bit() }); // 修正波特率为9600@8MHz OVER8模式 usart1.brr.write(|w| w.brr().bits(0x341));
内容的提问来源于stack exchange,提问作者Osama Qamar
相关产品推荐
相关产品推荐

