You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:39:03