STM32 UART2 BRR 未给出预期结果

Posted

技术标签:

【中文标题】STM32 UART2 BRR 未给出预期结果【英文标题】:STM32 UART2 BRR Not Giving Expected Results 【发布时间】:2021-09-15 06:47:03 【问题描述】:

我目前正在探索板上使用 STM32F407VG。我正在检查外围设备,并试图通过仅操作寄存器(无 HAL)来使每个外围设备工作。

当我去初始化 UART2 时,它正在将我写入的字符传输到 DR,但它这样做的速度比预期的快 12 倍,我正在拍摄 9600 波特。我使用示波器(每比特约 8-9 us)测量了这一点,并使用了 Putty 中的波特率(111,111 波特以显示实际字符)。

我正在最大化芯片 168 MHz SYSCLK、APB1 预分频器“/4”、APB2 预分频器“/2”的时钟速度。我很确定我的时钟处于应有的状态,以验证我设置了 TIMER12,它共享 APB1 时钟并将预分频器设置为 8400,并且每次比较匹配时都会生成一个中断(CCR = 5000)并溢出。我用示波器测量了这个,我得到了一个 1 Hz 的方波,这意味着定时器 12 的 APB1 为 84 MHz。

这是我的时钟初始化代码:

void SysClockConfig ( void )

    //setting up the MCO output to see the clock signal
    //RCC->CFGR |= ( 6 << 24 ) | (3 << 21 ) | ( 4 << 27 );

    //1. ENABLE HSE and wait for the HSE to become Ready
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY));

    // 2. Set the POWER ENABLE CLOCK and VOLTAGE REGULATOR
    RCC->APB1ENR  |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS;

    // 3. Configure the FLASH PREFETCH and the LATENCY Related Settings
    FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY_5WS;

    //4. Configure the PRESCALARS HCLK, PCLK1, PCLK2
    // AHB PR
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

    // APB1 PR
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

    // APB2 PR
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;

    //5. Configure the MAIN PLL
    RCC->PLLCFGR = (PLL_M << RCC_PLLCFGR_PLLM_Pos) | (PLL_N << RCC_PLLCFGR_PLLN_Pos) | (PLL_Q << RCC_PLLCFGR_PLLQ_Pos) | (RCC_PLLCFGR_PLLSRC_HSE);

    //6. Enable the PLL and wait for it to become ready
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY));

    //7. Set source
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);

这是我的 UART2 配置代码:

void UART2_Config ( void )

    RCC->APB1ENR |= RCC_APB1ENR_USART2EN;  //clock UART
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;   //clock GPIOA
    GPIOA->MODER |= ( 2 << GPIO_MODER_MODER2_Pos ) | ( 2 << GPIO_MODER_MODER3_Pos ); //set PA2 and PA3 alternate function
    GPIOA->OSPEEDR |= ( 3 << GPIO_OSPEEDR_OSPEED2_Pos ) | ( 3 << GPIO_OSPEEDR_OSPEED3_Pos ); //clock GPIO pin at fastest speed
    GPIOA->AFR[0] |= ( 7 << GPIO_AFRL_AFSEL2_Pos ) | ( 7 << GPIO_AFRL_AFSEL3_Pos ); //set PA2 and PA3 to alt func UART2

    USART2->CR1 = 0;
    USART2->CR1 |= USART_CR1_UE;  //UART Enable
    //USART2->BRR = (0x16 << USART_BRR_DIV_Mantissa_Pos) | (0xc << USART_BRR_DIV_Fraction_Pos);  //Set Baud rate
    USART2->BRR = 4300;
    //USART2->CR1 |= USART_CR1_RE;  //Receiver enable
    USART2->CR1 |= USART_CR1_TE;  //Transmitter enable
    //Baud rate is off by a factor of 12ish

最后,我的 main 和 while 循环带有发送字符的函数:

void UART2_SendChar ( uint8_t c )

    USART2->DR = c;
    while ( !(USART_SR_TC));


int main ( void )

    SysClockConfig();
    GPIO_Config();
    TIM10_Config();
    TIM12_Config();
    UART2_Config();
    //NVIC_SetPriority (TIM1_UP_TIM10_IRQn, 1);
    //NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);

    NVIC_SetPriority (TIM8_BRK_TIM12_IRQn, 1);
    NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
    while ( 1 )
    
        //GPIOD->BSRR |= (1<<12);
        //delay(2000000);
        //GPIOD->BSRR |= (1<<28);
        delay(4000000);
        UART2_SendChar('a');
    

我在参考手册中找不到任何解释此行为的内容。这告诉我我做错了什么,但我似乎无法追踪它。最后一点,我将 Putty 设置为接收 9600 波特并使用 BRR 并将其设置为 4300 的值输出所需的字符。将该值代入参考手册中的波特率方程给了我一个 660 MHz 的疯狂系统时钟,再次告诉我我遗漏了一些可能很明显的东西。

【问题讨论】:

不要使用幻数。使用 CMSIS 位定义 公平地说,我很懒惰,试图把这东西一起破解。原始代码已修复为使用 CMSIS 声明。 【参考方案1】:

我最近回答了一个类似的问题here,所以让我复制一下:

BRRQ12.4格式定点数,在选择OVER8模式时需要额外操作。

OP 的问题是关于 STM32F4,但是如果查看 STM32F030 参考手册,他/她可以找到相同的逻辑,但用不同的公式表示。 IMO,那个(F030)更清晰,更容易理解。

要将 uint16_t (Q16.0) 转换为 Q12.4,您需要将其乘以 16。

基本上,对于OVER16 的情况,BRR 简单地变为PeripheralClock / BaudRate

对于OVER8的情况,首先需要计算一个临时变量为temp = 2 * PeripheralClock / BaudRate。写入BRR时,需要将其低4位右移一次。

查看示例代码:

void setBaudRate(uint32_t baud, bool over8)

    const uint32_t pClock = 42000000ull; // Hard-code or call a function to obtain it
    uint32_t usartDiv = (over8) ? (2 * pClock / baud) : (pClock / baud);

    uint32_t reg = USART1->BRR;
    reg &= ~0xffff; // Clear the lower 16 bits
    if (over8) 
        reg |= (usartDiv & 0xfff0) | ((usartDiv & 0xf) >> 1);
    
    else  // over16
        reg |= usartDiv;
    
    USART1->BRR = reg;

因此,对于您的情况,BRR 的正确值为 4375

【讨论】:

以上是关于STM32 UART2 BRR 未给出预期结果的主要内容,如果未能解决你的问题,请参考以下文章

关于STM32 GPIO->BSRR GPIO->BRR的问题

Jsonmodel - 模型集合映射未给出预期结果

SQL 查询未按预期给出结果

查找 QPolygon 是不是包含 QPoint - 未给出预期结果

LINQ - 按多个键分组未给出预期结果

配置单元查询中的多个计数未给出预期结果