stm32 HAL库 ADC+DMA多通道采集

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("本文章编辑于""Weifang University""\r\n"); 

六、结束语

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

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

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

定时器code数据处理数据采集文章编辑debugwordnvc计算公式
  • 本文作者:李琛
  • 本文链接: https://wapzz.net/post-12460.html
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
本站部分内容来源于网络转载,仅供学习交流使用。如涉及版权问题,请及时联系我们,我们将第一时间处理。
文章很赞!支持一下吧 还没有人为TA充电
为TA充电
还没有人为TA充电
0
  • 支付宝打赏
    支付宝扫一扫
  • 微信打赏
    微信扫一扫
感谢支持
文章很赞!支持一下吧
关于作者
2.3W+
5
0
1
WAP站长官方

OpenAI竞对用256轮对话「灌醉」大模型,Claude被骗造出炸弹!

上一篇

谷歌在Pixel 8上禁用自家大模型!会占用大量手机内存

下一篇
  • 复制图片
按住ctrl可打开默认菜单