STM32F4 adc ölçümünde tutarsızlık var

Başlatan XX_CİHAN_XX, 10 Aralık 2012, 09:49:31

XX_CİHAN_XX

Aşağıdaki gibi bir kod yazdım. Amacım 4 farklı kanaldan istediğim zamanlarda çevrim yaptırabileceğim bir fonksiyon oluşturmak.

//Single mode adc çevrimi için gerekli ayarlamalar yapilir
void adc_setup (ADC_TypeDef* ADCX)
{
	ADC_InitTypeDef  ADC_InitStructure;
	if(ADCX==ADC1)
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	if(ADCX==ADC2)
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
	if(ADCX==ADC3)
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

	ADC_DeInit();	
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfConversion = 1;
	ADC_Init(ADCX, &ADC_InitStructure);
	ADC_Cmd(ADCX, ENABLE);
}

uint16_t adc_read (ADC_TypeDef* ADCX, uint8_t channel)
{
	ADC_RegularChannelConfig(ADCX, channel, 1, ADC_SampleTime_56Cycles);
	ADC_SoftwareStartConv(ADCX);
	while(ADC_GetFlagStatus(ADCX, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADCX);	
}


Fonksiyonu kullanım şeklim:

batV = adc_read(ADC1, ADC_Channel_8);
				delay_ms(50);
				fotoV = adc_read(ADC1, ADC_Channel_5);
				delay_ms(50);
				supV = adc_read(ADC1, ADC_Channel_1);
				delay_ms(50);
				lnbV = adc_read(ADC1, ADC_Channel_2);
				delay_ms(50);


Bağlı olduğu pinler:
/*
Pin A1 -> (Charge_On_Off) Adaptör Voltaji
Pin A2 -> LNB Akimi
Pin A5 -> Foto Detector Voltaji
Pin B0 -> Batarya Voltaji
*/


Ölçüm alıyorum ancak çok oynak değerler geliyor ve 12 bitlik çevrimde yaklaşık 150-200 değer kadar sapması olabiliyor. Sizce sebebi yazılımsal mı yoksa donanımsal mıdır?
Yirmi yaşındaki bir insan, dünyayı değiştirmek ister . Yetmiş yaşına gelince , yine dünyayı değiştirmek ister, ama yapamayacağını bilir.

Klein

150-200 çok yüksek değer. AVDD-AVSS arsından  bir gerilim bölücü ile ADC için giriş al. Eğer yine bu kadar oynak ise, yazılımla ilgili olabilir. Değilse giriş işaretin oynaktır. Taş çatlasın 3 bitlik ( 7-8 ) oynama olması gerek.

Yazılımda ilk bakışta bir anormallik görünmüyor. Ama ADC enable yapıldıktan sonra bir müddet kendine gelmesini beklemek gerektiğine ilişkin bir şeyler okuduğumu hatırlıyorum. Eğer ADC deinit yapıldığında ADC kapatılıyorsa, yeniden açıldığında bu süreyi beklemek geekebilir. 

Bu işlemcide  çok kanal okuma yapmak için her seferinde janal değiştirip , çevirim bitene kadar beklemek bana çok anlamlı gelmiyor.  Adam çoklu çevirim seçeneği koymuş. DMA kullanıp tüm kanalları okumak bence daha iyi bir yöntem.

XX_CİHAN_XX

Peki hocam  DMA kullanmayı deneyeceğim ancak birşey dikkatimi çekti.
Benim kullandığım ADC pinleri bu şekilde.

Pin A1 -> ADC123_IN1
Pin A2 -> ADC123_IN2
Pin A5 -> ADC12_IN5
Pin B0 -> ADC12_IN8

Burada iki tanesi ADC123 kısmında diğer iki kanal da ADC12 kısmında ben bunların hepsini ADC1 olarak ölçüyorum.
Bunun bir sakıncası var mı yoksa ben ADC123 mantığını yanlış mı anladım?
ADC123 demek ADC1, ADC2 ve ADC3 ten bu kanala erişebilirsin,
ADC12 de sadece ADC1 ve ADC2 den erişebilirsin demek oluyor değil mi?

Bu şekilde düşünerek tüm kanallara sadece ADC1 den erişmeyi uygun gördüm.
Yirmi yaşındaki bir insan, dünyayı değiştirmek ister . Yetmiş yaşına gelince , yine dünyayı değiştirmek ister, ama yapamayacağını bilir.

Klein


pisayisi

Ben basit bir gerilim bölücü pot devresi ile analog değer okumuştum değerler de hiç sapma yoktu, muhtemelen analog olarak girilen işaretlerde sıkıntı vardır. Birde böyle basit bir gerilim bölücü ile ölçüm yapmayı deneyin, sonra yazılımda skııntılar olabilirmi düşünmek lazım.
Murat

muhittin_kaplan

#5
bugün ben bir şarj ünitesinin giriş ve çıkışını ölçmek istedim. değerler çok oynak (300mV kadar) sabitlemek için unutulan geçmş algoritması kullandım. 30 lu dizi ile çalıştım.

mesaj birleştirme:: 10 Aralık 2012, 17:34:28

şarj devresinde bulunan bir röle çektiğinde devre reset atıyor ve çalışmıyor tekrar.(ters diyot var) sebebi MClear dan kaynaklanabilir mi ? siz MClear ı nasıl donanımlandırıyorsunuz ?

Klein

30'lu dizi ile düzelltebildiysen çok oynama yoktur zaten.
Programlayıcıbağlı değilken de resetleniyor mu?   

muhittin_kaplan

hocam programlayıcı bağlı değil. MCU var sadece ve diğer devre. beslemeyi de diğer devreden aldım.

Klein

Reset pini ile programlama soketi arasındaki mesafe çok mu uzak?
genellikle 4u7,4K7 ikilisi bir de hızlı deşarj için diyot kullanırım. 
Şu an üzerinde çalıştığım kart, bu işlemci ile yaptığım ilk kart. Reset devrem dışarıda. Bu yüzden standart yapı kullanmadım. Uçma kaçma testlerine gelmedim daha. Şimdilik böyle bir sorun yaşamadım.

Erhan YILMAZ

Hocam unutulan geçmiş algoritması nedir?

muhittin_kaplan

Hafızalı bir ortalama alma algoritması. örneğin 10 luk bir dizi ile yapalım.

int Deger[10];
int LoopValue;
int Toplam;

//dizinin yerlerini değiştirelim
for (LoopValue=0;LoopValue<10;LoopValue++)
{
Deger[LoopValue]=Deger[LoopValue+1]
}

Deger[9]=OlculenDeger

// Dizi değerlerini toplayalım
for (LoopValue=0;LoopValue<10;LoopValue++)
{
Toplam+=Deger[LoopValue]
}

//sonucu bulalım
Toplam=Toplam/10


http://muhittinkaplan.com/2012/02/unutulan-gecmis/

Klein

Şimdi bir test yaptım.
Reset devremi  ve programlayıcıyı ayırdım. Resette sadece 100n kapasite kaldı. (Pull-Up direnci işlemcinin içinde var)
Beslemeyi verdiğim  switching güç kaynağının 230V girişinden kontaktör ile seri arklar oluşturdum.
Kontaktörün bobininin 2 ucu da kontaktörün NC kontağına bağlı. Enerji verildiğinde sürekli açık kalmıyor. 15-20Hz civarında sürekli açıp kapama yapıyor.
Kontaktörün tek ucunu açıp kapatınca oluşan ark yeterince zorlamıyor. iki ucunu birden kesmek ve bağlamak çok daha yüksek gürülyü oluşturuyor. Aynı zamanda kontaktörü elimle tuttuğum için elimin titreşmesi nedeniyle açma kapama süreleri düzensizleşiyor. Böylece düzensiz arklar elde ediyorum.

Sistemi zorlamak adına RS485 haberleşme hzını 256000 bauda çıkardım. Her sorgulamada 132 bayt veri okuyorum. 2300 kez sorguladım.  12 kez haberleşme hatası aldım. ( kaç bayt veri yanlış gitti bilmiyorum. CRC yanlış gelince haberleşmehatası alıyorum).

Resetlenme yaşamadım.


muhittin_kaplan

arkadaşın konusunuda kirlettik ama kusrumuza bakmasın artık.
hocam ben doğrudan 3.3v a bağladım. muhtemel hata bende değil ama tabiki tereddütlerim var. 100n ile şaseleyeceğim yarın.
(ayrıca mclre ye pullup bağlamaya gerek yok diye biliyorum doğrumuyum ?)

Erhan YILMAZ

Sağolun hocam. Belli sayıda okuma yapıp bunların ortalamasını alıyoruz doğru mu anlamışım? Kullanılan bi yöntem mi hocam ne kadar verimlidir öğrenmek açısından soruyorum.

Klein

#14
@muhittin

Her seferinde yeniden tüm değerleri toplamana ve tüm diziyi kaydırmana gerek yok. Bu işlem çok uzun zaman alır.
Tablo için bir index tut.  Her işlemden sonra indeksi bir artır.
Her yeni veri geldiğinde  tablonun indexin gösterdiği adresindeki  veriyi genel toplamdan çıkar , yeni gelen veriyi genel toplama ekle , aynı zamanda da  son gelen veriyi tablonun aynı adresine yaz. indeksi bir artır.

örnek:
  
Total -=  Buf[Index];
Total += new_adc_value;
Buf[Index]= new_adc_value;
 
FilteredValue = Total / FILTERSIZE;

if(++Index == FILTERSIZE)
{
       Index=0;
}

Filtre tampununun büyüklüğünü 2'nin katları şeklinde ayarlarsan bölme daha kolay olur.



mesaj birleştirme:: 10 Aralık 2012, 18:38:24

Alıntı yapılan: Erhan YILMAZ - 10 Aralık 2012, 18:22:40
Sağolun hocam. Belli sayıda okuma yapıp bunların ortalamasını alıyoruz doğru mu anlamışım? Kullanılan bi yöntem mi hocam ne kadar verimlidir öğrenmek açısından soruyorum.

Kullanılan bir yöntemdir. Oldukça etkili ve basittir ancak çok fazla ram gerektirir.  Kayan ortalama yöntemi de denir.
Klasik ortalama almadan biraz farklıdır. 
Klasik ortalamada kaç  ortalama alacaksanız, o kadar veri gelene kadar toplar sonra ortalamasını alırsınız ve yeni verilerin gelmesini beklersiniz. Ancak çok az ram kullanırsınız.
Kayan ortalamada ise ,  bir diziniz olur.  Her yeni veri geldiğinde dizideki ilk kayıt atılır , son gelen veri dizinin sonuna eklenir.