在STM32微控制器中,USART(通用同步异步接收发射器)配合DMA(直接存储器访问)用于接收数据,可以大幅提升数据处理的效率,尤其是在接收大量数据时。通过利用DMA,CPU可以从数据传输过程中解放出来,专注于其他任务。以下是配置USART使用DMA接收数据的步骤:
1. 配置USART
首先,需要对USART进行基本配置,这包括设置波特率、数据位、停止位、奇偶校验等。必须确保USART的接收功能被使能。
2. 配置DMA
选择一个合适的DMA通道与USART接收请求相关联,并对该通道进行配置:
- 设置DMA传输方向:由外设到内存。
- 设置外设地址:USART数据寄存器的地址。
- 设置内存地址:指向用于存储接收到的数据的缓冲区的指针。
- 设置数据传输量:指定DMA传输的数据量,或者选择循环模式,DMA在达到指定数据量后会自动重新开始。
- 设置外设和内存的数据宽度:通常为 8 位或 16 位,根据USART配置而定。
- 配置增量模式:通常配置外设地址固定,内存地址增量
3. 使能DMA接收请求
在USART配置中,需要确保使能了DMA接收请求。这通常涉及到设置USART的相关CR(控制寄存器)中的位。
4. 配置DMA中断(可选)
可以配置DMA以在传输完成时产生中断,从而允许软件立即处理接收到的数据。这包括使能DMA通道的传输完成中断,并在NVIC中配置DMA中断。
- 启动DMA传
最后,启动DMA传输。这通常通过设置DMA通道的相应控制寄存器启动。
以下是一个配置示例(以串口1 USART1 和 DMA通道 5 为例,具体寄存器请根据实际情况和微控制器参考手册调整)
cpp
// USART1 初始化(示例,需要根据实际情况调整)
USART_InitTypeDef USART_InitStruct;
USART_StructInit(&USART_InitStruct);
USART_InitStruct.USART_BaudRate = 9600; // 设置波特率
// 其他配置...
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); // 使能USART1的DMA接收请求
// DMA 初始化(以DMA1_Channel5为例)
DMA_InitTypeDef DMA_InitStruct;
DMA_DeInit(DMA1_Channel5);
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)buffer; // buffer 是数据存储区
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = sizeof(buffer)/sizeof(buffer[0]);
// 其他配置...
DMA_Init(DMA1_Channel5, &DMA_InitStruct);
DMA_Cmd(DMA1_Channel5, ENABLE); // 启动DMA
// 如有必要,配置中断...
如何配置DMA以在传输完成时产生中断?
要配置DMA在传输完成时产生中断,你需要执行以下步骤(假设使用STM32标准库):
1. 配置DMA通道
首先,初始化DMA通道并在初始化结构体中选择合适的参数,包括源和目的地址、数据传输方向、缓冲区大小等。
cpp
DMA_InitTypeDef DMA_InitStructure;
// 假设为DMA1的Channel1(以STM32F1系列为例)
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; // buffer是数据接收的目的缓冲区
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = bufferSize;
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_Mode_Circular,视情况而定
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
2. 使能DMA传输完成中断
在DMA通道初始化之后,使能特定的DMA中断。这通常意味着传输完成中断(TC,Transfer Complete)。
cpp
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
3. 配置NVIC来使能DMA中断
接着,需要配置嵌套向量中断控制器(NVIC),以使能并设置DMA中断的优先级。
cpp
NVIC_InitTypeDef NVIC_InitStructure;
// 为了使用DMA1_Channel1中断
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 预抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
4. 实现DMA中断处理程序
在中断处理程序中,你需要检查传输完成标志,并且可能要清除该标志。此外,你可以在这一点上处理数据或者再次启动DMA传输。
cpp
void DMA1_Channel1_IRQHandler(void)
{
// 检查是否DMA1_Channel1传输完成
if(DMA_GetITStatus(DMA1_IT_TC1))
{
DMA_ClearITPendingBit(DMA1_IT_TC1); // 清除中断标志位
// 传输完成,处理数据
}
}
- 对于循环传输模式(
DMA_Mode_Circular
),请注意处理数据的速度要跟得上DMA传输的速度,避免数据丢失。 - 中断处理程序名(例如
DMA1_Channel1_IRQHandler
)是固定的,根据DMA通道而决定,参考相应的微控制器参考手册确定准确的名称。