CICERO双引擎架构:语言模型与规划器协同的AI谈判系统
2026/6/9 18:55:57
目录
一、DMA 基础入门
二、经典应用案例
1. 串口 (UART) DMA 收发
2. ADC DMA 数据采集
三、常见问题答疑
1. 配置问题
2. 中断与性能问题
3. 实战疑难
四、初学者建议
总结
DMA(Direct Memory Access)是一种无需 CPU 参与就能完成数据传输的硬件机制,特别适合高速、批量数据处理场景,可显著降低 CPU 负载,提高系统效率。
HC32L130 DMA 特性:
应用场景:
配置步骤:
// 1. 使能时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA, ENABLE); // DMA时钟 RCC_APBPeriphClockCmd(RCC_APBPeriph_UART0, ENABLE); // UART时钟 // 2. 配置GPIO复用 GPIO_SetFunc(GPIO_PORTB, GPIO_PIN_6, GPIO_FUNC_2); // UART0 TX GPIO_SetFunc(GPIO_PORTB, GPIO_PIN_7, GPIO_FUNC_2); // UART0 RX // 3. 初始化UART UART_InitTypeDef UART_InitStructure; UART_StructInit(&UART_InitStructure); UART_InitStructure.BaudRate = 115200; UART_Init(UART0, &UART_InitStructure); // 4. 配置DMA DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA_CH0); // 复位通道0 // 配置DMA接收(外设→内存) DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART0->DR; // UART数据寄存器 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)uart_rx_buf; // 接收缓冲区 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 方向:外设→内存 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; // 8位数据 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 8位数据 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 单次传输模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 高优先级 DMA_Init(DMA_CH0, &DMA_InitStructure); // 5. 关联DMA与UART UART_DMACmd(UART0, UART_DMA_Rx, ENABLE); // 使能UART接收DMA // 6. 启动DMA传输 DMA_Cmd(DMA_CH0, ENABLE); // 7. 传输完成中断处理(可选) DMA_ITConfig(DMA_CH0, DMA_IT_TC, ENABLE); // 使能传输完成中断 NVIC_EnableIRQ(DMA_IRQn); // 使能DMA中断进阶应用:串口 DMA + 定时器实现空闲超时接收
在实际通信中,我们常需要处理不定长数据包,可结合高级定时器实现空闲超时检测:
// 1. 初始化定时器6(高级定时器) Timer_InitTypeDef Timer_InitStructure; Timer_StructInit(&Timer_InitStructure); Timer_InitStructure.Prescaler = 71; // 预分频系数(72MHz/72=1MHz计数时钟) Timer_InitStructure.CounterMode = Timer_CounterMode_Up; Timer_InitStructure.AutoReload = 1000; // 1ms溢出 Timer_Init(TIMER6, &Timer_InitStructure); // 2. 使能定时器中断 Timer_ITConfig(TIMER6, Timer_IT_Update, ENABLE); NVIC_EnableIRQ(TIMER6_IRQn); // 3. 串口DMA接收配置(同前) // 4. 在UART接收中断/回调中重启定时器 void UART0_IRQHandler(void) { if (UART_GetITStatus(UART0, UART_IT_RXNE) != RESET) { Timer_Cmd(TIMER6, ENABLE); // 接收到数据,重启定时器 UART_ClearITPendingBit(UART0, UART_IT_RXNE); } } // 5. 定时器中断处理 void TIMER6_IRQHandler(void) { if (Timer_GetITStatus(TIMER6, Timer_IT_Update) != RESET) { Timer_Cmd(TIMER6, DISABLE); // 关闭定时器 Timer_ClearITPendingBit(TIMER6, Timer_IT_Update); // 处理已接收数据 process_received_data(); // 重新启动DMA接收新数据 DMA_SetCurrDataCounter(DMA_CH0, 100); // 重置传输长度 DMA_Cmd(DMA_CH0, ENABLE); // 重新启动DMA } }应用场景:
配置步骤:
// 1. 使能时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA, ENABLE); // DMA时钟 RCC_APBPeriphClockCmd(RCC_APBPeriph_ADC0, ENABLE); // ADC时钟 // 2. 配置GPIO为模拟输入 GPIO_SetFunc(GPIO_PORTA, GPIO_PIN_0, GPIO_FUNC_0); // ADC通道0 // 3. 初始化ADC ADC_InitTypeDef ADC_InitStructure; ADC_StructInit(&ADC_InitStructure); ADC_InitStructure.Resolution = ADC_Resolution_12b; // 12位分辨率 ADC_InitStructure.ScanMode = DISABLE; // 单通道模式 ADC_InitStructure.ContinuousConvMode = ENABLE; // 连续转换 ADC_Init(ADC0, &ADC_InitStructure); // 4. 配置通道 ADC_ChannelConfig(ADC0, ADC_Channel_0, ADC_SampleTime_55_5Cycles); // 通道0,采样时间 // 5. 配置DMA DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA_CH1); // 复位通道1 // ADC→内存传输配置 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC0->DR; // ADC数据寄存器 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_buf; // 存储缓冲区 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 外设→内存 DMA_InitStructure.DMA_BufferSize = 50; // 传输50个数据 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址固定 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16位数据 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 16位数据 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式(采集满后自动从头开始) DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 高优先级 DMA_Init(DMA_CH1, &DMA_InitStructure); // 6. 关联DMA与ADC ADC_DMACmd(ADC0, ENABLE); // 使能ADC DMA // 7. 启动ADC与DMA ADC_Cmd(ADC0, ENABLE); ADC_SoftwareStartConvCmd(ADC0, ENABLE); // 软件触发转换 DMA_Cmd(DMA_CH1, ENABLE); // 启动DMAQ1:DMA 传输没有启动 / 没有反应?
A1:
DMA_Cmd(DMA_CHx, ENABLE)启动传输UART_DMACmd(UARTx, UART_DMA_Rx/Tx, ENABLE)Q2:DMA 传输数据错误或乱码?
A2:
__align(4)修饰数组)Q3:DMA 传输完成后没有触发中断?
A3:
DMA_ITConfig(DMA_CHx, DMA_IT_TC/DMA_IT_ERR, ENABLE)使能中断Q4:DMA 传输影响系统性能 / 导致其他功能异常?
A4:
Q5:串口 DMA 接收时,数据丢失或不完整?
A5:
Q6:ADC+DMA 采集的数据总是 0 或固定值?
A6:
Q7:使用 DMA 时系统死机,但无错误标志?
A7:
DMA_Cmd(DMA_CHx, DISABLE)暂时关闭 DMA从简单案例入手:先掌握内存→内存的数据搬运,理解 DMA 基本工作流程
// 内存到内存传输示例 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory; // 内存→内存 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)src_buf; // 源地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)dst_buf; // 目标地址善用 HAL 库函数:HC32L130 提供完善的 HAL 库,可大幅简化 DMA 配置,减少寄存器操作错误
调试技巧:
资源规划:
DMA 是 HC32L130 等现代 MCU 的重要功能,能显著提升系统性能和实时性。通过本文介绍的串口和 ADC 应用案例,你已掌握 DMA 最常见的使用场景。建议先在开发板上实践基础例程,再尝试结合定时器等外设实现更复杂的功能,逐步建立对 DMA 技术的深入理解。