串口配置使用的一般步驟及實例解讀

串口配置的一般步驟

  1. 串口時鐘使能,GPIO時鐘使能:RCC_APB2PeriphClockCmd();
  2. 串口復位:USART_DeInit(); 這一步不是必須的
  3. GPIO端口模式設置:GPIO_Init(); 模式設置爲GPIO_Mode_AF_PP
  4. 串口參數初始化:USART_Init();
  5. 開啓中斷並且初始化NVIC(如果需要開啓中斷才需要這個步驟)
    NVIC_Init();
    USART_ITConfig();
  6. 使能串口:USART_Cmd();
  7. 編寫中斷處理函數:USARTx_IRQHandler();
  8. 串口數據收發:
    void USART_SendData(); //發送數據到串口,DR
    uint16_t USART_ReceiveData(); //接受數據,從DR讀取接受到的數據
  9. 串口傳輸狀態獲取:
    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
    void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
    注:使用中斷需要操作5、7、8步驟,否則不需要。
    部分官方庫函數的解讀在該博客內有說明
    https://blog.csdn.net/DX5618258/article/details/95999557

串口整體初始化函數(非庫函數/整合上述步驟1-6)

#define USART_WordLength_8b                  ((uint16_t)0x0000)
#define USART_StopBits_1                      ((uint16_t)0x0000)
#define USART_Parity_No                       ((uint16_t)0x0000)
#define USART_HardwareFlowControl_None        ((uint16_t)0x0000)
#define USART_Mode_Rx                        ((uint16_t)0x0004)
#define USART_Mode_Tx                        ((uint16_t)0x0008)

void uart_init(u32 bound)     //串口整體初始化函數
{
  //各種結構體聲明
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  //使能USART1,GPIO時鐘   對應上述步驟1
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	
  
  //初始化USART1_TX端口對應的GPIOA9    對應上述步驟3
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   //設置GPIO端口號爲PA9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //設置傳輸速度爲50MHz
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//輸出模式爲複用推輓輸出
  GPIO_Init(GPIOA, &GPIO_InitStructure);     //初始化GPIOA9
  
  //初始化USART1_RX端口對應的GPIOA10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  //設置GPIO端口號爲PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //輸入模式爲浮空輸入
  GPIO_Init(GPIOA, &GPIO_InitStructure);   //初始化GPIOA10
  
  //串口初始化設置    對應上述步驟4
  USART_InitStructure.USART_BaudRate = bound;   //設置串口的波特率爲函數的入口參數
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長爲8位數據格式
  USART_InitStructure.USART_StopBits = USART_StopBits_1;  //停止位一個
  USART_InitStructure.USART_Parity = USART_Parity_No;     //無奇偶校驗位
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //無硬件數據流控制
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收發模式
  USART_Init(USART1, &USART_InitStructure);    //初始化串口1,該函數的部分內容在上一篇
  
  //串口中斷設置     對應上述步驟5
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;       //選定串口1的中斷通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;  //搶佔優先級3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	     //子優先級3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	     //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);	//根據指定的參數初始化VIC寄存器
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  //開啓串口接收中斷
  
  //使能串口1        對應上述步驟6
  USART_Cmd(USART1, ENABLE);   //該函數在上文已說明
}

串口中斷服務函數

//頭文件的定義
#define USART_REC_LEN  	 200  	      //定義最大接收字節數爲200
#define EN_USART1_RX 	 1	            //使能(1)/禁止(0)串口1接收
extern u8  USART_RX_BUF[USART_REC_LEN];  //接收緩衝,最大USART_REC_LEN個字節,末尾爲換行符
extern u16 USART_RX_STA;         		 //接收狀態標記
void uart_init(u32 bound);
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;  //枚舉變量
#define USART_IT_RXNE  ((uint16_t)0x0525)	//10100100101
//源文件的定義
#if EN_USART1_RX   //如果使能了接收
u8  USART_RX_BUF[USART_REC_LEN];     //接收緩衝,最大USART_REC_LEN個字節
u16  USART_RX_STA=0;  //接收狀態標記   bit15 接收完成標誌,接收完成後爲1;
           接上一行bit14 接收到0x0d後爲1;bit13-bit0 爲接收到的有效字節數
    
//串口中斷服務函數     對應上述步驟7
void USART1_IRQHandler(void)
{
  u8 Res;
  //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
  //獲取串口1的當前狀態,如果不等於0,則滿足條件
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)	
  {
    Res =USART_ReceiveData(USART1); //讀取接收到的數據(按字節接收)
    //接收狀態標記(初始爲0)和0x8000進行與運算,若位15不爲0,則滿足條件
    if((USART_RX_STA&0x8000)==0) //正在接收(未完成接收)
    {
      //接收狀態標記變量和0x4000進行與運算,若位14不爲0,則滿足條件
      if(USART_RX_STA&0x4000) //上一次接收已經接收到了0x0d
      {
        //如果當前接收到的字節不是0x0a,則接收錯誤,接收狀態標記清零
    	if(Res!=0x0a)USART_RX_STA=0;  //接收錯誤,重新開始
        //如果當前字節是0x0a,則設置USART_RX_STA變量的位15爲1
    	else USART_RX_STA|=0x8000;	//接收完成
      }
      else //上一次接收還沒有收到0x0d
      {
        //如果該次接收收到了0x0d,設置接收狀態標記的位14爲1
    	if(Res==0x0d)USART_RX_STA|=0x4000;
    	else //該次接收還沒收到0x0d
    	{
          //USART_RX_BUF數組的第 位爲接收的字符(存入緩衝區)
    	  USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
    	  USART_RX_STA++;   //接收次數自增(字符數+1)
          //如果接收的字符數超過最大字符數-1個
    	  if(USART_RX_STA>(USART_REC_LEN-1)) 
          {   
            USART_RX_STA=0; //接收數據錯誤,重新開始接收
          }
    	}		 
      }
    }   		 
  } 
}

串口收發函數(上述函數的應用主函數)

int main(void)    //串口收發函數    對應上述步驟8
{
	u8 t;   u8 len;	 u16 times=0; 
    //初始化延時、中斷、串口、LED
	delay_init();	    	 //延時函數初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置中斷優先級分組
	uart_init(9600);	 //串口初始化爲9600
	LED_Init();		  	 //初始化與LED連接的硬件接口
	while(1) 
	{    
        //接收狀態標記變量和0x8000進行與運算,若位15爲1(接收完成)則進入
		if(USART_RX_STA&0x8000) 
		{					   
			//接收狀態標記變量與0x3fff進行與運算,獲取位13-0存儲的數據長度
            len=USART_RX_STA&0x3fff;
			printf("\r\n您發送的消息爲:\r\n");  //打印到串口
			for(t=0;t<len;t++)
			{
                //將DR=USART_RX_BUF中存儲的數據按位傳輸給DR寄存器
				USART1->DR=USART_RX_BUF[t];
                //等待SR寄存器的位6爲1時(發送完成時),跳出循環
				while((USART1->SR&0X40)==0);   //等待發送結束
			}
			printf("\r\n\r\n");    //插入換行
			USART_RX_STA=0;    //清空接收狀態標記變量
		}
        else   //接收未完成
		{
			times++;  //時間自增
			if(times%5000==0)  //每5000次輸出一次
			{  
			  printf("\r\n串口實驗\r\n ");
			}
			if(times%200==0)   //每200次輸出一次
            {  
              printf("請輸入數據,以回車鍵結束\r\n");  
            }
			if(times%30==0)LED0=!LED0;  //每30次閃爍LED一次,提示系統正在運行
			delay_ms(10);   
		}
	}
}

文中函數和部分內容摘自正點原子stm32資料與官方庫函數

自學新手,個人總結,如有出入,請多指教!

發佈了13 篇原創文章 · 獲贊 2 · 訪問量 2018
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章