[通用ARM系列] HC32F10x 系列单片机的 DMA(直接内存访问)模块来实现 ADC 数据的自动传输

[复制链接]
 楼主| 734774645 发表于 2025-2-27 11:10 | 显示全部楼层 |阅读模式
AD, DM, ADC, DMA, HC
代码功能概述
ADC 配置:配置 ADC1 和 ADC2 为规则同步模式,采集两个通道的模拟信号。
DMA 配置:配置 DMA1 通道 1,将 ADC1 的转换结果自动传输到内存数组 ADC_DualConvertedValueTab 中。
中断处理:当 DMA 传输完成时,触发中断,用户可以在中断中处理采集到的数据。

(1) 系统时钟配置 (RCC_Configuration)
  1. void RCC_Configuration(void)
  2. {
  3.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  // 使能 DMA1 时钟
  4.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);  // 使能 ADC1、ADC2、AFIO 和 GPIOA 时钟
  5. }
功能:使能 DMA1、ADC1、ADC2、AFIO 和 GPIOA 的时钟。

关键点:
DMA1 挂载在 AHB 总线上,因此需要使能 RCC_AHBPeriph_DMA1。
ADC1 和 ADC2 挂载在 APB2 总线上。

GPIO 配置 (GPIO_Configuration)
  1. void GPIO_Configuration(void)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;
  4.        
  5.     // 配置 PA1 和 PA2 为模拟输入
  6.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
  7.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  // 浮空输入模式
  8.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 速度 50MHz
  9.     GPIO_Init(GPIOA, &GPIO_InitStructure);  // 初始化 GPIOA
  10. }
功能:配置 PA1 和 PA2 为模拟输入模式,用于 ADC 采样。

关键点:
ADC 通道 1 对应 PA1,通道 2 对应 PA2。

ADC 配置 (ADC_Configuration)
  1. void ADC_Configuration(void)
  2. {
  3.     ADC_InitTypeDef ADC_InitStructure;
  4.        
  5.     ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;  // 规则同步模式
  6.     ADC_InitStructure.ADC_ScanConvMode = DISABLE;  // 禁用扫描模式
  7.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  // 使能连续转换
  8.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 无外部触发
  9.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 数据右对齐
  10.     ADC_InitStructure.ADC_NbrOfChannel = 1;  // 1 个通道
  11.     ADC_Init(ADC1, &ADC_InitStructure);  // 初始化 ADC1
  12.     ADC_Init(ADC2, &ADC_InitStructure);  // 初始化 ADC2

  13.     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);  // 配置 ADC1 通道 1
  14.     ADC_RegularChannelConfig(ADC2, ADC_Channel_2, 1, ADC_SampleTime_55Cycles5);  // 配置 ADC2 通道 2
  15.        
  16.     ADC_ExternalTrigConvCmd(ADC2, ENABLE);  // 使能 ADC2 外部触发
  17.     ADC_DMACmd(ADC1, ENABLE);  // 使能 ADC1 的 DMA 请求
  18.        
  19.     ADC_Cmd(ADC1, ENABLE);  // 使能 ADC1
  20.     ADC_Cmd(ADC2, ENABLE);  // 使能 ADC2
  21.        
  22.     ADC_SoftwareStartConvCmd(ADC1, ENABLE);  // 软件启动 ADC1 转换
  23. }
功能:配置 ADC1 和 ADC2 为规则同步模式,并启动 ADC1 的转换。

关键点:
ADC_Mode_RegSimult:ADC1 和 ADC2 同时转换。
ADC_DMACmd:使能 ADC1 的 DMA 请求,将转换结果通过 DMA 传输到内存。

DMA 配置 (DMA_Configuration)
  1. void DMA_Configuration(void)
  2. {
  3.     DMA_InitTypeDef DMA_InitStructure;
  4.        
  5.     DMA_DeInit(DMA1, DMA_Channel1);  // 复位 DMA1 通道 1
  6.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;  // 外设地址(ADC1 数据寄存器)
  7.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_DualConvertedValueTab;  // 内存地址
  8.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  // 传输方向:外设到内存
  9.     DMA_InitStructure.DMA_BufferSize = 4;  // 缓冲区大小(4 个数据)
  10.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // 外设地址不递增
  11.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  // 内存地址递增
  12.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;  // 外设数据宽度:32 位
  13.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;  // 内存数据宽度:32 位
  14.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // 循环模式
  15.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;  // 高优先级
  16.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  // 禁用内存到内存模式
  17.     DMA_Init(DMA1, DMA_Channel1, &DMA_InitStructure);  // 初始化 DMA1 通道 1
  18.        
  19.     DMA_ITConfig(DMA1, DMA_Channel1, DMA_IT_TC, ENABLE);  // 使能 DMA 传输完成中断
  20.     DMA_Cmd(DMA1, DMA_Channel1, ENABLE);  // 使能 DMA1 通道 1
  21. }
功能:配置 DMA1 通道 1,将 ADC1 的转换结果自动传输到内存数组 ADC_DualConvertedValueTab 中。

关键点:
DMA_Mode_Circular:循环模式,传输完成后自动重新开始。
DMA_IT_TC:使能传输完成中断。

NVIC 配置 (NVIC_Configuration)
  1. void NVIC_Configuration(void)
  2. {
  3.     NVIC_InitTypeDef NVIC_InitStructure;
  4.   
  5.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;  // DMA1 通道 1 中断
  6.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;  // 抢占优先级
  7.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;  // 子优先级
  8.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  // 使能中断
  9.     NVIC_Init(&NVIC_InitStructure);
  10. }
功能:配置 DMA1 通道 1 的中断优先级并使能中断。


DMA 中断处理 (DMA1_Channel1_IRQHandler)
  1. void DMA1_Channel1_IRQHandler(void)
  2. {
  3.     DMA_ClearITPendingBit(DMA1_IT_TC1);  // 清除 DMA 传输完成中断标志

  4.     // 当进入 DMA 完成中断,意味数据采集完成
  5.     // 此处可直接对 ADC_DualConvertedValueTab 数据进行分析
  6. }
功能:在 DMA 传输完成时触发中断,用户可以在中断中处理采集到的数据。

关键点:
DMA_ClearITPendingBit:清除中断标志。

主函数 (main)
  1. int main()
  2. {
  3.     RCC_Configuration();  // 配置时钟
  4.     GPIO_Configuration();  // 配置 GPIO
  5.     DMA_Configuration();  // 配置 DMA
  6.     ADC_Configuration();  // 配置 ADC
  7.     NVIC_Configuration();  // 配置 NVIC

  8.     while (1) {}
  9. }
功能:初始化系统并启动 ADC 和 DMA。


 楼主| 734774645 发表于 2025-2-27 11:11 | 显示全部楼层
该代码通过 DMA 实现了 ADC 数据的自动传输,减少了 CPU 的负担。通过配置 ADC、DMA 和 NVIC,可以高效地采集和处理模拟信号。

o88ne 发表于 2025-3-4 09:28 来自手机 | 显示全部楼层
如果你的 ADC 采样通道不是 PA0 和 PA1,可以修改 GPIO_Pin_x 选择其他 ADC 采样通道
zhengshuai888 发表于 2025-3-6 08:22 来自手机 | 显示全部楼层
用DMA收发数据,处理效率更高。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

210

主题

3585

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部

210

主题

3585

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部