8kanal PWM-DAC uygulaması (MPLAB C18 )

Başlatan PROTECH_, 21 Nisan 2010, 20:33:47

PROTECH_

Merhaba arkadaşlar
Yaklaşık 2 hafta kadar oldu hi-tech ten mplab c18 e geçiş yaptım, hazır c18 e geçmişken bir kaç uygulama yapayım dedim.

Bilindiği üzere pwm uygulamalarda bir çok kolaylıklar sağlayan bir yöntemdir, fakat microcontrollerlarda donanım olarak yeralan pwm-modülü sayısı sınırlıdır. Bazen uygulamalarda sayı olarak fazla miktarda pwm ihitiyaca olmaktadır.
Bu nedenle mplab c18de pwm işlemini pwm modullerine ihtiyaç duymadan yerine getirecek küçük bir program yazdım.

İşleyişi kısaca şu şekildedir:
Struct olarak oluşturduğumuz sanal pwm modüllerini timer ve kesme yardımı ile program içerisinde dutycycle karşılaştırmalarını yapıp istediğimiz bir portun isteğimiz pininden genişliği ayarlanmış puls çıkışı veriyoruz.

Puls genişliği yazılımsal olarak kontrol edildiği için pwm kanal sayısı ve işlemci hızı verim açısından büyük rol oynamaktadır.

Pwm çıkışlarından analog sinyal elde etmek için alçak geçiren filitreden geçirilmektedir. Alçak geçiren filitre için gereken bilgiler aşağıdaki application note ta yeralmaktadır
     
http://ww1.microchip.com/downloads/en/AppNotes/00538c.pdf

kaynak kodları:
not: kodaları düzenleyip hi-tech içinde kullanabilirsiniz

/* **************************************************************

PROJECT NAME	: 8 kanal yazlimsal PWM çikis

AUTHOR 			: PROTECH_

DATE 			: 21,nisan, 2010

ABSTRACT		: Yazilimsal PWM modüllerini olusturulup
					Timer ve interrupt yardimi ile , 8 kanal 
				  8 bit çözünürlükte pwm çikisi saglamak.
				  
				  Istege bagli olarak çikislar low-pas yada alçakçak 
				  geçiren olarak adlandirdigimiz filitreden geçirilip
				  analog çikis alinabilir, DAC(dijital analog çevirici)
				  olarak kullanilabilir.

COMPILER 		: Microchip C18 	

PROCESSOR		: pic18f452-I/P    (I=industrial process 40Mhz)

SPEED			: 10mips (10Mhz X HSPLL=40Mhz  ) 
				  

REFERENCES 		: PWM, www.microchip.com Application notes
**********************************************************************/

#include <p18f452.h>
#include <math.h>
#include <delays.h>

#pragma config WDT=OFF, OSC=HSPLL, DEBUG=OFF

#define pwmport	PORTD									// PWM portu 
#define pwmtris TRISD									// çikis olarak seçilebilmesi için TRIS reg.


#pragma udata  gpr0						    			//degiskenlerimiz BANK0a yerlestrilsin (not:istege bagli) 		

  typedef  struct PWM { 								// PWM yapisi
	unsigned char dutycycle;							// PWM.dutycycle
	unsigned  	 timerov: 1;							//pwmtimer taşma bayrağı 					
	 					} PWM;							// PWM.pwmtimer over flow Bayragi

	PWM pwm1,pwm2,pwm3,pwm4,pwm5,pwm6,pwm7,pwm8;   		// 8 adet PWM olustruldu
        
        
	unsigned char 	pwmtimer=0;							// pwm sanal timer														
 	unsigned char  	i1=0;								// pwmdeger_ata fonksiyonu for döngüsü için
 				
				

#pragma udata gpr1										//
    unsigned char sinus[32];							//  sinus tablosu 
 	unsigned char kare[32];								//	kare dalga tablosu
 	unsigned char ucgen[32];							//  ucgen dalga tablosu
 	unsigned char testere[32];							//	testere dalga tablosu
    
 
//----------------------------------------------------------------------------------------------------------


void pwm_init(void);									// pwm ayar fonksiyonu
void sig_tblinit(void);									// pwm data table  
void pwmdeger_ata(void);								// pwm lere tablodan deger ata
void KESMEH(void);
void setpwmduty(unsigned char duty,unsigned char pwm);	// pwm dutycycle yazma fonksiyonlari

			
/*......................Main fonksiyonu					*/

void main()
	{
  		INTCON=0X00;									//kesmeler kapali
		
		sig_tblinit();									//sinyal tablolarini hesapla
		pwm_init();										// pwm degerlerini ayarlarini yap
	    
	   	
	   	
	   	while(1)
	   		{
		   	  pwmdeger_ata();				 			//pwmlere sinyal değerleri ata deger ata      
		    
		      Delay10KTCYx(5);							// 500u Sn bekle
		    
		    }
		 	

	}

/* ......................Main fonksiyonu bitis			 */



void pwmdeger_ata()
{


		  	if(pwm1.timerov)								// pwmtimerda tasma oldumu ?
		    	{
		       		setpwmduty(sinus[i1],1);              	// 1.pwmin dutycyle ı sinus[i1] degerine ayarla     
		       	    setpwmduty(testere[i1],2);              // 2.pwmin dutycyle ı testere[i1] degerine ayarla     
		       		setpwmduty(kare[i1],3);              	// 3.pwmin dutycyle ı kare[i1] degerine ayarla     
		       		setpwmduty(ucgen[i1],4);              	// 4.pwmin dutycyle ı ucgen[i1] degerine ayarla     
		       		setpwmduty(sinus[i1],5);              	// 5.pwmin dutycyle ı sinus[i1] degerine ayarla     
		       		setpwmduty(testere[i1],6);              // 6.pwmin dutycyle ı testere[i1] degerine ayarla     
		       		setpwmduty(kare[i1],7);              	// 1.pwmin dutycyle ı kare[i1] degerine ayarla     
		       		setpwmduty(ucgen[i1],8) ;             	// 1.pwmin dutycyle ı ucgen[i1] degerine ayarla     
		       		
		       		i1++;									// i1 index i bir arttir
		       		if(i1==32)
		          	{ i1=0; }								//i1 32 ye ulaştığında sıfırla
		       	 
		       	 	pwm1.timerov=0;							//timer taşma bayrağını sıfırla
		       	
		       	}	
}
			
			
/*---------------------------------------------------------------------
			KESME RUTINI
-----------------------------------------------------------------------*/			

#pragma interrupt KESMEH
void KESMEH(void)
{
 	unsigned char t0contemp;     
 
	if(INTCONbits.TMR0IF)
	  {
		 INTCONbits.TMR0IF=0;						//TIMER INT bayragini temizle 
		 
		 pwmtimer++;								// sanal timer lari artirma blogu
		 pwmtimer++;								//pwmtimer 2nin katları şeklinde artırılarak period değeri ayarlanabilir 		
		 														
		 if(pwmtimer>pwm1.dutycycle)			// eger timer degerinden duty cycle küçükse pwm çikisini sifirla			
		 { PORTDbits.RD0=0;  }
		  
		 if(pwmtimer>pwm2.dutycycle)
		 { PORTDbits.RD1=0;  }
		 
		 if(pwmtimer>pwm3.dutycycle)
		 { PORTDbits.RD2=0;  }
		 
		 if(pwmtimer>pwm4.dutycycle)
		 { PORTDbits.RD3=0;  }
		 
		 if(pwmtimer>pwm5.dutycycle)
		 { PORTDbits.RD4=0;  }
		 
		 if(pwmtimer>pwm6.dutycycle)
		 { PORTDbits.RD5=0;  }
		 
		 if(pwmtimer>pwm7.dutycycle)
		 { PORTDbits.RD6=0;  }
		 
		 if(pwmtimer>pwm8.dutycycle)
		 { PORTDbits.RD7=0;  } 
		 
		 
		 if(pwmtimer>0xfa)					//eger timer owerflow meydana gelirse pwm çikislarini set yap 
		 {PORTD=0xff; 
		   pwm1.timerov=1;					// taşma bayrağı set edildi
		   }	
	    
	     t0contemp=T0CON;					// Timer0 başlangıç değeri ata	
	     TMR0L=0X80;						// 128 cycle sonra kesme meydana gelir
	     T0CON=t0contemp;					  
	}

}

#pragma interruptlow KESMEL

void KESMEL(void)
{
	



}

//---------

#pragma code isrl=0x18
void isrlow(void)
{
	_asm GOTO KESMEL _endasm
}
#pragma code 

#pragma code isrh=0x08
void isrh(void)
{
	
	_asm GOTO KESMEH _endasm


}
#pragma code 

/*---------------------------------------------------------------------
			KESME RUTINI bitis
-----------------------------------------------------------------------*/

void pwm_init()
{
  
  pwmtris=0x00;										//PORTD çikis olarak ayarlandi							
  pwmport=0;										//PORTD=0;
  
  
  pwm1.dutycycle=128;								// pwm dutycycle baslangiç degerleri
  pwm2.dutycycle=128;								
  pwm3.dutycycle=128;
  pwm4.dutycycle=128;
  pwm5.dutycycle=128;
  pwm6.dutycycle=128;
  pwm7.dutycycle=128;
  pwm8.dutycycle=128;
  
  pwm1.timerov=0;									// pwm sanal timer overflow bayraklarini sil

  
  INTCON=0X00;										// kesme ayarları
  INTCONbits.TMR0IE=1;
  INTCONbits.GIE=1;
  RCONbits.IPEN=0;
  
 
  T0CONbits.T08BIT=1;								// TMR0 8 BIT
  T0CONbits.PSA=1;									//PRESCALER DIS.
  T0CONbits.T0CS=0;	
  T0CONbits.TMR0ON=1;								//TMR0 ON


}

//-------------------------------------------------------------------

void setpwmduty(unsigned char duty,unsigned char pwm)
{
	
	 pwm1.timerov=0;
		
		    if(pwm==1)
			{pwm1.dutycycle=duty;					//  pwm in duty degerini ata
			  
			}
			
		    if(pwm==2)
			{pwm2.dutycycle=duty;					//  pwm in duty degerini ata
			
			}
			
			if(pwm==3)
			{pwm3.dutycycle=duty;					//  pwm in duty degerini ata
			
			}
			
			if(pwm==4)
			{pwm4.dutycycle=duty;					//  pwm in duty degerini ata
			  
			}
						
			if(pwm==5)
			{pwm5.dutycycle=duty;					//  pwm in duty degerini ata
			 		 
			}
		
			if(pwm==6)
			{pwm6.dutycycle=duty;					//  pwm in duty degerini ata
			  
			 }
			
			if(pwm==7)
			{pwm7.dutycycle=duty;					//  pwm in duty degerini ata
			 
			 }
			
			if(pwm==8)
			{pwm8.dutycycle=duty;					//  pwm in duty degerini ata
			  
			}
             
}





#pragma code
void sig_tblinit()
	{   
	
		unsigned char i=0;
		char j;
		float a;

		
		ucgen[0]=1;									//baslangiç degerleri
		testere[0]=1;								// baslangiç degerleri
		kare[0]=255;
	for(i=1;i<32;i++)
		{
				
		kare[i]		= 32;							// kare dalga için sürekli dutycycle period / 2 
		
		if(i<17)									// ücgen dalga için
		{ucgen[i]=ucgen[i-1]+15;
		 kare[i]		=255;
		}
		else 
		{
		kare[i]		= 0;
		ucgen[i]=ucgen[i-1]-15;}
		
		 
		testere[i]	=testere[i-1]+8;
						// testere için
		} 
		
		for(j=0;j<32;j++)
		{
			a=sin(0.196*(float)j);					//sin(2*pi/32*j)
			sinus[j] =(unsigned char)(128+127*a);		//0-255 arasi boyutlandir
	    
	    }   
	 
	
	}


sinyal çıktıları
[IMG]http://img46.imageshack.us/img46/6549/pwmdac.jpg[/img]

[IMG]http://img688.imageshack.us/img688/1866/pwmdacsinyl.jpg[/img]
Multi-Core ,RTX,ThreadX, FreeRTOS, MODBUS  RTOS - Electronic-Hardware -- BERLIN

Erhan YILMAZ

Eline sağlık Turgutum sinüs ,kare ,üçgen ,testere falan güzel olmuş.

PROTECH_

Alıntı yapılan: tamirci_erhan - 22 Nisan 2010, 10:06:26
Eline sağlık Turgutum sinüs ,kare ,üçgen ,testere falan güzel olmuş.

sağol erhan hocam

Aslında PWM ile ilgili fikri olan varsa yapıp forumda yayınlayabiliriz!
Multi-Core ,RTX,ThreadX, FreeRTOS, MODBUS  RTOS - Electronic-Hardware -- BERLIN

fryrmnd

yeni konu açmayım dedim.

Alıntı Yaptypedef  struct PWM {                         // PWM yapisi
    unsigned char dutycycle;                     // PWM.dutycycle
    unsigned      timerov: 1;                     //pwmtimer taşma bayrağı
                    } PWM;   ;

timerov: 1;  bu ifade standart c ifadesimidir.  stuct yapısına mı özeldir. biri kullanımını açıklayabilir mi?