GD32F470之ADC0+ADC2+DMA(不中断)+多通道采集+吐槽DMA的库和C++的兼容问题

本文主要介绍了在GD32F470单片机上使用ADC0和ADC2配合DMA进行多通道采集的过程中遇到的C++兼容性问题,包括枚举类型限制及库函数的调整。详细展示了ADC和DMA的配置代码,并提到由于无缓存,数据读取需直接访问adcx_scr_data变量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先申明,本栏目用的都是GD32F470芯片240M,软件用的是keil,编写用的是C++(其实和C没有区别).,

吐槽的点:

1.因为我用的是C++,枚举类型是不能运算的。只能赋值。需要自己修改库函数
在这里插入图片描述
这是我自己的改的:
在这里插入图片描述
2.
GD32的 2016-08-15, V1.0.0, firmware update for GD32F4xx的库,连__cplusplus都写错,后面的新版本就没有了。

在这里插入图片描述
3.
同时如果要用C++,那么就注释掉这句。因为重复编译了。
3.0.0版本的库就没有了这一句。
在这里插入图片描述

ADC0+DMA配置代码:

IO配置:

	  rcu_periph_clock_enable(RCU_GPIOA);
		rcu_periph_clock_enable(RCU_GPIOB);
		//A5 :A
		//A4 : B
		//B1 : C
		gpio_mode_set(GPIOA,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_5|GPIO_PIN_4);
	
	
    gpio_mode_set(GPIOB,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_1);

ADC0寄存器配置:

注意:打开了扫描模式。还要打开连续模式才会一直循环采样
通道号和GPIO引脚的复用功能有关,可以查看芯片手册。
例如
在这里插入图片描述

	rcu_periph_clock_enable(RCU_ADC0);
		   /* config ADC clock */ //120M /4
    adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
	
	//IO初始化
		ADC0_Io_Config_Init();
		ADC0_DMA_Config_Init();
		
	/* ADC channel length config */
    adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,ADC0_CHANNEL_NUM);
    /* ADC regular channel config */
  	adc_regular_channel_config(ADC0,0,ADC_CHANNEL_5,ADC_SAMPLETIME_28); //A
    adc_regular_channel_config(ADC0,1,ADC_CHANNEL_4,ADC_SAMPLETIME_28);//B
    adc_regular_channel_config(ADC0,2,ADC_CHANNEL_9,ADC_SAMPLETIME_28);//C

    /* ADC external trigger enable */
    adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
    
    /* enable ADC interface */
    adc_enable(ADC0);
		delay_1ms(1);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC0);
    
    /* ADC DMA function enable */
    adc_dma_mode_enable(ADC0);
    adc_dma_request_after_last_enable(ADC0);
    /* ADC contineous function enable */
		//打开了扫描模式。还要打开连续模式才会一直循环采样
    adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,ENABLE); 
		adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);
    /* ADC software trigger enable */
  //  adc_software_trigger_enable(ADC0,ADC_REGULAR_CHANNEL);

ADC0的DMA配置(不中断):

DMA通道的对应关系可以查看手册
在这里插入图片描述

	rcu_periph_clock_enable(RCU_DMA1);
	    /* ADC_DMA_channel configuration */
    dma_single_data_parameter_struct dma_single_data_parameter_ado0;
    
    /* ADC DMA_channel configuration */
    dma_deinit(DMA1,DMA_CH0);
    
    /* initialize DMA single data mode */
    dma_single_data_parameter_ado0.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));
    dma_single_data_parameter_ado0.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_single_data_parameter_ado0.memory0_addr = (uint32_t)(adc0_scr_data);
    dma_single_data_parameter_ado0.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//内存自增
    dma_single_data_parameter_ado0.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;//这位数要和你的adc_value的类型一致
    dma_single_data_parameter_ado0.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
    dma_single_data_parameter_ado0.direction = DMA_PERIPH_TO_MEMORY;
    dma_single_data_parameter_ado0.number = ADC0_CONVERSION_NUM;
    dma_single_data_parameter_ado0.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA1,DMA_CH0,&dma_single_data_parameter_ado0);
		
		dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);
	
		#if DMA1_CH0_DONE_INT 
		nvic_irq_enable(DMA1_Channel0_IRQn, 0, 2);
		dma_interrupt_enable(DMA1,DMA_CH0,DMA_CHXCTL_FTFIE);
		#endif
    /* enable DMA channel */
    dma_channel_enable(DMA1,DMA_CH0);

中断函数:

extern "C"void DMA1_Channel0_IRQHandler()
{
		if(SET == dma_interrupt_flag_get(DMA1, DMA_CH0,DMA_INT_FLAG_FTF))
		{
				dma_interrupt_flag_clear(DMA1, DMA_CH0,DMA_INT_FLAG_FTF);
				
			//	adc0_DMA_done_flag=1;
	
				//printf("132131\r\n");
		}
}

ADC2+DMA配置代码:

io配置:

 rcu_periph_clock_enable(RCU_GPIOC);	
		 rcu_periph_clock_enable(RCU_GPIOF);	
		 gpio_mode_set(GPIOF,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_3|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);
	

		 gpio_mode_set(GPIOC,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_0);

ADC2配置:

	rcu_periph_clock_enable(RCU_ADC2);
		   /* config ADC clock */
    adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
		//IO初始化
		ADC2_Io_Config_Init();
		ADC2_DMA_Config_Init();

		    /* ADC channel length config */
    adc_channel_length_config(ADC2,ADC_REGULAR_CHANNEL,ADC2_CHANNEL_NUM);
    /* ADC regular channel config */

    adc_regular_channel_config(ADC2,0,ADC_CHANNEL_10,ADC_SAMPLETIME_28);

    adc_regular_channel_config(ADC2,1,ADC_CHANNEL_9,ADC_SAMPLETIME_28);//

    adc_regular_channel_config(ADC2,2,ADC_CHANNEL_15,ADC_SAMPLETIME_28);//

    adc_regular_channel_config(ADC2,3,ADC_CHANNEL_4,ADC_SAMPLETIME_28);//

    adc_regular_channel_config(ADC2,4,ADC_CHANNEL_5,ADC_SAMPLETIME_28);//
	
		adc_regular_channel_config(ADC2,5,ADC_CHANNEL_6,ADC_SAMPLETIME_28);//

    /* ADC external trigger enable */
    adc_external_trigger_config(ADC2,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC2,ADC_DATAALIGN_RIGHT);
		
		
		 /* ADC contineous function enable */
		//打开了扫描模式。还要打开连续模式才会一直循环采样
    adc_special_function_config(ADC2,ADC_CONTINUOUS_MODE,ENABLE); 
		adc_special_function_config(ADC2,ADC_SCAN_MODE,ENABLE);
    /* enable ADC interface */
    adc_enable(ADC2);
		delay_1ms(1);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC2);
    
    /* ADC DMA function enable */
    adc_dma_mode_enable(ADC2);
    adc_dma_request_after_last_enable(ADC2);//1:当 DMA=1,在每个规则转换结束时 DMA 机制产生一个 DMA 请求。

    /* ADC software trigger enable */
  //  adc_software_trigger_enable(ADC1,ADC_REGULAR_CHANNEL);

DMA配置(不中断):

	 /* ADC_DMA_channel configuration */
    dma_single_data_parameter_struct dma_single_data_parameter_ado1;
     rcu_periph_clock_enable(RCU_DMA1);
    /* ADC DMA_channel configuration */
    dma_deinit(DMA1,DMA_CH1);
    
    /* initialize DMA single data mode */
    dma_single_data_parameter_ado1.periph_addr = (uint32_t)(&ADC_RDATA(ADC2));
    dma_single_data_parameter_ado1.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_single_data_parameter_ado1.memory0_addr = (uint32_t)(adc2_scr_data);
    dma_single_data_parameter_ado1.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//内存自增
    dma_single_data_parameter_ado1.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;//这位数要和你的adc_value的类型一致
    dma_single_data_parameter_ado1.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
    dma_single_data_parameter_ado1.direction = DMA_PERIPH_TO_MEMORY;
    dma_single_data_parameter_ado1.number = ADC2_CONVERSION_NUM;
    dma_single_data_parameter_ado1.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA1,DMA_CH1,&dma_single_data_parameter_ado1);
		
		//用这个来选择外设
		dma_channel_subperipheral_select(DMA1, DMA_CH1, DMA_SUBPERI2);
	
		#if  DMA1_CH1_DONE_INT 
			nvic_irq_enable(DMA1_Channel1_IRQn, 0, 2);
			dma_interrupt_enable(DMA1,DMA_CH1,DMA_CHXCTL_FTFIE);
		#endif
    /* enable DMA channel */
    dma_channel_enable(DMA1,DMA_CH1);

中断函数:


extern "C"void DMA1_Channel1_IRQHandler()
{
		if(SET == dma_interrupt_flag_get(DMA1, DMA_CH1,DMA_INT_FLAG_FTF))
		{
				dma_interrupt_flag_clear(DMA1, DMA_CH1,DMA_INT_FLAG_FTF);
				
			//	adc2_DMA_done_flag=1;
	
				//printf("132131\r\n");
		}
}

结束:

由于没有cache,所以需要取数据的时候就直接读取adcx_scr_data就好就好了。
adcx_scr_data就是adc0_scr_data和adc2_scr_data

if(dma_flag_get(DMA1,DMA_CH1,DMA_INTF_FTFIF))
			{
		
					dma_flag_clear(DMA1,DMA_CH1,DMA_INTC_FTFIFC);
					}
### 关于GD32F470 ADC的使用教程 #### 1. GD32F470 ADC硬件特性 GD32F470是一款基于ARM Cortex-M4内核的高性能微控制器,内置多个模数转换器(ADC),支持高精度的数据采集。该系列芯片通常配备两个独立的12ADC模块,分别命名为`ADC0``ADC2`[^3]。 - **ADC数量与分辨率** GD32F470提供两组12位分辨率的ADC,每组具有多达16个外部输入通道以及若干内部信号源通道[^3]。 - **采样速率** 支持高达2 MSPS的最大采样率,适用于快速变化信号的捕捉。 --- #### 2. 配置步骤概述 为了在GD32F470上启用ADC功能并完成数据采集,以下是配置的关键环节: ##### (a) 初始化时钟树结构 确保ADC外设及其关联总线的时钟已使能。例如,在固件中可以通过如下代码片段实现: ```c /* 启用ADC相关的时钟 */ rcu_periph_clock_enable(RCU_ADC); ``` ##### (b) 设置工作模式 选择适合应用需求的工作模式,比如单次转换、连续转换或者扫描模式等。具体操作可通过初始化结构体来定义参数集: ```c adc_parameter_struct adc_initpara; adc_initpara.continuous_conversion = ENABLE; /* 开启连续转换 */ adc_initpara.scan_mode = ENABLE; /* 打开扫描模式 */ adc_initpara.external_trigger_convert = DISABLE;/* 使用外部触发 */ adc_initpara.data_alignment = ADC_DATAALIGN_RIGHT; /* 右对齐数据格式 */ adc_initpara.end_of_conversion_interrupt = DISABLE; /* 禁止EOC中断 */ adc_init(ADC0, &adc_initpara); /* 应用于ADC0实例化 */ ``` ##### (c) 定义输入通道 指定要使用的模拟输入端口,并将其映射到相应的ADC通道编号。例如,如果目标是连接至PC1引脚,则需执行以下命令: ```c gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_MAX, GPIO_PIN_1); adc_channel_config(ADC0, ADC_CHANNEL_11, ADC_SAMPLETIME_56CYCLES); /* PC1对应ADC0 CH11 */ ``` ##### (d) DMA传输优化 对于大批量或多路同步采样的场景,推荐引入直接存储访问(DMA)机制以减轻CPU负担。下面展示了一个简单的例子: ```c dma_single_data_transfer(DMA0, DMA_CH2, ENABLE); /* 激活特定DMA信道 */ adc_dma_mode_enable(ADC0); /* 将ADC切换成DMA驱动方式 */ ``` --- #### 3. 实际案例分析——光敏电阻传感器集成 假设需要测量环境光线强度并通过串口打印结果,可参照《GD32F470_光敏电阻光照传感器模块移植手册》中的指导[^4]。其中提到利用PC1作为额外的ADC入口之一,配合软件框架轻松达成目的。 另外,《ADS1115超小型16位模数转换器ADC 4通道模块移植教程》也提供了关于扩展外围设备的经验分享[^2]。尽管此文档主要聚焦I²C协议交互而非本地ADC单元本身,但它同样强调了理解器件地址分配的重要性。 --- #### 4. 注意事项 由于部分官方发行版可能存在兼容性缺陷,特别是针对现代编程范式的适应情况较差,开发者可能自行调整某些底层定义。例如修正错误宏名或重构涉及复杂类型声明的部分逻辑。 此外,务必仔细查阅最新版本的技术参考资料,确认所依赖API的行为是否有所更改。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值