最近开发基于PH、ORP数据采集项目,两路PH,两路ORP所以用到了STM32ADC多路采样,
不足之处望指正。
一、存在问题
1、采样数据不准确,几路数据相同。
2、通道间数据互相影响,不准确等。
二、开发过程
非DMA模式
最开始只是在单通道非DMA模式下增加多路通道,结果AD采样数据显示都一样,经过各种修改未发现问题。
DMA模式
在思绪百般无果下,想了下会不会是多路采样导致CPU负担过重,于是想起了DMA(个人理解DMA就是一个中转站,起到存数据,取数据的过程,这个存取过程不需要CPU直接参与,采样数据过大、过多时利用DMA收集数据,再处理,减轻了CPU负担),资源查询过程中又发现了一个问题,在非DMA模式下,多路ADC采集的数据储存位置是相同的,出现了数据覆盖,所以才会有互相影响,数据相同的奇怪现象。然而,开启ADC多通道DMA模式后采集数据还是存在互相干扰,最后查询资料得到的结论是,未连接的端口处于浮空状态,会受干扰,最后将每个采样口接通,恢复正常。
三、下面分享一下源码以及细节部分吧
1、ADC采样GPIO端口配置,这里配置六个PA端口
void ADC1_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6);
}
2、ADC和DMA一起配置
void ADC1_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCDAT;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 6;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel =6;
ADC_Init(ADC1, &ADC_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
3、注意细节
DMA_InitStructure.DMA_BufferSize = 6;这是配置DMA数据储存大小,由于STM32内置ADC采样为12位,所以一个IO口采集的数据咱们用16来储存,所以六个IO口填6。
ADC_DMACmd(ADC1, ENABLE); 这句是ADC请求DMA关键使能句,也就是ADC与DMA的桥梁。
其他区别对比单路ADC采样修改即可, DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCDAT,这里ADCDAT定义为u16ADCDAT[5]数组,刚好储存六个IO口ADC值,为了储存数据强制转化为32位,在主函数中直接读取读取数组即为对应ADC值。