STM32 串口DMA接收不定长数据
串口DMA接收数据,减少CPU占用
思路:DMA+空闲中断(无法确认数据帧结束)+循环缓存
DMA初始化
void DMA1_Stream_Config(DMA_Stream_TypeDef *DMA_Stream, uint32_t MemAddress, uint32_t ParAddress, uint32_t Size) { DMA_Stream->CR &= ~(1UL); //stream disable DMA_Stream->M0AR = MemAddress; DMA_Stream->PAR = ParAddress; DMA_Stream->NDTR = Size; } void DMA1_Stream_Enable(DMA_Stream_TypeDef *DMA_Stream) { DMA1->LIFCR = 0xFFFFFFFF; //clear all complete and half interrupt flag DMA_Stream->CR |= (1UL<<4); //enable DMA TC interrupt DMA_Stream->CR |= (1UL); //stream enable } void DMA1_Stream_Disable(DMA_Stream_TypeDef *DMA_Stream) { DMA_Stream->CR &= ~(1UL); //stream disable DMA1->LIFCR = 0xFFFFFFFF; //clear complete and half interrupt flag DMA_Stream->CR &= ~((1UL<<3)| (1UL<<4)); //disable DMA TC interrupt and HalfTC interrupt }
typedef struct
{
volatile uint8_t rx_buf[BUFF_SIZE]; // The rove receive buffer
volatile uint8_t rx_base_buf[BASE_BUFF_SIZE]; // The base receive buffer
volatile uint8_t tx_buf[BASE_BUFF_SIZE]; // The transmit buffer
volatile int16_t rx_front;
volatile int16_t rx_rear;
volatile int16_t rx_base_front;
volatile int16_t rx_base_rear;
volatile int16_t tx_front;
volatile int16_t tx_rear;
} UARTType;
extern UARTType uart7;
DMA1_Stream_Config(DMA1_Stream1, (uint32_t)uart7.rx_buf, (uint32_t)&(UART7->RDR), BUFF_SIZE);
DMA1_Stream_Enable(DMA1_Stream1);
UART 初始化
/* UART7 init function */ void MX_UART7_Init(void) { /* USER CODE BEGIN UART7_Init 0 */ uint8_t temp; /* USER CODE END UART7_Init 0 */ /* USER CODE BEGIN UART7_Init 1 */ /* USER CODE END UART7_Init 1 */ huart7.Instance = UART7; huart7.Init.BaudRate = 460800; huart7.Init.WordLength = UART_WORDLENGTH_8B; huart7.Init.StopBits = UART_STOPBITS_1; huart7.Init.Parity = UART_PARITY_NONE; huart7.Init.Mode = UART_MODE_TX_RX; huart7.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart7.Init.OverSampling = UART_OVERSAMPLING_16; huart7.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart7.Init.ClockPrescaler = UART_PRESCALER_DIV1; huart7.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart7) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_SetTxFifoThreshold(&huart7, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_SetRxFifoThreshold(&huart7, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_DisableFifoMode(&huart7) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN UART7_Init 2 */ UART7->CR3 |= (1U<<6); //Enable UART DMA Receive __HAL_UART_CLEAR_FLAG(&huart7, UART_CLEAR_IDLEF); __HAL_UART_ENABLE_IT(&huart7, UART_IT_IDLE); /* USER CODE END UART7_Init 2 */ }
.....................
/* UART7 clock enable */
__HAL_RCC_UART7_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**UART7 GPIO Configuration
PB4 ------> UART7_TX
PB3 ------> UART7_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_UART7;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_UART7;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* UART7 DMA Init */
/* UART7_RX Init */
hdma_uart7_rx.Instance = DMA1_Stream1;
hdma_uart7_rx.Init.Request = DMA_REQUEST_UART7_RX;
hdma_uart7_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_uart7_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_uart7_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_uart7_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_uart7_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_uart7_rx.Init.Mode = DMA_CIRCULAR;
hdma_uart7_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_uart7_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_uart7_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(uartHandle,hdmarx,hdma_uart7_rx);
/* UART7 interrupt Init */
HAL_NVIC_SetPriority(UART7_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(UART7_IRQn);
....................
中断处理函数
void DMA1_Stream1_IRQHandler(void) { /* USER CODE BEGIN DMA1_Stream1_IRQn 0 */ if(DMA1->LISR & (1UL<<11)) //TC { DMA1->LIFCR |= (1UL<<11); } else { /* USER CODE END DMA1_Stream1_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_uart7_rx); /* USER CODE BEGIN DMA1_Stream1_IRQn 1 */ } /* USER CODE END DMA1_Stream1_IRQn 1 */ }
void UART7_IRQHandler(void) { /* USER CODE BEGIN UART7_IRQn 0 */ BaseType_t status; /* if(UART7->ISR&(1<<5)) //RXNEIE { resume=1; uint16_t temp = uart7.rx_rear; uart7.rx_buf[temp] = UART7->RDR; temp = ((temp)>=BUFF_SIZE-1) ? 0 : (temp)+1; uart7.rx_rear = temp; SET_BIT(UART7->CR1, USART_CR1_RXNEIE); } else */ if(UART7->ISR & (1UL<<4)) //IDLE { uart7.rx_rear = (BUFF_SIZE - DMA1_Stream1->NDTR)>=BUFF_SIZE?0:BUFF_SIZE - DMA1_Stream1->NDTR; SCB_InvalidateDCache_by_Addr((uint32_t*)uart7.rx_buf, BUFF_SIZE);//DMA和D-Cache数据一致性处理 //唤醒数据处理任务 if(dataTaskHandle) { status = xTaskResumeFromISR(dataTaskHandle);//恢复任务 if(status==pdTRUE) { portYIELD_FROM_ISR(status); } } //获取星历命令 if(!(--IPSeph_Time)) { Send_Cmd(&huart7, "$PSTMDUMPEPHEMS\r\n"); IPSeph_Time = COUNT; } UART7->ICR |= (1UL<<4); } else if(UART7->ISR & (1UL<<3)) //ORE { UART7->ICR |= (1UL<<3); } else if(UART7->ISR & (1UL<<1)) //FE { UART7->ICR |= (1UL<<1); } else if(UART7->ISR & (1UL<<2)) //NE { UART7->ICR |= (1UL<<2); } else { /* USER CODE END UART7_IRQn 0 */ HAL_UART_IRQHandler(&huart7); /* USER CODE BEGIN UART7_IRQn 1 */ } /* USER CODE END UART7_IRQn 1 */ }
获取循环缓存数据
//写缓冲区 void WriteRxBuffer(UARTType * pUART, uint8_t info) { uint16_t temp = pUART->rx_rear; pUART->rx_buf[temp] = info; temp = ((temp)>=BUFF_SIZE-1) ? 0 : (temp)+1; pUART->rx_rear = temp; } //读缓冲区 uint32_t ReadRxBuffer(UARTType * pUART, uint8_t *info, uint32_t size) { uint32_t i; uint16_t temp = pUART->rx_front; for(i = 0; i<size; i++) { if(temp==pUART->rx_rear) break; info[i] = pUART->rx_buf[temp]; temp = ((temp)>=BUFF_SIZE-1) ? 0 : (temp)+1; } pUART->rx_front = temp; return i; } void StartDataTask(void *argument) { uint32_t nb[2] = {0}; uint8_t byte[1] = {0}; //存储从uart7.rx_buf缓冲区获取的1byte Rover数据 uint32_t get_size = 0; for(;;) { get_size = ReadRxBuffer(&uart7, byte, 1); if(get_size) { roveBuff[nb[0]++] = byte[0]; } if((byte[0]=='\n')&&(nb[0])) { MyPrintf((char*)roveBuff, nb[0]); //输出数据 memset(roveBuff, 0, nb[0]); nb[0] = 0; } } }
输出数据
void UART5_IRQHandler(void) { /* USER CODE BEGIN UART5_IRQn 0 */ uint8_t temp; if(UART5->ISR&(1<<5)) { temp = UART5->RDR; if(interr_receive_bytes < BASE_BUFF_SIZE) uart7.rx_base_buf[interr_receive_bytes++] = temp; __HAL_TIM_SET_COUNTER(&htim2, 0); SET_BIT(UART5->CR1, USART_CR1_RXNEIE); } else if(UART5->ISR&(1U<<7)&& UART5->CR1&(1U<<7))// { uint16_t temp = uart7.tx_front; UART5->TDR=uart7.tx_buf[temp]; temp = ((temp)>=BUFF_SIZE/2-1) ? 0 : (temp)+1; if(temp==uart7.tx_rear) { CLEAR_BIT(UART5->CR1,1U<<7);//数据发送完毕,禁止串口的发送缓冲区空中断 } uart7.tx_front = temp; } else if(UART5->ISR & (1UL<<3)) //ORE { UART5->ICR |= (1UL<<3); } else if(UART5->ISR & (1UL<<1)) //FE { UART5->ICR |= (1UL<<1); } else if(UART5->ISR & (1UL<<2)) //NE { UART5->ICR |= (1UL<<2); } else { /* USER CODE END UART5_IRQn 0 */ HAL_UART_IRQHandler(&huart5); /* USER CODE BEGIN UART5_IRQn 1 */ } /* USER CODE END UART5_IRQn 1 */ } //将字符串放入发送缓冲区并开启中断发送 void MyPrintf(char* str, uint32_t len) { //挂起所有任务,防止数据错乱 vTaskSuspendAll(); uint16_t temp = uart7.tx_rear; for(uint32_t i = 0; i<len; i++) { uart7.tx_buf[temp] = str[i]; temp = ((temp)>=BUFF_SIZE/2-1) ? 0 : (temp)+1; } uart7.tx_rear = temp; //恢复所有任务 xTaskResumeAll(); SET_BIT(UART5->CR1,1U<<7);//使能串口的发送缓冲区空中断 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律