本帖最后由 supermiao123 于 2019-3-7 23:16 编辑
这篇测评带来H7的ADC功能测试,主要带来ADC的DMA采集,采集的是H7的自带DA的输出波形,通过示波器和TFT分别来展示DA输出的波形和AD采集的波形。 由于采集波形,ADC和DAC需要等间隔采集也要等间隔获取,最好的方式就是DMA,用计算好的波形数据给DA输出,AD采集好的数据直接存入数组,最后通过数据转换显示到TFT屏上。这就是大概本次测评的原理。
说到DMA,H7和以往系列的不同在于H7比之前更灵活了,DMA源先通过DMAMUX分配到指定通道,再进入DMA控制器,而之前的DMA应该都是指定通道只能是某几种外设的DMA。
代码生成继续之前的测评,在之前的基础上加上ADC的初始化
加上ADC的DMA
配置DAC
加上DAC的DMA
代码按上图初始化就好了,还有就是记得中断都打开,有可能会用到,不用放着也不碍事。
- __HAL_RCC_VREF_CLK_ENABLE();
- VREFBUF->CSR =0x2;
-
-
- ADC1->CR |= ADC_CR_ADEN;
-
- __HAL_RCC_DMA1_CLK_ENABLE();
-
- DMA1_Stream1->CR |= 0x00012D1E;
- DMA1_Stream1->FCR |= DMA_SxFCR_FEIE ;
- DMA1_Stream1->NDTR =ADC_BUF_SIZE;
- DMA1_Stream1->PAR =(uint32_t)&(ADC1->DR);
- DMA1_Stream1->M0AR =(uint32_t)adc_data;
- DMA1_Stream1->CR |=1;
- ADC1->CR |= ADC_CR_ADSTART;
复制代码
生成好初始化代码后增加上面的代码,START后就开始采集,我选用的DMA模式是ONE_SHOT,就是采完一个序列后就停止,然后刷屏,之后再开始。H7的REF别忘了使能,这里使用的是电源电源做参考。
电压转换如上图所示。
ADC的采样率看DS上写着16位可以3.6MSPS
ADC的时钟框图如下,本程序设置的是17MHz时钟输入不分频。
ADC的速度配置如下图
管脚速度如下图
DAC的用户代码如下所示
- __HAL_RCC_VREF_CLK_ENABLE();
- VREFBUF->CSR =0x2;
- __HAL_RCC_TIM1_CLK_ENABLE();
- TIM1->CR1 = TIM_CR1_ARPE ;
- TIM1->CR2 = TIM_CR2_MMS2_1 | TIM_CR2_MMS_1;
- TIM1->SMCR |= TIM_SMCR_SMS_1 | TIM_SMCR_SMS_2;
- TIM1->DIER |= TIM_DIER_TDE |TIM_DIER_UDE |TIM_DIER_UIE;
- TIM1->EGR |= TIM_EGR_TG;
- TIM1->ARR = 50;
- TIM1->CR1 = TIM_CR1_CEN ;
-
- __HAL_RCC_DMA1_CLK_ENABLE();
-
- DMA1_Stream2->CR = 0x00012D40;
- DMA1_Stream2->FCR |= DMA_SxFCR_FEIE;
- DMA1_Stream2->NDTR =10000;
- DMA1_Stream2->PAR =(uint32_t)&(DAC1->DHR12R1);
- DMA1_Stream2->M0AR =(uint32_t)dac_data;
-
-
- DAC1->CR |= DAC_CR_DMAEN1 |DAC_CR_TEN1|DAC_CR_TSEL1_0|DAC_CR_TSEL2_0;
- DAC1->CR |= DAC_CR_EN1 ;
-
- DMA1_Stream2->CR |=1;
复制代码
除了要注意基准外,DAC的DMA时钟需要TIM提供。
DA的速度可达1MHz。
除此以外DAC需要波形数据,再运行前先生成数据。
- for(int i=0;i<10000;i++)
- {
- dac_data[i]=(float)da_amp/100*((sin(6.28/100*i)*0x800))+0x800;
- }
复制代码
最后就是将采集到的数据显示到TFT上了
- void UserADCReadChart(unsigned char mode,float range,float offset ,unsigned char samples)
- {
-
- float fcnt=0.0;
- float f_max=0.0;
- float f_min=0.0;
- unsigned int temp=0;
- unsigned char tdata[100]={0};
- unsigned short ADC_RESOLUTION= 0;
- f_max=0;
- f_min=10;
- if(DMA_OK)
- {
- DMA_OK=0;
- temp=ADC1->CFGR;
- temp&=0x1C;
- temp>>=2;
- switch(temp)
- {
- case 0:
- display_STR(0,120,"ADC_RESOLUTION_16B");
- ADC_RESOLUTION=0xffff;
- break;
- case 1:
- display_STR(0,120,"ADC_RESOLUTION_14B");
- ADC_RESOLUTION=0x3fff;
- break;
- case 2:
- display_STR(0,120,"ADC_RESOLUTION_12B");
- ADC_RESOLUTION=0xfff;
- break;
- case 3:
- display_STR(0,120,"ADC_RESOLUTION_10B");
- ADC_RESOLUTION=0x3ff;
- break;
- case 4:
- display_STR(0,120,"ADC_RESOLUTION_8B");
- ADC_RESOLUTION=0xff;
- break;
- }
- for(int ii=1;ii<ADC_BUF_SIZE;ii++)
- {
- chartdata[ii-1]=(float)((float)adc_data[ii]/(float)ADC_RESOLUTION)*3.3;
- if(f_max<chartdata[ii-1])f_max=chartdata[ii-1];
- if(f_min>chartdata[ii-1])f_min=chartdata[ii-1];
- }
- display_STR(0,80,"VPP(V):");
-
- switch(mode)
- {
- case AutoRange:
-
- tft_chart(0,0,128,80,(f_max-f_min),chartdata,f_min,samples);
- display_float(0,90,(f_max-f_min));
- display_STR(0,100,"OffSet(V):");
- display_float(0,110,(f_max+f_min)/2);
- break;
- case SetRange:
- tft_chart(0,0,128,80,range,chartdata,offset,samples);
- display_float(0,90,range);
- break;
- }
-
- ADC1->CR |= ADC_CR_ADSTART;
- }
- }
复制代码
上面是TFT显示的部分代码。下面是采集的实际照片。
16位采集大幅度(对焦示波器)
16位采集大幅度(对焦TFT)
8位采集大幅度(对焦示波器)
8位采集大幅度(对焦TFT)
16位采集小幅度(对焦示波器)
16位采集小幅度(对焦TFT)
8位采集小幅度(对焦示波器)
8位采集小幅度(对焦TFT)
以上图片分别展示了相同配置下大幅度波形输出时候和小幅度波形输出时16位与8位的波形对比。
1、通过图片可以看到,波形形态差别不大。
2、通过图片可以看到,波形形态差别很大。
以上主要由于8位在采小信号时分辨率不足导致。
3、通过上面图片可以看到,16位显示波形比8位显示的波形多。
由此可以验证下面的图,精度越低采样率越高。
4、通过图片可以看到,H7的ADC采集到的VPP和示波器的VPP大致范围基本一致,由于示波器是定性分析,而H7也未校准,看个大概不偏离太多即可。
本篇测评到此结束,之后有机会把ADC的速度和精度做个详细测评。谢谢观看!!
此内容由EEWORLD论坛网友supermiao123原创,如需转载或用于商业用途需征得作者同意并注明出处