由于公司的产品上需求运用AD来检测电池电压,要求不是很高,忽然想用下DMA+ADC+TIM,曾经认为很简单,实际运用中让我觉得很羞愧,遇到的问题让我一会儿蒙了,不断的查材料,不断的测验,总算一个一个的问题都处理了,一同对stm32的ADC有了新的知道,而且计划再空闲时刻内将stm32的资源尽量的实践下。
我用的是STM32F4 来调试ADC3+DMA+TIM1(单通道),首要我先检查了下DMA的材料,之后参阅官方供给的ADC3+DMA很快能够正常读取数据,之后我直接增加定时器触发AD转化,成果失利,我开端查材料看手册,逐步对这三者之间的联系有了一个知道
首要定时器发生触发信号,AD检测到转化信号后开端转化,每转化一次就经过DMA将数据放到指定的内存地址中,直到到达DMA设定的DMA_BufferSize设定值后DMA置位相应的标志位,然后完结一次DMA传输。
由上面的联系的能够得知ADC转化是一次一次即单次非扫描形式(我测验的是AD单通道),由于接连形式一旦触发就会不断的转化,这样的话定时器触发转化就失去了含义,之后DMA设置成一般形式,即完结一次DMA传输后,中止传输,之后的DMA恳求不被呼应,由于DMA传输完结后认为着能够进行数据处理了,这个时分为了避免数据被掩盖(网上还有其他办法避免数据被掩盖)。
1>关于定时器的PWM输出
一开端我用定时器1的CH1来作为AD的触发信号对应的管脚是PA8,管脚装备的时分装备成复用形式没有调用 GPIO_PinAFConfig,将PA8复用成TIM1的输出脚,关于定时器的时钟我疏忽了一个重要的要素,所以设置的频率一向不对
检查stmf4的参阅手册 假如APBx_PRESC为1则定时器的时钟为PCLKx的时钟 否则为2倍的PCLKx
-假如是定时器1和定时器8 需求调用TIM_CtrlPWMOutputs来敞开pwm输出之后经过示波器能够正确检查PA8的的波形输出。
2>AD转化
-ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
我对这句一点都不明白,经过查材料发现stm32F4的ADC的DMA有4种形式,首要是为了经过联合运用ADC模块提高采样速度,其间默许形式和形式1差不多,
DMA mode 1 enabled (2 / 3 half-words one by one – 1 then 2 then 3)
//从顺次取ADC的值,分辨率为12位,
DMA mode 2 enabled (2 / 3 half-words by pairs – 2&1 then 1&3 then 3&2)
//能够联合运用这三个ADC模块进行采样,采样速度也是独自的三倍(2.4*3Msps),分辨率是12位,完结两次转化后,将值取走应该是
//ADC2+ADC1 ,ADC1+ADC3 ,ADC3+ADC2
DMA mode 3 enabled (2 / 3 bytes by pairs – 2&1 then 1&3 then 3&2)
//形式3和形式2差不多 可是分辨率要求是8位或6位,尽管分辨率降低了可是转化时刻相对12位的要短。
-ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
//接连形式有必要被制止,否则定时器触发就失去了含义
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
//检查寄存器,发现需求使能外部触发,上面便是敞开并拟定触发信号的极性
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
//挑选触发时刻
-一旦运用外部触发,那么 软件触发就不需求再调用。
3> DMA的传输
-ADC每转化一次,DMA转移一次,到达指定的次数后,完结一次传输。
-DMA重启,看了网上很多人说DMA封闭后再敞开后无法完成DMA传输,在stm32研讨会的演讲稿上有关于DMA重启的处理办法,
我依照第二种办法测验,发现假如处理数据时刻长就会有问题,之后我吧定时器和ADC一同封闭之后处理数据,再装备DMA,在敞开AD和定时器,就正常了。不太清楚哪里的问题。
-stm32f4的DMA分为数据流和通道,其间通道与stm32f1的触发源相似,F4的数据流与F1的通道相似
这样ADC+DMA+TIM就正常工作了。
我想用内部ADC把收集的波形经过ucgui显现出来,然后加强对AD的运用与知道,我用stm32收集信号发生器的法波信号进行收集,一次收集300个点,之后经过ucgui将其显现在TFT屏上,为了让波形美观一些,我查了下网上的一些例程和示波器的材料,里边讲到能够经过数字内插的办法将波形重现和回放,数字内插的办法常用的有两种,一种是线性内插一种是sinx/x内插,线性内插比较好了解,关于sinx/x内插就杂乱的多,只是是了解就很费事,数学功底严重不足的悲惨剧,原理都不明白想用c言语描绘就别想了,所以只能用线性内插了,不过网上有关于sinx/x内插的c言语实例,运用线性内插后,波形比之前美观多了,经过调整TIM1的触发信号的频率到达了t/div 的作用怎么算频率,一开端我计划把AD收集的成果的最大值和最小值的下标做个差,之后绝对值再乘tim1的周期 后来决断抛弃,原因很明显。后来我查询最大值和最小值 之后求平均值,然后一次查询(前一个AD值比均值小且这今后一个值比均值大)记载下标,之后查询前一个AD值比均值大且这今后一个值比均值小 记载下标,将两次下标做差求绝对值之后与触发信号的频率运算能够求出收集的波形的频率。现在我只是测验了占空比为50%的方波信号,作用还好,不过还要完善,比方占空比不为50%的状况。
折腾了几个晚上,我发现stm32的资源很丰厚,而我只把握了很少很少的一部分根底的东西。今后要不断的完善和实践。将折腾的过程中遇到的问题和了解写出来与我们共享,其间有误的当地期望我们提出来沟通。