avatar_elektro77

Süresi değiştirilebilir TMR0 kesmesi

Başlatan elektro77, 05 Ekim 2023, 09:44:00

elektro77

Geçenlerde yine buna benzer bir soru sormuştum ama bu sorunun o proje ile bir ilişkisi yok.
Aşağıdaki programda;
Değeri, US_UP ve US_DOWN butonuna bağlı olan US isminde bir değişken var.
US değişkenin aldığı 8 farklı değere bağlı olarak kesme içindeki PCA_ENB pininin
1-100mS de bir toggle
2-250mS de bir toggle
3-500mS de bir toggle
4-750mS de bir toggle
5-1000mS de bir toggle
6-1500mS de bir toggle
7-2000ms de bir toggle 
8-2500ms de bir toggle    olmasını sağlamaya çalışıyorum. Fakat mantığı kuramadım.
OSC Frekansım 20MHz.
Nasıl bir mantık kurmalıyım?
#config
 __config _HS_OSC & _WDT_ON & _LVP_OFF & _CP_OFF
#ENDconfig

DEFINE OSC 20
'--------------------------------------------------------------------------------
TRISA=%111111:TRISB=%00000011:TRISC=%00111010:TRISD=%11111111:TRISE=%111
PORTA=0 :PORTB=0:PORTC=0:PORTD=0:PORTE=0
'-------------------------------------------------------------------------------
CMCON=7                   
ADCON1=7                   'ADC KANALLARI DİJİTAL YAPILDI - ADC İPTAL
INTCON=%10100000           'Global kesmeler aktif,TMR0 kesmesi aktif
OPTION_REG=%10000110   	   '1/128 AT 20MHz 
TMR0=128                   '1000mS İÇİN ÖN YÜKLEME DEĞERİ
PAUSE 50
'-------------------------------------------------------------------------------
US VAR BYTE: US=1
SAY VAR BYTE:SAY=0
SYMBOL PCA_ENB=PORTC.0     :  PCA_ENB=1  '0 İSE PCA AKTİF
SYMBOL US_UP=PORTC.1
SYMBOL US_DOWN=PORTC.5
PAUSE 300
ON INTERRUPT GoTo KESME

BASLA:'*************************************************************************

'------------------------------UYGULAMA SÜRESİ ARTIR----------------------------
IF US_UP=1 THEN
while US_UP=1:wend
US=US+1
IF US=9 THEN US=8 
ENDIF
'------------------------------UYGULAMA SÜRESİ AZALT----------------------------
IF US_DOWN=1 THEN 
while US_DOWN=1:wend
US=US-1
IF US=0 THEN US=1  
ENDIF

GOTO BASLA
'**************************ALT PROGRAMLAR---------------------------------------        
DISABLE
KESME:   
SAY=SAY+US  
IF SAY=128 then     
   SAY=0
   TOGGLE PCA_ENB
ENDIF            
'-------------------------------------------------------------------------------
INTCON.2=0  
RESUME
ENABLE
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

Bu kesmee sürelerinin ortak bölenini bulacaksın öncelikle. Zaten hemen göze çarpıyor 50 olarak görüyorum. Yani bu süreler 50 nin katları şeklinde tanımlanabilir.
Her bir süre için kaç adet 50 us den oluştuğunu hesaplayıp ya bir lokkup tablosundan değer alman yada if satırları ile bu katsayıları programa vermen gerekiyor. Daha sonra kesme süresini 50us olarak ayarlayıp kesme adedini sayman ve istediğin katsayıya ulaştığı zaman çıkışı toggle yaptırman gerekir.

Örnek vereyim,
100us için 2 adet kesme sayman gerekiyor
250us için 5 adet kesme sayman gerekecek

Bu aklıma gelen kolay yol idi. Birde zor yolu var gibi gözüksede listenin altlarında doğru toggle süreleri çok uzuyor ve TMR0 sayacı bunu bir kerede sağlayamaz. Bu nedenle kolay zaten tek yol gibi gözüküyor.
Ete

elektro77

#2
Cevap için teşekkür ederim. Peki sorumu şöyle sorsam nasıl bir mantık kurmalıyım Hocam.
Low da bekleyen bir çıkışı yine TMR0 kesmesi kullanarak
1-1000mS de bir 100mS high
2-1500mS de bir 100mS high
3-2000ms de bir 100mS high
4-2500ms de bir 100mS high nasıl yaparım...   
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

#3
TMR0 sayacı ile büyük miktarlarda ms gecikmeleri yaratmak mümkün değil. Bu nedenle küçük dilim kullanmak gerekecek ve dilim sayılacak yine.
Hesaplarıma göre 4 mHZ ocs frekansında 50ms lik dilimler elde etmek mümkün olabiliyor.
OSC Frekansını 20Mhz kullanırsan en büyük 10ms lik gecikme yaratabilirsin.
Diyelimki 4Mhz OSC kullanıyorsun. Bu durumda TMR0 kesmesini 50ms olarak belirleyeceksin.Bunun için bölme oranın 1/256 olacak ve TMR0 ön yükleme değerinde 60 olacak.
Hesap yapmak gerekir ise ; TMR0 60 dan 256 ya kadar (256-60)=196 adım sayar. Bölme oranı 1/256 olduğu için 196x256=50.176 defa saymış olacaktır. Her bir adım 1us olduğundan toplam süre 50.176 us edecektir. Görüleceği gibi net 50ms gibi bir seçenek yok maalesef. 60 rakamını 1 artırırsan süre (256-61)*256 =49.920us ye düşer. Belkide bir miktar komut gecikmesi ile bu süre daha uygun olabilir.
Her neyse 50ms de bir kesme yaptırınca kesmeleri sayarak (1000/50=20) kesme sonunda 1000ms lik süre,  (1500/50=30) kesme sonund 1500 ms lik süre elde edersin. Diğerlerinide sen hesaplarsın artık.
İstenilen sayıya ulaşınca çıkışı high yapıp 100 ms lik gecikme (Pause 100)verip süre sonunda çıkışı LOW yapmak işini çözecektir.

Ete


elektro77

#4
Alıntı yapılan: ete - 05 Ekim 2023, 11:57:54TMR0 sayacı ile büyük miktarlarda ms gecikmeleri yaratmak mümkün değil. Bu nedenle küçük dilim kullanmak gerekecek ve dilim sayılacak yine.
Hesaplarıma göre 4 mHZ ocs frekansında 50ms lik dilimler elde etmek mümkün olabiliyor.
OSC Frekansını 20Mhz kullanırsan en büyük 10ms lik gecikme yaratabilirsin.
Diyelimki 4Mhz OSC kullanıyorsun. Bu durumda TMR0 kesmesini 50ms olarak belirleyeceksin.Bunun için bölme oranın 1/256 olacak ve TMR0 ön yükleme değerinde 60 olacak.
Hesap yapmak gerekir ise ; TMR0 60 dan 256 ya kadar (256-60)=196 adım sayar. Bölme oranı 1/256 olduğu için 196x256=50.176 defa saymış olacaktır. Her bir adım 1us olduğundan toplam süre 50.176 us edecektir. Görüleceği gibi net 50ms gibi bir seçenek yok maalesef. 60 rakamını 1 artırırsan süre (256-61)*256 =49.920us ye düşer. Belkide bir miktar komut gecikmesi ile bu süre daha uygun olabilir.
Her neyse 50ms de bir kesme yaptırınca kesmeleri sayarak (1000/50=20) kesme sonunda 1000ms lik süre,  (1500/50=30) kesme sonund 1500 ms lik süre elde edersin. Diğerlerinide sen hesaplarsın artık.
İstenilen sayıya ulaşınca çıkışı high yapıp 100 ms lik gecikme (Pause 100)verip süre sonunda çıkışı LOW yapmak işini çözecektir.

Ete


Yazdıklarınızı çok iyi anladım ama inşallah koda dökebilirim.
Aslında us lik tam süreler gerekmiyor. Bir çıkışı belli aralıklarla hızlandırıp yavaşlatmak istiyorum. Sadece sorumu sorarken süre belirterek sordum.
Osc frekansımı ise malesef değiştiremiyorum. Çünkü program 12 adet tuş, 12C iletişim ve lcd ekran yazdırma komutları ile oldukça fazla yüklü. 4MHz ye düşersem sorun olabilir. Birde pause komutu koyar isem iyice yavaşlayacak.
Bu nedenle aşağıdaki gibi bir programı simülede çalıştırdım ama hangi zaman aralıklarında çalıştığını hesaplamadan ezbere yani deneme yanılma ile yaptım.
Bir TMR0 önyükleme değeri de tanımlamadım.
Ama artırıp azaltabiliyorum. Fakat toggle mantığımda. Aşağıdaki program hakkında ne söyleyebilirsiniz Hocam;
Tamamen ezbere hesapsız bir program..
#config
 __config _HS_OSC & _WDT_ON & _LVP_OFF & _CP_OFF
#ENDconfig
	 
DEFINE OSC 20
'--------------------------------------------------------------------------------
TRISA=%111111:TRISB=%00000011:TRISC=%00111010:TRISD=%11111111:TRISE=%111
PORTA=0 :PORTB=0:PORTC=0:PORTD=0:PORTE=0
'-------------------------------------------------------------------------------
DEFINE LCD_DREG PORTB    'LCD data bacaklari hangi porta bagli ? 
DEFINE LCD_DBIT 4        'LCD data bacaklari hangi bitten basliyor ?
DEFINE LCD_EREG PORTB    'LCD Enable Bacagi Hangi Porta bagli ?
DEFINE LCD_EBIT 3        'LCD Enable Bacagi Hangi bite bagli ?
DEFINE LCD_RSREG PORTB   'LCD RS Bacagi Hangi Porta bagli ?
DEFINE LCD_RSBIT 2       'LCD RS bacagi Hangi Bite bagli ?
DEFINE LCD_BITS 4        'LCD 4 bit mi yoksa 8 bit olarak ba?ly ?
DEFINE LCD_LINES 4       'LCD Kaç syra yazabiliyor ? 
DEFINE LCD_COMMANDUS 2000'Command delay time in us 
DEFINE LCD_DATAUS 50     'Data delay time in us   
'-------------------------------------------------------------------------------
CMCON=7                   
ADCON1=7                   'ADC KANALLARI DİJİTAL YAPILDI - ADC İPTAL
INTCON=%10100000           'Global kesmeler aktif,TMR0 kesmesi aktif
OPTION_REG=%10000110   	   '1/128 AT 20MHz 
'TMR0=0                   '1000mS İÇİN ÖN YÜKLEME DEĞERİ
PAUSE 50
'-------------------------------------------------------------------------------
US VAR BYTE: US=10
SAY VAR WORD:SAY=0
W   VAR WORD
SYMBOL PCA_ENB=PORTC.0     :  PCA_ENB=1  '0 İSE PCA AKTİF
SYMBOL US_UP=PORTC.1
SYMBOL US_DOWN=PORTC.5
PAUSE 200
LCDOUT $FE,1
PAUSE 200
ON INTERRUPT GoTo KESME
	 
BASLA:'*************************************************************************
      lcdout $FE,$80,"US:",#US,"       "
      lcdout $FE,$C0,"TMR0:",#TMR0,"       "
      lcdout $FE,$90,"SAY:",#SAY,"       "            
      lcdout $FE,$D0,"PCAENB",#PCA_ENB,"    "            
'------------------------------UYGULAMA SÜRESİ ARTIR----------------------------
      IF US_UP=1 THEN
        US=US+10
        IF US=200 THEN US=190  
        while US_UP=1:wend
        say=0
        gosub GECIKME
      ENDIF
'------------------------------UYGULAMA SÜRESİ AZALT----------------------------
	IF US_DOWN=1 THEN 
	  US=US-10
	  IF US=0 THEN US=10 	
          while US_DOWN=1:wend
          say=0
          gosub GECIKME
	ENDIF
	 
	GOTO BASLA
'**************************ALT PROGRAMLAR---------------------------------------        
GECIKME:
	FOR W =0 TO 5000
	NEXT
	RETURN
    
DISABLE
KESME:   
      SAY=SAY+1 :lcdout $FE,$90,"SAY:",#SAY,"        " 
      IF SAY=us then     
	 SAY=0
	 TOGGLE PCA_ENB
      ENDIF            
'-------------------------------------------------------------------------------
'TMR0=0
      INTCON.2=0  
      RESUME
      ENABLE
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

Söylediğim ile benzer mantık.
Tek kusuru sabit 6,5ms lik kesme süresi ile çalışıyor. 1/128 bölme oranı ve TMR0=0 önyükleme ile çalışıyor. Sende US değişkeni ile bunun katlarını kullanıyorsun hepsi bu. Katlarıda 10'ar artırıyorsun yada azaltıyorsun. Yani her artış sana 65ms lik fark getiriyor (yada götürüyor).

Ete

elektro77

Ete Hocam Merhabalar;
Bir önceki iletimde bulunan kodlarda bir sorun yaşıyorum.
Uygulama süresini artırdığımda sorun yok ama azaltırken program bazen ayarlanan sayıyı kaçırarak 256 ya kadar gittiği oluyor.
Örneğin sayı 20 ve azalt butonu ile 10 a düşürüyorum. İşte bu noktada 10 kadar değil 256 kadar gidip tekrar başa dönüyor.
Bunu nasıl çözebilirim?
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

#7
Öncelikle Artırma ve eksiltme kodlarını biraz düzeltmek gerekir.
Tuş titremesi denilen somut bir gerçek var ve bundan kaçınmanın tek yolu tuşu bıraktığın anı yakalayıp o anda yaklaşık 100 ms lik bir gecikme uygulamak. Bunu uygulamaz isen sen tuşu bırakmadan program yeniden tuş kontrolüne gelir ve artır tuşuna basıyor isen değer artırımı yapar.

    IF US_UP=1 THEN
    while US_UP=1:wend
    US=US+10
    IF US=200 THEN US=190 
    ENDIF
Şimdi bu artırma kodlarına bakalım. US_UP tuşuna basılmış ise önce tuşun bırakıldığını test ediyorsun buna gerek yok. Önce işi yap en sonda tuş bırakılmışmı kontrol et.Bırakılmış ise biraz gecikme ver. Kesme kullandığın için döngüsel gecikme kullan. Şöyle
    
IF US_UP=1 THEN
  US=US+10
  IF US=200 then US=190
  while US_UP=1:wend
  GOSUB GECIKME
ENDIF
Doğru tuş kontrolü bu şekildedir.
Gecikme için programın başında bir Word değişkeni (W) tanımla ve alt program olarak şu kodu ekle.

GECIKME:
FOR W=0 to 5000
NEXT
RETURN

Şimdi gelelim asıl sorununa Neden SAY değişkenin 10 a kadar değilde 256 ya kadar sayıyor.
Bu konuda biraz sanal düşünce gerekiyor. Hayal et. Program çalışıyor US değerin o anda 45 ve sen onu 10' a düşürdün. Program sayıyor idi ve SAY değerin ise o anda henüz 25 de. Ama sen 10' düşürünce program SAY=US eşitliğini yakalayamayacaktır. Önce SAY=255 ardından 0 olacak ve daha sonra 10 olduğunda senin istediğin yerine getirilecektir.
Bu nedenle işin doğrusunu yapmak istiyor isen US değerini değiştirdiğin anda SAY=0 da yapman gerekir. Böylece o andan itibaren SAY değerin sıfırdan başlar ve 10 olunca sistem gereğini yapar. US değerini artırmada sorun olmadığını sen söyledin. Mantıklı çünki değeri büyütüyorsun.
Azalttığın zaman sorun olması ihtimali çok fazla SAY değerini sıfırlamadığın için.
Umarım anlamışsındır.
Ete

NOT: Yukarıdaki programı bu mantığa göre düzenledim.!!!!

elektro77

#8
Çok teşekkürler Hocam. Deneyeceğim...

Edit: Çok iyi çalıştı. Tekrar teşekkürler Hocam...

"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

elektro77

#9
ETE Hocam tekrar merhaba. Soracağım soru yine bu başlık ile ilgili olduğu için buradan tekrar sorayım dedim.
Aşağıdaki resimdeki gibi bir PWM oluşturmak istiyorum. Üstesinden gelemedim bir türlü.
Start a basınca TMR0 kesmesi ile ayarlanan,  belli bir süre içindeki bir pwm in, başlangıcının soft geçişli(yukselme zamanının),sonunun da soft duruşlu(dusme zamanının) olmasına çalıştım.
Elimde örnek kodlar olmasına rağmen işin içinden çıkamadım.
Dosyalar ilişiktedir.
Yardımcı olur musunuz lütfen.


"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

#10
Sorun-1:
Kesme içinde iken kesme dışındaki bir yere GOTO yada GOSUB ile gidemezsin. Bu stack taşmasına sebep olur ve program çalışmaz.

Sorun-2:
Program mantığın neredeyse bütün işin kesme içinde yapılmasını gerektiriyor.
Bu gibi durumlarda program yine kesme dışında yürütülür ama kesme içinde bir işaret biti kullanılmalıdır.

Sorun-3
     
  DUTY=SLOW_DUTY   
         FOR DUTY=X TO MAX_DUTY STEP 2
burada DUTY değerini Slow_Duty e eşitledikten sonra döngüyüde DUTY ile kurunca o eşitlediğinin bir hükmü kalmamış oluyor. Ne yapmak istedin anlamadım ama orada yaılması gereke şey şu olmalı. Duty değerin o anda ne ise ve onu artırmak istiyor isen başlangıcın o andaki Duty değerin olmalı. O halde TEMP=DUTY demen ve döngüyüde  For DUTY=Temp to Max_Duty aralığında kurman lazım. Tabiiki o anda PWM kapalı ise ve sen Soft-start yapıyor isen başlangıcın 0 olmalı.
Soft Start ve Soft duruş döngülerinde Pausus 700 gibi bir gecikme kullanmışsın ki bu TMR0 kesmesi için tehlike yaratacak seviyede. O gecikmeler esnasında Tmr0 kesmesi oluşabilir ama gecikme bitmeden program kesme etiketine gidemez. Kural böyle basic komutu işlemesi bitmeden kesmeye gidemezsin. Burada pauseus yerine yine döngüsel gecikme kullanılması gerekir.

Sorun-2 yi halledince otomatikman Sorun-1 de hallolmuş olacak. Bu konuya geçmeden önce anlayamadığım bir iki şeyi sorayım.
Soft Kalkış ve Softduruş yapacak bir PWM sinyali yaratılacak. Programa bakarak bu sinyalin START tuşuna basıldığında başlayacağını ve STOP tuşuna basıldığında duracağını anlıyorum.

Peki TMR0 kesmesinin bu işteki rolü nedir onu anlamadım.? Ama soru soruş şekline bakılır ise start ile başlayan PWM sinyali tmr0 kesme sayısı ile bağlantışı bir şekilde sürmesi gerekiyor ama tam anlaşılmıyor.

Başka bir sorun da Kesme içinde start tuşuna basılınca ver=1 olsun demişsin. Bu işi ana program kısmında yapabilirdin. Kesme içinde de VER=1 kontrolü yaparak o istediklerini yapabilirsin.

Sonuç olarak program başta sona yanlış, doğru bir şey yok amaca uygun değil neresinden tutacağımı kestiremedim doğrusu.
Cevap olarak o bahsini ettiğin PWM sinyali ne zaman başlayacak ?, ne kadar devam edecek devam süresini kim belirleyecek ve sonunda ne zaman duracak ve durma işini kim belirleyecek bu 3 soruyu cevaplarsan belki konun biraz daha anlaşılır olacak.

Ete

elektro77

#11
Alıntı yapılan: ete - 14 Aralık 2023, 11:40:14Sonuç olarak program başta sona yanlış, doğru bir şey yok amaca uygun değil neresinden tutacağımı kestiremedim doğrusu.
Cevap olarak o bahsini ettiğin PWM sinyali ne zaman başlayacak ?, ne kadar devam edecek devam süresini kim belirleyecek ve sonunda ne zaman duracak ve durma işini kim belirleyecek bu 3 soruyu cevaplarsan belki konun biraz daha anlaşılır olacak.
Starta basınca tmr0 daki SAY=S değeri kadar CCP1 pwm çıkışı açılıp kapanacak.
P değişkenini  Toggle da yapabiliriz.
P her 1 olduğunda pwm çıkışı açılır ve taki dur butonuna basıncaya kadar bu devam eder.
Açıkçası bir ems cihazı yaptım.
Bir boost devresini 100khz pwm ile sürerek kapasitörü şarj ediyorum.
Bu kapasitörün deşarj olmasını sağlayan ve yine başka bir pwm ile sürülen bir H köprü transistör deşarj devresini de P değişkeni aktif ediyor.
P=1 olduğunda deşarj devresi aktif oluyor ve ilk deşarj puls ini verdiğinde kapasitör maksimum şarjda olduğu için kaslara olan etkisi sert oluyor.
Deşarj devresinin puls leri ile oynayamıyorum. Sabit bir pwm i var.
Bunun yerine İlk başta deşarj devresini aktif edip yani P=1 yaparak, şarjı sağlayan ccp1 çıkışını soft olarak şarj ederken aynı zamanda deşarj etmek istiyorum. Yada buna benzer bir şey. Denemelerim devam ediyor.
Sonuç olarak kapasitörün max şarjda iken gerçekleşen o ilk deşarjı yumuşatmaya çalışıyorum.   
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

TMR0 fonksiyonunu şöyle tarif edebilirmiyiz.
Her kesmede SAY değeri bir artırılacak ve SAY=US olduğunda P değişkeni konum değiştirecek.
P=1 ise PWM soft start ile açılacak ve açık kalacak. Ne zaman kadar dersek P=0 oluncaya kadar.
P=0 olunca bu sefer PWM soft_dur yapacak ve bekleyecek. Tekrar P= olunca PWM tekrar açılacak.
Bu iş START tuşuna basılmış ise yani VER=1 ise bu şekilde çalışacak. DUR tuşuna basılınca sistem tamamen duracak.

Ben bu şekilde anladım. Umarım doğrudur.

Ete


elektro77

Alıntı yapılan: ete - 14 Aralık 2023, 12:41:25TMR0 fonksiyonunu şöyle tarif edebilirmiyiz.
Her kesmede SAY değeri bir artırılacak ve SAY=US olduğunda P değişkeni konum değiştirecek.
P=1 ise PWM soft start ile açılacak ve açık kalacak. Ne zaman kadar dersek P=0 oluncaya kadar.
P=0 olunca bu sefer PWM soft_dur yapacak ve bekleyecek. Tekrar P= olunca PWM tekrar açılacak.
Bu iş START tuşuna basılmış ise yani VER=1 ise bu şekilde çalışacak. DUR tuşuna basılınca sistem tamamen duracak.

Ben bu şekilde anladım. Umarım doğrudur.

Ete


Aynen Hocam. Çok doğru anlamışsınız....
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

#14
Aşağıdaki programı bir dene bakalım
Ete

#config
 __config _XT_OSC & _WDT_ON & _LVP_OFF & _CP_OFF
#ENDconfig
DEFINE OSC 4
TRISA=%011111:TRISB=%00000011:TRISC=%00111010:TRISD=%11111111:TRISE=%011
PORTA=0 :PORTB=0:PORTC=0:PORTD=0:PORTE=0
'-------------------------------------------------------------------------------
CMCON=7                   
ADCON0=%01000000     
'ADCON1=%10000010
ADCON1=%10001110             'ADC LER AÇLDI İLK 
INTCON=%10000000             'global kesmeler aktif,TMR0 kesmesi aktif
OPTION_REG=%10000101            'Pull up dirençleri İPTAL- Bölme oranı 1/64. 4 mhz de bu ayar ve TMR0=61 değeri tam 1sn sayar. 
TMR0=60
PAUSE 50 

T2CON=%00000100       '%000001XX İLK İKİ BİT %00=1/1  %01=1/4   %10=1/16
PR2  =9             ' 100kHZ PWM FREKANSI MAX DUTY 40 OLACAK. 100KHz ÇOK İYİ PERFORMANS VERDİ.
PAUSE 50
CCP1CON=%00000000

US VAR BYTE 56
SAY VAR BYTE 57
ARA   VAR BYTE 58
KES VAR BYTE

W VAR WORD
TEMP VAR WORD:TEMP=0

SYMBOL P=ARA.0
SYMBOL VER=ARA.1
SYMBOL ILK=ARA.2

X         VAR WORD   ':X=0
DUTY      VAR WORD 70   ':duty=0
SLOW_DUTY var word   :SLOW_DUTY=1
MAX_DUTY  var word 
TUS_DUTY  VAR WORD 
 
PAUSE 50
'-------------------------------------------------------------------------------
DEFINE LCD_DREG PORTB    'LCD data bacaklari hangi porta bagli ? 
DEFINE LCD_DBIT  4       'LCD data bacaklari hangi bitten basliyor ?
DEFINE LCD_EREG PORTB    'LCD Enable Bacagi Hangi Porta bagli ?
DEFINE LCD_EBIT  3       'LCD Enable Bacagi Hangi bite bagli ?
DEFINE LCD_RSREG PORTB   'LCD RS Bacagi Hangi Porta bagli ?
DEFINE LCD_RSBIT 2       'LCD RS bacagi Hangi Bite bagli ?
DEFINE LCD_BITS  4       'LCD 4 bit mi yoksa 8 bit olarak ba?ly ?
DEFINE LCD_LINES 4       'LCD Kaç syra yazabiliyor ? 
DEFINE LCD_COMMANDUS 2000'Command delay time in us 
DEFINE LCD_DATAUS 50     'Data delay time in us 

symbol START  =portD.6
symbol DUR    =portD.7
symbol V_ARTIR=PORTE.0
SYMBOL V_AZALT=PORTE.1
SYMBOL LED=PORTE.2

PAUSE 200
MAX_DUTY=40
US=60:p=0
SAY=0:ver=0
TUS_DUTY=25
ON INTERRUPT GoTo KESME
'**********************************************************************************
BASLA:
        IF START=1 THEN 
          VER=1:INTCON.5=1:SAY=0:P=1
'          IF TUS_DUTY>0 THEN GOSUB SOFT_GEC
          WHILE START=1:WEND
          GOSUB DELAY
        ENDIF
        
        IF DUR=1 THEN   'PWM DURDURMA
          INTCON.5=0
          VER=0:GOSUB SOFT_DUR
          CCP1CON=0:PORTC.2=0
          SAY=0
        ENDIF
            
        if V_ARTIR=1 then   
          TUS_DUTY=TUS_DUTY+1
          IF TUS_DUTY=MAX_DUTY+1 THEN TUS_DUTY=MAX_DUTY
          DUTY=TUS_DUTY:IF VER=1 THEN gosub pwm_ver
          while V_ARTIR=1:wend
          GOSUB DELAY
        endif 
        
        if V_AZALT=1 then  
          TUS_DUTY=TUS_DUTY-1
          IF TUS_DUTY=0 THEN TUS_DUTY=1
          DUTY=TUS_DUTY:IF VER=1 THEN gosub pwm_ver
          while V_AZALT=1:wend
          GOSUB DELAY
        endif

        IF P=1 AND DUTY=0 THEN gosub SOFT_gec        

        IF P=0 AND DUTY>0 THEN GOSUB SOFT_DUR

        GOSUB LCDGOSTER
        goto basla
'------------------------------------------------------------------------------   
DELAY:
      FOR W=0 TO 3000
      NEXT
      RETURN
      
KISA_DELAY:
      FOR W=0 TO 100:NEXT
      RETURN           
      
LCDGOSTER:     
            lcdout $FE,$C0,"DUTY:",#DUTY,"  "
            lcdout $FE,$C8,"T_DUY:",#TUS_DUTY,"  "
            RETURn
'--------------------------------------------------------------------------------

SOFT_GEC:
         lcdout $FE,$80,"SOFT GECTE"
         FOR DUTY=0 TO TUS_DUTY STEP 2
           GOSUB PWM_VER 
           GOSUB KISA_DELAY           
         NEXT  
         RETURN

SOFT_DUR:
         lcdout $FE,$80,"SOFT DURDA"
         LCDOUT $FE,$C0,"P=",DEC1 P,"  SAY=",DEC2 SAY
         FOR DUTY=TUS_DUTY TO 0 STEP -2
           GOSUB PWM_VER
           GOSUB KISA_DELAY                        
         NEXT
         LED=0
         duty=0:GOSUB PWM_VER:CCP1CON=0:PORTC.2=0 
         RETURN

PWM_VER: lcdout $FE,$80,"PWM VERDE"
         IF CCP1CON=0 THEN CCP1CON=%00001100
         X=DUTY
         CCP1CON.4=X.0
         CCP1CON.5=X.1
         CCPR1L=(X>>2)
         RETURN
'-----------------------------------------------------------------        
DISABLE
KESME:
 INTCON.7=0
IF VER=1 THEN   'PWM BAŞLATMA
   SAY=SAY+1 
   IF SAY=US then
     SAY=0 :p=1-P:LED=p
   ENDIF
ENDIF 
'-------------------------------------------------------------------------------
INTCON.7=1
TMR0=60
INTCON.2=0  
RESUME
ENABLE
'--------------------------------------------------------------------------

Programdan da görebileceğin gibi TUS_DUTY değerine başlangıçta 25 verdim sen gerekirse değiştirebilir yada sıfırdan başlatırsın. Simulasyonda PWM açılınca sistem çok yavaşlıyor ve tuş ile Duty artırmak zorlaşıyor o nedenle öndeğer verdim ama zaten bir default değeri olması lazım sıfırdan başlamak da yanlış.

Ete

Powered by EzPortal