stm32串口通信DMA接收
STM32串口通信中,使用DMA接收数据可以提高数据传输效率和可靠性。通过配置串口的DMA接收功能,可以实现在接收数据时不需要CPU介入,从而减轻CPU的负担。
具体实现步骤如下:
- 首先,需要使用STM32CubeMX生成串口初始化代码,并使能相应的DMA通道。
- 在生成的代码中,配置DMA接收缓冲区及缓冲区大小,一般可以使用循环缓冲区的方式,即接收满后自动从头部接收。
- 在DMA接收完成中断中,可以在回调函数中处理接收到的数据。注意,在接收半完成中断和接收完成中断之后的空闲中断中不能重复取接收数据。
- 使用相关函数,如DMA_Init()、HAL_UART_Receive_DMA()等,将串口和DMA进行关联,实现串口数据的DMA接收。
stm32串口通信DMA
STM32 使用 DMA 实现串口通信
配置环境与工具链
为了简化开发流程并提高效率,建议使用STM32CubeMX作为初始配置工具。通过STM32CubeMX可以快速生成初始化代码框架,减少手动编写底层驱动的时间成本[^1]。
初始化设置
在启动任何DMA传输之前,需先完成基本硬件参数设定:
- 打开STM32CubeMX软件,创建新工程并选择目标MCU型号(如STM32H750或STM32F103)。
- 进入Pinout & Configuration界面,找到USART外设节点,将其工作模式调整为Asynchronous异步通讯模式。
- 对于UART接口的选择取决于实际应用场景;对于多端口转发需求,则可参照实例分别指定不同UART用于接收和发送操作[^2]。
编程要点解析
UART/DMA关联配置
确保所选UART已正确绑定至相应的DMA流/通道上,并开启对应方向上的请求使能位。例如,在stm32f1xx_hal_msp.c
文件内添加如下回调函数以完成低级资源分配:
void HAL_UART_MspInit(UART_HandleTypeDef* huart){
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN USARTx_MspInit 0 */
if(huart->Instance==USART1 || huart->Instance==USART2){
/* Peripheral clock enable */
__HAL_RCC_USARTx_CLK_ENABLE();
/**USARTx GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1; // or AF7 for USART2 on pins PA2,PA3
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// Enable and configure the DMA channel associated with this UART instance.
hdma_usart_rx.Instance = DMACHANNEL_INSTANCE;
hdma_usart_rx.Init.Request = DMAREQUEST_SOURCE;
hdma_usart_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart_rx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_usart_rx);
__HAL_LINKDMA(huart, hdmarx, hdma_usart_rx);
/* Configure NVIC for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(DMACHANNEL_IRQN, PREEMPTION_PRIORITY, SUB_PRIORITY);
HAL_NVIC_EnableIRQ(DMACHANNEL_IRQN);
}
}
上述代码片段展示了如何针对特定UART设备初始化其对应的DMA控制器及其相关联的NVIC中断源。注意替换宏定义中的具体数值以便适配不同的芯片平台特性。
数据缓冲区管理策略
考虑到实时性能的要求以及可能存在的大数据量交换场景,采用循环缓冲结构能够有效提升系统的鲁棒性。当DMA完成一次完整的读取周期后触发ISR服务程序更新指针位置即可维持连续不断的I/O流转过程[^5]。
uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint16_t head=0,tail=0;
// Inside main loop check available data length without blocking
int get_available_data_length(){
int size=(head-tail)&(RX_BUFFER_SIZE-1);
return (size<0)?(RX_BUFFER_SIZE+size):size;
}
// Non-blocking read function to fetch received bytes from circular buffer
int non_blocking_read(uint8_t *data,int max_len){
int i,size=get_available_data_length();
if(!size)return 0;
size=((max_len<size)?max_len:size);
for(i=0;i<size;++i){
*(data+i)=rx_buffer[tail++];
tail&=(RX_BUFFER_SIZE-1);
}
return size;
}
此部分实现了非阻塞式的字符读取逻辑,允许应用程序层灵活控制数据获取时机而不必担心因等待而造成响应延迟问题。
完整示例应用案例分析
结合前述理论知识点来看,下面给出一段综合性的测试脚本用来验证整个架构的有效性。这里假设我们正在构建一个简单的回声服务器——即接收到的信息会立即原样返回给客户端终端模拟器显示出来:
#include "main.h"
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart2_tx;
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/**
* @brief Main program.
* @param None
* @retval None
*/
int main(void){
/* Reset of all peripherals, Initializes the Flash interface and Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init(); // Set up as receiver only using DMA
MX_USART2_UART_Init(); // Set up as transmitter only using DMA
while (true) {
static uint8_t tempBuffer[1]; // Temporary storage used during echo back operation.
// Check whether there is any incoming message waiting inside RX buffer...
if(non_blocking_read(tempBuffer,sizeof(tempBuffer))>0){
// Forward it directly through another port via DMA transmission mechanism...
HAL_UART_Transmit_DMA(&huart2,tempBuffer,strlen((char*)tempBuffer));
}else{
// Otherwise just keep looping until new input arrives...
continue;
}
}
}
这段代码体现了双向桥接的概念,其中一端负责监听外部输入并将捕获到的内容即时反馈回去形成闭环效应。值得注意的是,由于采用了DMA技术,CPU几乎不需要参与具体的搬移动作从而极大地减轻了核心负担。
stm32f103串口dma接收
stm32f103是一款32位ARM Cortex-M3处理器的微控制器,具有丰富的外设资源,其中包括多个串口接口。串口通信是常用的一种通信方式,它通过两条线进行双向数据传输。在stm32f103中,通过使用DMA(直接内存访问)来实现串口接收功能,可以有效提高数据传输的效率和可靠性。
首先,需要开启串口和DMA的时钟,设置串口和DMA的工作模式。打开时钟可以通过设置寄存器RCC_APB2Periph_USART1和RCC_AHBPeriph_DMA1来实现。然后,在串口的收发控制寄存器USART_CR1中设置RE位(接收使能),以及在DMA的配置寄存器DMA_CPARx和DMA_CMARx中设置源地址和目的地址。接着,设置DMA的传输模式、数据长度等参数。可以选择循环模式或非循环模式,根据需要设置数据长度为1个字节或更多字节。
在接收数据阶段,可以使用中断或轮询两种方式进行。如果选择中断方式,可以配置NVIC和USART_CR1中的RXNEIE位(接收寄存器非空中断使能),在中断服务函数中读取接收到的数据。如果选择轮询方式,可以使用USART_SR寄存器的RXNE位进行判断,如果置位表示有数据接收到,然后读取数据。无论使用哪种方式,接收的数据会自动存储到DMA的目的地址中。
最后,在接收完成后,需要清除DMA的标志位和释放资源。可以根据需要设置DMA_IT_TC或DMA_IT_HT位(传输完成或半传输中断使能),在中断服务函数中进行相应的处理。同时,清除USART_SR寄存器中的RXNE位,以及DMA_IFCR寄存器中的相应标志位,以便下次接收。
总之,使用DMA来实现串口接收可以提高系统的性能和可靠性,在处理数据时能够更高效地利用处理器的资源,同时降低了处理器的负载。
相关推荐












