使用STM32 HAL库实现ADC DMA多通道采集

利用stm32的adc可以采集多路模拟量,使用DMA方式非常简答方便。本文章采用使用广泛的stm32f103c8系列芯片。

下面程序的功能:

1、对DMA中采集到的4个adc数据进行中值滤波和算术平均值滤波,确定各个通道的电压平均值。

2、使用软件触发或者定时器触发方式连续采集10次数据

一、软件触发方式

1、配置你相关的cube设置,这里不在赘述。直接上adc配置以及讲解

2、ADC配置

如果你打开了不连续转换,那么就不能再打开连续转换,这里我打开演示一下它的用途

在这里的55.5Cycles代表着采样时间,注意:采样时间太小会导致采样时间不准确,越大采样越精确,但是会影响你的采样速度。一般选用55.5,想要详细了解adc转换时间计算的,可以直接划到最下面看。

3、DMA配置:

DMA中断默认打开,ADC中断可以不打开。

4、代码部分:

时钟选择72Mhz,就可以生成代码了

main.c中:初始化

/*****************************ADC*************************/
  HAL_ADCEx_Calibration_Start(&hadc1 );//adc校准
  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)My_adcData, adc_max );

adc.c

这里一定要定义的uint16_t 的数据,因为我们在Cube选择的就是Half Word 类型的数据

uint16_t My_adcData [adc_max]={0};
adcValue_type adcValue ;




/* USER CODE BEGIN 1 */
	/*
	*adc数据处理
	*每通道的数据进行10次获取,数据的每一组的第一个和最后一个不要,并且将剩下的进行取平均值
	*
	*/
void ADC_dispose (void)
{
	adcValue .value1=adcValue .value2=adcValue .value3=adcValue .value4 =0;
	HAL_ADC_Start_DMA(&hadc1, (uint32_t *)My_adcData,adc_max);//因为你选择的软件触发,所以每次采集都需要开启一次
	static   uint8_t i;
	for(i=1;i<=8;i++){                       							 //遍历10次,进行滤波
		adcValue .value1 += My_adcData[0+4*i]*330/4096;					
		adcValue .value2 += My_adcData[1+4*i]*330/4096;
		adcValue .value3 += My_adcData[2+4*i]*330/4096;
		adcValue .value4 += My_adcData[3+4*i]*330/4096;
	}
	adcValue .value1 = adcValue .value1/8 ;
	adcValue .value2 = adcValue .value2/8 ;
	adcValue .value3 = adcValue .value3/8 ;
	adcValue .value4 = adcValue .value4/8 ;

	if(adcValue .value1<5)adcValue .value1=0;
}
/* USER CODE END 1 */

adc.h

extern  uint16_t My_adcData [adc_max];
typedef struct {
	uint16_t value1;
	uint16_t value2;
	uint16_t value3;
	uint16_t value4;
}adcValue_type;

extern  adcValue_type adcValue ;


void ADC_dispose (void);

剩下的可以直接调用ADC_dispose ();函数,然后直接串口打印或者显示

adcValue .value1、adcValue .value2、adcValue .value3、adcValue .value4的数值就可以了

二、定时器触发方式

1、cube配置

在上面的软件触发方式讲解的内容中,需要改一下下面的部分

TIM部分:

开中断

ADC部分:

2、代码部分

adc.c

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
	printf("adc1:%d,adc2:%d,adc3:%d,adc:%d\r\n",ADC_value[0],ADC_value[1],ADC_value[2],ADC_value[3]);
}

main.c

HAL_ADCEx_Calibration_Start(&hadc1);    //ADC校准
HAL_TIM_Base_Start_IT(&htim3);			//开启定时器
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0]));  
printf("定时器触发ADC-DMA采集\r\n");  

这样你的代码就会输出这四个通道的ADC值了。

3、输出结果

三、ADC转换时间的计算

adc每一次转换过程所需要的时间被称为转换时间。时间长短取决于ADC的工作频率和采样周期两个参数。

下面我会介绍一个非常简单的时间计算

转换时间的计算公式为:     转换时间T=采样周期+12.5周期

计算过程:已知时钟频率是12MHz,那么一个周期就是  T=1/f=1/12=0.0833333

55.5+12.5=68个周期

那么时间就是   68* 0.0833333  = 5.66666667us

非常的简单。

四、遇到的问题总结

1、检查MX_DMA_Init();是否在MX_ADC1_Init();之前调用,不然程序会死掉

2、如果ADC_Valuesuint32_t类型的,并不影响数据搬运行为,但访问ADC_Values [0]时,得到的uint32_t类型的数值是通道ch1ch2合并而来的,还要取高16位和低16位将两帧分开。对于每一帧,低12位是数据,剩余的4位被0填充。

3、adc通常,采样周期应该大于等于转换时间,以确保在每次转换之间有足够的时间。采样时间可以设置。检查转换时间是否够用!!Sampling Time不够用的话程序可能会死在 HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Values,ADC_MAX_NUM);

五、stm32的串口重定向代码

在usart.c中添加以下代码,并打开你神奇的微库

/* USER CODE BEGIN 0 */
#include "stdio.h"

int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE * f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1,&ch, 1, 0xffff);
  return ch;
}


/* USER CODE END 0 */

然后你就可以随意的 printf 了!

printf("本文章编辑于山东潍坊学院\r\n");  

六、结束语

以上就是本文章的全部内容,供大家参考,如有错误,还希望大家指出,一起进步!

这个ADC-DMA采集数据我用在了做一个小四轴遥控器上,大家有兴趣可以看看。

小四轴遥控器摇杆数据采集_哔哩哔哩_bilibili

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32 HAL库实现ADC DMA多通道采集

发表评论