|
几个问题: 1、状态寄存器(USART_SR)中的TC(Transmission complete)何时置位?它和TXE(Transmit data register empty,发送数据寄存器空)有何区别?可以先看看下面的图:
: L: O' ], r# q+ ?' Y: s2 c* b6 f3 Z9 v# `# o
根据上面的图,TC置位的条件就是在上一个字节发完之后,数据寄存器仍为空(TXE=1)。USART_DR中的数据,只要移位寄存器把上一字节发完,马上就可以移入移位寄存器,而USART_DR可以装入新的数据。 2、波特率(Baud)的设置 从手册知道,stm32的串口可以设置分数波特率,可以从APB时钟得到精确的波特率。查看标准库(v3.5)的设置波特率的部分函数,这种设置的方法精度足够,以及发现一个在手册里面(rev 14)没有提到的位,先看代码: - Init BRR* x* r6 S7 e/ L* ~$ E
- * ] a0 U! K: l7 y
- /* USART OverSampling-8 Mask */! b3 T a1 n! E/ e, Q
- #define CR1_OVER8_Set ((u16)0x8000) /* USART OVER8 mode Enable Mask */
8 M1 h8 V, ~! z: d* w. n - #define CR1_OVER8_Reset ((u16)0x7FFF) /* USART OVER8 mode Disable Mask */0 d4 t- _- I5 y5 }, L
5 {% k; S8 B3 K* N- uint32_t tmpreg = 0x00, apbclock = 0x00;
# U2 D* W; z7 X& ]( g1 C0 A - uint32_t integerdivider = 0x00;4 Y4 g, T7 X8 w2 z E6 T
- uint32_t fractionaldivider = 0x00;: l+ V* g! s) d* G7 D- e( W
- /*---------------------------- USART BRR Configuration -----------------------*/. _0 I/ M, g4 Q# V- O; ?4 {
- /* Configure the USART Baud Rate -------------------------------------------*/
" t1 i# A. d( Z - RCC_GetClocksFreq(&RCC_ClocksStatus);
% {6 T$ D2 E# O4 Y1 t7 T- D - if (usartxbase == USART1_BASE)8 [3 M0 u1 ?7 O5 W. E3 `
- {
. Z) D) L2 G" r% ~6 T8 A - apbclock = RCC_ClocksStatus.PCLK2_Frequency;- ~) M- t4 L7 P* q1 J
- }% S% V4 _$ ?3 q
- else1 u. a. u( r1 V0 M( j
- {) g5 S; Z: C5 u0 S! N! W% o
- apbclock = RCC_ClocksStatus.PCLK1_Frequency;
6 ]1 [7 R9 Z, N% R+ ]$ Y - }
$ g, ]4 i9 T+ b/ x7 s+ I' H5 e -
5 }+ O1 {% E- Z3 B3 X - /* Determine the integer part */
5 R! Y4 x; H/ K - if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
8 V2 {& Y! _: i1 R& o! S. K - {
8 H! X" _' q0 }8 m4 {! b( q) |2 W - /* Integer part computing in case Oversampling mode is 8 Samples */9 P: ?6 m( q4 g- Y5 v, r+ E
- integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate))); 2 J( Y* d0 a o2 ~
- }. L: L: ~# _6 b' v
- else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
" A/ J6 P% M( [5 P; U - {$ A, w# C, r( ~+ d6 ]
- /* Integer part computing in case Oversampling mode is 16 Samples */3 _! E& k F/ K, O) r9 a1 v5 q7 J* \
- integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate))); * Q' r* Y1 a% f% U7 H2 z& B5 {
- }
6 }0 N$ z Z1 Q- B- _! q R - tmpreg = (integerdivider / 100) << 4;
: Y, E, [1 a! D: I( d- M
& l# |% W# G* K: a7 h. U- /* Determine the fractional part */# ?! [" o+ k2 s3 H# j; R
- fractionaldivider = integerdivider - (100 * (tmpreg >> 4));
; t {% J3 {. a( n8 O: a - 7 V7 ~! g+ n4 F+ U
- /* Implement the fractional part in the register */
, ^% N) W7 Y% y4 { - if ((USARTx->CR1 & CR1_OVER8_Set) != 0)6 l; h: I1 Q( J+ n5 J5 h$ C0 C" E; H
- {
6 _+ o- p% ?( U) t4 a, u$ A - tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);/ t% I, R# Y, c; A7 s+ i& n( d
- }7 {; l6 G- `" L- X; f8 I. ]2 N/ C
- else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
. ~; D% b" r: P% d - {5 e- |2 B4 i2 c* p' _5 ^4 F" K
- tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
% O' y+ A I: H5 Q$ o0 r7 V* w6 E4 Z. w* r - }
# P+ c- t% @' W - @. p2 M' |& C$ C9 ?
- /* Write to USART BRR */% @. w- _& o5 M+ y+ D% Q7 ?
- USARTx->BRR = (uint16_t)tmpreg;
复制代码 ; |. l& m# t" w8 P4 h2 f$ W. l2 d
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;
. {2 j3 }1 _8 \7 ]7 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时钟下的最大的波特率提升一倍。 & b, }( O/ V- y9 X/ i3 w0 l
|