从零实现 ADC(三)、多通道连续采集(DMA)

前言:

此次采用DMA的方式采集多通道,这个过程是参照微雪课堂来修改的http://www.waveshare.net/study/article-646-1.html

与不采用DMA的方式多通道连续采样相比,开启了DMA采样询问

cubemx:

从零实现 ADC(三)、多通道连续采集(DMA)_第1张图片

添加DMA,设置模式为循环,数据宽度为16位(跟微雪不同,因为精度为12位,最大也就是4096,够用即可)

从零实现 ADC(三)、多通道连续采集(DMA)_第2张图片

代码实现:

由于DMA采用了连续传输的模式,ADC采集到的数据会不断传到到存储器中(此处即为数组ADC_Value)。ADC采集的数据从ADC_Value[0]一直存储到ADC_Value[99],然后采集到的数据又重新存储到ADC_Value[0],一直到ADC_Value[99]。所以ADC_Value数组里面的数据会不断被刷新。这个过程中是通过DMA控制的,不需要CPU参与。我们只需读取ADC_Value里面的数据即可得到ADC采集到的数据。

在我们的实验里,ADC_Value[0]放通道4,ADC_Value[1]放通道5,ADC_Value[2]放通道4。。。以此类推。。。

uint16_t 	_u16ADC_Value[100];
uint32_t 	_u32Value1;
uint32_t 	_u32Value2;

int main(void)
{
    uint8_t 	i = 0;
    MX_ADC1_Init();
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&_u16ADC_Value, 100);
    while(1)
    {
        for(i=0,_u32Value1=0,_u32Value2=0;i < 100;)
	{
		_u32Value1 += _u16ADC_Value[i++];
		_u32Value2 += _u16ADC_Value[i++];
	}
	_u32Value1 = _u32Value1/50;
	_u32Value2 = _u32Value2/50;
	sprintf((char*)InLtdcBuff1, "ADC1_CH4: %1.2f V\r\n", _u32Value1*3.3f/4096);  
	sprintf((char*)InLtdcBuff2, "ADC1_CH5: %1.2f V\r\n", _u32Value2*3.3f/4096); 
 
        LTDC_Refresh(InLtdcBuff1, InLtdcBuff2);				//屏幕的刷新
        
        //喂狗
	HAL_IWDG_Refresh(&hiwdg);
	delay_ms(100);
    }
}

现象如下图:

总结:

DMA方式采集ADC还是十分简单的,而且真的很方便有没有,还节省CPU资源,还刷新速度超快,还顺便把滤波给做了。以后就这么用就完事儿了!

集思广益,续写:

DMA是按照什么速度采样呢?

其实DMA就是提CPU干活儿的而已,采样频率和采样时间是设置ADC是固定的。可以理解为,本来是CPU进行ADC采样的处理,而这个事儿让DMA去干了,我们定义一个buffer,告诉DMA这个buffer的地址,采集n个数放在这个buffer中。然后DMA就会不断地把最新采集到的数放入这个地址上。用户定期去使用即可。

DMA的采样方式?

但是值得注意的是,如果DMA采集方式为单次的话,那么采集完n个数后,就停止了,需要重新开始DMA。如果是循环方式的话,那么DMA就可以循环采集放入buffer中了。

会不会出现在for循环中采集到的值还未累加,就又被DMA传输的数据覆盖的情况?

但是代码运行是需要时间的,我们在去使用这个buffer的时候,其实这个buffer是在更新的,所以可能会产生意料之外的事儿。所以我一般是做好硬件滤波,软件上进行滑动平均。

那么采样时间和采样频率是什么关系,怎么计算呢?
根据芯片手册中的描述

从零实现 ADC(三)、多通道连续采集(DMA)_第3张图片

用本例中的设置计算,ADC1是用APB2即90Mhz,分频4,采样时间为480Cycles

那么采样频率ADCCLK为90/4=22.5Mhz,周期为1/22.5M=0.04us

那么采样时间为(480+12)*0.04=21.86666us

 

 

 

你可能感兴趣的:(嵌入式编程)