STM32-----採用DMA的方式實現串列埠收發資料
阿新 • • 發佈:2018-12-21
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實現 點選下載