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,所以让我复制一下:
BRR为Q12.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的问题