前言:
此次采用DMA的方式采集多通道,这个过程是参照微雪课堂来修改的http://www.waveshare.net/study/article-646-1.html
与不采用DMA的方式多通道连续采样相比,开启了DMA采样询问
cubemx:
添加DMA,设置模式为循环,数据宽度为16位(跟微雪不同,因为精度为12位,最大也就是4096,够用即可)
代码实现:
由于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是在更新的,所以可能会产生意料之外的事儿。所以我一般是做好硬件滤波,软件上进行滑动平均。
那么采样时间和采样频率是什么关系,怎么计算呢? 根据芯片手册中的描述
用本例中的设置计算,ADC1是用APB2即90Mhz,分频4,采样时间为480Cycles
那么采样频率ADCCLK为90/4=22.5Mhz,周期为1/22.5M=0.04us
那么采样时间为(480+12)*0.04=21.86666us
|