Picproje Elektronik Sitesi

DERLEYİCİLER => Microchip MPLAB C serisi => Microchip C18 => Konuyu başlatan: PROTECH_ - 21 Nisan 2010, 20:33:47

Başlık: 8kanal PWM-DAC uygulaması (MPLAB C18 )
Gönderen: PROTECH_ - 21 Nisan 2010, 20:33:47
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] (http://img46.imageshack.us/i/pwmdac.jpg/)

[IMG]http://img688.imageshack.us/img688/1866/pwmdacsinyl.jpg[/img] (http://img688.imageshack.us/i/pwmdacsinyl.jpg/)
Başlık: Ynt: 8kanal PWM-DAC uygulaması (MPLAB C18 )
Gönderen: Erhan YILMAZ - 22 Nisan 2010, 10:06:26
Eline sağlık Turgutum sinüs ,kare ,üçgen ,testere falan güzel olmuş.
Başlık: Ynt: 8kanal PWM-DAC uygulaması (MPLAB C18 )
Gönderen: PROTECH_ - 22 Nisan 2010, 13:51:15
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!
Başlık: Ynt: 8kanal PWM-DAC uygulaması (MPLAB C18 )
Gönderen: fryrmnd - 25 Nisan 2012, 13:03:04
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?