Sometimes, dc signals from physical parameters (temperature, current, voltage, etc.) may show a little variation in time caused by electromagnetic interference, or even by its own nature. For example, in dc power plants, even high-frequency rectifiers deliver a 0.2-V ripple when managing large loads. This signal variation is observed when an MCU displays its own (or external) analog-to-digital converter's (ADC's) sample conversions taken at different times. The figure shows a dc signal that has variations in time. If the samples are taken at t0, t1, t2, t3, t4, etc., and every sample is displayed on an LCD, the user might not know the measured signal's real level.
This instability may look like a system failure and cause uncertainty of the real measured value. A low-pass filter can solve this problem in some cases. But for others, such as when hardware is limited by pc-board space or budget, the best choice is to average the signal. This is accomplished by taking many samples and dividing the sum by the number of samples. The average of N samples of a parameter X is:
where Xi is the i-th sample taken from the parameter X, and N is the total number of samples.
Adding 10-bit numbers is made easy because they can be divided in two registers. Whenever a carry occurs in the addition of the two least significant bytes, the most significant byte must be incremented.
In some 8-bit RISC-based MCUs, there's no instruction available for performing arithmetical divisions. In principle, any number can be divided by 2 just by rotating its binary representation to the right. For example, the number (14)10 = (1110)2, then (14/2)10 = (7)10 = (0111)2. Similarly, it's possible to divide any number by 4, 8, 16, 32, and so on. In this case, particularly for Microchip's PIC MCU family, a short subroutine can solve this obstacle (see the code listing).
The first nine lines are an example of a source code that uses the subroutine "Average" to calculate the average of 64 samples taken from a particular ADC's channel (channel 3 in this case). As shown, these nine lines can be used similarly to call the same subroutine to calculate the average of any other channel by just changing the value of the constant defined in line 5.
The subroutine "Average" first calls a delay used to adjust the time taken to convert the 64 samples. It's recommended to take the 64 samples in a time that equals a multiple of the ripple's period. If the ripple isn't so large, this subroutine can be omitted. The best results occur if TEMPO is calculated as follows:
TEMPO ~ 1/64 mTR
where m is an integer and TR is the period of the ripple in seconds.
From line 10 to 18, the sum of the samples is made. The whole subroutine might be as short as that, because the average final result will be contained in registers AddM (the 8 most significant bits) and AddL (the 2 least significant bits), when the condition in line 17 will make the PC counter skip to line 19. If the programmer has a subroutine to convert binary to BCD (typical format to display characters in LCD) that may work with the actual result, then the code in line 35 shall be written in line 19 to exit the subroutine.
From line 19 to 34, the subroutine just shifts the result of the average in such a way that the eight least significant bits are stored in register LSB, and the two most significant are stored in register MSB, which is more likely to convert to BCD. The final result will be a steady, fixed, and more reliable reading on the screen, LCD, or seven-segment display.