timer1 kesmesi

Başlatan black, 26 Eylül 2014, 16:36:05

black

Merhaba forum üyeleri,

BCF      PIR1,TMR1IF     MOVLW    0xFC   MOVWF    TMR1H            MOVLW    0xFDMOVWF    TMR1L


osilatör = 10mhz

prescaler = 1:2

tmr1h + tmr1l =64765

timer

x =((65536 - (tmr1h+tmr1l))* prescaler*count) / fkomut

x = (771*2*count)/2500000

x: süre sonra kesme olacak.

buradaki count nedir ?

Yardımlarınızı bekliyorum


ete

Hesaplamanın Hz cinsinden ve süreninde us cinsinden hesaplanması için count=1.000.000 değerini alan bir çevrim faktörüdür.
Ben hesabı şöyle yaparım.
TMR1= 64765 değerinden saymaya başlayacak. Nereye kadar 65536 ya kadar . O halde ne kadar sayacak 65536-64765= 771
Bölme oranı 1/2 olduğu için bu rakamı 2 ile çarparım. O halde sayılacak puls değeri 771*2=1542 puls.
OSC frekansı 10 Mhz olduğundan bir komut çevrimi 1/10=0,4us olacaktır. O halde 1542 komut çevrimi ,
1542 x 0,4=616,8 us bu durumda her 618,8 us de bir kesme oluşacak demektir.

Ete

black

yani count formülde olmaması gereken bir değişken.

matematiksel olarak hesapladığımızda zaten us veya ms çıkacaktır.

formülümden count değerini çıkarıyorum.

timer1 taşma süresi böyle hesaplanıyorum diyorum o zaman ete hocam teşekkürler.


ete

#3
İlla bir formül istiyorsan,

X=((65535-(TMR1)+1)*Bölme_Oranı*4)/Kristal Frekansı (Mhz)
Örneği tekrarlarsak,
X=((65536-64765)*2*4)/10
X=(771)*2*4/10=616,8 olarak bulunmuş olur.

Senin formülde yer alan yanlış bir ifadeyide düzeltmek gerekir. O da şu , (tmr1h+tmr1l)
Biliyorsun TMR1 16 bitlik bir sayac ve her biri 1 byte olan iki bileşeni var. Bunlar TMR1H ve TMR1L bileşenleri.
Bunları bir birine ekleyerek TMR1 değerine ulaşılmaz. Desimal sistemde bu iş (TMR1H*256+TMRL) hesabı ile yapılır.
Bu nedenle o formülde bu iki bileşen yerine direk TMR1 yazılması daha doğru olur. Sonuçta orada 65536 dan TMR1 değeri çıkartılmaktadır.

Ete

black

konu net bir şekilde anlaşıldı.

teşekkürler ete hocam.

Hattuşa

#5
sevgili ete hocam, timer0 ile bir kesme oluşturdum ve bu kesme ile yaklaşık 8mS de bir işlem yaptırıyorum buraya kadar sorun yok. sorunum şu; timer1 de aktif edip ölçtüğüm adc değerine göre değişen [min.500 hz (2mS)- max. 5khz (200uS)] bir çıkış alabilirmiyiz?
sorunum şu hocam 40mhz le çallıştığımız için min. 4khz altına inemiyoruz. o yüzden bu işi pwm e yaptırma şansımız yok.

ete

#6
sorunun cevabını PicMultiCalc yardımcı programı ile bulmak mümkün.
"Timer Helper" seçeneğini seçip,
-OSC hanesine 40 yani 40 Mhz yazıp
- "Interrupt/Frequency" hanesinde Hz seçeneğini seçip kutuya 500 yazarsan
Sana aşağıda TMR1 seçeneklerini verecektir. Tercihen 1/1 bölme oranını kullanarak 500 Hz için Preload olarak 45543 değerini alıyoruz.
Benzer şekilde bu sefer de 5 Khz için yine 1/1 bölme oranı ile preload değerini 63542 olarak alıyoruz.
Bundan sonrası zor değil artık. Zira bu iki değerin farkı Fark=63542 - 45543= 17999 olarak bulunur. Bu değer bizim ADC ile değiştireceğimiz değer olacaktır. Yani ADC den sıfır değer okuduğumuzda TMR1 değerimiz 45543 olacak , ADC den 1023 okuduğumuzda ise TMR1 ön yükleme değerimiz 63542 olacaktır. Yapılacakları şöyle sıralayabiliriz.
- Timer1 kesmesi 1/1 bölme oranı ile aktive edilecek.
- ADC den okunacak olan 0-1203 (toplam 1024 aralık) aralığında bir değer elde edilecektir.
- Bu değeri Önyükleme değerine çevirecek bir formül kullanılacak ve öyükleme değeri hesaplanacak
- En sonunda kesme içinde kesmeden çıkmadan yeni önyükleme değeri olarak bu değer kullanılacaktır.
- Böylece sistem ADC değerine bağlı olarak istenilen aralıkta kesme üretecektir.

Bu aşamada bir formül hesaplamamız gerekiyor.
Fark=17999 idi. Bunu 18000 kabul edelim ve 1024'e bölelim. bölersek 17,5578125 gibi bir değer elde ediyoruz. Bunu 256 ile çarparak sabit çarpanımızı buluruz. Buda 4500 değeri olacaktır.
Bu durumda formülümüz , On_Yukleme=(Adc_Deger+1)*/4500+45542 şeklinde olacaktır.
Hemen bir deneme yaparsak , ADC=0 değerine karşılık Önyükleme =45543 , ADC=1023 değerine karşılık ise 63542 değeri hesaplanmış olacaktır. Bu da istediğimiz değerdir.

Kesmeye min değer olan 45543 değeri verilerek başlanmalıdır.
Hemen ardından ADC okunarak karşılık gelen ön yükleme hesaplanıp ilk kesme içinde yeni önyükleme değeri olarak bu hesaplanan değer verilmelidir. Bu şekilde sistem istenildiği gibi çalışacaktır.

Ete

Hattuşa

#7
slm ete hocam;

kusura bakmayın rahatsız edip duruyorum. bahsettiğiniz şekilde olursa şayet ben şuan üzerinde kullandığım devreden HPWM1 kanalını ve devamında cny-17 ve 555 i iptal edeceğim ki bu benim için çok iyi olur.
yukarıda bahsettiğiniz şekilde yaptım (yada anladığım kadarıyla yapmaya çalıştım)
kod şu şekilde acaba söylediklerinizi yanlış mı anladım hocam bir kontrol edebilirmisiniz? gerçekte henüz deneyemedim ama isisde deniyorum bir çıkış veriyor ancak isisde işlemciyi GLCD yüzünden 40 mhz de çalıştıramadığımız için çok yavaş çalıştırıyoruz (6mhz) buda çıkışı etkiliyor.

NOT: hocam kafama takıldı şimdi şöylesi bir sorum var, tmr0 8 bitlik bir sayaçta tmr1 ise 16 bitlik kesme içerisinde ifleri kullanırken öncelik tmr1 den mi başlamalıyım yoksa aşağıda ki gibi de olur mu?
kod şu şekilde;
Print At 1,1,"TMR0 and TMR1" Print At 2,1,"ADC:" DelayMS 10 '500 herz = 1/1 oranında 45543 '5khz =1/1 oranında 63542 'fark = 63542 -45543 =17999 =fark =18000 INTCON.7 =1B00_MaIn:While KeS =1KeS =0T1 =1   AdC =ADIn 0While ADCON0.1 ==1 :Wend  T1 =0   OnDeGeR =(AdC +1) */4500 +45543Print At 2,5,Dec AdC," " Print At 3,5,Dec OnDeGeR," "  WendGoTo B00_MaInZ0_KeSMe:        Context SaveIf INTCON.2 =1 Then       INTCON.2 =0          KeS =1         EndIfIf INTCON3.0 =1 ThenINTCON3.0 =0           Inc SaY           If SaY =OnDeGeR Then SaY =45543 :Toggle P1           EndIf        Context Restore        Stop  End

ete

Sorduğun soru ADC den okunan değere bağlı olarak 500us de bir yada maksimum 200us de bir çıkış alabilirmiyiz şeklinde idi ve bende bunu nasıl TMR1 kesmesi ile yapacağını anlattım.
Bu son verdiğin programda TMR1 kesmesi ile ilgili bir şey göremedim.
Yaptıklarınıda anlamadım doğrusu.
İşin içine proton karışınca ve kod parçası tam verilmeyince anlamam zor oluyor. Ama anladığım kadarı ile TMR1 kesmesi oluşturmadanbir şeyler yapmaya kalkışmışsın.
Hem TMR0 hemde TMR1 kesmesi kullanırsan kesme etiketi altında her ikisinide kontrol etmen gerekiyor.
If INTCON.2 =1 Then
       INTCON.2 =0
         KeS =1
EndIf

kodları TMR0 kesmesine ait bu tamam. İşlemcin belli olmadığı için TMR1 kesmesi ile ilgili bir şey yazamadım.
Ancak , TMR1 kesmesi pek çok işlemcide PIE1 registerinden set edilir. Kesme bayrağı PIR1 registerinde yer alır.
Kesmeyi aktif ettiğini kabul edersek yine kesme etiketinde şunu yapman gerekirdi;
IF PIR1.0=1 then
    PIR1.0=0
    TOGGLE CIKIS  'hangi çıkış ise veya CIKIS=1 yazıp program içinde çıkışı LOW yapabilirsin.
    TMR1L=OneDeger.Byte0
    TMR1H=OneDeger.Byte1
ENDIF

Ete



Hattuşa

hocam tmr1 ile 500hertz ile 5khz arasında değişken frekans üretmek istiyorum. multicalc ile verdiğiniz değerler doğru geldi bana.
tmr1 conf. eklemedim k. bakmayın.hata benden kaynaklı..
konu ile ilgili dosya ektedir.
http://www.yukletr.com/download.php?file=70c294cc10a8623241a670defb3291ef

kod ise ;
Device 18F4520Xtal 10Config_Start   OSC = HSPLL ; HS oscillator, PLL enabled (Clock Frequency = 4 x FOSC1)   FCMEN = OFF ; Fail-Safe Clock Monitor disabled   IESO = OFF ; Oscillator Switchover mode disabled   PWRT = OFF ; PWRT disabled   BOREN = OFF ; Brown-out Reset disabled in hardware and software   WDT = OFF ; WDT disabled (control is placed on the SWDTEN bit)   MCLRE = On ; MCLR pin enabled; RE3 input pin disabled   LPT1OSC = OFF ; Timer1 configured for higher power operation   PBADEN = OFF ; PORTB<4:0> pins are configured as digital I/O on Reset'   CCP2MX = PORTB ; CCP2 input/output is multiplexed with RB3   STVREN = OFF ; Stack full/underflow will not cause Reset   LVP = OFF ; Disabled   XINST = OFF ; Instruction set extension and Indexed Addressing mode disabled (Legacy mode)   Debug = OFF ; Background debugger disabled, RB6 and RB7 configured as general purpose I/O pinsConfig_EndDeclare PLL_Req TRUE '40mhzDeclare All_Digital =0Declare LCD_DTPort =PORTDDeclare LCD_ENPin =PORTB.2Declare LCD_RWPin =PORTB.0Declare LCD_RSPin =PORTB.1Declare LCD_CS1Pin =PORTC.5Declare LCD_CS2Pin =PORTC.4Declare LCD_Type = GraphicDeclare Internal_Font =OnDeclare Font_Addr = 0 TRISA =%00000001TRISB =%00000000TRISC =%00000000TRISD =%00000000TRISE =%00000000PORTA =0PORTB =0PORTC =0PORTD =0PORTE =0 Symbol T1   =PORTA.5Symbol P1 =PORTA.3Symbol LmB  =PORTB.5Output T1Output P1Output LmBDeclare All_Digital =FALSEA00_kUr:INTCON =%11100000    'INTCON2 =%11000100INTCON3.3 =1T0CON =%11000111         '1:128 bölme oranıT1CON =%11111001ADCON1 =%00001110   '1 kanal AdcADCON2.7 =1Declare Adin_Res 10         ' 10-bit result required      '-----------------------bvuraya hexi yüklerken baaaaaaaaaaaaakDeclare Adin_Tad =64_FOSC       ' RC OSC chosen Declare Adin_Stime 3   ' Allow 50us sample time On_Hardware_Interrupt GoTo Z0_KeSMeINTCON.7 =0A01_DeG:Dim AdC As WordDim KeS As Byte            :KeS =0Dim OnDeGeR As WordDim SaY As WordSaY =45543A02_BASLA:   ClsDelayMS 100 Print At 1,1,"TMR0 and TMR1" Print At 2,1,"ADC:" DelayMS 10 '500 herz = 1/1 oranında 45543 '5khz =1/1 oranında 63542 'fark = 63542 -45543 =17999 =fark =18000 INTCON.7 =1B00_MaIn:While KeS =1KeS =0T1 =1   AdC =ADIn 0While ADCON0.1 ==1 :Wend  T1 =0   OnDeGeR =(AdC +1) */4500 +45543Print At 2,5,Dec AdC," " Print At 3,5,Dec OnDeGeR," "  WendGoTo B00_MaInZ0_KeSMe:        Context SaveIf INTCON.2 =1 Then       INTCON.2 =0          KeS =1         EndIfIf INTCON3.0 =1 ThenINTCON3.0 =0           Inc SaY           If SaY =OnDeGeR Then SaY =45543 :Toggle P1           EndIf        Context Restore        Stop  EndInclude "FONT.INC"


bu arada TMR1L ve TMR1H değerleri hiç aklıma gelmedi.  ;D

Hattuşa

ete hocam yapamadım ya;
Z0_KeSMe:        Context SaveIf INTCON.2 =1 Then       INTCON.2 =0          KeS =1         EndIfIf PIR1.0 =1 ThenPIR1.0 =0TMR1L =OnDeGeR.Byte0TMR1H =OnDeGeR.Byte1P1 =1           EndIf        Context Restore        Stop 


böyle yapınca tmr1 den hiç çıkmıyor ve adc dahi okumuyor.

ete

#11
Data sheet kurcalamak en büyük eksikliğin ve bu konuda ısrar ediyorsun hala.
TMR1 sayacı T1CON registeri tarafından kontrol ediliyor. BU registere verdiğin değere bakalım.
T1CON =%11111001
Data sheet'e de bakarsak,
Bit7:TMR1 in 16 bit mi yoksa 8 bitmi çalışacağını belirliyor 1=16 bit
Bit6:TMR1 osc sinin aynı zamanda işlemci osilatörümü olacağını belirliyor buraya sıfır verilmeli
Bit5-4: Bölme oranı , buraya 00 verilmeli
Bit3: TMR1 enabled veya kapalı seçimi buraya 1 verilmeli
Bit2: TMR1 external CLK select biti burası sıfır yada 1 farketmez asıl değeri 1 ama bir sonraki bit sıfır olunca bu bit göz ardı ediliyor zaten.
Bit1: TMR1 CLK kaynağı seçme biti , buraya 0 erilmeli yani internal clk.
bit0: Enable Tmr1 yani buraya 1 verilmeli
Bu durumda TMR1 resigerine=%10000001 değerinin verilmesi gerekiyor.
Kesmeyi aktive etmek için;
Önce RCON.7=0 verilmeli. Bu kesmelerde öncelik biti olup kesmeler senin anlayacağın şekilde çalışsın istiyorsan bu biti sıfır yapman daha doğru.
Sonra;
INTCON=%11100000
PIE1.0=1
PIR1.0=0
Şeklinde kesmeleri aktive etmen gerekir.
PBP da ayrıca ON INTERRUPT GOTO KESME diye bir komut daha ekliyoruz. Proton karşılığı neyse eklersin.
Kesmeye bağlı bir karedalga üretebilmek için her kesme oluştuğunda sinyalin çıkacağı pine konum değiştirmek gerekir. Bunu yapan komut da TOGGLE komutudur. Yada 1-ÇıkışPini demek yeterli olur. Seninkodlarında buna benzer bir şey göremedim.
TMR0 kesmesi ne işe yarıyor acaba? Görünüşe bakılırsa sadece Kes=1 yapıyor ne amacı var bunun.?
Her neyse ben TMR1 kesmesine odaklanayım.

Sonra Kesme içinde,
Z0_KeSMe:
        Context Save
If INTCON.2 =1 Then
       INTCON.2 =0
         KeS =1
         EndIf
If PIR1.0 =1 Then
   PIR1.0 =0
   Toggle CıkısPini veya CıkısPini=1-CıkısPini yazman sinyali oluşturacaktır.
   TMR1L =OnDeGeR.Byte0
   TMR1H =OnDeGeR.Byte1
   P1 =1 'bu neyse silinebilir
EndIf
        Context Restore

Bu işlemcide bir kesme önceliği sistemi olduğunu belirtmiştim. Şayet aynı anda kesme oluştuğu zaman öncelik TMR1 kesmesine verilsin istiyor isen bu özelliği kullanabilirsin. Bunun için RCON.7=1 vereceksin. Ayrıca IPR1.0=1 vermen gerekiyor. Böylece bu kesme önceliğe sahip olmuş olacaktır.
Ancak yukarıdaki kullanım şeklinde ilk bakılan TMR0 registeri olacak ve şayet aynı zamanda TMR1 kesmeside oluşmuş ise onunda işlemi aynı seferde yapılacaktır. Bence öncelik kullanmaya gerek yok.
Hepsi bu kadar.
Ete

Hattuşa

#12
@ete hocam
bizim sorunumuz şu (en azından benim), bu yazılımı öğrenirken kopyele yapıştır yapıyoruz. yani bir yerlerden kopyelediğimiz kodları zaman içerisinde değişikliğe uğrattığımızda bu tip sıkıntılar yaşıyoruz.

hocam herneyse hazır bir cevap yazmışken sizi biraz daha sıkıştırayım. ;D

proton veya basicte iki tip kesme var sanırım. bunlardan birisi sizin kullandığınız "ON INTERRUPT GOTO KESME" ve benim kullandığım "On_Hardware_Interrupt GoTo KeSMe"


ON INTERRUPT GOTO KESME de


disablekesme:' kodlarresumeenable



On_Hardware_Interrupt GoTo KeSMe de ise
kesme:context save' kodlarcontext restore


kullanılmaktadır. aralarında ki fark nedir, birbirlerine üstünlükleri veya dezavantajları varmıdır?


bu arada mesajda yazdıklarınızı ilk fırsatta deneyeceğim. bize tahammül ettiğiniz için tşk ederim.

NoT: hocam az önce denedim isisde doğru çalışıyor. ben neden ekledim bilmiyorum ama INTCON3.3 =1 yapmışım onu silince çalıştı.  ;D

ete

Biri yaılım diğeri donanım kesmesi olarak gözüküyor. Donanım kesmesinde işlemcinin can alıcı registerleri kayıt edilip kesmeden çıkarken yeniden geri yükleniyorki bu olması gereken gerçek kesme. PBP bunu yapamadığı için basic komutu bitmeden kesme oluşturamıyor. Donanım kesmesinde komuta bağımlı olmadan kesme oluşacaktır sanırım. Daha fazla detay bilmiyorum.
Ete

Hattuşa

hocam ya size özel mesaj yazayım dedim beceremedim.
bu konu ile ilgili son bir soru daha sormak istiyordum ama çok olmaktan çekiniyorum.
sorum şuydu. oluşturduğumuz frekans 500 hertz ile 5 khz değerinde buraya kadar sorun yok. sorunum şu oluşan frekans %50-%50  duty değerinde ve en azından duty değeri ile 10 basamak oynama şansımız varmı? varsa öneriniz nedir?

Powered by EzPortal