• 源：STM32 USART 波特率计算

源：STM32 USART 波特率计算

展开全文
• The baud rate for the receiver and transmitter (Rx and Tx) are both set to the same value ...STM32库函数USART波特率计算的奇葩问题 转载于:https://www.cnblogs.com/huangyangquan/p/9300880.html

The baud rate for the receiver and transmitter (Rx and Tx) are both set to the same value
as programmed in the Mantissa and Fraction values of USARTDIV.

从上图可以看出，该寄存器高 16 位无效，最低 4 位为小数部分，其余部分为整数部分。
这样的设计可以使波特率更加精确。关于波特率的产生，有这么一段话来解释：
分数波特率的产生:  接收器和发送器（RX和TX）都是设置成为 USARTDIV 整数和小数寄存器中配置的值。
This give the following equation for baud rate:
Tx/Rx baud = CK_APB1 / (8 x (2 - OVER8) x USARTDIV)
Where USARTDIV is an unsigned fixed point number that is coded on the USART_BRR register.
When OVER8=0, the fractional part is coded on 4 bits and programmed by the DIV_fraction[3:0] bits in the USART_BRR registerTx/Rx baud = CK_APB1 / (16 x USARTDIV) When OVER8=1, the fractional part is coded on 3 bits and programmed by the DIV_fraction[2:0] bits in the USART_BRR register, and bit DIV_fraction[3] must be kept cleared.Tx/Rx baud = CK_APB1 / (8  x USARTDIV)
The baud counters are updated to the new value in the baud registers after a write operation to USART_BRR.
Hence the baud rate register value should not be changed during communication.

The USARTs are on the APB1 bus, Figure 12 in the reference manual is the clock tree, which shows how the APB1 clock is derived from the PLL clock. The maximum APB1 clock is 32MHz.
OVER8=1 is required for higher speeds, giving: baud = 32000000 / (USARTDIV x 8).
So USARTDIV = 32000000 / (baud x 8)
For 4Mbps therefore, USARTDIV=1 (see table 138 S.No.12 for details).
For 2Mps, USARTDIV=2.
To achieve 3Mbps you will have to reduce the APB1 clock to 24MHz and set USARTDIV=1 (see table 131).
But note that the clock rate changes for all other APB1 peripherals too.
The simplest way to correctly program the USART baud rate is via the STM32L1xx standard peripheral library.
Also to determine the correct peripheral clock settings (and more), and generate initialisation code,
you can use STM's MicroXplorer tool.
Fpclk = 12 MHz, Baud = 460800 Bps : OVER8 = 0
DIV = 12000000 / ( 16 * 460800 ) = 1.6276
DIV_Mantissa = 1
DIV_Fraction = 0.6276 * 16 = 10
USARTDIV = ( 1 << 4 ) | 10 = 0x001 A = 1.625
12000000 / ( 16 * 1.625 ) = 12000000 / 26 = 461538.5 Bps

Fpclk = 12 MHz, Baud = 460800 Bps : OVER8 = 1
DIV = 12000000 / ( 8 * 460800 ) = 3.255
DIV_Mantissa = 3
DIV_Fraction = 0.255 * 8 = 2.04
USARTDIV = ( 3 << 4 ) | 2 = 0x003 2 = 3.25
12000000 / ( 8 * 3.25 ) = 12000000 / 26 = 461538.5 Bps

stm32波特率设置，在115200时候，实际是115384，会有0.15%的误差， 不过还是可以接受的。
其实stm32的uart还是蛮简单的，初始化4个寄存器完事，就是波特率方面需要算算。 原文：
stm32 中文资料中有如下计算公式 ：
Tx / Rx 波特率 ＝ fPCLKx/（16*USARTDIV）；
这里的fPCLKx(x=1、2)是给外设的时钟(PCLK1用于USART2、3、4、5，PCLK2用于USART1)
USARTDIV是一个无符号的定点数。这12位的值设置在USART_BRR寄存器。
如果使用USART1,系统时钟为72MHZ,USART1使用PCLK2时钟，也定义为72MHz.
定义波特率=9600，fPCLK2=72MHz,则： 计算USARTDIV=72MHz/9600/16=468.75
取整数468=0x1D4. 小数0.75*16=12=0x0C. 所以写入寄存器USART_BRR中的值为：USART_BRR=0x1D4C.
如果使用USART2,USART2使用PCLK1时钟,PCLK1时钟为36MHz.
定义波特率=9600，fPCLK1=36MHz,则： 计算USARTDIV=36MHz/9600/16=234.375
取整数234=0xEA.小数0.375*16=6=0x06.所以写入寄存器USART_BRR中的值为：USART_BRR=0xEA6.

24000000 / 19200 = 1250 = 0x4E2 --> 78 + 2/16 = 78.125

24000000 / ( 16 * 19200 ) = 78.125

24000000 / 921600 = 26 = 0x1A --> 1 + 10/16 = 1.625

24000000 / ( 16 * 921600 ) = 1.625

uint32_t tmpreg = 0x00, apbclock = 0x00;    uint64_t integerdivider = 0x00;    uint32_t fractionaldivider = 0x00;
/* Determine the integer part */
if ((USARTx->CR1 & USART_CR1_OVER8) != 0)
{
/* Integer part computing in case Oversampling mode is 8 Samples */
integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));        // ( 2^^32 - 1 ) / 25 = 4294967295 / 25 = 171798691.84 = 171.8 MHZ    // STM32F429 MAX 180MHz
}
else /* if ((USARTx->CR1 & USART_CR1_OVER8) == 0) */
{
/* Integer part computing in case Oversampling mode is 16 Samples */
integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));
}
tmpreg = (integerdivider / 100) << 4;

/* Determine the fractional part */
fractionaldivider = integerdivider - (100 * (tmpreg >> 4));

/* Implement the fractional part in the register */
if ((USARTx->CR1 & USART_CR1_OVER8) != 0)
{
tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);
}
else /* if ((USARTx->CR1 & USART_CR1_OVER8) == 0) */
{
tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
}

/* Write to USART BRR register */
USARTx->BRR = (uint16_t)tmpreg;

(1)将算出的USARTDIV扩大100倍保留整数部分。
(2)百位以上的送入BRR[15:4],百位以下的换算成16进制值送入[3:0]
也即对于USARTDIV小数部分，只有小数点后两位保留，两位以后的全部舍去，
比如理论计算得到 USARTDIV = 234.28125 被处理为 USARTDIV = 234.28，这样就损失了精度，
造成了最终送入BRR的实际值并不是理论值的四舍五入(5以上的有可能也被舍去)
如想要得到完全符合四舍五入原则的精确结果，则USART至少应该放大 100000 倍，
保留小数点后5位，5位以后的部分全部舍去也仍然落在正确的区间内。新程序如下：

baudsource = apbclock * 100000 / ( 16 * BaudRate );
interger = baudsource / 100000;
fractional = ( baudsource % 100000 + 3125 ) / 6250;
USART1->BRR = ( interger << 4 ) + fractional;

以一个例子说明：  如设置波特率为Baud Rate = 19207 bps

72000000 / ( 16 * 19207 ) = 234.28958192325714583224865934295...

(1) BRR[3:0]理论值：16 * 0.28958192325714583224865934295... = 4.6333107721143333159785494871661...
按四舍五入的原则取 BRR[3:0] = 0x05
(2)官方库：( 28 * 16 + 50 ) / 100 = 498 / 100 = 4, BRR[3:0] = 0x04 与理论值差1
(3) 新程序：( 28958 + 3125 ) / 6250 = 32173 / 6250 = 5, BRR[3:0] = 0x05，与理论值一致。
STM32的串口速率：APB速度/波特率 = USARTDIV [ OVER8 = 0 ]

uint32_t USART_BRR( uint32_t clock, uint32_t baud )
{
uint64_t clcok_x = clock * 10000ULL;
uint64_t brr = ( ( clcok_x / baud ) + 5000ULL ) / 10000ULL;
return brr;
}

72000000 * 10000 / 19207 = 37486333
37486333 + 5000 = 37491333
37491333 / 10000 = 3749 = 0x0EA5 --> 234.3125
72000000 / ( 16 * 234.3125 ) = 19205

#define UART_BRR_SAMPLING16(_PCLK_, _BAUD_)     (((_PCLK_)+(_BAUD_)/2)/_BAUD_)
__INLINE static uint16_t UART_BRR_SAMPLING8(uint32_t _PCLK_, uint32_t _BAUD_)
{
uint16_t Div = (_PCLK_ + _BAUD_/2)/_BAUD_;
return ((Div & ~0x7)<<1 | (Div & 0x07));
}

精度能到多高，由BRR的4bit小数决定了，不管乘多大的数，最终一除还是4bit小数。
理论误差最大就是正负0.5bit了，也就是分频系数的1/32。
如果要保证1%的精度，分频系数>100/32=3.125就够了，一般系统都可以满足。
也就是要么分频系数够大，要么尽量整除，误差就可以满足要求。
如果硬要扯绝对精度，当BAUD为奇数时，除了那0.5bit的误差，
还有因为BAUD/2除不尽再来的误差，也就是1/BAUD bit。
那0.5bit的误差都可以忽略了，1/BAUD bit的误差就更不用提了吧？
而且有谁的系统里波特率是奇数？
PS：我们用的系统都是有限精度系统，只要精度满足要求就行了。
STM32库函数USART波特率计算的奇葩问题
不管乘多大数再除掉，精度不可能超过这个算法：
(PCLK + BAUD/2)/BAUD，
只不过增加运算法。
STM32库函数USART波特率计算的奇葩问题

转载于:https://www.cnblogs.com/huangyangquan/p/9300880.html
展开全文
• 硬件平台是STM32F429，...使用 USART1 和 USART2 进行串口输出，但是用示波器一看，波特率明显不对。 我的代码如下： RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB

硬件平台是STM32F429，运行在 180MHz 主频下，固件库版本V1.2.1。使用 USART1 和 USART2 进行串口输出，但是用示波器一看，波特率明显不对。

我的代码如下：

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);

USART_InitStruct.USART_BaudRate = 9600;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_Mode = USART_Mode_Tx;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(UART_CHN0, &USART_InitStruct);
USART_Init(UART_CHN1, &USART_InitStruct);

USART_Cmd(UART_CHN0, ENABLE);
USART_Cmd(UART_CHN1, ENABLE);

一开始严重怀疑 USART_InitStruct.USART_BaudRate 的设置不应该那么简单，但仔细看了 USART_Init() 函数才发现这个波特率是自动计算出来的，也没有轻易怀疑官方固件库存在问题。网上别人也是这么写的，都没有问题。
于是看了手册。这里说下 STM32 的波特率设置寄存器，其实是一个定点数存储器，如下：

从上图可以看出，该寄存器高 16 位无效，最低 4 位为小数部分，其余部分为整数部分。这样的设计可以使波特率更加精确。关于波特率的产生，有这么一段话来解释： “分数波特率的产生:接收器和发送器（RX和TX）都是设置城USARTDIV整数和小数寄存器中配置的值。TX/RX波特率=Fck/（16*USARTDIV)例子：从BRR寄存器的值计算得到USARTDIV如果DIV_Mantissa=27D，DIV_Fraction=12D(BRR=1BCH)，那么Mantissa(USARTDIV)=27DFraciton(USARTDIV)=12/16=0.75D因此，USARTDIV=27.75D”（其中，D表示十进制） 按照这个说法，看了一下 USART_Init() 函数计算的 BRR 寄存器值，发现明显的不对，先给出 USART_Init() 函数中 BRR 寄存器计算部分的代码：

uint32_t tmpreg = 0x00, apbclock = 0x00;  uint32_t integerdivider = 0x00;  uint32_t fractionaldivider = 0x00;/* Configure the USART Baud Rate */  RCC_GetClocksFreq(&RCC_ClocksStatus);  if ((USARTx == USART1) || (USARTx == USART6))  {    apbclock = RCC_ClocksStatus.PCLK2_Frequency;  }  else  {    apbclock = RCC_ClocksStatus.PCLK1_Frequency;  }    /* Determine the integer part */  if ((USARTx->CR1 & USART_CR1_OVER8) != 0)  {    /* Integer part computing in case Oversampling mode is 8 Samples */    integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));  }  else /* if ((USARTx->CR1 & USART_CR1_OVER8) == 0) */  {    /* Integer part computing in case Oversampling mode is 16 Samples */    integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));  }  tmpreg = (integerdivider / 100) << 4;  /* Determine the fractional part */  fractionaldivider = integerdivider - (100 * (tmpreg >> 4));  /* Implement the fractional part in the register */  if ((USARTx->CR1 & USART_CR1_OVER8) != 0)  {    tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);  }  else /* if ((USARTx->CR1 & USART_CR1_OVER8) == 0) */  {    tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);  }    /* Write to USART BRR register */  USARTx->BRR = (uint16_t)tmpreg; 可以看出，这里用于计算的 Fck 是直接从寄存器中读出来的，读出的值是正确的。接下来计算整数部分，这里就出错了。进一步跟踪“integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));”这段代码，看汇编程序，发现当 apbclock 为 180,000,000 的时候计算结果是错的，原因在于 25*180000000=4500000000，已经超过了 2^32=4294967296 所能表示的最大数，因此计算结果溢出。因此，将计算整数部分的代码修改如下：     /* Determine the integer part */  if ((USARTx->CR1 & USART_CR1_OVER8) != 0)  {    /* Integer part computing in case Oversampling mode is 8 Samples *///    integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));    integerdivider = ((25 * (apbclock / 2)) / (USART_InitStruct->USART_BaudRate));  }  else /* if ((USARTx->CR1 & USART_CR1_OVER8) == 0) */  {    /* Integer part computing in case Oversampling mode is 16 Samples *///    integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));    integerdivider = ((25 * (apbclock / 4)) / (USART_InitStruct->USART_BaudRate));  } 经测试验证，该计算结果正确，波特率正确，USART 能够正常通信。我在我的博客里再次质问下 ST 吧，这样的边界问题，你们不做测试么？

展开全文
• 串口波特率计算方式

万次阅读 多人点赞 2018-10-05 23:19:55
STM32下波特率计算方式解释： 波特率的计算  STM32下的波特率和串口外设时钟息息相关，USART 1的时钟来源于APB2，USART 2-5的时钟来源于APB1。在STM32中，有个波特率寄存器USART_BRR，如下：  STM32串口波特...
STM32下波特率计算方式解释：
波特率的计算
STM32下的波特率和串口外设时钟息息相关，USART 1的时钟来源于APB2，USART 2-5的时钟来源于APB1。在STM32中，有个波特率寄存器USART_BRR，如下：

STM32串口波特率通过USART_BRR进行设置，STM32的波特率寄存器支持分数设置，以提高精确度。USART_BRR的前4位用于表示小数，后12位用于表示整数。但是它还不是我们想要设置的波特率，想要设置我们串口的波特率大小还需要进行计算。其实有关波特率的计算是下面这一条表达式：

从上面的表达式，我们引入了一个新量USARTDIV，它表示对串口的时钟源fck进行分频。假设我们已知道了波特率和fck时钟频率的大小，那么通过上式便可以计算出USARTDIV的具体大小，然后再通过USART的值大小对波特率寄存器进行设置。
USARTDIV通过上面的表达式得出，是一个带有小数的浮点数（如27.75）。将小数部分和整数部分分开，分别得到一个整数值n（如27）和一个小数值m（如0.75）。有了这两个值我们便可以填写USART_BRR寄存器进而设置我们串口波特率大小了。
将整数部分m（27 = 0x1B）直接写入USART_BRR的后12位部分；将小数部分n乘以16后得到的整数值（如0.75 x 16 = 12 = 0xC）写入USART_BRR前4位部分,最后USART_BRR的值为0x1BC。
注意：如果小数部分乘以16之后仍带有小数，则要四舍五入去除小数部分得到一个新的整数，再将其写入USART_BRR的前四位。

为什么在计算波特率的公式中要乘以16？
​我们知道串口通信是通过TXD和RXD这两条线进行通信的，当接收器的RXD连接着发送器的TXD，接收器的TXD连接着发送器的RXD，接收器和发送器可以通过RXD和TXD互传数据。当接收器检测到RXD这条线的电平被拉为低电平，立即开始接收发送器发送过来的数据，刚刚那个低电平只是一个告知接收器可以接收数据的起始位而已。
在数据的传输中，信号可能受到一些干扰而产生一些抖动，如下图。如果接收端只对这些信号数据采样一次，那么它有可能采样到的是抖动的不准的数据，进而使数据传输不准确，所以接收端在采样数据线上的数据，通常都要采样多次，然后通过比较获得准确的数据。

前面已经说过，USARTDIV，它表示对串口的时钟源fck进行分频，而这16表示的正是1bit数据的采样次数。为什么呢？
，将这个表达式的分子分母倒过来，可以得到下面这条表达式

每一位的传输时间只有1/TX_baud，这个总时间除以16，所以每采样一次的时间正好是T1，即新分频后的周期。而初始的串口时钟信号来自于APBx，APBx时钟信号需要经过分频才会等于T1，所以才需要分频USARTDIV。
本文链接：http://www.cnblogs.com/cposture/p/4268910.html
展开全文
• 置顶/星标公众号，不错过每一条消息！ 使用、参考STM32标准外设库，寄存器开发的朋友也需要注意一些细节问题。1USART串口预分频许多朋友用寄存器开发，就需要对寄...
• 1.处理器与外部设备通信的两种方式： 并行通信 传输原理：数据各个位同时传输。 优点：速度快 缺点：占用引脚资源多 串行通信 传输原理：数据按位顺序传输。...半双工：允许数据在两个方向上传输，但是，在某一时刻...
• 串口波特率计算详解

千次阅读 2019-01-10 15:16:07
STM32下波特率计算详解 波特率的计算     STM32下的波特率和串口外设时钟息息相关，USART 1的时钟来源于APB2，USART 2-5的时钟来源于APB1。在STM32中，有个波特率寄存器USART_BRR，如下：     STM32串口...
• XmegaUsarT 波特率 计算表 Excel 文件很好用
• 某日，一工程师咨询在使用STM32F407 MCU开发产品时用到UART5和USART6做串行异步通信，将二者波特率配置为1200bps时，发现UART5正常，而USART6工作不正常。 咋听起来的确有点奇怪。怀疑其相关配置有问题，查看...
• 问题描述：串口配置完成，波特率不正确，正常配置为115200，串口在此波特率下输出乱码，把波特率修改为34800正常输出； 1.串口配置完成，配置如下 void Usart_init(void) { rcu_periph_clock_enable(RCU_GPIOA); ...
• 一、概要 使用UART串口时往往比较喜欢配置波特率为标准的9600、115200等，而实际应用中需要更高的波特率。如果在配置UART波特率时任意输入一个很高的波特率，如200000...二、STM32F4波特率计算方法 以stm32f4系列为例
• 程序目前支持9600、19200、38400、57600、115200，如需要其他波特率请根据计算方法加入代码中，输入的时钟信号为50MHz module SpeedSet(clk,reset,cnt); input clk,reset; output cnt; ///波特率对应的脉冲的...
• 波特率的计算

千次阅读 2019-06-20 17:11:59
第二个F是波特率。12.82KHZ。 第三个是一个周期的时长。78us。 QG一句话：一个问题： 78us发送了一位； 波特率的意思就是 1s发送了多少位？ 回答： （1）78us发送了一位。（上升沿发送给一位）。78us=78*10...
• 波特率寄存器，生成波特率 fck 时钟源 over8 八倍采样=1 16倍采样=0 USARTDIV 串口分频值（未知需要求出来） USARTDIV = fCK / 波特率 X 8 X (2-OVER8) 举例： Fck = 84MHz OVER8=0 (16倍过采样) ...
• 一、分数波特率的产生 ...注： 在写入USART_BRR之后，波特率计数器会被波特率寄存器的新值替换。因此，不要在通信进行中改变波特率寄存器的数值。如何从USART_BRR寄存器值得到USARTDIV 例1： 　如果 DIV_Mant
• 什么是波特率 ...下面以STM32单片机为例，讲解一下串口波特率计算方法。 STM32波特率相关的寄存器 STM32单片机设置波特率的寄存器只有一个：USART_BRR寄存器，如下图所示。 该寄存器的有效位数为16位，
• 【转】波特率计算串口速度

千次阅读 2019-06-12 15:46:00
波特率115200 ＝ 115200 (位/秒)。 如果没有校验位，就应该除以 10，得到的是每秒字节数：波特率115200 ＝ 115200 (位/秒) ＝ 11520 (字节/秒)。 再除以 1024，就是每秒 KB 数：波特率115200 ＝ 115200 (位/秒) ＝...
• 波特率传输字节数计算方法

千次阅读 2020-05-26 00:00:00
用 9600 波特率来举例，就是最高每秒可以检测到 9600 个电平变化（上升沿/下降沿），也可以说最大每秒可以接收 9600 位数据，bit ，也就是二进制数（0/1），每个电平发生跳变的时钟周期为：1/9600 s. 2 传输字节数...
• 官方：我的理解：关于为什么加这种约定：二、计算波特率与串口通信1.公式2.12M和11.05926M晶振区别3.串口通信收发代码三、总结 前言 很多同学在学习单片机过程中遇到了很多的问题，比如串口，串口是单片机的一块...
• 波特率计算 STM32下的波特率和串口外设时钟息息相关，USART 1的时钟来源于APB2，USART 2-5的时钟来源于APB1。在STM32中，有个波特率寄存器USART_BRR，如下： STM32串口波特率通过USART_BRR进行设置，STM32的...
• 难的东西学不会是因为简单的知识没学好 ...（2）一种特定的通信协议，一般叫串口通信，串行通信，UART USART等都指串口通信。 （3）这种通信的特点：异步，串行，全双工 1.1.1串行通信的工作方式： （1）3根线(GND TX
• 时钟频率＝波特率*16倍*分频系数对于传输速度而言，时钟速度越大，传输速率越快。其中，波特率与分频系数关系如下 ：比特率频率分频系数范围对比数9600153600325.520832632419200307200162.76041631623840061440081....
• 不同波特率传输时间计算

万次阅读 2016-12-14 23:12:57
1、有关波特率600 bits per second涉及的传输时间计算 一帧数据包括： 1个起始位： 8个数据位； 1个标志位； 1个停止位； 总共11bits； 现有三帧数据要发送因此有3*11bits发送； 1bits的发送时间 = 1000 /...
• 转自：http://m.elecfans.com/article/611035.html?fromtype=app1. 什么是波特率不管是什么单片机，在使用串口通信的时候，...下面以STM32单片机为例，讲解一下串口波特率计算方法。2. STM32波特率相关的寄存器ST...
• UART 波特率的认识与理解
• STM32串口自动识别波特率

千次阅读 2019-01-21 18:00:12
置顶/星标公众号，不错过每一条消息！ 最近有朋友问关于UART串口自动识别波特率的问题，今天就在这里写点相关内容。1写在前面关于自动识别UART串口波特率的这个问题...

...