几个问题: 1、状态寄存器(USART_SR)中的TC(Transmission complete)何时置位?它和TXE(Transmit data register empty,发送数据寄存器空)有何区别?可以先看看下面的图: # Y) v9 d& i9 @9 ?* B
J W& B% p/ k9 I9 j& |+ Z- d根据上面的图,TC置位的条件就是在上一个字节发完之后,数据寄存器仍为空(TXE=1)。USART_DR中的数据,只要移位寄存器把上一字节发完,马上就可以移入移位寄存器,而USART_DR可以装入新的数据。 2、波特率(Baud)的设置 从手册知道,stm32的串口可以设置分数波特率,可以从APB时钟得到精确的波特率。查看标准库(v3.5)的设置波特率的部分函数,这种设置的方法精度足够,以及发现一个在手册里面(rev 14)没有提到的位,先看代码: - Init BRR
1 I1 Y+ A* p7 t5 M - * m9 H' `; S, W( _) B& @
- /* USART OverSampling-8 Mask */
4 }2 `# z& g# C# p9 Z6 A. d - #define CR1_OVER8_Set ((u16)0x8000) /* USART OVER8 mode Enable Mask */0 k. D7 {/ k& I! |0 R
- #define CR1_OVER8_Reset ((u16)0x7FFF) /* USART OVER8 mode Disable Mask */
. Q l4 }( Q' _+ v- C r
3 O- n6 v( m, m. O$ K- uint32_t tmpreg = 0x00, apbclock = 0x00;
7 N1 `3 D( k! _% |: t - uint32_t integerdivider = 0x00;
; K, I, q4 l6 j. C! C( N - uint32_t fractionaldivider = 0x00;: Z6 [, G1 ~ ^3 |& j! y }
- /*---------------------------- USART BRR Configuration -----------------------*/
' R. H8 Q) K7 g; h7 ^# W$ ?% s - /* Configure the USART Baud Rate -------------------------------------------*// q# _% A1 U) d m, K' c: u- m1 Y
- RCC_GetClocksFreq(&RCC_ClocksStatus);8 h' |0 _, M+ f$ L- f0 S6 @
- if (usartxbase == USART1_BASE)8 F7 B% D' |0 k6 X" K
- {2 C+ |% W- K4 i! m6 a7 w: r6 b5 P5 R
- apbclock = RCC_ClocksStatus.PCLK2_Frequency;, M# G* H$ D) H/ x0 O0 \0 |
- }+ p- }! P; T2 s. f$ [
- else
R* B/ k4 C( J% g6 G I e3 M- w - {5 Q" c! W% k/ ^: ~
- apbclock = RCC_ClocksStatus.PCLK1_Frequency;8 P( [/ h: O) D# s8 O# Z
- }
3 J' R# j V2 c- \' u8 @. L -
% U/ E6 b& \( |' y4 @ - /* Determine the integer part */4 B* D' _% x( h6 F! z: A# C. ^: A
- if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
1 r1 i n' }1 K3 Z - {# L# f8 h/ f+ F, }$ O
- /* Integer part computing in case Oversampling mode is 8 Samples */8 ~5 W' f5 x5 S5 a6 P/ c
- integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));
& I& b% C- R$ Q# Y' n& q- A+ c3 x- F - }
& s# ^! V! D- ] - else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */ x* M {1 v; A- w& L7 h: ^
- {
7 F: {' v: [/ B2 i, Q- U( T) Y - /* Integer part computing in case Oversampling mode is 16 Samples */
9 N& f7 o& I4 L4 l3 S9 X - integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate))); . V. A9 ^; s" B* a0 ?9 j5 c. X" H m
- }
. n2 ~" c4 F9 E. y; ^9 ? - tmpreg = (integerdivider / 100) << 4;
1 ]7 Y+ ~% k! ~$ | i! ^ - & |2 S2 {# ^3 H; p( V- f' z4 q
- /* Determine the fractional part */; P% {4 A, z5 v) j
- fractionaldivider = integerdivider - (100 * (tmpreg >> 4));) N) a/ r# ^- N8 `& k
- 8 Y( {9 `$ U5 h, s' N9 L! d
- /* Implement the fractional part in the register */! p* ^8 q( i2 N* a
- if ((USARTx->CR1 & CR1_OVER8_Set) != 0), ^0 z: x3 T' q% e6 ~
- {2 f. f+ R, E7 P# C" l' t
- tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);1 ~; U/ F2 e* v: [" P
- }( N E2 R, ^! f+ X# L
- else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */1 m F0 g7 e+ u) H% S9 u- R
- {
$ y* ~; M, k2 ~: C) U. V& X# D - tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
3 A. i6 L4 |' A$ c3 ?/ ` - }6 s3 J+ Q5 W- g% Y; U- k! m
- 0 R' S7 |" U2 x) p' f0 C7 W5 D
- /* Write to USART BRR */
0 E, g$ U! ^+ A+ g, Z - USARTx->BRR = (uint16_t)tmpreg;
复制代码 7 ?6 y) q, Z- a1 P9 e, f+ s9 Y( q
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;
8 Z" i% J% Y8 u. m7 k9 c1 C所以再除以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时钟下的最大的波特率提升一倍。 ; h8 O- J' T7 r' r% o
|