STM32之ADC多路采样开发踩过的坑

最近开发基于PH、ORP数据采集项目,两路PH,两路ORP所以用到了STM32ADC多路采样,

不足之处望指正。

一、存在问题

1、采样数据不准确,几路数据相同。

2、通道间数据互相影响,不准确等。

二、开发过程

非DMA模式

最开始只是在单通道非DMA模式下增加多路通道,结果AD采样数据显示都一样,经过各种修改未发现问题。

 DMA模式

在思绪百般无果下,想了下会不会是多路采样导致CPU负担过重,于是想起了DMA(个人理解DMA就是一个中转站,起到存数据,取数据的过程,这个存取过程不需要CPU直接参与,采样数据过大、过多时利用DMA收集数据,再处理,减轻了CPU负担),资源查询过程中又发现了一个问题,在非DMA模式下,多路ADC采集的数据储存位置是相同的,出现了数据覆盖,所以才会有互相影响,数据相同的奇怪现象。然而,开启ADC多通道DMA模式后采集数据还是存在互相干扰,最后查询资料得到的结论是,未连接的端口处于浮空状态,会受干扰,最后将每个采样口接通,恢复正常。

三、下面分享一下源码以及细节部分吧

1、ADC采样GPIO端口配置,这里配置六个PA端口

 void ADC1_GPIO_Config(void)
{ 
  GPIO_InitTypeDef GPIO_InitStructure;    
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		   
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOA,GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6);
		
}

2、ADC和DMA一起配置

void ADC1_Mode_Config(void)
{

  ADC_InitTypeDef ADC_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  DMA_DeInit(DMA1_Channel1);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCDAT;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 6;	
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  DMA_Cmd(DMA1_Channel1, ENABLE); 
	
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	
	
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 
  ADC_InitStructure.ADC_ScanConvMode = ENABLE; 		 
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;			 
  ADC_InitStructure.ADC_NbrOfChannel =6;  			
  ADC_Init(ADC1, &ADC_InitStructure);
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);   
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 ); 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 ); 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5);
  ADC_DMACmd(ADC1, ENABLE);	
  ADC_Cmd(ADC1, ENABLE);
  ADC_ResetCalibration(ADC1);  

  while(ADC_GetResetCalibrationStatus(ADC1));

  ADC_StartCalibration(ADC1);

  while(ADC_GetCalibrationStatus(ADC1));  

  ADC_SoftwareStartConvCmd(ADC1, ENABLE);  
}

3、注意细节

DMA_InitStructure.DMA_BufferSize = 6;这是配置DMA数据储存大小,由于STM32内置ADC采样为12位,所以一个IO口采集的数据咱们用16来储存,所以六个IO口填6。

ADC_DMACmd(ADC1, ENABLE);    这句是ADC请求DMA关键使能句,也就是ADC与DMA的桥梁。

其他区别对比单路ADC采样修改即可, DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCDAT,这里ADCDAT定义为u16ADCDAT[5]数组,刚好储存六个IO口ADC值,为了储存数据强制转化为32位,在主函数中直接读取读取数组即为对应ADC值。

 

    

  • 9
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
STM32上进行多路ADC采样时,可以使用循环扫描模式。循环扫描模式允许我们一次性采样多个通道,每个通道的采样结果都被存储在相应的寄存器中。 以下是一个简单的示例代码,实现了ADC1、ADC2、ADC3三个通道的循环扫描采样: ```c // 定义通道数组 uint32_t channels[] = {ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2}; // 初始化ADC HAL_ADC_Init(&hadc1); // 配置ADC采样模式 ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; HAL_ADC_ConfigChannel(&hadc1, &sConfig); // 配置循环扫描模式 hadc1.Init.ScanConvMode = ENABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.NbrOfConversion = 3; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; HAL_ADC_Init(&hadc1); // 启动ADC HAL_ADC_Start(&hadc1); // 循环采样 for (;;) { // 等待采样完成 HAL_ADC_PollForConversion(&hadc1, 100); // 读取采样结果 uint16_t result1 = HAL_ADC_GetValue(&hadc1); uint16_t result2 = HAL_ADC_GetValue(&hadc1); uint16_t result3 = HAL_ADC_GetValue(&hadc1); // 处理采样结果 // ... // 启动下一轮采样 HAL_ADC_Start(&hadc1); } ``` 在上面的代码中,我们首先定义了一个通道数组 `channels`,其中包含了需要采样的三个通道。然后我们通过 `HAL_ADC_Init` 函数初始化了ADC,并设置了采样模式。接着,我们将 `hadc1.Init.ScanConvMode` 设置为 `ENABLE`,表示启用循环扫描模式,并将 `hadc1.Init.NbrOfConversion` 设置为 3,表示采样三个通道。最后,我们通过调用 `HAL_ADC_Start` 函数启动ADC。 在循环中,我们首先调用 `HAL_ADC_PollForConversion` 函数等待采样完成,然后通过 `HAL_ADC_GetValue` 函数读取每个通道的采样结果,最后对采样结果进行处理。最后,我们再次调用 `HAL_ADC_Start` 函数启动下一轮采样

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值