ortalama alma işlemi

Başlatan secretagent, 22 Şubat 2011, 21:30:18

Hattusa

bu şekilde derleyebildim ama isisde lcd ye görüntü gelmiyor ve isisde hata veriyor

Device 16F877A
Xtal 4

Declare Adin_Res 10   ' Sets the number of bits in the result
Declare Adin_Tad 32_Fosc  ' Sets the ADC's clock source
Declare Adin_Stime 10   ' Allows the internal capacitors to fully charge
                                                                 
'-------------------------- LCD connection settings ------------------------
                                                                  
Declare  LCD_Type ALPHA   ' Alphanumeric LCD type
Declare  LCD_DTPin  PORTD.4   ' LCD data port
Declare  LCD_ENPin  PORTD.3   ' E line
Declare  LCD_RSPin  PORTD.2   ' RS line
Declare  LCD_Interface  4   ' 4-line or 8-line interface
Declare  LCD_CommandUs  100   ' Time to wait (in uS) between commands sent to the LCD
Declare  LCD_DataUs  50   ' Time to wait (in microseconds) between data sent to the LCD
Declare  LCD_Lines   4   ' How many lines the LCD has

ADCON1 = %10000010                                                            
'-------------------------- Ports settings ---------------------------------
   
TRISA = %00011111
PORTA = 0
TRISB = %00000000
PORTB = 0
TRISC=  %00000000 
PORTC = 0
TRISD = %00000000
PORTD = 0
TRISE = %00000000
PORTE = 0

Symbol fR = PORTE.0
Symbol OrNk1 = PORTE.1
Symbol oRnK2 = PORTE.2

'-------------------BUBBLE SORT DEĞİŞKENLERİ--------------------------
Symbol NuMuNeSaY1 = 10
Symbol nUmUnEsAy2 = 10
Dim gDegIsKeNa As Word
Dim GdEgIsKeNb As Word
Dim nDeX1 As Byte
Dim NdEx2 As Byte
Dim AdCoKu1 As Word
Dim aDcOkU2 As Word
Dim StAmAm1 As Byte
Dim sTaMaM2 As Byte
Dim SaMpLe1[NuMuNeSaY1 + 1] As Word
Dim sAmPlE2[nUmUnEsAy2 + 1] As Word
Dim N1 As Byte
Dim N2 As Byte
Dim X As Byte



AyArT:
GoSub TARAMA
GoSub BUBBLE_SORTA
GoSub BUBBLE_SORTB

Cls
Print At 1,1, Dec SaMpLe1[N1]
Print At 2,1, Dec sAmPlE2[N2]
Print At 3,1, Dec X
DelayMS 10
GoTo AyArT

TARAMA:
X = 1
 
Repeat
fR = 1
DelayUS 500
fR = 0
DelayUS 200
OrNk1 = 1
DelayUS 5
SaMpLe1[N1] = ADIn 1    '1 adc okuması
DelayUS 5
OrNk1 = 0
DelayUS 50
oRnK2 = 1
DelayUS 5
sAmPlE2[N2] = ADIn 4  '2 adc okuması
DelayUS 5
oRnK2 = 0
DelayUS 8000


Inc N1
Inc N2 

Until X = 10

Return

BUBBLE_SORTA:
Repeat           
StAmAm1 = 0                                              
nDeX1 = 0            
Repeat                
If SaMpLe1[nDeX1] > SaMpLe1[nDeX1 + 1] Then                    
gDegIsKeNa = SaMpLe1[nDeX1]                
SaMpLe1[nDeX1] = SaMpLe1[nDeX1 + 1]  
SaMpLe1[nDeX1] = gDegIsKeNa                 
StAmAm1 = 1                  
EndIf                
Inc nDeX1            
Until nDeX1 = NuMuNeSaY1             
Until gDegIsKeNa = 0         
Return

BUBBLE_SORTB:
Repeat           
sTaMaM2 = 0                                              
NdEx2 = 0            
Repeat                
If sAmPlE2[NdEx2] > sAmPlE2[NdEx2 + 1] Then                    
GdEgIsKeNb = sAmPlE2[NdEx2]                
sAmPlE2[NdEx2] = sAmPlE2[NdEx2 + 1]  
sAmPlE2[NdEx2] = GdEgIsKeNb                 
sTaMaM2 = 1                  
EndIf                
Inc NdEx2            
Until NdEx2 = nUmUnEsAy2             
Until GdEgIsKeNb = 0         
Return
vardım ilim meclisine eyledim talep, meğer ilim en gerideymiş illa EDEP, illa EDEP <muhyiddin Arabi K.S.>

muhittin_kaplan

Unutulan Geçmiş Yöntemi
saygıdeğer Melih Karakelle nin bana anlattığı bir yöntem

Alıntı YapEvet benzer sebeplerden ben de başlayıp pek çok kez vazgeçtim.
Mikroişlemciye Kalman yaptıracağım diye float değişken hesaplatıp sonra da yeterli ölçüm sıklığına ulaşamadığın için kalmansız durumdan beter olmak var işin ucunda 

Benim yöntem çok basit, bilgisayar programcısının can simididir unutulan değişken filtresi, hayat boyu binlerce yerde kullanmışımdır heralde.

Yöntem şöyle;

int X[10]; // bu array değişkenimiz olsun

yeniX = sensör_verisi; // bu da okuduğumuz değer olsun

for (i=0;i<9;i++) // 9 kere döngüyü döndürelim
{
j = 8 - i; //8 den 0 e doğru geriye saydıralım
X[j+1] = X[j] ; // Her seferinde eski X[j] değerini bir eskisinin yerine taşıyalım
}

veya aynı for işleminin daha az işlemci yükü gerektireni
X[9] = X[8];
X[8] = X[7];
X[7] = X[6];
X[6] = X[5];
X[5] = X[4];
X[4] = X[3];
X[3] = X[2];
X[2] = X[1];
X[1] = X[0];

Böylece her değişkeni bir alta taşıdık (bunun daha farklı yolu da var ama bu anlatılması en kolayı)

X[0] = yeniX ; // böylece ilk değer son sensör verisi oldu

OrtalamaX = SUM(X) / 10; // tüm X değerlerini toplayıp 10 a bölüyoruz.

ve elimizde en son 10 değerin ortalaması ile elde edilmiş OrtalamaX değeri kalıyor


Yöntem bukadar basit, bu yöntemin en büyük avantajı işlemci yükünün minimum olmasında, yukarıdaki halinden daha fazla optimize etmek de mümkün ve bu hali ile saniyede binlerce kez ölçüm alıp işlemeni mümkün kıldığı için en önemli sorun olan sensör parazitlerini ve titreşimi de gidermek çok kolay oluyor.

Ayrıca sensör çıkışında lowpass filtre kullanırsan bu tip yazılımsal taklaları daha da azaltman mümkün. Ben çıkışlarda 100kOhm direnç ve 100nF kondansatör kullanıyorum, çıkış sinyalini oldukça iyi yumşatıyor (30hz civarında) , eğer daha yavaş ve yumuşak sinyaller istersen 1 megaohm direnç kullan.
Hiçbir yazılımsal filtre gerçek bir kondansatör ve dirençten daha güzel sinyal yumşatamaz, bu yüzden analog sensörler hala dijitallerden daha kullanışlı.

Hattusa

muhiddin hocam verdiğiniz bilgiler için teşekkür ederim.
söylediğiniz tekniği emin olun deneyeceğim. benim sorunum 10 kez okuttuğum ADC değerinde pik atan (amiyane deyim sanırım) adc ölçümlerini hesaplamadan çıkartmak, yani 10 tane ADC okutma sonucum,
(100,101,99,110,108,200,96,250,102,105) işte 10 tanede benim ortalama aldırdığım sonuçtan 2 sini hiç hesaba katmamak, sanırım bu iş söylemek kolay yapmak zor... ;D
vardım ilim meclisine eyledim talep, meğer ilim en gerideymiş illa EDEP, illa EDEP <muhyiddin Arabi K.S.>

pcb

@TR_PRO
bence aritmetik ortalama, filtre vs. ile sinyali düzeltmek yerine, böyle spike ların oluşduğu çıkış ile uğraşmak daha önemli bence.
sonuç değer kısa sürede tepki vermesi gereken başka bir sinyali tetiklemesi gerekiyorsa 10-20 kere ortalama aldırmaktan vazgeçecek ve bozuk sinyal çıkış kaynağına tekrar döneceksiniz.
Toplam zaman kaybı , sample aldığınız noktaların tekrarlama (frekans) süresinin toplamı ile alakalı. Hareket halinde veya 50-60hz parazit yüklü bir sinyalle uğraşıyorsunuz sanırım.
50-60hz parazit elimine edici adc ler var piyasada. incelemenizi tavsiye ederim.

Projeniz hakkında hiç bir fikrim yok ve diğer sayfalardaki yazıları okumadım, benimki sadece bir tavsiye

Hattusa

Alıntı yapılan: pcb - 24 Şubat 2011, 23:03:45
@TR_PRO
bence aritmetik ortalama, filtre vs. ile sinyali düzeltmek yerine, böyle spike ların oluşduğu çıkış ile uğraşmak daha önemli bence.
sonuç değer kısa sürede tepki vermesi gereken başka bir sinyali tetiklemesi gerekiyorsa 10-20 kere ortalama aldırmaktan vazgeçecek ve bozuk sinyal çıkış kaynağına tekrar döneceksiniz.
Toplam zaman kaybı , sample aldığınız noktaların tekrarlama (frekans) süresinin toplamı ile alakalı. Hareket halinde veya 50-60hz parazit yüklü bir sinyalle uğraşıyorsunuz sanırım.
50-60hz parazit elimine edici adc ler var piyasada. incelemenizi tavsiye ederim.

Projeniz hakkında hiç bir fikrim yok ve diğer sayfalardaki yazıları okumadım, benimki sadece bir tavsiye

ustam bunlarla ilgili örnek bir entegre verebilirmisiniz, çalıştığım frekans 100 hertz ve ben bu 100 hertzlik kare dalga sinyalden her pals bitiminde 2 farklı adc okutuyorum. ve bu işlemi 10 ile 20 kez yapıyorum ortalamasını aldırıyorum. sonuçtan memnun değilim. zira 8 bit ADC de sorun yok, 10 bit ADC biraz artıyor, 12 bit ADC de dahada artacak, belki 24 bite yükseldiğimizde nasıl stabileştireceğim?
vardım ilim meclisine eyledim talep, meğer ilim en gerideymiş illa EDEP, illa EDEP <muhyiddin Arabi K.S.>

pcb

10 bit çok hassas okumalar için yeterli bence daha yüksek çözünürlüklerde okumalar içinden çıkılmaz sonuçlar oluşturabilir.
sözünü ettiğim 50-60hz parazit elimine edici ADC ler 50-60hz de 1 kere okuma yapıyor ve delta-sigma adc olarak bilinir, tabi bu ADC lerin sample alma hızları değiştirilebliyor. sadece 50-60hz de okuma yapma durumu malum sürekli aynı noktayı okuduğundan parazitin değerinide hep aynı görüyor yani o noktadaki değeri.

Max11040 diye bir ADC var muhteşem bir ürün ama pahallı biraz, 1 mikrosaniye aralıklarla 3-4 okuma yapabiliyor bu süre daha uzatılabiliyor. delta sigma özelliği yok ama 1 mikrosaniye aralıklı okumanın birbirine çok yakın olması gerekli buradan çözüme ulaşılabilir.
LTC2480 delta-sigma ADC dir parazit önleyici özelliği var. Tabi siz 100hz frekansınızı 50-60hz e düşürmeniz gerekiyor.
Veya şöyle olabilir, siz çalışma frekansınızı 100hz değilde 120 hz e yükseltirseniz 60hz paraziti engelleyebilirsiniz ama 2 pals da bir okuma yaparak bu sabit değeri koruyabilirsiniz.
Delta sigma adc diye arama yapın onlarca bulacaksınız.
kolay gelsin

Hattusa

Alıntı yapılan: muhittin_kaplan - 24 Şubat 2011, 21:58:07
Unutulan Geçmiş Yöntemi
saygıdeğer Melih Karakelle nin bana anlattığı bir yöntem

Alıntı YapEvet benzer sebeplerden ben de başlayıp pek çok kez vazgeçtim.
Mikroişlemciye Kalman yaptıracağım diye float değişken hesaplatıp sonra da yeterli ölçüm sıklığına ulaşamadığın için kalmansız durumdan beter olmak var işin ucunda 

Benim yöntem çok basit, bilgisayar programcısının can simididir unutulan değişken filtresi, hayat boyu binlerce yerde kullanmışımdır heralde.

Yöntem şöyle;

int X[10]; // bu array değişkenimiz olsun

yeniX = sensör_verisi; // bu da okuduğumuz değer olsun

for (i=0;i<9;i++) // 9 kere döngüyü döndürelim
{
j = 8 - i; //8 den 0 e doğru geriye saydıralım
X[j+1] = X[j] ; // Her seferinde eski X[j] değerini bir eskisinin yerine taşıyalım
}

veya aynı for işleminin daha az işlemci yükü gerektireni
X[9] = X[8];
X[8] = X[7];
X[7] = X[6];
X[6] = X[5];
X[5] = X[4];
X[4] = X[3];
X[3] = X[2];
X[2] = X[1];
X[1] = X[0];

Böylece her değişkeni bir alta taşıdık (bunun daha farklı yolu da var ama bu anlatılması en kolayı)

X[0] = yeniX ; // böylece ilk değer son sensör verisi oldu

OrtalamaX = SUM(X) / 10; // tüm X değerlerini toplayıp 10 a bölüyoruz.

ve elimizde en son 10 değerin ortalaması ile elde edilmiş OrtalamaX değeri kalıyor


Yöntem bukadar basit, bu yöntemin en büyük avantajı işlemci yükünün minimum olmasında, yukarıdaki halinden daha fazla optimize etmek de mümkün ve bu hali ile saniyede binlerce kez ölçüm alıp işlemeni mümkün kıldığı için en önemli sorun olan sensör parazitlerini ve titreşimi de gidermek çok kolay oluyor.

Ayrıca sensör çıkışında lowpass filtre kullanırsan bu tip yazılımsal taklaları daha da azaltman mümkün. Ben çıkışlarda 100kOhm direnç ve 100nF kondansatör kullanıyorum, çıkış sinyalini oldukça iyi yumşatıyor (30hz civarında) , eğer daha yavaş ve yumuşak sinyaller istersen 1 megaohm direnç kullan.
Hiçbir yazılımsal filtre gerçek bir kondansatör ve dirençten daha güzel sinyal yumşatamaz, bu yüzden analog sensörler hala dijitallerden daha kullanışlı.

s.a.
Muhiddin hocam "UNUTULAN GEÇMİŞ" işlemini anlayamadım, yani bu teknik ile nasıl bir filtreleme oluyor. yani örnek olarak elimde 10 tane ADC ölçümü var diyelim bunlar;
A0= 200
A1= 500
A2= 210
A3= 190
A4= 205
A5= 450
A6= 195
A7= 202
A8= 212
A9= 300

burda elimdeki değerlerde sorun olduktan sonra A1 ile A0 ın yerinin değişiminin filtreleme işleminde ne gibi bir faydası olacak, bu konuda bilgisi olan arkadaşların önerilerini bekliyorum.
vardım ilim meclisine eyledim talep, meğer ilim en gerideymiş illa EDEP, illa EDEP <muhyiddin Arabi K.S.>

Hattusa

#37
Alıntı Yap
TARAMA:
X = 1
Repeat
fR = 1
DelayUS 500
fR = 0
DelayUS 200
OrNk1 = 1
DelayUS 5
SaMpLe1 = ADIn 1    '1 adc okuması
DelayUS 5
OrNk1 = 0
DelayUS 50
oRnK2 = 1
DelayUS 5
sAmPlE2 = ADIn 4  '2 adc okuması
DelayUS 5
oRnK2 = 0
DelayUS 8000
'ben buraya repeat komutu  oluşturduğum 10 turluk döngüde her turda okuttuğum ADC değerlerini registerlerin içerisine 'kaydedemiyorum.
Until X = 10
Return
'ben buraya repeat komutu  oluşturduğum 10 turluk döngüde her turda okuttuğum ADC değerlerini Sample1[x1],sample1[x2],sample1[x3]........sample1[x10] aynı şekild sample2 değerlerini registerlerin içerisine kaydedemiyorum.
bana bu konuda yardımcı olmanızı bekliyorum.
vardım ilim meclisine eyledim talep, meğer ilim en gerideymiş illa EDEP, illa EDEP <muhyiddin Arabi K.S.>

muhittin_kaplan

Hocam Kodla değilde mümkün olduğunca mantığını anlatmaya çalışayım. (kodlar hatalıdır not defterinde yazıyorum)
siz 10 adet kayıtı bir değişkene atmak istiyorsunuz sanırım

dim Okunan_1[10] as byte        ;Değişken Tanımla
dim Okunan_2[10] as byte        ;Değişken Tanımla
dim Loop as byte

Oku:
      for loop=0 to 9
         okunan_1[Loop]=adin 0
         delayms 100
         okunan_2[Loop]=adin 1
         delays 100
      next


Yaparak her kanalın okuduğu 10 değeri, 10 adet derinliğindeki değişkene atarsın..

     
     

Hattusa

Alıntı yapılan: muhittin_kaplan - 26 Şubat 2011, 13:22:33
Hocam Kodla değilde mümkün olduğunca mantığını anlatmaya çalışayım. (kodlar hatalıdır not defterinde yazıyorum)
siz 10 adet kayıtı bir değişkene atmak istiyorsunuz sanırım

dim Okunan_1[10] as byte        ;Değişken Tanımla
dim Okunan_2[10] as byte        ;Değişken Tanımla
dim Loop as byte

Oku:
      for loop=0 to 9
         okunan_1[Loop]=adin 0
         delayms 100
         okunan_2[Loop]=adin 1
         delays 100
      next


Yaparak her kanalın okuduğu 10 değeri, 10 adet derinliğindeki değişkene atarsın..

     
     

peki hocam benim anlamadığım, okunan_1 ve okunan_2  bunlar ADC değerleri ise byte boyundan büyük değil mi? yani 10 bit ADC değerimiz 1023 değerinde.
birde LCD ye bu değerleri basmak istersem mesela adin 0' ın 5. sırada okunan değerini bunu nasıl tanımlamalıyım? yani
print at 1,1,dec okunan_1[5] dediğimde hata veriyor?  ;D
sanırım bu kısmı karıştırdım ya hadi hayırlısı...
vardım ilim meclisine eyledim talep, meğer ilim en gerideymiş illa EDEP, illa EDEP <muhyiddin Arabi K.S.>

muhittin_kaplan

pek tabiki hocam 10bit se word olmalı.
Aşağıdaki kodları derliyor.
Basla:
        For Loop=0 To 9 
            Okunan_1[Loop]=loop*100
            DelayMS 100
            Print At 1,1,Dec Okunan_1[Loop]
        Next
        GoTo Basla
        Stop

frederic

#41
Merhaba aşağıdaki kodu değiştirip denedim, x değeri 5 olduğunda 251 gibi alakasız bir ortalama veriyor fakat x değerini 0 yapınca ortalama değer olarak 10 değerini veriyor, yani doğru değeri veriyor. X değeri baştan ve sondan bir takım değerleri atmak için tasarlanmış konunun başında anlaşılacağı üzere, 251 değeri gibi alakasız bir değeri neden üretiyor acaba?

#include <18F46K22.h>
#device ADC=10

#FUSES INTRC_IO
#FUSES NOMCLR

#use delay(internal=16000000)

#include <4x20LCD.c>


int d[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
int i, j, g, x = 5, toplam, ort;

void main()
{  
   
   
   setup_adc (adc_off);
   setup_adc_ports (no_analogs);
   lcd_init();

    //diziye öylesine 20 deger atıyorum
   
   //sıralıyorum
   for (i = 0; i < sizeof(d);i++)
   {
      for(j=0; j < sizeof(d);j++)
      {
         if(d[i] > d[j])
         {
            g = d[i];
            d[i] = d[j];
            d[j] = g;
         }
      }
   }
   //başından ve sonundan x değeri kadarını yoksayıp, toplayıp ortalamalarını alıyorum
   for(i = x; i < sizeof(d) - x ; i++)
      toplam += d[i];
   ort = toplam / sizeof(d) - (x * 2);
   
   lcd_gotoxy(1,1);
    printf(lcd_putc,"value    W=%u       ",ort);
    
 

}

kantirici

Alıntı yapılan: pro-TR - 24 Şubat 2011, 22:12:16
muhiddin hocam verdiğiniz bilgiler için teşekkür ederim.
söylediğiniz tekniği emin olun deneyeceğim. benim sorunum 10 kez okuttuğum ADC değerinde pik atan (amiyane deyim sanırım) adc ölçümlerini hesaplamadan çıkartmak, yani 10 tane ADC okutma sonucum,
(100,101,99,110,108,200,96,250,102,105) işte 10 tanede benim ortalama aldırdığım sonuçtan 2 sini hiç hesaba katmamak, sanırım bu iş söylemek kolay yapmak zor... ;D

Bu pik değerini neyi referans alıp atacaksın peki. 110 değeri neye göre pik değer sayılmalı ?

aliveli

@RcALTIN dediği radial olypic ve oldukça faydalıdır. alınan ölçümlerden en düşük ve en yüksek değerleri pik kabul edip hesaplamadan çıkarır. aşağıdaki kod c içindir basic için fikir verebilir. basic diline çeviren olursa başkasına da faydalı olacaktır.
//16 kere adcden okuma yapılır, değerler sıralanır, alttaki ve üstteki dört değer çıkarılır,ortadaki 8 değerin ortalaması alınır
unsigned int16 adchlx(void){  

 unsigned int8 i;  unsigned int16 accum=0;  
 unsigned int16 s, b[16]; int1 didswap=1; 

//bu döngü 16 kere okuma yapar ve b[] dizisine yerleştirir
   for ( i = 0 ; i < 16;  i++ ) { 
           b[i]= read_adc(ADC_start_and_read); // ADC okunur diziye  atılır
           delay_us(8);  
     } 

// bubble sort algoritması b[] dizisindeki elemanlar küçükten büyüğe sıralanır.
   while(didswap){  
     didswap=0; 
     for (i=0; i<15; i++){ // i 0-15 
      if(b[(i)]>b[(i+1)]){ // eğer değer sonrakinden büyükse sırayı değiştir 
           s=b[i]; // yükseği tut
           b[i]=b[(1+i)]; 
           b[(1+i)]=s; 
           didswap=1; // yer değiştirme işi bitince döngüden çıkartır duruma göre işlemi kısaltabilir
      } // ~if 
     } // ~for 
    } // ~while 

   //elemanları sıralanan  b[] dizisinde ortadaki 8 değerin ortalaması alınır.
   for (i=4; i<12; i++){  accum +=b[i];  } 
   return(accum>>3); 
}



burada verilen 16 , 4 değerleri isteğe göre artırılıp azaltılabilir.


Mr.Java

#44
Diziyi sıralama algoritması geliştirilebilir.Hız faktörü hesaplanıp daha stabil programlar yazılabilir.Aşağıdaki kod yol gösterebilir.

#include<stdio.h>
#include<conio.h>

void quick_sort(int arr[20], int, int);

void main()
{
	int arr[20], n, i;
	clrscr();
	printf("Enter the number of elements in the Array: ");
	scanf("%d", &n);
	printf("\nEnter %d elements:\n\n", n);

	for (i = 0; i < n; i++) {
		printf(" Array[%d] = ", i);
		scanf("%d", &arr[i]);
	}

	quick_sort(arr, 0, n - 1);
	printf("\nThe Sorted Array is:\n\n");

	for (i = 0; i < n; i++) {
		printf(" %4d", arr[i]);
	}
	getch();
}

void quick_sort(int arr[20], int low, int high)
{
	int pivot, j, temp, i;
	if (low < high) {
		pivot = low;
		i = low;
		j = high;

		while (i < j) {
			while ((arr[i] <= arr[pivot])&&(i < high)) {
				i++;
			}

			while (arr[j] > arr[pivot]) {
				j--;
			}

			if (i < j) {
				temp = arr[i];
				arr[i] = arr[j];
				arr[j] = temp;
			}
		}

		temp = arr[pivot];
		arr[pivot] = arr[j];
		arr[j] = temp;
		quick_sort(arr, low, j - 1);
		quick_sort(arr, j + 1, high);
	}
}