ADC modülü kullanarak frekans okuma

Başlatan kemskems, 05 Temmuz 2010, 10:23:25

kemskems

Arkadaşlar merhabalar,
Pic programlamaya yeni başlamış biri olarak herhangi bir PIC'in (örn: 16f877,16f28 vb.)  ADC modülünü kullanarak bir tür frekans metre yapmam gerekiyor. ADC nin volt okuma ile ilgili örneklerini anladım fakat frekans ile ilgili herhangi bir örnek bulamadım,bulduklarımda da ADC kullanılmamıştı.
ADC modülüyle frekans nasıl okuyabilirim??yardımlarınız için şimdiden teşekkürler..

radres

Fikir vermek açısından şöyle yapabilirsin. ADC pini girişindeki sinyalin dijital karşılığı 00000000'dan büyük olduğu zaman yani giriş sinyali 0V üzerine çıktığı an timerı saymaya başlatırsın. ADC girişindeki sinyal tekrar 0V olunca (tabi bunu ADC olayı ile tespit ediyon) timer'ı durdurursun. Geçen süre bir alternansın süresini verir. Bunu 2 ile çarparsan sinyalin periyodunu bulursun (T). T=1/f formülünden de frekansı hesaplatabilirsin.

picmanya

frekans metreyi sıfır geçiş dedektörüyle yapılacaksa harici kesme (CN_kesme,External_kesme) pinleriyle daha rahat yapılır.
Ama bu iş için işlemcinin özel donanımı vardır.Hemde frekansın üst ve alternanslarının sürelerinide verecek kadar geniş bir çalışma yapar.
Oda Input Capture girişleridir işlemcinde bu pinler varsa bu konuyu bir incele derim.

kemskems

Öncelikle cevaplar için teşekkür ediyorum ve de çok saçma sorularım olabilir daha işin çok başındayım çünkü,o yüzden de zamanınızı alacağım için özür diliyorum.
@radres
Tabi bunu ADC olayı ile yapacaksın dediğini biraz açabilir misin?? Yani burada timerı dijital 0'a kurmam mantıklı geldi gayet yapacağım işlem için,ama bunun okunma işlemini ADC ile nasıl yapacağımı tam anlayamadım.
@picmanya
Dediklerinden maalesef neredeyse hiç bişey anlamadım,amatörlüğüm sebebiyle kusura bakmayın tekrardan.

radres

Girişteki analog sinyali PIC'in ADC birimi vasıtası ile dijitale çevireceksin. Elde ettiğin dijital değer 0 ise kullanmak istediğin bir zamanlayıcıyı-timer'ı (timer0, timer1 vs.) başlatacaksın. Tabi bu esneda girişteki analog sinyalin dijital karşılığına çevirme işlemi devamlı yapılacak. Elde ettiğin ikinci dijital 0 değerinde zamanlayıcıyı durduracaksın. Zamanlayıcı değeri sana girişteki analog sinyalin bir alternansının değerini verecek. Gerisi önceki mesajda olduğu gibi.

Bu arada @picmanya arkadaşın dediği gibi denetleyicinin içinde input capture varsa veya kullandığının zamanlayıcında bu özellik varsa bu özelliği kullanarak da daha basitçe halledebilirsin. İstersen ilk dediğimi yap sonrada diğer metoda bakarsın.

muhittin_kaplan

""Geçen süre bir alternansın süresini verir"" denmiş ama 0 dan 0 a Yarım Saykıldır.
Ayrıca ADC okumak için belli bir Çevrim Süresi Gerelklidir. Bu Esnada Okuma Olmaz Bundan Dolayı "0" ı Yakalayamazsanız Problem Olur.
Ben Olsam RC0 ve RC1 girişlerini kullanırdım.

camby

istenen aslında frekans-voltaj çevirici olmasın?

LM2907/LM2917 Frequency to Voltage Converter

radres

Alıntı yapılan: muhittin_kaplan - 06 Temmuz 2010, 02:22:03
""Geçen süre bir alternansın süresini verir"" denmiş ama 0 dan 0 a Yarım Saykıldır.
Ayrıca ADC okumak için belli bir Çevrim Süresi Gerelklidir. Bu Esnada Okuma Olmaz Bundan Dolayı "0" ı Yakalayamazsanız Problem Olur.
Ben Olsam RC0 ve RC1 girişlerini kullanırdım.

Bir alternans dediğim zaten yarım saykıl (Pozitif veya negatif alternans yani sinyalin yarım saykılı). Periyot için bunun 2 katının alınmasını gerektiğini de belirtmiştim. ADC çevrim süresi sıfır geçişlerini algılamada sorun yaratabilir doğru. Bu nedenle okunacak sinyalin maksimum frekansının bilinmesi gerekir ki bu yöntemin çalışma sınırlarını aşıyorsa bu yöntem kullanılamaz, haklısın. Ama giriş sinyalinin maksimum frekansı ADC çevrim süresi etkisine maruz kalmıyorsa bu yöntem de kullanılabilinir.

kemskems

Öncelikle yanıt veren herkese tekrar teşekkür ediyorum. ADC den direk frekans okuma konusunda biraz zayıf olduğumu düşünerek öncelikle gelen bir voltajı 4 basamaklı 7 segmente sayısal büyüklük olarak yazdırmayı denedim. Programı yazıp proteusta gerçekledim ancak displayin bacakları yanmasına rağmen ekranda veri alamıyorum acaba kodumun yanlış veya eksik kısmı neresi bu konuda yardımcı olabilirseniz çok sevinirim..
#include <htc.h>
#include "delay.h"
#include <stdio.h>

int voltaj;
float oran= 5.0/1024;
const unsigned char
segment[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void segment_yazdir(int i)
	{
		if(i<10)
		{
		PORTC=0x0E;
		PORTB=segment[i];
		DelayMs(5);
		}
		else
		if(i<100)
		{
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}
		else	 
		if(i<1000)
		{
		PORTC=0x0B;
		PORTB=segment[i/100];
		DelayMs(5);
		i=i%100;
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}
		else
		if(i<10000)
		{
		PORTC=0x07;
		PORTB=segment[i/1000];
		DelayMs(5);
		i=i%1000;
		PORTC=0x0B;
		PORTB=segment[i/100];
		DelayMs(5);
		i=i%100;
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}	
		else
		if(i>10000)
		i=0;
		
}
	
	
void main()
{
	TRISA=0x01;
	TRISC=0x00;
	PORTC=0x00;
	
	ADCON0=0x85;
	ADCON1=0x8E;

	ADCS0=0;
	ADCS1=1;
	
	PCFG3=1;
	PCFG2=1;
	PCFG1=1;
	PCFG0=0;
	
	ADFM=1;
	ADON=1;
	
	while(1)
	{
		CHS0=0;
		CHS1=0;
		CHS2=0;
		DelayMs(20);
		ADGO=1;
		voltaj=(ADRESH*256+ADRESL);
		segment_yazdir(voltaj);
		DelayMs(10);
		}
	}

kemskems

TRISB,,PORTA,PORTB değerlerini girmeyi unutmuşum,şu an volt ölçme çalışıyor.

kemskems

Tekrardan merhabalar..
Önerilerden ve araştırmalarımdan yola çıkarak bir kod parçası yazdım zar zor,ancak çalışmıyor yine..
Yazdığım kod parçasının işlem olarak şöyle birşey yapmasını istiyorum aslında bakarsanız..
Dijital değeri kontrol edilen işaretin(voltaj_1), bir dahaki tekrar edilmesine kadar(ki burda amaçladığım bir periyodu hesaplamak),timer1 modülü sayacak,tekrar ettiği anda ise timer1 modülü saymayı durduracak. Durulan andaki değerler ile frekans hesabı yapılacak. Bu frekans displayde gösterilecek.
Sabahtan beri uğraştığım için çok saçma hatalar da yapmış olabilirim, bu konuda önerileriniz bekliyorum..
#include <htc.h>
#include "delay.h"
#include <stdio.h>

int voltaj_1;
int frekans;
const unsigned char
segment[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void segment_yazdir(int i)
	{
		if(i<10)
		{
		PORTC=0x0E;
		PORTB=segment[i];
		DelayMs(5);
		}
		else
		if(i<100)
		{
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}
		else	 
		if(i<1000)
		{
		PORTC=0x0B;
		PORTB=segment[i/100];
		DelayMs(5);
		i=i%100;
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}
		else
		if(i<10000)
		{
		PORTC=0x07;
		PORTB=segment[i/1000];
		DelayMs(5);
		i=i%1000;
		PORTC=0x0B;
		PORTB=segment[i/100];
		DelayMs(5);
		i=i%100;
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}	
		else
		if(i>10000)
		i=0;
		
}
	
	
void main()
{
	TRISA=0x01;
	TRISB=0x00;
	TRISC=0x00;
	PORTA=0x00;
	PORTB=0x00;
	PORTC=0x00;
	
	ADCON0=0x85;
	ADCON1=0x8E;

	ADCS0=0;
	ADCS1=1;
	
	PCFG3=1;
	PCFG2=1;
	PCFG1=1;
	PCFG0=0;
	
	ADFM=1;
	ADON=1;

	TMR1CS=0; 
	T1CKPS1=0; 
	T1CKPS0=0;
	T1SYNC=1; 
	TMR1IF=0; 
	TMR1IE=1; 
	TMR1H=0x00;
	TMR1L=0x00;
	PEIE=1; 
	GIE=1; 
	int i=0;

	while(1)
	{
		
		CHS0=0;
		CHS1=0;
		CHS2=0;
		ADGO=1;
		DelayMs(5);	
		voltaj_1=(ADRESH*256+ADRESL);
		if(700<voltaj_1<750)
		{
			TMR1ON=1;	
			i=i+1;
			if(i==3)
			{
			TMR1ON=0;
			frekans= 1/((TMR1H*256+TMR1L)*0.0000002);
			segment_yazdir(frekans);
			DelayMs(10);			
		}
		}
	
	}
}

kemskems

Timer1 modülü kullanarak sayma işlemini yaptırmaya çalışıyorum ancak timerda bir sorun var.. yazdığım koddaki amacım voltaj değerinde timerın saymaya başlaması ve bir daha aynı voltajı gördüğünde saymayı durdurup aradaki sayma sayısı yardımıyla frekansı hesaplaması..
yardımcı olabilirseniz çok sevinirim çünkü fena halde tıkandım şu an projemde..
kodu yazıyorum son haliyle:
#include <htc.h>
#include "delay.h"
#include <stdio.h>

int voltaj_1;
int frekans;
const unsigned char
segment[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void segment_yazdir(int i)
	{
		if(i<10)
		{
		PORTC=0x0E;
		PORTB=segment[i];
		DelayMs(5);
		}
		else
		if(i<100)
		{
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}
		else	 
		if(i<1000)
		{
		PORTC=0x0B;
		PORTB=segment[i/100];
		DelayMs(5);
		i=i%100;
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}
		else
		if(i<10000)
		{
		PORTC=0x07;
		PORTB=segment[i/1000];
		DelayMs(5);
		i=i%1000;
		PORTC=0x0B;
		PORTB=segment[i/100];
		DelayMs(5);
		i=i%100;
		PORTC=0x0D;
		PORTB=segment[i/10];
		DelayMs(5);
		PORTC=0x0E;
		PORTB=segment[i%10];
		DelayMs(5);
		}	
		else
		if(i>10000)
		i=0;
		
}
	
	
void main()
{
	TRISA=0x01;
	TRISB=0x00;
	TRISC=0x00;
	PORTA=0x00;
	PORTB=0x00;
	PORTC=0x00;
	
	ADCON0=0x85;
	ADCON1=0x8E;

	ADCS0=0;
	ADCS1=1;
	
	PCFG3=1;
	PCFG2=1;
	PCFG1=1;
	PCFG0=0;
	
	ADFM=1;
	ADON=1;
	
		
	T1CON=0x05;
	TMR1H=0;
	TMR1L=0;
	TMR1CS=0; 
	T1CKPS1=0; 
	T1CKPS0=0;
	int i=0;

	while(1)
	{
		
		CHS0=0;
		CHS1=0;
		CHS2=0;
		ADGO=1;
		DelayMs(5);			
		voltaj_1=(ADRESH*256+ADRESL);
		if(voltaj_1>510&&voltaj_1<520&&i==0)
		{
			TMR1ON=1;
			i=i+1;			
		}
		if(voltaj_1>500&&voltaj_1<520&&i==1)
		{	
			TMR1ON=0;
			frekans=1/(2*(TMR1H*256+TMR1L)*0.0000002);
			segment_yazdir(frekans);
			DelayMs(50);
		}