細數STM32F103的那些坑

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 );

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章