STM32基于hal库的adc以DMA的多通道采样以及所遇问题解决

目录

准备

配置

步骤

 总结


 

准备

正点原子的STM32F103ZET6开发板(精英版)

CUBEMX配置软件

KEIL5

配置

 右对齐就是正常的数据格式。左对齐除以16后得正常数据。(当输出非常大时考虑是否改了对齐方式,默认都是右对齐)

 扫描模式,连续转换模式使能。(多通道下扫描模式自动使能)

采样周期 SamplingTime 越大越精确,越小则则会频繁触发DMA中断(在开启dma中断时,我试了在14M的adc时钟程序进不来while(因为频繁触发DMA中断)

看数据手册,知道三个adc中(adc1,adc2,adc3只有adc1和adc3能用DMA通道。

 ADC的时钟不能超过14Mhz,

配置外设到内存(cubeMX自动配置好了),外设adc地址是不变的,而DMA把数据存到存储器的地址是增长的。

Circular循环模式连续搬运adc数据。

在配置DMA时,因为ad的精度是12位,最大也就是4096,而DMA转储adc是一个通道接着一个通道去存储的,所以转储的时候dma搬运半字(stm32 32位为一个字,半字16位 最大位4096*16)就可以了,节省dma资源提升速度。然后在程序里用一个缓存为uint16_t去接受就不会有问题。

 __IO uint16_t adcbuf[100]={0};

 开启DMA

HAL_ADC_Start_DMA(&hadc1,  (uint32_t*)&adcbuf,100);//

不推荐的的一种配置,也不是不可以,接受数据缓存定义位32位

 

正常情况下我们还是配置成半字长的

 

 

 而我走的一个坑点就adcbuf这个DMA转移数据的缓存数组定义成立uint32_t,(在dma半字转移下)结果就翻船。。。

想着不应该啊,大类型接受小类型数据C是不会出问题的。

  int temp=0;
    for (int i=0 ;i < 100; ){
		temp=i;
		//adcreal[0]+=  adcbuf[i++]*3.3/4096;
		//adcreal[1]+= adcbuf[i++]*3.3/4096;
 		 printf(" %d-Channel1:%d\r\n", temp,adcbuf[i++]);
 		 printf(" %d-Channel2:%d\r\n",temp ,adcbuf[i++]);
  
	   }

依次取两个通道的数据(i为偶数是通道1,i为奇数则是通道二),看串口打印结果(两个通道,一个接3.3v一个接5v电压)

 

 前50是3.3v电压采集,后50是接地采集结果,完全乱了。这种情况下把接受类型改成uint16_t就解决了。

步骤

定义接受缓存(定义成单字转移)

 __IO uint16_t adcbuf[100]={0};
float adcreal[2]={0};

开启接受 

   HAL_ADC_Start_DMA(&hadc1,  (uint32_t*)&adcbuf,100);//

打印数据 (平均滤波)

HAL_Delay(1000);
	 adcreal[0]=0.0;
	 adcreal[1]=0.0;
	 
    for (int i=0 ;i < 100; ){
	 
		 adcreal[0]+=  adcbuf[i++]*3.3/4096;
		 adcreal[1]+= adcbuf[i++]*3.3/4096;
 		 
  
	   }
	 
		 printf(" -Channel1:%1.3f\r\n",adcreal[0]/50);
		 printf(" -Channel5:%1.3f\r\n",adcreal[1]/50);
		 printf("\r\n");

 结果

 

 总结

配置时单字dma转移,uint32_t类型定义缓存。

配置时半字dma转移,uint16_t类型定义接受缓存。

 

物联沃分享整理
物联沃-IOTWORD物联网 » STM32基于hal库的adc以DMA的多通道采样以及所遇问题解决

发表评论