STM32學習筆記(二)——串口控制LED


 

開發板芯片:STM32F407ZGT6

PA9-USART1_TX,PA10-USART1_RX;

PF9-LED0,PF10-LED1;

 

一、串口1配置過程(不使用串口中斷):

1.使能時鍾,包括GPIO時鍾和串口1時鍾使能,注意它們是掛載在不同的時鍾總線上的。

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);    //使能端口時鍾
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);    //使能串口時鍾

2.端口映射到串口1。

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//端口映射到串口
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

3.GPIO初始化,注意配置模式時,要設置為復用模式,其他和GPIO基本配置相同

    IO_Init。GPIO_Mode = GPIO_Mode_AF;            //設置為復用模式
    IO_Init。GPIO_OType = GPIO_OType_PP;
    IO_Init。GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
    IO_Init。GPIO_PuPd = GPIO_PuPd_UP;
    IO_Init。GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &IO_Init);

 

4.串口1初始化,包括:波特率,發送接收使能,數據位,停止位,奇偶校驗,硬件控制流

    UT_Init。USART_BaudRate = 9600;        //波特率
    UT_Init。USART_HardwareFlowControl = USART_HardwareFlowControl_None;    //無硬件控制流
    UT_Init。USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //發送接收
    UT_Init。USART_Parity = USART_Parity_No;            //無奇偶校驗
    UT_Init。USART_StopBits = USART_StopBits_1;        //停止位1
    UT_Init。USART_WordLength = USART_WordLength_8b;    //數據位8
    USART_Init(USART1, &UT_Init);

 

5.串口1使能。

    USART_Cmd(USART1, ENABLE);            //串口使能

 

二、相關的函數和寄存器介紹

 1、數據接收

1.1.狀態寄存器

其中的位5:RXNE就是可以接收完成標志位,當數據接收完成時,RXNE會自動置1,我們可以通過讀取該位的狀態,來判斷是否接收到數據,直接讀取該位的方法是

  u8 Receive_Data = 0;

 Receive_Flag = USART1->SR & 1 << 5;        //若接收到數據則標志位=1

 

 上面的方法就是直接讀取位5的值,接收完成則Receive_Flag=1。

其實我們更喜歡用一個函數來讀取RXNE的狀態:

USART_GetFlagStatus(USART1, USART_IT_RXNE)

該函數不僅可以讀取RXNE的狀態,還可以讀取其他位的狀態,若標志置1,該函數則會返回SET,即1。

我們可以看看該函數是如何實現的呢?

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
  FlagStatus bitstatus = RESET;
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_FLAG(USART_FLAG));

  /* The CTS flag is not available for UART4 and UART5 */
  if (USART_FLAG == USART_FLAG_CTS)
  {
    assert_param(IS_USART_1236_PERIPH(USARTx));
  } 
    
  if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

 可以看出該函數也是通過讀取寄存器相應的位來返回相應的狀態。

還有另一個函數和這個很相似:

USART_GetITStatus(USART1, USART_IT_RXNE);

這個函數也是讀取RXNE的狀態,不同的是當我們打開了串口中斷,接收到數據時,這個函數才會返回1.

也就是說,無論串口中斷是打開,接受完成后RXNE標志位都會置1,即USART_GetFlagStatus(USART1, USART_IT_RXNE)返回1,如果開啟了中斷,那么USART_GetFlagStatus(USART1, USART_IT_RXNE)和USART_GetITStatus(USART1, USART_IT_RXNE)都會置1。

當RXNE置1,即接收到數據后,我們要及時的讀取接收到的數據,相應的函數是Receive_Data = USART_ReceiveData(USART1);

我們也可以直接讀取USART1->DR寄存器,如Receive_Data = USART1->DR;

1.2.數據寄存器

 

當讀取完成后,RXNE將自動清零,如果沒有讀取數據,則需要軟件清零,可以使用函數USART_ClearFlag(USART1,USART_IT_RXNE);來進行手動清零,或通過將狀態寄存器位5-RXNE置為0:USART1->SR &= ~(1 << 5);這一點是很重要的。

2.數據發送

將數據進行處理后,我們需要回復一些數據,我們可以通過函數USART_SendData(USART1,data);來向外發送數據,當然我們也可以像讀取數據那樣,將數據寫入DR寄存器來實現 USART1->DR=data。其實我們更多的是通過重定向printf()函數來向外格式化輸出數據,如printf("Receive Succsed: %d \r\n", Data);這個更方便一些。

三、程序實現

那么我們怎么來實現電腦發送0x01來控制LED反轉呢?

1.串口配置函數

void USART1_Config()
{
    GPIO_InitTypeDef IO_Init;
    USART_InitTypeDef UT_Init;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);    //使能端口時鍾
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);    //使能串口時鍾
    
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//端口映射到串口
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

    IO_Init.GPIO_Mode = GPIO_Mode_AF;            //設置為復用模式
    IO_Init.GPIO_OType = GPIO_OType_PP;
    IO_Init.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
    IO_Init.GPIO_PuPd = GPIO_PuPd_UP;
    IO_Init.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &IO_Init);

    UT_Init.USART_BaudRate = 9600;        //波特率
    UT_Init.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    //無硬件控制流
    UT_Init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //發送接收
    UT_Init.USART_Parity = USART_Parity_No;            //無奇偶校驗
    UT_Init.USART_StopBits = USART_StopBits_1;        //停止位1
    UT_Init.USART_WordLength = USART_WordLength_8b;    //數據位8
    USART_Init(USART1, &UT_Init);

    USART_Cmd(USART1, ENABLE);            //串口使能
}

 

2.主函數

主函數怎么寫呢?其實很簡單,就是對接收的數據進行一下判斷就OK了,如果接收到的數據==0x01,那么LED=!LED,是不是很簡單呢?

int main(void)
{
    LED_Init();
    delay_init(168);
    USART1_Config();
    LED0_OFF;
    LED1_OFF;
    while(1)
    {
        u8 Receive_Data = 0;
        if(USART_GetITStatus(USART1, USART_IT_RXNE))        //若接收到數據
        {
            Receive_Data = USART_ReceiveData(USART1);        //讀取數據后,RXNE標志位自動清零;
            printf("Receive Succsed: %2x \r\n", Receive_Data);
            if(Receive_Data == 0x01)
                LED0 = !LED0;
//        USART_ClearFlag(USART1,USART_IT_RXNE);        //手動清零
        }
        else
        {
            LED1 = !LED1;
            printf("Running....\r\n");
            delay_ms(500);
        }
    }
}

 

這里使用了串口發送“Running....”和LED1閃爍來指示程序正在運行,這種方法很常用,可以指示程序的運行狀態。

本文章沒有使用串口中斷來進行控制,下一篇文章將會介紹如何使用串口中斷來控制LED。

 

參考資料:

STM32F4xx中文參考手冊

STM32F4開發指南-庫函數版本_V1.1

USART_百度百科

 

以上是我學習過程的一些個人理解,有不對或不准確的地方,歡迎各位大神指正。

 

2017年4月16日21:58:46

歡迎大家關注我的個人博客 http://www.wangchaochao.top/
微信掃碼關注我的公眾號

 

不定期更新個人學習筆記和技術總結,歡迎大家互相學習交流!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM