1、串口時鐘
- GPIO外設時鐘都掛載在APB1總線上
- 串口1的時鐘掛在APB2上,而串口2、串口3則是掛在APB1上
所以,在初始化串口1時,我們可以使用以下代碼:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
卻不可以使用以下代碼初始化串口2、串口3:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART2|RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART2|RCC_APB2Periph_GPIOB, ENABLE);
若要正確初始化串口相關時鐘並且兼顧代碼風格的統一性,推薦使用:
//串口1:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA時鐘
//串口2:
RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART2, ENABLE); //使能USART2時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA時鐘
//串口3:
RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART3, ENABLE); //使能USART3時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB時鐘
2、串口中斷
在進入串口中斷後,需要對中斷的類型進行判斷,這裏有兩個容易混用的函數:
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint32_t USART_IT)
該函數不僅會判斷標誌位是否置1,同時還會判斷是否使能了相應的中斷。所以在串口中斷函數中,如果要獲取中斷標誌位,通常使用該函數。
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint32_t USART_FLAG)
該函數只判斷標誌位。在沒有使能相應的中斷時,通常使用該函數來判斷標誌位是否置1。
在串口中斷中,使用的應該是函數USART_GetITStatus(),而USART_GetFlagStatus()通常用在串口輪詢的場合。
參考:https://www.cnblogs.com/leo0621/p/8709944.html
串口中斷函數常用代碼如下:
void USART1_IRQHandler(void)
{
uint8_t data;
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收寄存器非空中斷
{
data = USART_ReceiveData(USART1); //讀取字符
//添加你的代碼
}
if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //發送寄存器空中斷
{
//添加你的代碼
//如果所有數據都已發送完畢,則關閉發送中斷
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
}
更加喪心病狂一點的寫法:(參考資料:https://blog.csdn.net/xiahailong90/article/details/94595005)
void USART1_IRQHandler(void)
{
uint8_t data;
if (USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET)
{
USART_ReceiveData(USART1);
USART_ClearFlag(USART1, USART_FLAG_PE);
}
if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)
{
USART_ReceiveData(USART1);
USART_ClearFlag(USART1, USART_FLAG_ORE);
}
if (USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET)
{
USART_ReceiveData(USART1);
USART_ClearFlag(USART1, USART_FLAG_FE);
}
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收寄存器非空中斷
{
USART_ClearFlag(USART1, USART_FLAG_RXNE);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
data = USART_ReceiveData(USART1); //讀取字符
//添加你的代碼
}
if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //發送寄存器空中斷
{
USART_ClearFlag(USART1, USART_FLAG_TXE);
USART_ClearITPendingBit(USART1, USART_IT_TXE);
//添加你的代碼
//如果所有數據都已發送完畢,則關閉發送中斷
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
}
三、結構體局部變量
STM32的庫函數大量使用了結構體,不夠規範的使用方法會導致奇怪的問題,比如說PWM上電初始化後正常輸出,程序內再次初始化後沒有輸出這樣莫名其妙的BUG。
1、通常的寫法
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
2、保險一點的寫法
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};
3、規範的寫法
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructInit(TIM_TimeBaseStructure );