2013-11-25 02:22 AM
hello dear forum,
( STM32F103 ) I am trying to measure 5 analog signal with most simple way I am taking10 consecutiveADC result and take their avarage however I have trouble with ADC , the measurements are wrong sometimes the ADC ''get stuck'' with a fake value sometimes it measures wrong value btw I am measuring 5 analog channels, I showed 2 of them below beouse the idea is the same have a look at my code and please adviseint16_t averhold[5][20];
void
ADCinit(
void
){
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channels configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_28Cycles5);
/* Regular discontinuous mode channel number configuration */
ADC_DiscModeChannelCountConfig(ADC1, 1);
/* Enable regular discontinuous mode */
ADC_DiscModeCmd(ADC1, ENABLE);
/* Enable ADC1 external trigger conversion */
ADC_ExternalTrigConvCmd(ADC1, ENABLE);
/* Set injected sequencer length */
/* ADC1 injected channel configuration */
/* ADC1 injected external trigger configuration */
/* Enable ADC1 injected external trigger conversion */
/* Enable JEOC interupt */
// ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
/* Enable ADC1 DMA */
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while
(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while
(ADC_GetCalibrationStatus(ADC1));
}
here is the measurement block
void
GetADCRes(
void
){
int16_t *RAMptr ;
int8_t avi;
//avi2;
int32_t avertotal=0;
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 1, ADC_SampleTime_28Cycles5);
for
(avi=0;avi<10;avi++){
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while
(ADC_GetSoftwareStartConvStatus(ADC1));
Delay(20);
RAMptr= &averhold[0][avi];
*RAMptr= ADC_GetConversionValue(ADC1);
}
avertotal=0;
for
(avi=0; avi<10; avi++) avertotal += averhold[0][avi];
RAMptr=&RAM[PARAMETERS + 100*2 ];
*RAMptr= avertotal / 10;
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_28Cycles5);
for
(avi=0;avi<10;avi++){
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while
(ADC_GetSoftwareStartConvStatus(ADC1));
Delay(20);
RAMptr= &averhold[1][avi];
*RAMptr= ADC_GetConversionValue(ADC1);
}
avertotal=0;
for
(avi=0; avi<10; avi++) avertotal += averhold[1][avi];
RAMptr=&RAM[PARAMETERS + 101*2 ];
*RAMptr= avertotal / 10;
}
what I want to ask is , is this measurement code correct ?
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_28Cycles5);
for
(avi=0;avi<10;avi++){
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while
(ADC_GetSoftwareStartConvStatus(ADC1));
Delay(20);
RAMptr= &averhold[1][avi];
*RAMptr= ADC_GetConversionValue(ADC1);
}
this rank , should it be different for every channel ? I am taking it ''1'' for every channel
void
ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
thank you
#stm32
2013-11-25 06:43 AM
Both the C and implementation are pretty awful.
Why the use pointers, delays, and not using EOC status? There are far more elegant ways to solve this problem.2013-11-25 10:00 AM
hello thanks for the answer
the STM32F10x peripheral library gives only DMA or ext_trigger examples for ADC does anyone have a working example for software_conversion_start for 2 or more channels ADC measurement ? thank you2013-11-25 10:28 AM
That's likely because the simple/elegant way to do what you're attempting is to use DMA, and compute the average for all channels/samples in the DMA's TC interrupt?
I'm still confused by why you are using pointers to access an array element. Something like this would seem to be a clearer interpretation of the library functions. (F4 here but should port)uint16_t ADCReadValue(uint8_t Channel)
{
ADC_RegularChannelConfig(ADC1, Channel, 1, ADC_SampleTime_28Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return(ADC_GetConversionValue(ADC1));
}
2013-11-25 11:03 AM
now I know its not smart to access array element with pointer
however this code is written when I was new to STM and C and I learned C after 40 age :) maybe thats why originally I measured only single ADC channel with this code and it worked fine thats why I didnot changed it since then now for another project I need to measure 5 channels and I got into trouble thank you for the advice and I assume you say OK to my initialization routine2013-11-25 12:05 PM
Honestly this looks to be extraneous, and you're not using an external trigger.
/* Regular discontinuous mode channel number configuration */
ADC_DiscModeChannelCountConfig(ADC1, 1);
/* Enable regular discontinuous mode */
ADC_DiscModeCmd(ADC1, ENABLE);
/* Enable ADC1 external trigger conversion */
ADC_ExternalTrigConvCmd(ADC1, ENABLE);