Measuring the ADC Noise (Deflection) and Introduction to the ADC Noise Reduction
Mode
Let's measure the amount returned to us by Mrs. ADC. Is she being a good clerk,
or is she baffled with all of the noise around her. We can find out exactly! Just
determine the difference from each of her responses and add it all up in the end.
We are doing this to see how well Mr. Cap and the brothers in that family launder
the currency the best and keep the currency in Mrs. ADC's hands fast enough for
us to use her returned number currency. We need this number currency pretty fast
because we may have some critical systems that we need to keep stable. For instance,
we may need to feed this information to a balancing robot that is charged to keep
the enemy aliens at bay without falling down and failing at his duties.
Let's get scientific with the ADC. If we keep the voltage currency as level as possible
from Mr. Gravity (the accelerometer) then we can determine how well Mrs. ADC is
responding with her number currency. Because of all the n oises around her, we don't
really know what she will give us. So, when she gives us a response, remember that
response and then when she gives another response, we can subtract the one we remembered
and the one that we just received. Now we have a delta (the difference between the
remembered response from Mrs. ADC and the new response). Now we can forget that
remembered response, because we now have the delta in our back pocket, but we need
to remember the new response for the next response we will get. We will keep all
of these deltas that we collected and add them all up.
The remembered response is:
static volatile uint16_t previousResult = 0;
and later used in the interrupt routine like this:
previousResult = theTenBitResults;
The assignment of theTenBitResult is done only after the sample of the difference
of the previous and current result is determined.
The static volatile is used so that the variable will not be "optimized out" by
the compiler (the mechanism that turns our code into a .hex file that the microcontroller
can understand). I have found that this static volatile is needed when the variable
will be used in interrupt routines.
The uint16_t is the datatype used because the previous result can be as high as
the result, which is a 10-bit number.
The deflection (difference from the previous response and the current response)
is declared in the interrupt routine becuase it is local to the interrupt routine.
In other words, the number will be used in a total summation in the variable "totalDeflectionOverTime"
so don't need to remember the deflection variable outside of the interrupt routine.
int deflection = theTenBitResults - previousResult;
if (deflection < 0 ) deflection = previousResult - theTenBitResults;
Send_An_IntegerToMrLCD(13,2,deflection, 4);
...
totalDeflectionOverTime += deflection;
The deflection is declared as an int because we need to know if the subtraction
it does is negative or positive. We can't use uint8_t or uint16_t because those
are always positive numbers. Since we always want positive numbers in the end, we
need to know if the subtraction will create a negative number so we can reverse
the subtraction problem.
The variable totalDeflectionOverTime is the total of all of the differences, but
only for a set number of samples, so we can compare apples to apples with other
components such as Mr. Cap and his brother Caps (various Capacitor values) and how
well they can clean our voltage curency.
We needed to hire an intern to stand next to Mrs. ADC with a clicker (a counter)
to count how many samples we are getting so the intern can inform us when to display
our total and zero the totalDeflectionOverTime variable so we can start all over.
If all of this were to be put together in a concise program, it might look like
this:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "MrLCD.h"
static volatile uint16_t previousResult = 0;
static volatile int totalDeflectionOverTime = 0;
static volatile uint16_t sampleCount = 0; int main(void)
{
InitializeMrLCD();
Send_A_StringToMrLCDWithLocation(1,1,"ADC Result:");
Send_A_StringToMrLCDWithLocation(1,2,"Deflection:");
Send_A_StringToMrLCDWithLocation(1,3,"Total:");
ADCSRA |= 1<<ADPS2;
ADMUX |= (1<<REFS0) | (1<<REFS1);
ADCSRA |= 1<<ADIE;
ADCSRA |= 1<<ADEN;
sei();
MCUCR |= 1<<SM0;
MCUCR |= 1<<SE;
ADCSRA |= 1<<ADSC;
while (1)
{
}
}
ISR(ADC_vect)
{
uint8_t theLowADC = ADCL;
uint16_t theTenBitResults = ADCH<<8 | theLowADC;
Send_An_IntegerToMrLCD(13,1,theTenBitResults, 4);
int deflection = theTenBitResults - previousResult;
if (deflection < 0 ) deflection = previousResult - theTenBitResults;
Send_An_IntegerToMrLCD(13,2,deflection, 4);
previousResult = theTenBitResults;
totalDeflectionOverTime += deflection;
sampleCount++;
if (sampleCount >= 300)
{
Send_An_IntegerToMrLCD(8,3,totalDeflectionOverTime, 6);
totalDeflectionOverTime = 0;
sampleCount = 0;
}
ADCSRA |= 1<<ADSC;
}