GD32F450板卡的ADC使用规则(附上代码):

文章讨论了STM32ADC使用DMA获取多通道值的方法,指出GD芯片限制了非DMA方式下的通道数量,同时提到GD32F130R8T6的ADC存在通道间干扰问题。作者提供了GD32F450ZGT6使用DMA采集多通道ADC的示例代码,以及如何配置ADC和DMA以避免数据错位。
摘要由CSDN通过智能技术生成

处理要求:不使用DMA可以获取多通道的值吗?

答:根据这个链接网站所描述的:STM32的ADC1采集多条通道 可以不使用DMA功能吗?-电子发烧友网 (elecfans.com)

ST芯片可以,具有转换通道的函数,但GD芯片不行,不使用DMA,最多可以借助扫描模式获取两个通道的值,再多一个就需要DMA了。。

1、主要参照两个链接,一个讲解了GD板卡的ADC规则:

(49条消息) GD32F130FXP6学习笔记六:cortex-m3系列的ADC初识_无痕幽雨的博客-CSDN博客

2、DMA的添加,可以参考这个链接:

 (49条消息) 立创梁山派GD32F450ZGT6--使用DMA实现多通道ADC采集_老怪.的博客-CSDN博客_gd32 多通道adc

void ADC_DMA_Init(void)
{
				/* dma初始化结构体 */
			dma_single_data_parameter_struct dma_single_data_parameter;
	
			/* 使能dma时钟 */
			rcu_periph_clock_enable(RCU_DMA1);
			
			/*   使能规则组通道每转换完成一个就发送一次DMA请求   在扫描模式下   */  
			adc_dma_request_after_last_enable(ADC0); 
	
			//开启ADC0的 DMA功能
			adc_dma_mode_enable(ADC0);
	
			/*   清除 DMA通道0 之前配置    */
			dma_deinit(DMA1, DMA_CH0);
	
			/* DMA初始化配置    */
		 dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));      //设置DMA传输的外设地址为ADC0基地址
		 dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;        //关闭外设地址自增
		 dma_single_data_parameter.memory0_addr = (uint32_t)(ADC_value_arry);           //设置DMA传输的内存地址为 gt_adc_val数组
		 dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;         //开启内存地址自增(因为不止一个通道)
		 dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT; //传输的数据位 为 16位
		 dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;                   //DMA传输方向为 外设往内存
		 dma_single_data_parameter.number = 10;                                      //传输的数据长度为:2个通道 * 每个通道采集5次 
		 dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;                          //设置高优先级
		 dma_single_data_mode_init(DMA1, DMA_CH0, &dma_single_data_parameter);      //将配置保存至DMA0的通道0
		 
		 /* DMA通道外设选择      */
		 dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);
		 
		 /* 使能DMA0通道0循环模式  循环获取数据   */
		 //dma_circulation_enable(DMA1, DMA_CH0);
		 dma_circulation_disable(DMA1, DMA_CH0);
 
		 /* 启动DMA0的通道0功能      */
		 dma_channel_enable(DMA1, DMA_CH0); 
}

其中,ADC的设置为:

		adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,DISABLE);//关闭连续转换
	  adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);//使能多通道扫描

这样,DMA就会自动获取数据,并且自动递增数组地址,存入我们的缓存地址,我使用了一个全局二维数组

uint16_t ADC_value_arry[5][2] = {0};
//DMA是按顺序来获取通道值的,因此若有两
通道,则依次存入[2]中,[5]表示每次获取5个
两通道的数值,共10个数值,我们再用循环的
方式获取对应通道的值即可

该链接对应的原文:

这次调试有些久,缺乏的知识很多,最重要的是ADC的引脚配置为浮空之后,如果没有接入东西,其读取的ADC值是不确定的,所以在测试的时候,一定要把对应的电压接入ADC引脚,测量的值才是准确的。

上代码。

adc.c
#include "adc.h"
 
/***********************
采样次数  30
ADC通道    4
***********************/
uint16_t gt_adc_val[30][4];  //DMA缓冲区
              
// ADC Init
void ADC_DMA_Init(void)
{
    /* DMA初始化功能结构体定义 */
    dma_single_data_parameter_struct dma_single_data_parameter;
	
	/* 使能GPIOC组时钟 */
    rcu_periph_clock_enable(RCU_GPIOC);		
	
	/* 使能ADC0时钟 */
    rcu_periph_clock_enable(RCU_ADC0);		
  
	/* 使能DMA1时钟 */
	rcu_periph_clock_enable(RCU_DMA1);
 
	/*	配置ADC时钟	*/ 
    adc_clock_config(ADC_ADCCK_PCLK2_DIV4);	
	
	/*	配置PC1 PC2 PC3 PC4 为浮空模拟输入模式	*/
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1); // PC1 : ADC012_IN11 
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2); // PC2 : ADC012_IN12 
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_3); // PC3 : ADC012_IN13 
    gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4); // PC4 : ADC012_IN14 
 
	/*	配置ADC为独立模式	*/
    adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
	
    /*	使能连续转换模式	*/
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
	 
    /*	使能扫描模式	*/
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
   
	/*	数据右对齐	*/        
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    
    /*	ADC0设置为规则组  一共使用2个通道		*/  
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 4);
		
    /*	ADC规则通道配置:ADC0的通道11,12,13,14的扫描顺序分别为0,1,2,3;采样时间:15个周期		*/  
	/*	DMA开启之后 gt_adc_val[x][0] = PC1的数据   gt_adc_val[x][3] = PC4的数据  x的范围0-29 */
    adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_11, ADC_SAMPLETIME_15);//PC1
    adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_12, ADC_SAMPLETIME_15);//PC2
	adc_regular_channel_config(ADC0, 2, ADC_CHANNEL_13, ADC_SAMPLETIME_15);//PC3
	adc_regular_channel_config(ADC0, 3, ADC_CHANNEL_14, ADC_SAMPLETIME_15);//PC4
 
	/*	ADC0设置为12位分辨率		*/  
	adc_resolution_config(ADC0, ADC_RESOLUTION_12B); 
	
	/*	ADC外部触发禁用, 即只能使用软件触发		*/  
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
    
    /*	使能规则组通道每转换完成一个就发送一次DMA请求		*/  
    adc_dma_request_after_last_enable(ADC0);  
    
	/*	使能DMA请求		*/  
	adc_dma_mode_enable(ADC0);
    
	/*	使能DMA		*/  	
	adc_enable(ADC0);
    
	/*	等待ADC稳定		*/  
	delay_1ms(1);
    
	/*	开启ADC自校准		*/
    adc_calibration_enable(ADC0); 
 
    /*	清除 DMA通道0 之前配置 	*/
    dma_deinit(DMA1, DMA_CH0);
   
	/*	DMA初始化配置 	*/
	dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));		//设置DMA传输的外设地址为ADC0基地址
	dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;			//关闭外设地址自增
	dma_single_data_parameter.memory0_addr = (uint32_t)(gt_adc_val);				//设置DMA传输的内存地址为 gt_adc_val数组
	dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;			//开启内存地址自增(因为不止一个通道)
	dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;	//传输的数据位 为 16位
	dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;							//DMA传输方向为 外设往内存
	dma_single_data_parameter.number = 4*30;																//传输的数据长度为:4个通道 * 每个通道采集30次
	dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;									//设置高优先级
	dma_single_data_mode_init(DMA1, DMA_CH0, &dma_single_data_parameter);		//将配置保存至DMA1的通道0
	
	/*	DMA通道外设选择		*/
	/*	数据手册的195页根据PERIEN[2:0]值确定第三个参数,例是100 则为DMA_SUBPERI4  	例是010 则为DMA_SUBPERI2 	*/
	/*	我们是ADC0功能,PERIEN[2:0]值为000,故为DMA_SUBPERI0		*/
	dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);
 
	/*	使能DMA1通道0循环模式		*/
	dma_circulation_enable(DMA1, DMA_CH0);
 
	/*	启动DMA1的通道0功能		*/
	dma_channel_enable(DMA1, DMA_CH0); 
	
	/*	开启软件触发ADC转换		*/
	adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL); 
}
 
 
//对DMA保存的数据进行平均值计算后输出
//传入参数:CHx 第几个扫描的数据 
//         根据前面的配置得知:PC1为0 PC2为1 PC3为2 PC4为3
//返回数据:对应扫描的ADC值
unsigned int Get_Adc_Dma_Value(char CHx)
{
	unsigned char i = 0;
	unsigned int AdcValue = 0;
    
    /* 因为采集30次,故循环30次 */
	for(i=0;i<30;i++)
	{
        /*    累加    */
		AdcValue+=gt_adc_val[i][CHx];
	}
    /* 求平均值 */
	AdcValue=AdcValue/30;
    
	return AdcValue;
}
 
adc.h
#ifndef _ADC_h_
#define _ADC_h_
 
#include "gd32f4xx.h"
#include "usart0.h"
#include "stdio.h"
#include "systick.h"
 
 
extern uint16_t gt_adc_val[30][4];  //DMA缓冲区
 
/************************
//之前的单路采集
void ADC_Init(void);
unsigned int Get_ADC_Value(void);
**************************/
void ADC_DMA_Init(void);
unsigned int Get_Adc_Dma_Value(char CHx);
 
#endif
主函数
#include "gd32f4xx.h"
#include "systick.h"
#include "usart0.h"
#include "stdio.h"
#include "adc.h"
 
int main(void)
{
	unsigned char temp_buff[200]; 
	unsigned int  show_buff[4];
	
	nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 优先级分组
	systick_config();																	 //系统滴答定时器   定时1MS
	USART1_Init();
	ADC_DMA_Init();         
	USART0_send_String((unsigned char *)"--开始--");
  while(1)  
	{        
		/*	获取数据		*/
		show_buff[0] = Get_Adc_Dma_Value(0);	//根据扫描顺序得知数组[0] = PC1的数据
		show_buff[1] = Get_Adc_Dma_Value(1);	//根据扫描顺序得知数组[1] = PC2的数据
		show_buff[2] = Get_Adc_Dma_Value(2);	//根据扫描顺序得知数组[2] = PC3的数据
		show_buff[3] = Get_Adc_Dma_Value(3);	//根据扫描顺序得知数组[3] = PC4的数据
		
		/*	串口显示数据		*/
		sprintf((char *)temp_buff, "PC1=%d\r\nPC2=%d\r\nPC3=%d\r\nPC4=%d\r\n",\
			show_buff[0], show_buff[1], show_buff[2], show_buff[3]);					
		USART0_send_String(temp_buff);
		
		/*	串口显示刷新太快,加个延时    */
		delay_1ms(1000);
	}    
}
实际效果
对PC1和PC3接入3.3V,因为ADC是12位的,所以最大采集数为4096,实际采集也接近了4096。

对PC2和PC4接入GND,实际采集也接近0。

注意!引脚不能浮空进行采集!不然数据是不确定的!
————————————————
版权声明:本文为CSDN博主「老怪.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_51930953/article/details/127542174

 4、但这样使用DMA获取各个通道数值的话,会出现一个问题

网友在使用的时,也遇到了我这样的问题:GD32F130R8T6的ADC问题 - - 21ic电子技术开发论坛

就是在一个通道的值改变时,其他通道的值也会跟着改变,这个是ST与GD芯片都会有的问题,需要这样处理:

(49条消息) STM32的ADC多路采集 DMA传输 数据错位_EmbededCoder的博客-CSDN博客

尚未验证。。。

STM32的ADC采样DMA方式通道间有干扰-解决思路 - 腾讯云开发者社区-腾讯云 (tencent.com)

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值