• Email
  • Forum

Uśrednianie wyników ADC

O uśrednianiu słyszał każdy, ale nie każdy do końca rozumie sposoby i ich konsekwencje. Postaram się przedstawić trzy przykłady.

Zwykła średnia

Najprostszym sposobem jest zebranie kilku próbek i podzielenie ich. Na przykład, wynik z ADC ma maksymalnie 1023 a Word pomieści 65536. Można więc spokojnie w jednym takim Word dodać do siebie 64 pomiary i potem szybko podzielić przez 64. Wadą tego rozwiązania jest to, że program się tu zatrzymuje na czas pomiarów. Czyli musi 64 razy zmierzyć... Można zbierać mniej próbek... W zależności od programu nie musi to wcale przeszkadzać. Kod takiego rozwiązania, gotowy do przetestowania w Bascomowym symulatorze, poniżej. Zwróć uwagę że Bascom pod suwakiem ADC pokazuje co ustawiłeś a na wyświetlaczu masz wynik ;)


$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 16
$framesize = 32
 
$sim
'OZNACZA PRZYGOTOWANIE KODU DO SYMULACJI - USUNĄĆ DLA PRAWDZIWEGO MIKROKONTROLERA
 
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16x2
Deflcdchar 0 , 32 , 32 , 14 , 17 , 31 , 16 , 14 , 1
Deflcdchar 2 , 32 , 32 , 14 , 1 , 15 , 17 , 15 , 1
Cursor Off
Cls
 
Config Adc = Single , Prescaler = Auto , Reference = Avcc
 
Const Ilosc_probek = 50
 
Dim Adc_read As Word , Idx As Byte
 
 
Do
 
 Adc_read = 0
 
  For Idx = 1 To 64
   Adc_read = Adc_read + Getadc(0)
  Next
   Shift Adc_read , Right , 6
 
   Locate 1 , 1 : Lcd Adc_read ; "   "
 
Loop

Średnia ciągniona

Innym sposobem jest przechowywanie większej ilości poprzednich wyników a nowe odczyty pomału wpływają na na całość średniej. W tym celu musimy mieć tablicę Wordów(n) i to jest po części wadą tego rozwiązania jeśli mamy uC z małą ilością SRAM.
Sposób działania jest prosty. Mamy zmienną która pokazuje do której komórki tablicy zapiszemy sobie nowy wynik (tuaj Idx). Zawsze odczytujemy nowy wynik i zawsze sumujemy wszystkie próbki a potem dzielimy przez ilość próbek. To jakby drugi minus tego rozwiązania.


$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 16
$framesize = 32
 
$sim
'OZNACZA PRZYGOTOWANIE KODU DO SYMULACJI - USUNĄĆ DLA PRAWDZIWEGO MIKROKONTROLERA
 
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16x2
Deflcdchar 0 , 32 , 32 , 14 , 17 , 31 , 16 , 14 , 1
Deflcdchar 2 , 32 , 32 , 14 , 1 , 15 , 17 , 15 , 1
Cursor Off
Cls
 
Config Adc = Single , Prescaler = Auto , Reference = Avcc
 
Const Ilosc_probek = 50
 
Dim Tablica(ilosc_probek) As Word
Dim Idx As Byte , Iteration As Byte
Dim Sum As Dword , Wynik As Word
 
 
 
Do
 
 Incr Idx : If Idx > Ilosc_probek Then Idx = 1
 
 Tablica(idx) = Getadc(0)
 
 Sum = 0
 For Iteration = 1 To Ilosc_probek
  Sum = Sum + Tablica(iteration)
 Next
 
 Sum = Sum / Ilosc_probek
 Wynik = Sum
 
  Locate 1 , 1 : Lcd Wynik ; "   "
 
Loop

Inne rozwiązanie ;)

Kolejne rozwiązanie nie potrzebuje ani czekać na dużo pomiarów, ale też nie potrzebuje tablicy. Poprzednia suma jest przechowywana w zmiennej typu DWORD.
Wystarczy popatrzeć żeby zobaczyć jak to działa ;) Jeśli masz więcej kanałów ADC do uśrednienia to dla każdego potrzebujesz osobną Sumę DWORD (cztery bajty).


$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 16
$framesize = 32
 
$sim
'OZNACZA PRZYGOTOWANIE KODU DO SYMULACJI - USUNĄĆ DLA PRAWDZIWEGO MIKROKONTROLERA
 
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16x2
Deflcdchar 0 , 32 , 32 , 14 , 17 , 31 , 16 , 14 , 1
Deflcdchar 2 , 32 , 32 , 14 , 1 , 15 , 17 , 15 , 1
Cursor Off
Cls
 
Config Adc = Single , Prescaler = Auto , Reference = Avcc
 
 
Dim Adc_read As Word
Dim Suma As Dword
Dim Wynik As Word
Dim Help As Dword
 
Do
 
      Adc_read = Getadc(0)
       Help = Suma
       Shift Help , Right , 3
       Suma = Suma - Help
       Suma = Suma + Adc_read
       Help = Suma
       Shift Help , Right , 3
       Wynik = Help
 
       Locate 1 , 1 : Lcd Wynik ; "    "
 
Loop
End

Dla dwóch ostatnich kodów nagrałem film z symulacji Bascomowej. Sam oceń co działa/reaguje szybciej. Oczywiście metodą średniej ciągnionej przyspieszymy kod zmniejszając ilość próbek (wielkość tablicy). Można też użyć ilośc próbek która będzie potęgą dwójki czyli 16,32,64 i skorzystać z szybkiego dzielenia przesunięciem bitowym Shift.


FILM MOŻNA ZOBACZYĆ NA FORUM

Email

Jeśli mogę w czymś pomóc, napisz.