幾個問題:
1、狀態寄存器(USART_SR)中的TC(Transmission complete)何時置位?它和TXE(Transmit data register empty,發送數據寄存器空)有何區別?可以先看看下面的圖:
根據上面的圖,TC置位的條件就是在上一個字節發完之后,數據寄存器仍為空(TXE=1)。USART_DR中的數據,只要移位寄存器把上一字節發完,馬上就可以移入移位寄存器,而USART_DR可以裝入新的數據。
2、波特率(Baud)的設置
從手冊知道,stm32的串口可以設置分數波特率,可以從APB時鍾得到精確的波特率。查看標准庫(v3.5)的設置波特率的部分函數,這種設置的方法精度足夠,以及發現一個在手冊里面(rev 14)沒有提到的位,先看代碼:

/* USART OverSampling-8 Mask */ #define CR1_OVER8_Set ((u16)0x8000) /* USART OVER8 mode Enable Mask */ #define CR1_OVER8_Reset ((u16)0x7FFF) /* USART OVER8 mode Disable Mask */ uint32_t tmpreg = 0x00, apbclock = 0x00; uint32_t integerdivider = 0x00; uint32_t fractionaldivider = 0x00; /*---------------------------- USART BRR Configuration -----------------------*/ /* Configure the USART Baud Rate -------------------------------------------*/ RCC_GetClocksFreq(&RCC_ClocksStatus); if (usartxbase == USART1_BASE) { apbclock = RCC_ClocksStatus.PCLK2_Frequency; } else { apbclock = RCC_ClocksStatus.PCLK1_Frequency; } /* Determine the integer part */ if ((USARTx->CR1 & CR1_OVER8_Set) != 0) { /* Integer part computing in case Oversampling mode is 8 Samples */ integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate))); } else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 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 & CR1_OVER8_Set) != 0) { tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07); } else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */ { tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F); } /* Write to USART BRR */ USARTx->BRR = (uint16_t)tmpreg;
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;
所以再除以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時鍾下的最大的波特率提升一倍。