几个问题: 1、状态寄存器(USART_SR)中的TC(Transmission complete)何时置位?它和TXE(Transmit data register empty,发送数据寄存器空)有何区别?可以先看看下面的图: ; B2 |# T, I: B$ @
; o6 W1 y9 ~+ C5 D6 m根据上面的图,TC置位的条件就是在上一个字节发完之后,数据寄存器仍为空(TXE=1)。USART_DR中的数据,只要移位寄存器把上一字节发完,马上就可以移入移位寄存器,而USART_DR可以装入新的数据。 2、波特率(Baud)的设置 从手册知道,stm32的串口可以设置分数波特率,可以从APB时钟得到精确的波特率。查看标准库(v3.5)的设置波特率的部分函数,这种设置的方法精度足够,以及发现一个在手册里面(rev 14)没有提到的位,先看代码: - Init BRR/ p5 u, ~1 g. o4 o2 P
% G$ N* A' p9 E- /* USART OverSampling-8 Mask */9 }" \" f# X& w% _6 F
- #define CR1_OVER8_Set ((u16)0x8000) /* USART OVER8 mode Enable Mask */
/ j: u7 Q1 `/ z8 f' O; \ - #define CR1_OVER8_Reset ((u16)0x7FFF) /* USART OVER8 mode Disable Mask */4 T& V9 A& N2 ]
% t4 `# h2 M6 ^+ Z( E. L: S- uint32_t tmpreg = 0x00, apbclock = 0x00;
: @0 x' z* s) X2 E; n( v - uint32_t integerdivider = 0x00;2 F$ V& a, r- i8 z: @2 ]' |' A
- uint32_t fractionaldivider = 0x00;
( {9 ~' G( u% l; c9 T - /*---------------------------- USART BRR Configuration -----------------------*/9 M$ U! P4 r$ R1 l' Q( L" f" R
- /* Configure the USART Baud Rate -------------------------------------------*/& }3 w7 c- \& t1 t
- RCC_GetClocksFreq(&RCC_ClocksStatus);
( Y& x( m9 H% |' ]+ B - if (usartxbase == USART1_BASE)0 Y- }. @8 L2 y) u6 d, c5 @
- {2 u8 C6 `) I7 ]0 v. v. P
- apbclock = RCC_ClocksStatus.PCLK2_Frequency;/ U; I) l' @9 m
- }
' h k0 H% @) p( m' K7 Q" J - else
/ J5 v; j9 `6 C$ z/ P" p% q4 f - {, e/ P& _0 V+ Y% Z/ Y
- apbclock = RCC_ClocksStatus.PCLK1_Frequency;
$ t( Z+ v1 f9 ]! R6 ] - }
4 t3 B1 h$ T+ D. g3 b6 a -
3 h, ~% ]8 f, j! a+ B8 z - /* Determine the integer part */
5 \) c, N/ c/ g - if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
( Z7 p# _0 T/ j5 ?/ X/ Q - {0 }( u% x5 L# r Z% K6 J3 a- p
- /* Integer part computing in case Oversampling mode is 8 Samples */
8 e0 Z& d9 m u5 \; I - integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));
2 L; a- X: L. a3 G8 f @. } - }7 ~4 [- o7 u5 i" Y0 B2 }1 h& F1 o
- else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
' D! y i; t6 L# K0 t1 l - {) G# U/ S$ {: _" H9 i0 q1 O+ I
- /* Integer part computing in case Oversampling mode is 16 Samples */8 z7 l3 k' C8 g
- integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));
4 m! t2 k9 Z- y5 @7 k" @ k - }9 ~' b3 p2 n) j" \
- tmpreg = (integerdivider / 100) << 4;
+ T8 ]0 }7 Y/ A; ^
9 T s5 L! E5 o- /* Determine the fractional part */
: C8 y% d/ L- }8 K% r - fractionaldivider = integerdivider - (100 * (tmpreg >> 4));. v# i( G& z H
- % }( H! {4 e6 R+ I+ x
- /* Implement the fractional part in the register */& i/ O2 O b3 m9 n
- if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
& l) E* [! Q0 x# S# A' j - {
7 `# \" T4 D0 E; R( S; D - tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);0 v- h' Y+ f1 x
- }
3 e0 S- N6 C! m2 K" k - else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */* g5 _+ ~: _3 P7 H. o, z- D ]" V
- {8 r5 Q2 t& z% d# Z& X6 M( r
- tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
. r& f2 l( E- G I( q C9 t - }
7 |/ U, ?. P/ A( S7 P x3 b - - R) [/ z7 W* K; _/ q% l2 p0 Y
- /* Write to USART BRR */( Z: |# h" m8 W2 X
- USARTx->BRR = (uint16_t)tmpreg;
复制代码
; H3 [7 k* \ }* `, e" Ta、新的设置位:CR1_OVER8_Set,位于CR1的第15位,但是手册里面没有提到(rev14);根据手册里面提到的波特率计算公式,估计默认这个位是0,代表每个bit采样16次,而置位的时候,每bit采样8次。手册里的计算公式: 这个计算公式即按照每bit采样16周期来计算的,所以上面的代码在采样8周期的时候,除以2了。 b、integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate))); 的计算与上面公式不一致,这是因为这行代码下面还有这么一句: tmpreg = (integerdivider / 100) << 4;
8 O4 e- G3 Z) t- r所以再除以100,合起来就相当于除以16了,为什么这样子做?因为integerdivider是一个uint32,为了提高精度,所以那里乘以100了。 c、这个精度够不够?乘以100,相当于保留到小数点后两位,而我们知道BRR的分数部分有4位,精度为1/16 = 0.0625,所以可以看到这个精度是够的。那么上面可以不可以改成乘以250再除以1000呢?不行,因为加入apbclock用最高的频率(72M),那么250*apbclock/4将溢出(uint32). d、如果波特率特别高,而apbclock又较低,导致按照上面公式计算,结果USARTDIV小于1,则这样是不行的,你不能指望USART还能自己提时钟速度。这个时候,CR1_OVER8应该会有些作用,可以将在目前APB时钟下的最大的波特率提升一倍。 * v- A. Y/ b2 h1 f m
|