如何正确配置STM32L476RG uC中的USART_BRR寄存器?
How to properly configure the USART_BRR register in STM32L476RG uC?
我正在尝试在 STM32L476RG Nucleo 板上为 USART_TX 编写自己的驱动程序。
这里是 datasheet and the reference manual.
我使用的是 Keil uVision 5,我在“管理”对话框中设置:
- CMSIS > 核心
- 设备 > 启动
- Xtal=16MHz
我想创建一个单字符发送器。根据第二节中的手册说明。 40 p 1332 我写了这段代码:
// APB1 connects USART2
// The USART2 EN bit on APB1ENR1 is the 17th
// See alternate functions pins and label for USART2_TX! PA2 is the pin and AF7 (AFRL register) is the function to be set
#include "stm32l4xx.h" // Device header
#define MASK(x) ((uint32_t) (1<<(x)));
void USART2_Init(void);
void USART2_Wr(int ch);
void delayMs(int delay);
int main(void){
USART2_Init();
while(1){
USART2_Wr('A');
delayMs(100);
}
}
void USART2_Init(void){
RCC->APB1ENR1 |= MASK(17); // Enable USART2 on APB1
// we know that the pin that permits the USART2_TX is the PA2, so...
RCC->AHB2ENR |= MASK(0); // enable GPIOA
// Now, in GPIOA 2 put the AF7, which can be set by placing AF7=0111 in AFSEL2 (pin2 selected)
// AFR[0] refers to GPIOA_AFRL register
// Remember: each pin asks for 4 bits to define the alternate functions. see pg. 87
// of the datasheet
GPIOA->AFR[0] |= 0x700;
GPIOA->MODER &= ~MASK(4);// now ... we set the PA2 directly with moder as alternate function "10"
// USART Features -----------
//USART2->CR1 |=MASK(15); //OVER8=1
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
//USART2->BRR = 0x1A1; //This one works!!!
USART2->CR1 |=MASK(0); //UE
USART2->CR1 |=MASK(3); //TE
}
void USART2_Wr(int ch){
//wait when TX buffer is empty
while(!(USART2->ISR & 0x80)) {} //when data is transfered in the register the ISR goes 0x80.
//then we lock the procedure in a while loop until it happens
USART2->TDR =(ch & 0xFF);
}
void delayMs(int delay){
int i;
for (; delay>0; delay--){
for (i=0; i<3195; i++);
}
}
现在,问题:
系统工作,但不正常。我的意思是:如果我以 9600 波特率使用 RealTerm,如 USART_BRR reg 中的 0x683 配置,它会显示错误的字符,但 如果我将 2400 设置为实际波特率,它会起作用!
要在 USART_BRR reg 中提取 0x683,我参考了 Sec。 40.5.4 USART 波特率生成 它说如果 OVER8=0 USARTDIV=BRR。在我的例子中,USARTDIV=16MHz/9600=1667d=683h.
我认为问题在于此代码行:
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
因为如果我将其替换为
USART2->BRR = 0x1A1; //USARTDIV=16Mhz/9600?
系统工作在 9600 波特率。
我的代码或 USARTDIV 计算理解有什么问题?
提前感谢您的支持。
真诚的,
通用
USART 的默认时钟源是 PCLK1
(图 15)PCLK1
是 SYSCLK / AHB_PRESC / AHB1_PRESC
。如果 0x1A1
导致波特率为 9600,则表明 PCLK1
= 4MHz。
当 运行 来自内部 MSI RC 振荡器时,4MHz 恰好是您的处理器(和 PCLK1
)在启动时的默认频率。所以最可能的解释是你没有配置时钟树,并且不是你认为的来自 16MHz HSE 的 运行。
要么将时钟树配置为使用 16MHz 源,要么对 MSI 频率执行计算。 MSI 精度在正常温度范围内足以保持足够准确的波特率,但并不理想。
我正在尝试在 STM32L476RG Nucleo 板上为 USART_TX 编写自己的驱动程序。 这里是 datasheet and the reference manual.
我使用的是 Keil uVision 5,我在“管理”对话框中设置:
- CMSIS > 核心
- 设备 > 启动
- Xtal=16MHz
我想创建一个单字符发送器。根据第二节中的手册说明。 40 p 1332 我写了这段代码:
// APB1 connects USART2
// The USART2 EN bit on APB1ENR1 is the 17th
// See alternate functions pins and label for USART2_TX! PA2 is the pin and AF7 (AFRL register) is the function to be set
#include "stm32l4xx.h" // Device header
#define MASK(x) ((uint32_t) (1<<(x)));
void USART2_Init(void);
void USART2_Wr(int ch);
void delayMs(int delay);
int main(void){
USART2_Init();
while(1){
USART2_Wr('A');
delayMs(100);
}
}
void USART2_Init(void){
RCC->APB1ENR1 |= MASK(17); // Enable USART2 on APB1
// we know that the pin that permits the USART2_TX is the PA2, so...
RCC->AHB2ENR |= MASK(0); // enable GPIOA
// Now, in GPIOA 2 put the AF7, which can be set by placing AF7=0111 in AFSEL2 (pin2 selected)
// AFR[0] refers to GPIOA_AFRL register
// Remember: each pin asks for 4 bits to define the alternate functions. see pg. 87
// of the datasheet
GPIOA->AFR[0] |= 0x700;
GPIOA->MODER &= ~MASK(4);// now ... we set the PA2 directly with moder as alternate function "10"
// USART Features -----------
//USART2->CR1 |=MASK(15); //OVER8=1
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
//USART2->BRR = 0x1A1; //This one works!!!
USART2->CR1 |=MASK(0); //UE
USART2->CR1 |=MASK(3); //TE
}
void USART2_Wr(int ch){
//wait when TX buffer is empty
while(!(USART2->ISR & 0x80)) {} //when data is transfered in the register the ISR goes 0x80.
//then we lock the procedure in a while loop until it happens
USART2->TDR =(ch & 0xFF);
}
void delayMs(int delay){
int i;
for (; delay>0; delay--){
for (i=0; i<3195; i++);
}
}
现在,问题:
系统工作,但不正常。我的意思是:如果我以 9600 波特率使用 RealTerm,如 USART_BRR reg 中的 0x683 配置,它会显示错误的字符,但 如果我将 2400 设置为实际波特率,它会起作用!
要在 USART_BRR reg 中提取 0x683,我参考了 Sec。 40.5.4 USART 波特率生成 它说如果 OVER8=0 USARTDIV=BRR。在我的例子中,USARTDIV=16MHz/9600=1667d=683h.
我认为问题在于此代码行:
USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
因为如果我将其替换为
USART2->BRR = 0x1A1; //USARTDIV=16Mhz/9600?
系统工作在 9600 波特率。
我的代码或 USARTDIV 计算理解有什么问题?
提前感谢您的支持。
真诚的, 通用
USART 的默认时钟源是 PCLK1
(图 15)PCLK1
是 SYSCLK / AHB_PRESC / AHB1_PRESC
。如果 0x1A1
导致波特率为 9600,则表明 PCLK1
= 4MHz。
4MHz 恰好是您的处理器(和 PCLK1
)在启动时的默认频率。所以最可能的解释是你没有配置时钟树,并且不是你认为的来自 16MHz HSE 的 运行。
要么将时钟树配置为使用 16MHz 源,要么对 MSI 频率执行计算。 MSI 精度在正常温度范围内足以保持足够准确的波特率,但并不理想。