STM32F030-UART1_DMA使用提示


STM32F030-UART1_DMA使用提示

前言:

         今天把STM32F030C8T6的串口DMA學習了一下,為了加快各位研發人員的開發進度,避免浪費大量的時間在硬件平台上,寫出個人代碼調試的經驗。個人水平有限,如有錯誤,還請指正mr.li.ming@qq.com。

 

提示:使用的內部RC時鍾,最大速度48MHz;使用USART1-PA9/PA10.

 

 

第一步:初始化端口

/*******************************************************************************

  * @brief  串口1端口初始化

  * @param  None

  * @retval None

****************************************************************Author:Liming**/

void USART1_GPIO_Init(void)

{

    GPIO_InitTypeDef    GPIO_Initstructure;

 

    RCC_AHBPeriphClockCmd(USART1_GPIO_CLK,ENABLE);  

 

    /* Connect pin to Periph */

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);   // 注意這里是GPIO_PinSource9

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);

 

    GPIO_Initstructure.GPIO_Pin=USART1_TX_PIN;

    GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AF;

    GPIO_Initstructure.GPIO_OType=GPIO_OType_PP;  // 推挽輸出

    GPIO_Initstructure.GPIO_PuPd=GPIO_PuPd_UP;

    GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;   

    GPIO_Init(USART1_GPIO_PORT,&GPIO_Initstructure);

 

    GPIO_Initstructure.GPIO_Pin = USART1_RX_PIN;  // 浮空輸入 

    GPIO_Init(USART1_GPIO_PORT,&GPIO_Initstructure);

}

第二步:初始化UART1

/*******************************************************************************

  * @brief  串口1初始化

  * @param  None

  * @retval None

****************************************************************Author:Liming**/

void USART1_Init(uint32_t BaudRate)

{

    USART_InitTypeDef   USART_Initstructure;

 

    RCC_APB2PeriphClockCmd(USART1_CLK,ENABLE);

   

    USART1_GPIO_Init(); // 調用了上面的端口初始化,故主函數里調用此函數即可。

    

    USART_Initstructure.USART_BaudRate = BaudRate;

    USART_Initstructure.USART_Parity   =USART_Parity_No;

    USART_Initstructure.USART_WordLength =USART_WordLength_8b; 

    USART_Initstructure.USART_StopBits  =USART_StopBits_1;

    USART_Initstructure.USART_Mode     = USART_Mode_Rx|USART_Mode_Tx;

    USART_Initstructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;

    USART_Init(USART1,&USART_Initstructure);

 

    USART_ClearFlag(USART1,USART_FLAG_TC);

    USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);

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

}

 

 

 

第三步:DMA1中斷配置

/*******************************************************************************

  * @brief  DMA1中斷配置

  * @param  None

  * @retval None

****************************************************************Author:Liming**/

void DMA1_NVIC_Init(void)

{

    NVIC_InitTypeDef    NVIC_InitStructure;

   

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_3_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_InitStructure.NVIC_IRQChannelPriority = 2;

   

    NVIC_Init(&NVIC_InitStructure);

}

注意事項:

1.     USART1發送數據 使用的是DMA1的第二通道。查表可知,為什么還有第四通道呢,那是給USART1端口重映射了之后使用的。

 

 

 

第四步:DMA1配置

/*******************************************************************************

  * @brief  DMA1配置

  * @param  None

  * @retval None

****************************************************************Author:Liming**/

void DMA1_Init(void)

{

    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

   

    DMA_InitStructure.DMA_BufferSize = 12;  // 緩存大小

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;    // 內存到內存關閉

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;   // 普通模式

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  // 內存到外設

    DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA通道優先級

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 內存地址遞增

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->TDR;   // 外設地址   

    DMA_InitStructure.DMA_PeripheralInc =  DMA_PeripheralInc_Disable;// 外設地址不變

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 內存數據長度

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)UART1_TXBUFFER;   // 定義內存基地址

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外設數據長度

   

    DMA_Init(DMA1_Channel2,&DMA_InitStructure);

    DMA_ClearITPendingBit(DMA1_IT_TC2); // 清除一次DMA中斷標志

    DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);// 使能DMA傳輸完成中斷

   

DMA1_NVIC_Init(); // 調用了上面的中斷配置,故主函數里調用此函數即可

    DMA_Cmd(DMA1_Channel2,ENABLE);

}

注意事項:

1.     緩存大小:就是你一次要發送多長的數據。

2.     DMA方向:因為是串口發送數據,所以是從內存到外設,USART1對於單片機來講是個外設。定義的發送數組是內存。

3.     內存地址遞增:其實不難理解,從發送數組的UART1_TXBUFFER[0]- UART1_TXBUFFER[n]肯定是遞增的。

4.     外設地址不遞增:所有的數據都是通過串口發送寄存器發出去,所以外設地址不變。

5.     內存/外設數據長度:串口發送的數據都是字節為單位,所以長度是Byte

6.     DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);注意這一句不要寫錯。

 

 

 

第五步:DMA1的中斷處理函數

/**

  * @brief  DMA1_Channel1中斷服務函數

  * @param  無

  * @retval 無

  */

void DMA1_Channel2_3_IRQHandler(void) 

         /*判斷DMA傳輸完成中斷*/

         if(DMA_GetITStatus(DMA1_IT_TC2) != RESET)                       

         {

        UART1_STATE = 2;// send over

         }

         /*清除DMA中斷標志位*/   

         DMA_ClearITPendingBit(DMA1_IT_TC2);                     

}

這里使用了一個變量UART1_STATE作為標志位

 

 

 

 

第六步:使用DMA1發送串口數據

 

    USART1_Init(115200);

    DMA1_Init();

   

    while(1)

    {

        if(UART1_STATE==2)

        {

            UART1_STATE = 1;

            DMA_Cmd(DMA1_Channel2,DISABLE); // 發送完成先關掉DMA通道

            DMA_SetCurrDataCounter(DMA1_Channel2,12); // 設置需要發送的長度

            DMA_Cmd(DMA1_Channel2,ENABLE); // 再打開DMA通道

        }

        GPIO_SetBits(GPIOA,GPIO_Pin_4);Delay(500);

        GPIO_SetBits(GPIOA,GPIO_Pin_3);Delay(500);

        GPIO_ResetBits(GPIOA,GPIO_Pin_4);Delay(500);

        GPIO_ResetBits(GPIOA,GPIO_Pin_3);Delay(500);

       

    }

注意事項:

1.     一定要注意,DMA的傳輸有個長度計數器,DMA傳輸完成后,計數器里的值就變成了0;數據是不傳了,但是通道並沒有關閉。所以想要再次傳輸就需要修改這個長度計數器的值,但是這個值的修改必須要關閉通道后修改。所以就有了上面的步驟,關閉通道—修改計數值—打開通道

 

 

希望對各位看官有所幫助,並能觸類旁通,對於外設到內存啊,內存到內存啊,ADC與DMA啊,SPI與DMA都能輕松的應用。

 

 


免責聲明!

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



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