STM32的串口採用DMA方式接收數據測試
本文博客鏈接:http://blog.csdn.net/jdh99,作者:jdh,轉載請註明.
參考鏈接:http://www.amobbs.com/forum.php?mod=viewthread&tid=5511863&highlight=dma%E6%8E%A5%E6%94%B6
環境:
主機:WINXP
開發環境:MDK4.23
MCU:STM32F103CBT6
說明:
串口可以配置成用DMA的方式接收數據,不過DMA需要定長才能產生接收中斷,如何接收可變長度的數據呢?
方法有以下3種:
1.將RX腳與一路時鐘外部引腳相連,當串口一幀發完,即可利用此定時器產生超時中斷.這個實時性較高,可以做到1個字節實時監測.
2.不改變硬件,開啓一個定時器監控DMA接收,如果超時則產生中斷.這個實時性不高,因爲超時時間必須要大於需要接收幀的時間,精度不好控制.
3.STM32單片機有的串口可以監測總線是否處於空閒,如果空閒則產生中斷.可以用它來監測DMA接收是否完畢.這種方式實時性很高.
本文采用第3種方式.在波特率576000下大數據包衝擊證明可行.
源代碼:
- //串口接收DMA緩存
- #define UART_RX_LEN 128
- extern uint8_t Uart_Rx[UART_RX_LEN];
- //串口接收DMA緩存
- uint8_t Uart_Rx[UART_RX_LEN] = {0};
- //---------------------串口功能配置---------------------
- //打開串口對應的外設時鐘
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
- //串口發DMA配置
- //啓動DMA時鐘
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- //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配置
- DMA_DeInit(DMA1_Channel4);
- //外設地址
- DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
- //內存地址
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Send_Buffer;
- //dma傳輸方向單向
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
- //設置DMA在傳輸時緩衝區的長度
- DMA_InitStructure.DMA_BufferSize = 100;
- //設置DMA的外設遞增模式,一個外設
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- //設置DMA的內存遞增模式
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- //外設數據字長
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- //內存數據字長
- DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
- //設置DMA的傳輸模式
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
- //設置DMA的優先級別
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;
- //設置DMA的2個memory中的變量互相訪問
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel4,&DMA_InitStructure);
- DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
- //使能通道4
- //DMA_Cmd(DMA1_Channel4, ENABLE);
- //串口收DMA配置
- //啓動DMA時鐘
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- //DMA1通道5配置
- DMA_DeInit(DMA1_Channel5);
- //外設地址
- DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
- //內存地址
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx;
- //dma傳輸方向單向
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
- //設置DMA在傳輸時緩衝區的長度
- DMA_InitStructure.DMA_BufferSize = UART_RX_LEN;
- //設置DMA的外設遞增模式,一個外設
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- //設置DMA的內存遞增模式
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- //外設數據字長
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- //內存數據字長
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- //設置DMA的傳輸模式
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
- //設置DMA的優先級別
- DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
- //設置DMA的2個memory中的變量互相訪問
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel5,&DMA_InitStructure);
- //使能通道5
- DMA_Cmd(DMA1_Channel5,ENABLE);
- //初始化參數
- //USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;
- 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);
- //TXE發送中斷,TC傳輸完成中斷,RXNE接收中斷,PE奇偶錯誤中斷,可以是多個
- //USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
- //中斷配置
- 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方式發送
- USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
- //採用DMA方式接收
- USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
- //啓動串口
- USART_Cmd(USART1, ENABLE);
- //串口1接收中斷
- 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];
- //啓動串口狀態機
- usart_state_run();
- }
- //設置傳輸數據長度
- DMA_SetCurrDataCounter(DMA1_Channel5,UART_RX_LEN);
- //打開DMA
- DMA_Cmd(DMA1_Channel5,ENABLE);
- }
- __nop();
-
}
轉載地址:http://blog.csdn.net/jdh99/article/details/8444474