在STM32F103C8(“蓝色药丸”)上通过UART传输数据的问题

3
我是嵌入式系统的初学者。我正在尝试在STM32F103C8(即 Blue Pill板)的UART2上写入数据,并希望使用连接到STM32F103C8板的UART2的 FTDI 适配器在计算机端口中查看数据。但是在我的控制台上,我收到一些随机方块,而不是我要传输的字符。

这是我在 Keil IDE中编写的代码。

#include "stm32f10x.h"                  // Device header

void usart2_init(void);
void USART_write(int data);
void delayMs(int delay);

int main(void)
{
    usart2_init();
    while(1)
    {
       USART_write('A');
       delayMs(5000);
    }
}

void usart2_init(void)
{
       // Enable clock source for USART2
       RCC->APB1ENR |= 0x20000;           // 0b 0000 0000 0000 0010 0000 0000 0000 0000
       RCC->APB2ENR |= 0x4;
       GPIOA->CRL |= 0x900;               // Set PA2 as TX pin (AF)
       USART2->BRR  = 0x341;              // Setting Baudrate to 9600 @8 MHz.
       USART2->CR1 |= 0x00008;            // Enable TX only
       USART2->CR1 |= 0x02000;            // Enable USART module by setting bit 13 to 1 i
       USART->CR1 register
}

void USART_write(int data)
{
    // We need to wait until Tx buffer is empty for sending data.
    while(!(USART2->SR & 0x0080));        // 0x0080
    USART2->DR = (data & 0xFF);
}

void delayMs(int delay)
{
    int i;
    for( ; delay>0 ; delay--)
    {
        for(i=0; i<3195; i++)
        {
        }
    }
}

以下是我在调试时附加的屏幕截图。

点击这里查看屏幕截图

您可以看到不想要的方块代替字符,而不是我想传输的字符。在图像中,您还可以看到UART寄存器及其值。 我正在使用ST-LINK2上传固件。

在处理FTDI和Tera Term时,我是否遗漏了一些信息或犯了错误?这是我的Tera Term配置:

  • 波特率=9600
  • 数据=8位
  • 奇偶校验=无
  • 停止位=1
  • 控制流=无

我该如何修复这个问题?


1
一个随机的方块,听起来像是一个无法打印的字符。打印字节的十六进制值而不是字节本身,我敢打赌它小于0x20或大于126。 - Code Gorilla
1
BRR(波特率寄存器)的设置是错误的。该寄存器包含一个12位分频器和4位小数分频器。另一个错误是usart外设的时钟为36MHz,而不是8MHz。要获取正确的设置,请获取STM32F10X手册的副本,并在表192中查找值。或者简单地使用libopencm3非常容易使用。 - Frankie_C
嗨,@Frankie_C,感谢您的帮助。我的代码在36MHz频率下运行。 - Tushar Yadav
不用客气。请记住,这些设备既灵活又复杂,需要仔细编程。不要假设任何东西,始终仔细阅读数据表。谷歌搜索libopencm3,它可能会很有帮助,我更喜欢它而不是STM原生HAL开发。 - Frankie_C
2个回答

1
当使用这些设备时,您应该仔细阅读生产商网站上广泛提供的数据表/参考手册和可能适用的AN(应用笔记)。
在具体情况下,STM32F10x系列通常使用由内部PLL振荡器生成的72 MHz系统时钟,其使用外部水晶作为PLL电路的参考,蓝色Pill上的频率为8 MHz。 8 MHz晶体振荡器称为HSE,表示高速外部振荡器。
我说“通常”是因为用户可以通过编程特定的分频器和内部时钟电路来选择不同的系统时钟频率,这可能乍一看就变得非常复杂(甚至在第二次也是如此...)。
现在假设标准配置下的外围接口,其中系统时钟选为72 MHz,AHB预分频器为1,则两个外围时钟(PCLCKx)分别设置为36 MHz(PCLCK1:预分频器= 2)和72 MHz(PCLCK2)。
在STM32F10x芯片上,仅USART1从PCLCK2时钟,并且所有其他时钟均从PCKLK1时钟(最大36 MHz)中获取。

您的设备可能以36 MHz的频率运行。为了达到9600波特率,我们需要一个总除数:36 MHz / (9600 * 16) = 234.375

波特率发生器可以通过分别考虑整数部分和小数部分来处理分数除法。我们得到:

DIV_Fraction = 16 * 0.375 = 6 = 0x06
DIV_Mantissa = 234 = 0xEA
USART_BRR = (DIV_Mantissa << 4) | DIV_Fraction = 0xEA6

符号 0dxx 来自ST文档,表示十进制表示。

结论

在操作这些设备之前,请仔细阅读文档并尽可能使用帮助库进行编程。个人更喜欢 libopencm3 而不是标准的HAL库,因为它简化了使用。


很好的答案! - 点赞。- 我已经自由地修正了你描述中的一些要点,请确认您是否同意这种重新表述。 - HelpingHand
1
@HelpingHand 谢谢。我批准了编辑。实际上我用一些类似英语的外观写了答案... - Frankie_C

0

这个可以用,我测试过了

void init_Usart(void)
{
  // Enable clock source for USART2
  RCC->APB1ENR |= 0x20000;           // 0b 0000 0000 0000 0010 0000 0000 0000 0000
  RCC->APB2ENR |= 0x4;
  GPIOA->CRL |= 0x900;               // Set PA2 as TX pin (AF)
  USART2->BRR  = 0xEA6;              // Setting Baudrate to 9600 @8 MHz.
  USART2->CR1 |= 0x00008;            // Enable TX only
  USART2->CR1 |= 0x02000;            // Enable USART module 
   
}

void USART_write(int data)
{
  // We need to wait until Tx buffer is empty for sending data.
  while(!(USART2->SR & 0x0080));        // 0x0080
  USART2->DR = (data & 0xFF);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接