TIMER0 Kesme Süre Hesabını Bir Türlü Tutturamadım

Başlatan M.A.A, 10 Ocak 2016, 00:04:39

M.A.A

Merhaba Arkadaşlar
Pic18F4620 işlemci kullanıyorum. İşlemcinin dahili osilotörünü 8MHZ ye ayarladım.
Yapmak istediğim şey hassas bir kronometre. Saniyede 100 kez kesmeye girip kesme içerisinde iki adet değişkenin değerini artırmasını istiyorum. Fakat bir türlü beceremedim.

ZAMAN=11

'interrupt,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
On Interrupt GoTo KESME
INTCON=%11100000
'timer,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
T0CON=%11000011
TMR0L=ZAMAN
INTCON.2=0

ADCON1=%00001111
CMCON=07h

Disable
KESME:     
   
     SAYAC=SAYAC+1
     SAYAC2 =SAYAC2+1

     
     TMR0L=ZAMAN       
     INTCON.2=0     
     Resume
     Enable


Hesaplama yaparak işin içinden çıkamadım, deneme yanılma ile değer artırıp azalttım gene beceremedim.

Hattuşa

arkadaşım dahili kristal yerine harici ve yüksek değerde kristal kullansan ve 8 bit timer yerine 16 bit timer kullansan daha hassas işlem yaparsın diye düşünüyorum.

Bahri Bilir

BU arada özellikle kesme bulunan kodlarda pause kullamamaya özen gösterin.Bildiğim kadarıyla pause anında kesme oluşsa da program pause süresi bitmeden pauseden ayrılamıyor.Bittikten sonra gittiğinde de zaten geç kalmış oluyor.
"Hedeflerin bittiği tek yer, YENİ hedeflerin başlangıcıdır"

ete

Biraz mantık ve birazda hesap kullanarak bu sorunu aşabilirsin. Yolunu göstereyim.
1 sn 1000 ms ve oda 1000.000 us dir. 1 sn de 100 kez kesmeye girmen demek 1000/100=10 ms yani her 10 ms de bir kesme yaratman anlamına gelecektir.
İşlemci frekansın 8 Mhz ise 8/4=2 ve 1/2=0,5us bir komut çevrimi süresidir.  Yani TMR0 sayarken her 0,5us de bir sayac değeri bir artırılacak demektir.   Peki 1 komut çevrimi 0,5us ise 10 ms için (10.000 us) bize ne kadarlık bir komut çevrimi gerekli onu bulalım. 10.000/0,5=20.000  Bu sayı 8 bitlik olan TMR0 sayacının alabileceği maksimum değer olan 255 den çok büyük bir değerdir. O halde bölücü kullanmamız gerekecektir. Bu sayıyı en büyük bölen olan 256 ya bölersek, 78 değerini buluruz. Bu 255 den uzak bir değer. O halde bölmeyi bir kademe küçültebiliriz 128 deneyelim, 20.000/128=156 bu fena değil ama bakalım bir kademe daha küçültürsek ne oluyor. 20.000/64=312 buda 255 değerinden büyük olduğuna göre doğru bölme oranımız 128 olacaktır.
Peki 20.000 sayacağımıza göre bunu 128 e bölersek 156 küsür bir sayı elde ediyoruz. Bu benim 128 defa 156 saydırmam gerektiğini gösteriyor. O halde TMR0 sayacım sıfırdan başlayıp 255 e kadar saymamalı bu şekilde sayarsa 128x255=32.640us lik bir gecikme yaratır. Halbuki bana 10ms lik gecikme gerekiyor ve bunun yoluda sayacımın her seferinde 1/128 bölme oranı ile 156 sayması. O halde TMR1 sayacını sıfırdan değilde 255-156=99 değerinden başlatmam gerekir.
Şimdi bulduklarımızı bir deneyelim istersen.
Sayacı 99 dan başlattım. 99 dan 256 oluncaya kadar 255-99=157 sayacak. Her bir saymayı 128 puls de bir yapacağı için ve her bir puls in de 0,5us süresi olacağı için, 0,5 us x 128 x 157=10.048 us yada yaklaşık 10 ms lik bir süre geçmiş olacaktır.
O halde kesmeyi açarkan;
T0CON=%11000110 değerini vereceksin. Ardından TMR0L registerine ön yükleme değeriniz olan 99'u vereceksiniz. Yani,
TMR0L=99  ve Kesme içinde kesmeden çıkmadan evvel aynı TMR0L registerine 99 değerini yükleyerek çıkmanız gerekiyor.
Böylece sistem her 10 ms de bir kesme yaratacaktır.

Kısaca programda yer alan ZAMAN değişkeniniz değeri 99 olmalı. T0CON register değerinizide yukarı yazdım. Siz 1/16 bölme oranını almışsınız yanlış bir değer rastgele seçtiniz herhalde.

Ete

M.A.A

İlginiz için hepinize teşekkür ederim. Ete hocam verdiğiniz değerleri daha önce denemiştim, şimdi tekrar denedim. 1 dakikada 2911 defa kesmeye girdi. Programı epey sadeleştirip tekrar denedim sonuç gene benzer. Kodun sade halini ekliyorum.


Device = 18F4620

OSCCON = %01110000     'Internal 8 MHz clock select
Xtal=8

Config_Start
   OSC = INTIO67 ; Internal oscillator block, port function on RA6 and RA7
   PWRT = OFF ; PWRT disabled
   BOREN = OFF ; Brown-out Reset disabled in hardware and software
   BORV = 0 ; Maximum setting
   WDT = OFF ; WDT disabled (control is placed on the SWDTEN bit)
   MCLRE = OFF ; RE3 input pin enabled; MCLR disabled
   PBADEN = OFF ; PORTB<4:0> pins are configured as digital I/O on Reset
   LVP = OFF ; Single-Supply ICSP disabled
   CP0 = On ; Block 0 (000800-001FFFh) code-protected
   CP1 = On ; Block 1 (002000-003FFFh) code-protected
   CP2 = On ; Block 2 (004000-005FFFh) code-protected
   CP3 = On ; Block 3 (006000-007FFFh) code-protected
   CPB = On ; Boot block (000000-0007FFh) code-protected
   WRTD = OFF ; Data EEPROM not write-protected
Config_End


'LCD TANIMLAMALARI,,,,,,,,,,,,,,,,,,,,
Declare LCD_Type Alphanumeric        '
Declare LCD_DTPin PORTD.0            '
Declare LCD_ENPin PORTC.0     'e     '
Declare LCD_RSPin PORTC.1     'rs    '
Declare LCD_Interface 4              '
Declare LCD_Lines 4                  '
'''''''''''''''''''''''''''''''''''''
Declare All_Digital = True
SDA var PORTC.4                     ' RTC data
SCL var PORTC.3                     ' RTC clock

UZ1 VAR PORTB.7  'GİRİŞ
UZ2 VAR PORTB.6  'GİRİŞ
TRISB.7=1  'GİRİŞ
TRISB.6=1  'GİRİŞ

'Değişkenler,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

Dim SINYALSAYAC As Dword
Dim SINYALSAYAC2 As Dword
Dim SEGMENGSAYAC As Dword 
Dim ZAMAN As Byte
ZAMAN=99


'interrupt,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
On Interrupt GoTo KESME
INTCON=%11100000
'timer,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
T0CON=%11000110
TMR0L=ZAMAN
INTCON.2=0

ADCON1=%00001111
CMCON=07h

SINYALSAYAC=0


BASLA:

If UZ1=0 Then  SINYALSAYAC=0
If UZ2=0 Then  SINYALSAYAC2=SINYALSAYAC
Print At 4,1, Dec6 SINYALSAYAC  ,"        " , Dec6 SINYALSAYAC2   
GoTo BASLA


Disable
KESME:     
     SINYALSAYAC=SINYALSAYAC+1
     SEGMENGSAYAC =SEGMENGSAYAC+1

     TMR0L=ZAMAN       
     INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor
     Resume
     Enable

End



Devremdeki X tuşuna basınca SINYALSAYAC değişkenini sıfırlıyorum
Devremdeki Y tuşuna basınca SINYALSAYAC2 ye SINYALSAYAC daki değeri atıyorum.
Telefondaki kronometreyi başlatıp aynı anda X tuşuna basıyorum
1 dakika olunca Y tuşuna basıyorum. SINYALSAYAC2= 2910 civari oluyor.

ete

Denemeyi nerede yapıyorsun,
- simulasyon
- deney boardı
- gerçek devre
Hangisi?

Ete

M.A.A


ete

OSCCON registerine birde şu değeri vererek dene bakalım.

OSCCON=%01110110
Her ihtimale karşı TMR0H=0 şeklinde bir komutuda program başına eklemenizde yarar var.
Ayrıca değişkenleri tanımladıktan sonra 300ms lik bir açılış gecikmesi ekleyin programa.

Ete

M.A.A

OSCCON=%01110110
yapınca 2722 oldu, geçikme ve  TMR0H=0 ekleyince 2825 oldu

ete

Gerçekte 6000 civarında çıkması gereken değer anlamsız bir şekilde 2800-2900 civarında çıkıyor.
Hiç bir geçerli açıklaması yok bunun. Program kesmede çok vakit harcıyor sanırım.
Enteresan sonuç ve ne yapılması gerektiği konusunda hiç bir fikrim yok maalesef.
Son değişiklikler bana göre olması gereken değişiklikler ve alakasız bir şekilde sayac değeri dahada düşüyor bunları yapınca. Sayaca hiç etkisinin olmaması gereken Tmr0H=0 komutu bile etkiliyor nasıl olabiliyor anlamış değilim.

Ete

Hattuşa

ETE hocam hassas saymaktan bahsettiği için ben 16 bitlik timer kullanmasını tavsiye ettim. bunun içinde multicalculator oldukça kullanışlı bir program bu programı sizden öğrendik. şimdi bana 8MHZ lik de 10mS lazım ise aşağıdaki gibi programı seçer. 16 bitlik timer ile 45543 değerini TMRL ve TMRH değerine yükler işimi görürüm diye düşünüyorum. aynı programın üst tarafında 8bitlik timer değerini de vermiş fakat %0,512 hata oranı vermiş. 16 bitte %0 hata.
hocam benim bu teknikte daha iyi değil mi? timer1 ve timer0 konusunda kafama vura vura öğretmiştiniz geçen sene  ;D  ;D  ;D


Bu arada isis dosyasını eklemiş olsaydınız bizde biraz kodlarla oynayarak yardımcı olmaya çalışırdık...

ete

Tmr0 ın daha a hassas olduğunu söyleyemeyiz. Oda diğeri kadar hassastır. Üstelik birinde 1 byte lık ön yükleme diğerinde 2 bytelık ön yükleme değeri kullanılıyor. Daima daha az kod tercih edilmelidir.
Burada sözkonusu olan %100 gibi bir hata dır. Dolayısıyla timer hesabındaki hatayı gözardı etmemiz gerekiyor.
Ete

M.A.A

Devrenin ilgili kısmının isisini hazırlayıp en kısa zamanda ekleyeğim.
Evet 16 bit daha hassas görünüyor ama 8 bitte olan hatayı bulmam gerekiyor.

Hattuşa

usta isis şemasını çizermisin bilmem ama bir kodda ben yazdım, imkanınız varsa bunu bir deneyebilirmisiniz? kodun çalışacağını düşünüyorum. zira sizin yaptığınız hataları gördüm, ayrıca interruptu donanımsal kesmeye çevirdim ki kaçırmasın diye...

yalnız çalışıp çalışmadığını bildirirseniz memnun oluruz, hatamızı görürüz en azından


Device = 18F4620
CONFIG_START
   OSC = INTIO67 ; INTRC-OSC2 as RA6, OSC1 as RA7
   FCMEN = OFF ; Disabled
   IESO = OFF ; Disabled
   PWRT = OFF ; Disabled
   BOREN = OFF ; Disabled
   WDT = OFF ; Disabled
   MCLRE = OFF ; Disabled
   LPT1OSC = OFF ; Disabled
   PBADEN = OFF ; PORTB<4:0> digital on Reset
   STVREN = OFF ; Disabled
   LVP = OFF ; Disabled
   XINST = OFF ; Disabled
   DEBUG = OFF ; Disabled
   WRTD = OFF ; Disabled
CONFIG_END



OSCCON = %01110000     'Internal 8 MHz clock select
Xtal=8
trisa =%00000000
trisb =%11000000
trisc =%00000000
trisd =%00000000
trise =%00000000
porta =0
portb =0
portc =0
portd =0
porte =0


'LCD TANIMLAMALARI,,,,,,,,,,,,,,,,,,,,
Declare LCD_Type Alphanumeric        '
Declare LCD_DTPin PORTD.0            '
Declare LCD_ENPin PORTC.0     'e     '
Declare LCD_RSPin PORTC.1     'rs    '
Declare LCD_Interface 4              '
Declare LCD_Lines 4                  '
'''''''''''''''''''''''''''''''''''''
Declare All_Digital = True
symbol SDA =PORTC.4                     ' RTC data
symbol SCL =PORTC.3                     ' RTC clock

symbol UZ1 =PORTB.7  'GİRİŞ
symbol UZ2 =PORTB.6  'GİRİŞ
input uZ1
input UZ2

'Değişkenler,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

Dim SInYALSAyAC As Dword
Dim SINyALSAYAc2 As Dword
Dim SEGmENGsAYAC As Dword 
symbol ZAmAN =45543


'interrupt,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

SYMBOL TMR0IF = INTCON.2 ' TMR0 Overflow Interrupt Flag
SYMBOL TMR0IE = INTCON.5 ' TMR0 Overflow Interrupt Enable
SYMBOL GIE = INTCON.7    ' Global Interrupt Enable
tmr0ie =1
gie =0
On_Hardware_Interrupt GoTo KeSMe
'timer,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
T0CON=%10000000
INTCON.2=0

ADCON1=%00001111
CMCON=07h

SINYALSAYAC=0
tmr0l =zaman.lowbyte
tmr0h =zaman.highbyte

gie =1 'kesme aktif edildi
BASLA:

If UZ1=0 Then  SINYALSAYAC=0
If UZ2=0 Then  SINYALSAYAC2=SINYALSAYAC
Print At 4,1, Dec6 SINYALSAYAC  ,"        " , Dec6 SINYALSAYAC2   
GoTo BASLA


KeSMe:
Context Save
tmr0l =zaman.lowbyte
tmr0h =zaman.highbyte     
     SINYALSAYAC =SINYALSAYAC +1
     SEGMENGSAYAC =SEGMENGSAYAC +1
       
     TMR0IF =0        'TMR0 Kesme bayrağı sıfırlanıyor
context restore

End

M.A.A

Denedim sonuç gene hatalı. Hatanın nereden kaynaklandığını buldum. Ama çözümünü bilmiyorum.
Print At 4,1, Dec6 SInYALSAyAC  ,"        " , Dec6 SINyALSAYAc2

Komutunu kapatırsak, yani LCD ekranı devre dışı bırakırsak kesmeye doğru zamanda giriyor.

Powered by EzPortal