How to Improve ADC Resolution

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
It is...:D
It was always a dream to make PSU's and Amps
Since I have learned a lot about PIC and coding from members of AAC and I can buy everything I need to at a reasonable price from Aliexpress, Plus I can now make PCB's with help from a friend, I am, like on steroid. :D Always figuring out what else I can make.
If I making something, I don't sleep much ( I am up like 3 to 4 in the morning) and My wife is like, well you know what I mean.
 

RichardO

Joined May 4, 2013
2,270
I once made a digital thermometer using a silicon diode as the sensor. An amplifier was used to get the low diode voltage high enough for the full range of the A/D converter. I wasn't happy with the large jumps in the reading as temperature changed slowly. The solution was to increase the ac gain of the amplifier using a cap across the input resistor of the op-amp. With that small change, the abrupt changes in displayed temperatures went away.

As crutschow pointed out this did _not_ increase accuracy. It only made the change from one step of the A/D to the next smoother.

edit: I changed "resolution" to say "accuracy".
 
Last edited:

RichardO

Joined May 4, 2013
2,270
The signal from the diode is a DC signal. How does increasing the AC gain help?

Increasing the (DC) gain will definitively increase the resolution.
The noise caused by the increase in ac gain dithered the DC signal between two A/D steps. This was a crude way of getting random noise like OBW0549 mentioned in reply #4.


edit: I just noticed that I said "resolution" instead of "accuracy" in my first post. I will edit to fix the error.
 

ian field

Joined Oct 27, 2012
6,536
I am working on PSU project.
As of now I working on the code (mikroC Pro)
As I am not that good on coding I am asking for help.

I can get the voltage and current readings from Analog input but the Voltage resolution is 3mV.

I read around that this can be improved in software.
How can I do it.
I like to get 1mv resolution at best.
Vref is at Vdd (5V)
Max voltage is 35VDC scaled down by BB OPAMPS down to 5V for 35V output.

I searched a lot but I am getting no where.

Does any one got a working example of a 10 bit ADC displaying a Voltage at 1mV resolution ?
Or how can I do this or is it possible to do it in Software ?
Saw an application bulletin recently that noise can increase resolution if used properly.

I only skimmed over the article - but it might be worth seeking out.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Since we on the subject.

I found this while searching around.

Code:
' *
' * Project name:
'     ADC Oversampling (up to 16 bit)
' * Copyright:
'     (c) Thunderer (07/2014)
' * Revision History:
'     0 - 1st issue
' * Description:
'     See Mikrobasic forum: Florin YO2LIO post (Mikrobasic and Mikropascal)
' * Test configuration:
'     MCU:             PIC16F690
'     Oscillator:      INTOSC 8 MHz
'     Ext. Modules:    -
' *

program _16F690_ADC_Oversampling
' Declarations section
dim adc_rd0, adc_rd1,adc_rd2, adc_rd3     as longword
dim adc_res1, adc_res2, adc_res3          as longword
dim ch0, ch1, ch2, ch3                    as byte

' Lcd module connections
dim LCD_RS as sbit at RC5_bit
    LCD_EN as sbit at RC4_bit
    LCD_D4 as sbit at RC3_bit
    LCD_D5 as sbit at RC2_bit
    LCD_D6 as sbit at RC1_bit
    LCD_D7 as sbit at RC0_bit

    LCD_RS_Direction as sbit at TRISC5_bit
    LCD_EN_Direction as sbit at TRISC4_bit
    LCD_D4_Direction as sbit at TRISC3_bit
    LCD_D5_Direction as sbit at TRISC2_bit
    LCD_D6_Direction as sbit at TRISC1_bit
    LCD_D7_Direction as sbit at TRISC0_bit
' End Lcd module connections

'   Set-up the PIC
sub procedure InitMain()
    OPTION_REG =   0x80              ' Pull-up disabled PORTB
    INTCON     =   0x00              ' No INT

    CM1CON0    =   0x00              ' No COMP
    CM2CON0    =   0x00              ' No COMP
    CM2CON1    =   0x00              ' No COMP

    ANSEL      =   0x0F              ' PORTA Analog I/Os on AN0, 1, 2 and 3
    ANSELH     =   0x00              ' No Analog I/Os

    TRISA      =   0x17              ' Inputs RA0, 1, 2 and 4
    TRISB      =   0x00              ' All outputs
    TRISC      =   0x00              ' All outputs


    PORTA      =   0x00              ' Clear PORTA
    PORTB      =   0x00              ' Clear PORTB
    PORTC      =   0x00              ' Clear PORTC
end sub

sub function Adc_Read_Ext_Res(dim resolution, ch_ as byte) as longword
dim i as longword
    j as byte

  result = 0
  if resolution < 11 then exit end if ' minimum resolution is 11 bits
  resolution = resolution - 10
  j = resolution - 1
  i = 4
  while j > 0
    i = i << 2
    dec(j)
  wend
  while i > 0
    result = result + Adc_Read(ch_)
    dec(i)
  wend
  result = result >> resolution
end sub

'   Main program
Main:
  InitMain()
  Lcd_Init()                     ' Initialize Lcd
  Lcd_Cmd(_LCD_CLEAR)            ' Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF)       ' Cursor off

  ADC_Init()                     ' Initialize ADC module

' Display static text
  Lcd_Out(1,1," 0:")
  Lcd_Out(1,9," 2:")
  Lcd_Out(2,1," 4:")
'  Lcd_Out(2,9," 6:")


' The measurement
Measure:
  while (TRUE)
' Voltage ADC_10b
ADC0:
    adc_rd0 = ADC_read(0) * 48.82813
    ch0 = adc_rd0 div 10000
    Lcd_Chr(1, 4, 48+ch0)
    ch0 = (adc_rd0 div 1000) mod 10
    Lcd_Chr(1, 5, 48+ch0)
    ch0 = (adc_rd0 div 100) mod 10
    Lcd_Chr(1, 6, 48+ch0)
    ch0 = (adc_rd0 div 10) mod 10
    Lcd_Chr(1, 7, 48+ch0)
    ch0 = (adc_rd0 div 1) mod 10
    Lcd_Chr(1, 8, 48+ch0)
    Delay_ms(100)

' Voltage ADC_12b
ADC1:
    adc_res1 = Adc_Read_Ext_Res(12,1)  ' 12 bit resolution, channel 1
    adc_rd1 = adc_res1 * 12.20703
    ch1 = adc_rd1 div 10000
    Lcd_Chr(1, 12, 48+ch1)
    ch1 = (adc_rd1 div 1000) mod 10
    Lcd_Chr(1, 13, 48+ch1)
    ch1 = (adc_rd1 div 100) mod 10
    Lcd_Chr(1, 14, 48+ch1)
    ch1 = (adc_rd1 div 10) mod 10
    Lcd_Chr(1, 15, 48+ch1)
    ch1 = (adc_rd1 div 1) mod 10
    Lcd_Chr(1, 16, 48+ch1)

' Voltage ADC_14b
ADC2:
    adc_res2 = Adc_Read_Ext_Res(14,2)  ' 14 bit resolution, channel 2
    adc_rd2 = adc_res2 * 3.05176
    ch2 = adc_rd1 div 10000
    Lcd_Chr(2, 4, 48+ch2)
    ch2 = (adc_rd2 div 1000) mod 10
    Lcd_Chr(2, 5, 48+ch2)
    ch2 = (adc_rd2 div 100) mod 10
    Lcd_Chr(2, 6, 48+ch2)
    ch2 = (adc_rd2 div 10) mod 10
    Lcd_Chr(2, 7, 48+ch2)
    ch2 = (adc_rd2 div 1) mod 10
    Lcd_Chr(2, 8, 48+ch2)

'' Voltage ADC_16b
'ADC3:
'    adc_res3 = Adc_Read_Ext_Res(16,3)  ' 16 bit resolution, channel 3
'    adc_rd3 = adc_res3 * 0.76294
'    ch3 = adc_rd3 div 10000
'    Lcd_Chr(2, 12, 48+ch3)
'    ch3 = (adc_rd3 div 1000) mod 10
'    Lcd_Chr(2, 13, 48+ch3)
'    ch3 = (adc_rd3 div 100) mod 10
'    Lcd_Chr(2, 14, 48+ch3)
'    ch3 = (adc_rd3 div 10) mod 10
'    Lcd_Chr(2, 15, 48+ch3)
'    ch3 = (adc_rd3 div 1) mod 10
'    Lcd_Chr(2, 16, 48+ch3)

  wend
end.
I tried it to do it in MikroC Pro
For the life of me I could not understand the part below..everything else I was able to change to MikroC Pro

Code:
sub function Adc_Read_Ext_Res(dim resolution, ch_ as byte) as longword
dim i as longword
    j as byte

  result = 0
  if resolution < 11 then exit end if ' minimum resolution is 11 bits
  resolution = resolution - 10
  j = resolution - 1
  i = 4
  while j > 0
    i = i << 2
    dec(j)
  wend
  while i > 0
    result = result + Adc_Read(ch_)
    dec(i)
  wend
  result = result >> resolution
end sub
Can any body explain this area and how to change to MikroC

This part
Code:
sub function Adc_Read_Ext_Res(dim resolution, ch_ as byte) as longword
Gives me a headache
 

dannyf

Joined Sep 13, 2015
2,197
The noise caused by the increase in ac gain dithered the DC signal between two A/D steps.
If you feed a DC signal through an AC amplifier, you get an AC signal on the output.

You can never get a better output by adding noise to a system. Just not possible.
 

OBW0549

Joined Mar 2, 2015
3,566
You can never get a better output by adding noise to a system. Just not possible.
That is completely untrue. Dithering is a well-established technique for enhancing the effective resolution of ADCs; Google on the term, "dithering analog digital" and also read the attachment I provided in post #4 of this thread as well as the following attachment:
 

Attachments

Last edited:

joeyd999

Joined Jun 6, 2011
5,237
If you feed a DC signal through an AC amplifier, you get an AC signal on the output.

You can never get a better output by adding noise to a system. Just not possible.
Hmmmm...then I'll have to find an alternative explanation as to how I manage to achieve 16 bit performance from the 12 bit A/D in the PIC18F87K90 used in one of my most successful products.
 

OBW0549

Joined Mar 2, 2015
3,566
Anyone care to make comment on #27
The way I read it, "sub function Adc_Read_Ext_Res(dim resolution, ch_ as byte) as longword" is declaring a function called Adc_Read_Ext_Res which returns a longword and takes two arguments, resolution and ch_; the former is of whatever type is the default in that particular language (you'd have to look that up, it could be anything), and the latter is of type byte.

But I'm a mere assembly language jockey, so take the above with a grain of salt.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
This part does not work
"(dim resolution, ch_ as byte)as longword"
Unsigned int resolution ; -- works
Char ch_; -- does not work.....the under score is a problem
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Hmmm !

Problem is I do not understand in bracket it says " as byte" and out side it says"as Longword" o_O
 

joeyd999

Joined Jun 6, 2011
5,237
How many samples did you average to get that improvement?
For this application, there are 4 channels. Each channel is converted round-robin fashion, one conversion every 256µS (all four channels converted once each 1.024ms).

64 conversions of each channel are accumulated in their corresponding buckets, for a total accumulation time of 65.536ms for 4 channels, or 15.258 accumulations per second.

Each accumulation is pushed into a 16 stage boxcar filter and a new boxcar average is computed. So, essentially, 512 total a/d readings are summed for each of the boxcar outputs at 15.258 per second.

The output stream from the boxcar is further digitally filtered (FIR) and desampled to produce a final 3.5 readings per second with better than 16 bit resolution and accuracy (yes, I said accuracy).
 
Last edited:

crutschow

Joined Mar 14, 2008
34,285
................
The output stream from the boxcar is further digitally filtered (FIR) and desampled to produce a final 3.5 readings per second with better than 16 bit resolution and accuracy (yes, I said accuracy).
Resolution I understand but to get 16 bit accuracy, the converter has to be 16-bit accurate.
How do you get that from a converter that's only accurate to 12 bits? :confused:
 
Top