1. 程式人生 > >STM32-----採用DMA的方式實現串列埠收發資料

STM32-----採用DMA的方式實現串列埠收發資料

STM32-----採用DMA的方式實現串列埠收發資料


概述

想必看到這篇部落格的你已經知道了DMA的好處了吧,所以這兒就不過多地講述DMA對於緩解MCU壓力有多麼重要的用途,DMA在很多方面都可以使用,如IIC,SPI,USART等,這兒主要給出DMA在USART上面的一個例項。


程式碼實現

主要程式碼直接在一個程式中實現


全域性變數以及巨集定義

#define DEFAULT_BAUD 115200
#define UART_RX_LEN		128

/*串列埠接收DMA快取*/
uint8_t Uart_Rx[UART_RX_LEN] = {0};

/*串列埠傳送DMA快取*/
uint8_t Uart_Send_Buffer[100]={0};

uint8_t Data_Receive_Usart=0;

DMA和USART的初始化的函式

void usart_dma_init(void)
{
    GPIO_InitTypeDef	GPIO_InitStructure;
    USART_InitTypeDef	USART_InitStructure;
    DMA_InitTypeDef		DMA_InitStructure;
    NVIC_InitTypeDef	NVIC_InitStructure;


	
    /*  配置GPIO的模式和IO口 */	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;					//TX
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;			//複用推輓輸出
    GPIO_Init(GPIOA,&GPIO_InitStructure);					//初始化串列埠輸入IO
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;				//RX
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;		//模擬輸入
    GPIO_Init(GPIOA,&GPIO_InitStructure); 	


	
    /*初始化串列埠接收和傳送函式*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;  
    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_InitStructure.USART_BaudRate = DEFAULT_BAUD; 
	
    /*初始化串列埠*/
    USART_Init(USART1,&USART_InitStructure);
	
    /*中斷配置*/
    USART_ITConfig(USART1,USART_IT_TC,DISABLE);
    USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
    USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); 
	
    //配置UART1中斷  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;              //通道設定為串列埠1中斷  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;      //中斷佔先等級0  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;             //中斷響應優先順序0  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //開啟中斷  
    NVIC_Init(&NVIC_InitStructure);



    /*DMA傳送中斷設定*/
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
	
	
    /*DMA1通道4配置傳送*/
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_DeInit(DMA1_Channel4);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Send_Buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 100;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4,&DMA_InitStructure);
    DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
    //DMA_Cmd(DMA1_Channel4, ENABLE);//使能通道4,一般傳送的時候再使能
 
 

    /*DMA1通道5配置接收*/
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_DeInit(DMA1_Channel5);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = UART_RX_LEN;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel5,&DMA_InitStructure);
 
    /*使能通道5*/
    DMA_Cmd(DMA1_Channel5,ENABLE);

 
        
    //採用DMA方式傳送
    USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
	
    //採用DMA方式接收
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
	
    //啟動串列埠  
    USART_Cmd(USART1, ENABLE);
}

DMA傳送使能函式

/**@ brief 使能傳送資料
 *
 * 啟動DMA資料傳送功能
 * 
 * @param size表示需要傳送的DMA中資料的個數
 */
void uart_dma_send_enable(uint16_t size)
{
    DMA1_Channel4->CNDTR = (uint16_t)size; 
    DMA_Cmd(DMA1_Channel4, ENABLE);       
}	

串列埠接收的中斷函式

/**@ brief串列埠1接收中斷
 *
 * 收到一幀資料進入一次,進行DMA的讀取
 * 
 */
void USART1_IRQHandler(void)                               
{   
    uint32_t temp = 0;
    uint16_t i = 0;
	
    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    {
        //USART_ClearFlag(USART1,USART_IT_IDLE);
        temp = USART1->SR;
        temp = USART1->DR; //清USART_IT_IDLE標誌
		
        DMA_Cmd(DMA1_Channel5,DISABLE);
 
        temp = UART_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);
        for (i = 0;i < temp;i++)
        {
            Data_Receive_Usart = Uart_Rx[i];
			
            //+++對收到的資料加一後回發出去		
            Uart_Send_Buffer[i]=Data_Receive_Usart+1;						
            uart_dma_send_enable(temp);
            //+++			
        }
		
        //設定傳輸資料長度
        DMA_SetCurrDataCounter(DMA1_Channel5,UART_RX_LEN);
		
        //開啟DMA
        DMA_Cmd(DMA1_Channel5,ENABLE);
    } 
} 

DMA傳送中斷

/**@ brief DMA傳送中斷
 *
 * 傳送資料,將DMA中的資料傳送出去
 * 
 */
void DMA1_Channel4_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_FLAG_TC4)==SET)
    {
        DMA_ClearFlag(DMA1_FLAG_GL4);        
        DMA_Cmd(DMA1_Channel4, DISABLE);  
    }
}

到此為止主要程式碼就已經結束了,基本上能夠滿足測試要求


專案工程下載

串列埠1的DMA實現 點選下載

串列埠3的DMA實現 點選下載