几个问题: 1、状态寄存器(USART_SR)中的TC(Transmission complete)何时置位?它和TXE(Transmit data register empty,发送数据寄存器空)有何区别?可以先看看下面的图:
3 }! Q: P! r0 \. T8 F2 O! b2 f6 G- x1 b! O: T
根据上面的图,TC置位的条件就是在上一个字节发完之后,数据寄存器仍为空(TXE=1)。USART_DR中的数据,只要移位寄存器把上一字节发完,马上就可以移入移位寄存器,而USART_DR可以装入新的数据。 2、波特率(Baud)的设置 从手册知道,stm32的串口可以设置分数波特率,可以从APB时钟得到精确的波特率。查看标准库(v3.5)的设置波特率的部分函数,这种设置的方法精度足够,以及发现一个在手册里面(rev 14)没有提到的位,先看代码: - Init BRR
1 I& L/ c4 U' v0 O
$ L* y- S! y* ^- /* USART OverSampling-8 Mask */
0 R& e7 N/ J- v, F - #define CR1_OVER8_Set ((u16)0x8000) /* USART OVER8 mode Enable Mask */
0 }1 x) x( ^ T. k2 K5 p9 f ? - #define CR1_OVER8_Reset ((u16)0x7FFF) /* USART OVER8 mode Disable Mask */4 c5 o7 ^! ^' \* j( @4 N5 P
- / [3 Z% x j! P. S/ w2 a7 b9 \ u: |# }
- uint32_t tmpreg = 0x00, apbclock = 0x00;5 z$ ?( q3 W0 N% F. X: c6 \% f
- uint32_t integerdivider = 0x00;8 C) |+ J) ^3 a: ?8 A
- uint32_t fractionaldivider = 0x00;
2 ?9 s3 ]* U& A3 r" W, | - /*---------------------------- USART BRR Configuration -----------------------*/' K3 c2 ~* C) i$ Q$ C
- /* Configure the USART Baud Rate -------------------------------------------*/
: t& C( a5 ]- _' q% ] - RCC_GetClocksFreq(&RCC_ClocksStatus);
- o. r/ h: t6 ? - if (usartxbase == USART1_BASE): o% ]; k- h) d' i6 T
- {2 M( v$ f; _% W* b. V
- apbclock = RCC_ClocksStatus.PCLK2_Frequency;% S/ o" ~! E l3 G4 {7 g
- }% _) ]+ d8 i; G- ~; V( T/ L
- else1 c. C% l2 j, _& E; _
- {9 F! d5 P9 e# i7 T% R f1 X2 M
- apbclock = RCC_ClocksStatus.PCLK1_Frequency;
# c, i/ y" b1 |4 {( a/ H: N% W - }3 a5 ?- o1 S9 A+ ^6 o
-
* L7 p- n0 m4 J( L: j& [ - /* Determine the integer part */
) J) n$ k" `- W2 u' X! Q - if ((USARTx->CR1 & CR1_OVER8_Set) != 0)+ h- y& r( [& v A- {
- {
" ]& ~/ e/ q# j' |+ n" ?6 l7 B! T - /* Integer part computing in case Oversampling mode is 8 Samples */
N% C7 L" ^' q* T - integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate))); , V( W; s4 `& g: W4 Z
- }- \: J, V/ f" Y/ \$ A& ]5 b
- else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */% J6 l! ]; m4 H" K9 Y- I+ D9 V
- {5 G- U T& M3 x: Z' }; A2 s9 f+ s
- /* Integer part computing in case Oversampling mode is 16 Samples */0 W! {9 y7 n: ]2 g |
- integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));
( S0 ~) z Z' Y* X2 u - }3 y. L4 w3 j. M1 _# D
- tmpreg = (integerdivider / 100) << 4;
; z. ] z% `: u+ a+ R4 v
* n1 [1 `2 J7 ^2 f. [' a- s' B- /* Determine the fractional part */5 [3 i/ _$ s- o4 G+ M7 q
- fractionaldivider = integerdivider - (100 * (tmpreg >> 4));9 ?( Q' t3 \! Z
- ]; P$ q9 V$ `0 c
- /* Implement the fractional part in the register */
& F0 Z ?/ S9 p+ P2 d2 g - if ((USARTx->CR1 & CR1_OVER8_Set) != 0)+ f' I& C5 w+ e- C/ q3 W
- {
' ~ n& v5 M" k - tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);8 ]6 \9 Y% F/ |& |
- }! M9 M0 s8 t# m0 f& a# V9 ?
- else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */ b$ d/ x+ @$ T: L
- {( U ~2 v& ~ z1 Y
- tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
+ W+ ^7 T' ~( [5 z* T - }
2 I* ]$ E- i; I5 D7 D - # g' h! C6 C+ C/ [. t7 x$ A( Y) ^9 x& M
- /* Write to USART BRR */2 i; ~0 F0 W! C* i0 ^% N
- USARTx->BRR = (uint16_t)tmpreg;
复制代码 * v6 x& z6 z1 q g
a、新的设置位: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;
7 Y$ R+ o% N. _/ X所以再除以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时钟下的最大的波特率提升一倍。
% w) X; m5 t" {& X- g1 n$ O |