本主要是关于板子上的ADC使用,板子上有ADC1和ADC2,ADC1涉及两个外设的采集,一个是模拟输出的采集,一个是MCP4017的PB14的采集电压,ADC2是对另一个模拟输出的电压采集。
ADC的采集有两种方式:
- 直接采集,需要CPU资源
- DMA采集,消耗资源少
所以本篇文章也会提供两种方案,一份是ADC1双通道DMA,ADC2单通道DMA,另一份是ADC1直接采集,ADC2DMA采集,代码会上传的。
1.cubemx的配置
1.1时钟的配置
ADC的时钟是有要求的,需要事先分频,依据手册最高不超过52M:
cubemx里的时钟树:
1.2 ADC1配置
先来看ADC1的,这次我们要使用两条通道(扫描模式会开启,相当于轮询这两条通道),然后开启连续转换模式,不然就会转换一次就停止,DMA也就无法一直正确搬运数据。然后就是设置各通道的采样时间之类的,具体看下面:
时钟分频选择异步二分频,其实只要符合ADC频率要求就可以,可以参考下面这位的,他是F103的:http://t.csdnimg.cn/DUKAt
①和②分别使能扫描模式和连续转换模式,③必须等设置完DMA再回来使能。
再往下看,有一个叫Number of Conversion的选项,调为2,因为是两条通道嘛,这时候下面的rank会出现两个,分别设置,这个Rank的标号就是转换通道的顺序,这个顺序会影响到后面的计算顺序,④的通道是可以改变的,通过这里改变转换通道的顺序,⑤的采样时间设置的长一些,时间长采样准,可以直接拉满。
DMA的配置
Mode一定要选Circular,数据宽度这里并没有什么限制(保证数据能装下就行),最好两边对齐。要不可能出现一些错误。
1.3 ADC2配置
除了下图没有扫描模式了(因为ADC2只用了一个通道),其余和ADC1一样:
1.4 1.2和1.3的代码
ADC_Work()是开启ADC1,2的DMA传输模式,下面两个函数是对数据处理。
void ADC_Work()
{
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC1_Value,40);
HAL_ADC_Start_DMA(&hadc2,(uint32_t *)ADC2_Value,40);
}
void ADC1_processing_data()
{
uint32_t temp[2];
for(int i=0;i<2;i++)
{
for(int j=0;j<20;j++)
{
temp[i]+=ADC1_Value[j][i];
}
}
ADC1_channel1_value=3.3*(temp[0]/20.0)/(1<<12);
ADC1_channel2_value=3.3*(temp[1]/20.0)/(1<<12);
}
void ADC2_processing_data()
{
uint32_t temp;
for(int i=0;i<40;i++)
{
temp+=ADC2_Value[i];
}
ADC2_channel1_value=3.3*(temp/40.0)/(1<<12);
}
ADC1的数据处理:
首先定义一个二维数组:
uint32_t ADC1_Value[20][2];
因为二维数组在物理的存储就是这样排布的:
所以呢,列就是两个通道,行就是每个通道的不同次的不同采集值,这样我们就可以使用均值滤波来时数据更准确。使用FOR循环将每个通道的各组数据相加求均值再÷4096(因为默认选择了12位精度)再×3.3就得到了电压值。
使用在线调试,可以看到数组如下变化,下图是ADC2的:
1.5 另一种配置,直接采集
这种取消了连续采集,就需要不断开启才能采集:
下面代码可以放在LCD的显示函数里,借着while不断启动ADC采集:
float ADC1_Value()
{
HAL_ADC_Start(&hadc1);
uint32_t adc1_value = HAL_ADC_GetValue(&hadc1);
return adc1_value*3.3/(1<<12);
}