Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ADC Averaging problem

Status
Not open for further replies.
Hi,
I am trying to fix a problem with a semi-automatic aerial matching unit for Amateur Radio.

It comprises variable inductors and capacitors driven by DC motors. Position feedback is provided by precision variable resistors (pots) which input to 2 channels of ADC on a 18F4620.

Most of the time the unit works well, however occasionally the ADC feedback system gets spiked and gives a one off value away from the norm. I have spent some time making sure that the hardware is as robust noise wise as possible.

When the spike occurs it upsets the average ADC value that I get from the code below..


Code:
Function ADCGetL(AvgADCL As Byte) As Byte
' Read L ADC and calculate an average reading
'
ADCTemp = 0
'
For i=0 To 7                             'take 8 ADC readings
	ADCin 2,RawADCL                  'get ADC value for L from 2nd channel
	ADCTemp = ADCTemp + RawADCL
Next i
'
ADCgetL = ShiftRight(ADCTemp,3)		 'shift right 3 places to divide by 8
                                         'and return the averaged L ADC value
'
End Function

What I would like to do is filter out these infrequent LO/HI ADC values without affecting the averaging.

Any thoughts/code please...

Stewart
 
Instead of adding the ADC results, store them in a 8 word buffer. Then run through the buffer and work out the median value (most common ), then clip all the ADC values outside your tolerance (say 10%). Add them together, then divide by eight.

Cheers Ian
 
Last edited:
hi Stewart,
Do you have any hardware filtering on the ADC input pins.?
Whats the driving impedance to the ADC pins.?
 
Instead of adding the ADC results, store them in a 8 word buffer. Then run through the buffer and work out the median value (most common ), then clip all the ADC values outside your tolerance (say 10%). Add them together, then divide by eight.

Cheers Ian

Thanks Ian,
That makes a lot of sense.

Stewart
 
hi Stewart,
Do you have any hardware filtering on the ADC input pins.?
Whats the driving impedance to the ADC pins.?


Hi Eric,
I am driving the ADC pins from LM324 buffers to provide a low impedance feed to the cabling from the ATU to the control unit. The ADC inputs in the control unit have series 3.9k resistors with a 10uF capacitors in parallel.

73
Stewart
 
Hi Eric,
I am driving the ADC pins from LM324 buffers to provide a low impedance feed to the cabling from the ATU to the control unit. The ADC inputs in the control unit have series 3.9k resistors with a 10uF capacitors in parallel.

73
Stewart

Sorry there are also 0.1uF capacitors directly onto the ADC pins.

Hi Stewart,
You don't mean that the 10uF cap is in parallel with the 3k9 series resistor.??
 
Last edited by a moderator:
Hi Stewart,
You don't mean that the 10uF cap is in parallel with the 3k9 series resistor.??

Yes, I did. It was something that crept in.

The very occasional ADC excursion is still the same with them in or out (I have now taken them off).

Most of the time the ADC readings are very stable. I think that taking out extraneous readings in the
code is the way to go.

Cheers
Stewart
 
Last edited by a moderator:
Yes, I did. It was something that crept in.

The very occasional ADC excursion is still the same with them in or out (I have now taken them off).

Most of the time the ADC readings are very stable. I think that taking out extraneous readings in the
code is the way to go.

Cheers
Stewart

hi,
With a 10uF in parallel with the 3K9, it would allow almost any noise on the wire to enter the ADC.

I would suggest a 3k9 is series with another 3k9k from the voltage source to the adc pin.
Decouple the junction of the 3k9 and 3K9 with the 10uF to 0V

EDIT:
Goodness knows what happened there, the Forum software allowed me to edit your post!!!!
 
Last edited:
hi,
With a 10uF in parallel with the 3K9, it would allow almost any noise on the wire to enter the ADC.

I would suggest a 3k9 is series with another 3k9k from the voltage source to the adc pin.
Decouple the junction of the 3k9 and 3K9 with the 10uF to 0V

EDIT:
Goodness knows what happened there, the Forum software allowed me to edit your post!!!!

Yes, I was a bit surprised to see you editing my posts. However I trust you Eric :)

Agreed about the ADC input arrangement, however some intensive investigations today indicate that the problem is definitely not noise pickup.

It would appear to be ADC misreads associated with interrupts. I use interrupts for the RS232 data stream from the rig, and if I stop them
the ADC's for the L & C servos perform without any problems. I cannot at present disable/enable interrupts when doing an ADC read as it
messes up the data input.

I am now looking at calling the ADC's less frequently so there should be less chance of a conflict. It's all getting rather confusing, but at
least I have proved what it is not.

Cheers

Stewart
 
You may need to adjust the TAD to get stable reading if this is the case. It's possible the TAD is a little off of the 2 to 6 us time it takes to clock the ADC for optimal conversion. If too fast the conversion logic won't have time to settle, too slow the charge on the sample and hold capacitor might drift.

C18 ADC code functions:
https://www.electro-tech-online.com/custompdfs/2011/03/ADC20FUNCTIONS.pdf
 
Last edited:
Hmm ...I did run into something like this a couple months back. I was dual purposing an ADC line....using an interrupt to switch the adc to dig. out and drive a byte of serial data. This destabilised the adc no matter how much buffer time i included.

What helped somewhat was making sure any 'floating' pins were grounded. I also did a running avg to minimise the swings. Upon sampling, take the last adc sample (if not zero) add it to the latest raw sample and divide by 2 to make the new sample.
 
Hmm ...I did run into something like this a couple months back. I was dual purposing an ADC line....using an interrupt to switch the adc to dig. out and drive a byte of serial data. This destabilised the adc no matter how much buffer time i included.

What helped somewhat was making sure any 'floating' pins were grounded. I also did a running avg to minimise the swings. Upon sampling, take the last adc sample (if not zero) add it to the latest raw sample and divide by 2 to make the new sample.

Hi Mosaic,
Although I am not switching the ADC interrupts seem a common theme. Still investigation.

S.
 
stewart_bakeruk;964346 I am now looking at calling the ADC's less frequently so there should be less chance of a conflict. It's all getting rather confusing said:
Hi,
Depending upon what your ISR doing, it may be possible to grab the ADC reading just before you exit the ISR and process the value outside of the ISR.

Eric
 
To take that further...you can sample the ISR tick....determine if you have enough time to do the ADC or if the ISR will hit during the sample....simply defer the adc sample until the ISR tick < critical value.
 
Hi,
Depending upon what your ISR doing, it may be possible to grab the ADC reading just before you exit the ISR and process the value outside of the ISR.

Eric

Hi Eric,
That seems to have worked, one misread in an hour. The only slight downside is if the rig is off, there is no data, no interrupts and therefore no updating of the LCD ADC readout.

What I wanted to do is use a timer which would be reset every time the ISR was called. If it timed out then I would write a status message to the LCD.

However I can't find any Timer statements in the Oshon Basic. Do I have to do this in assembler, and if so how ?

Cheers
Stewart
 
Hi Eric,
That seems to have worked, one misread in an hour. The only slight downside is if the rig is off, there is no data, no interrupts and therefore no updating of the LCD ADC readout.

What I wanted to do is use a timer which would be reset every time the ISR was called. If it timed out then I would write a status message to the LCD.

However I can't find any Timer statements in the Oshon Basic. Do I have to do this in assembler, and if so how ?

Cheers
Stewart

hi,
What Timer period are you planning, I may be able to post a guide using Oshonsoft
 
hi Stewart,
Look at this demo version of an TMR1 interrupt.
I have kept the time short so that it can be run in Oshonsoft, but I'm sure you will get the idea.

Code:
'18F4620  Intr Stewart Demo 1

Define LCD_INITMS = 2
Define SIMULATION_WAITMS_VALUE = 1

AllDigital

Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTB
Define LCD_DBIT = 4  '0
Define LCD_RSREG = PORTB
Define LCD_RSBIT = 3
Define LCD_EREG = PORTB
Define LCD_EBIT = 2
Define LCD_RWREG = PORTB
Define LCD_RWBIT = 1
Define LCD_READ_BUSY_FLAG = 1


Dim i As Byte
Dim intrcnt As Byte

TRISB = 0x00


T1CON = %01001001

TMR1H = 0xe0
TMR1L = 0x00

INTCON.GIE = 1
INTCON.PEIE = 1

PIE1.TMR1IE = 1
PIR1.TMR1IF = 0

IPR1.TMR1IP = 0

Lcdinit
Lcdcmdout LcdClear
Lcdout "Ready for Intr"

Enable Low

i = 0

loop:
Toggle PORTB.0
Goto loop

End                                               

On Low Interrupt
Save System

PIR1.TMR1IF = 0

i = i + 1

'use this count to count the number of
'interrupts that will give ~10secs
'then restart count
'do your idle subr

Lcdcmdout LcdLine2Home

intrcnt = i Or 0x30

Lcdout intrcnt

TMR1H = 0xf0  'set this for max ie 0x00
TMR1L = 0x00  'set this for max ie 0x00

Resume
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top