PIC16F883 de Timer0 Kesmesini Doğru Çalıştıramadım

Başlatan M.A.A, 03 Mart 2014, 14:17:40

M.A.A

Merhaba Arkadaşlar
PIC16F883 de Timer0 kesmesi ile süre hesaplamak istiyorum. Örneğin bir Rolenin 10 dakika çekip bırakması gibi. Daha önce 18f4520 da timer0 i sorunsuz kullandım.

Programın timer0 ve kesme kısmı aşağıdaki gibi

'interrupt,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
On Interrupt GoTo KESME
INTCON=%11100000
'timer,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
OPTION_REG = %10000111 
INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor
TMR0=15

Clear

Disable
KESME:
If INTCON.2=1 Then
     LED=1-LED

     TMR0=15 
     INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor
End If
     Resume
     Enable
End


Yazdığım programa göre Led in aynı periyotta yanıp sönmesini bekliyorum. (x süre yan, x süre sön) Ama bu şekilde olmuyor. Kararsız davranıyor. 5-6 defa yanıp sönüyor (osiloskop ile bakıyorum) 1-2 saniye bekliyor tekrar 5-6 defa yapıp sönüyor.
Hata nerede olabilir?

M.A.A

Sorunun nedenini buldum ama çözümünü bulamadım. Ana programdan kaynaklanıyormuş sorun. Sıra işle denedim ana programdan for döngüsünü kaldırınca sorun kalmıyor. For döngüsünde böyle birşey daha önce başıma gelmemiş
DEGERA1=0
For y = 0 To 250 Step 1
ADCON0=%00001101  'AN3
ADCON0.1=1  'A/D başlat
bitmedia1:
If ADCON0.1=1 Then bitmedia1
SAYI.Byte0= ADRESL
SAYI.Byte1= ADRESH
    If DEGERA1 < SAYI Then
    DEGERA1 = SAYI
    End If
DelayUS 5
'Next

ete

Programın tamamını vermeden ne sen soruna cevap bulabilirsin nede biz bir sorun bulabiliriz.
Verdiğin program sadece ana programın bir parçası. Asıl sorun parçanın diğer kısmından kaynaklanıyor muhtemelen.

Ete

M.A.A

İlginiz için teşekkür ederim
Program çok uzun olunca tamamını vererek sizi meşkul etmek istememiştim.


Device = 16F883
OSCCON = %01110000     'Internal 8 MHz clock select,
Xtal=8

Asm
CONFIG_REQ
__CONFIG _CONFIG1, INTRC_OSC_NOCLKOUT & WDT_OFF & DEBUG_OFF & FCMEN_OFF & IESO_OFF & BOR_OFF & LVP_OFF & CPD_OFF & CP_ON & MCLRE_OFF & PWRTE_OFF
__CONFIG _CONFIG2, WRT_OFF & BOR21V
EndAsm

ANSEL=%00000000'all analogue ports to digital
ANSELH=%00000000'all analogue ports to digital
ADCON0.0=0'disable ADC
CM1CON0=%00000000'disable COMPARATOR 1
CM2CON0=%00000000'disable COMPARATOR 2
SSPCON=%00000000'disable SERIAL PORT
RCSTA=%00000000'disable SERIAL PORT
PCON=%00000000'disable BOR and ULPW
OPTION_REG=%00000000'disable INTERNAL PULLUPS
WPUB=%00000000'disable INDIVIDUAL PULLUPS
IOCB=%00000000'disable INTERRUPT ON CHANGE
CCP1CON=%00000000'disable ECCP1
PSTRCON=%00000000'disable PULSE STEERING MODE
T1CON=%00000000'disable TIMER

'Port Tanımlamaları,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

LED VAR PORTB.5  'ÇIKIŞ
TUSAUTO VAR PORTB.4  'GİRİŞ
TUSSTOP VAR PORTB.6  'GİRİŞ
TUSMAN VAR PORTE.3  'GİRİŞ

'Değişkenler,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Dim SAYI As Word   
Dim DEGERA1 As Word
Dim y As Byte  : Dim z As Byte 

'Port Ayarlamaları,,,,,,,,,,,,,,,,,,,,,,
      '76543210
TRISA=%00101000
TRISB=%01010111
TRISC=%00000110   
TRISE=%00000010

PORTA=0
PORTB=0
PORTC=0
PORTE=0

ADCON0=%00000000
ADCON1=%10000000

Clear
DelayMS 500



'interrupt,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
On Interrupt GoTo KESME
INTCON=%11100000
'timer,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
OPTION_REG = %10000111  'T0CON
INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor
TMR0=15
DelayMS 1000
Clear

BASLA:

Call OLCUM
DelayMS 100
GoTo BASLA

OLCUM:
ANSEL =%11111111
ANSELH=%11111111


DEGERA1=0
For z = 0 To 3 Step 1
For y = 0 To 250 Step 1
ADCON0=%00001101  'AN3
ADCON0.1=1  'A/D başlat
bitmedia1:
If ADCON0.1=1 Then bitmedia1
SAYI.Byte0= ADRESL
SAYI.Byte1= ADRESH
    If DEGERA1 < SAYI Then
    DEGERA1 = SAYI
    End If
DelayUS 5
Next
Next

ANSEL =%00000000'
ANSELH=%00000000'
ADCON0=%00000000
Return

Disable
KESME:
If INTCON.2=1 Then
     LED=1-LED

     TMR0=15
     INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor
End If
     Resume
     Enable
End



Bu şekilde LED çıkışından eşit kare dalga alamıyorum.





ete

INTCON=%11100000
şeklinde tanımlama ile Peripheral kesmeleri de aktif hale getirmişsiniz. Baktım bu tür kesme kullanmıyorsunuz. INTCON.6=0 olmalı.

For z = 0 To 3 Step 1
komut satırında yazdığınız Step 1 ifadesi gereksizdir. Siz onu yazsanızda yazmasanızda program zaten adımı 1 olarak uygulyacaktır.
Aynı şekilde diğer döngüdede benzer kusur bulunmaktadır.

TMR0 Kesmesi kullanılan bir programda DelayMS 100 şeklinde bir komut satırı kullanmak yanlış.
Bu satırı kaldırın . Çok gerekli ise döngü şeklinde gecikme yaratın aynı gecikmeyi;
FOR G=0 to 2000:next şeklinde de yaratabilirsiniz ve bu gecikmenin kesmeye etkisi olmaz.
DelayMS 100 komut satıır programı orada 100 ms bekletmeye alır. O esnada kesme oluşsa bile program kesmeye gidemez. 100 ms nin dolmasını bekler.

Aynı şekilde  DelayUS 5 şeklindeki komut satırıda sonucu fazla etkilememekle birlikte belirli bir gecikme yaratabilir 2us gibi bir değer koyun yeterlidir. Hatta orada gecikmeye ihtiyaç yoktur kaldırın gitsin.

Madem yalnızca tek kesme kaynağı (TMR0) kullanıyorsunuz o halde kesme içinde ,
If INTCON.2=1 Then şeklinde bir komut yerleştirmekte gereksizdir. Program kesme etiketine zaten TMR0 kesmesi oluşunca gidecek. Başka türlü gelmesi mümkün değil. Bu tür komutları birden fazla kesme kaynağınız var ise kullanmanız gerekir.
O halde Kesme kısmını şöyle yapmanız daha uygun olur;
Disable
KESME:
     TOGGLE LED  'bu komut sizin yazdığınıza göre daha az kod üretir.
     TMR0=15
     INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor
     Resume
     Enable
End

Ete


M.A.A

Hocam söylediğiniz bütün değişiklikleri yaptım. Sonuç gene istediğim gibi olmadı. Çıkışın fotografını ekliyorum.

[IMG]http://imagizer.imageshack.us/v2/xq90/69/ycrn.jpg[/img]



Device = 16F883
OSCCON = %01110000     'Internal 8 MHz clock select,
Xtal=8

Asm
CONFIG_REQ
__CONFIG _CONFIG1, INTRC_OSC_NOCLKOUT & WDT_OFF & DEBUG_OFF & FCMEN_OFF & IESO_OFF & BOR_OFF & LVP_OFF & CPD_OFF & CP_ON & MCLRE_OFF & PWRTE_OFF
__CONFIG _CONFIG2, WRT_OFF & BOR21V
EndAsm




ANSEL=%00000000'all analogue ports to digital
ANSELH=%00000000'all analogue ports to digital
ADCON0.0=0'disable ADC
CM1CON0=%00000000'disable COMPARATOR 1
CM2CON0=%00000000'disable COMPARATOR 2
SSPCON=%00000000'disable SERIAL PORT
RCSTA=%00000000'disable SERIAL PORT
PCON=%00000000'disable BOR and ULPW
OPTION_REG=%00000000'disable INTERNAL PULLUPS
WPUB=%00000000'disable INDIVIDUAL PULLUPS
IOCB=%00000000'disable INTERRUPT ON CHANGE
CCP1CON=%00000000'disable ECCP1
PSTRCON=%00000000'disable PULSE STEERING MODE
T1CON=%00000000'disable TIMER

'Port Tanımlamaları,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

LED VAR PORTB.5  'ÇIKIŞ
TUSAUTO VAR PORTB.4  'GİRİŞ
TUSSTOP VAR PORTB.6  'GİRİŞ
TUSMAN VAR PORTE.3  'GİRİŞ

'Değişkenler,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Dim SAYI As Word   
Dim DEGERA1 As Word
Dim y As Byte  : Dim z As Byte 

'Port Ayarlamaları,,,,,,,,,,,,,,,,,,,,,,
      '76543210
TRISA=%00101000
TRISB=%01010111
TRISC=%00000110   
TRISE=%00000010

PORTA=0
PORTB=0
PORTC=0
PORTE=0

ADCON0=%00000000
ADCON1=%10000000

Clear




'interrupt,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
On Interrupt GoTo KESME
INTCON=%10100000
'timer,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
OPTION_REG = %10000111  'T0CON
INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor
TMR0=15
For y=0 To 4000:Next
Clear

BASLA:

Call OLCUM
For y=0 To 2000:Next
GoTo BASLA

OLCUM:
ANSEL =%11111111
ANSELH=%11111111


DEGERA1=0
For z = 0 To 3
For y = 0 To 250
ADCON0=%00001101  'AN3
ADCON0.1=1  'A/D başlat
bitmedia1:
If ADCON0.1=1 Then bitmedia1
SAYI.Byte0= ADRESL
SAYI.Byte1= ADRESH
    If DEGERA1 < SAYI Then
    DEGERA1 = SAYI
    End If
Next
Next

ANSEL =%00000000'
ANSELH=%00000000'
ADCON0=%00000000
Return

Disable
KESME:

     Toggle LED

     TMR0=15
     INTCON.2=0        'TMR0 Kesme bayrağı sıfırlanıyor

     Resume
     Enable
End










ete

Bu durumda muhtemelen ADC okuması işlemciye vakit kaybettiriyor. Oradaki işlem bitmeden kesmeye giremiyor olsa gerek.
Döngüleri kaldırınca düzeliyorsa kesinlikle sorun bu olmalı. Basic komutu ile ADC okumayı denesene bakalım ne sonuç verecek.

Ete

ete

Şimdi simulasyonda deniyorum doğru çalışıyor. Bu durumda devrende yada programlamada bir sorun olduğunu düşünüyorum.
Doğru çalışıyor derken ADC yi iptal etmişim ondan doğru çalışıyormuş. ADC işlemi dahil edilince yanlış çalışıyor çünki belirlenen kesme süresi gerçekten çok kısa ve ADC sonuç önceliğine sahip olduğu için  program oradan sonuç almayınca kesmeye gitmiyor.
Normal ADCIN komutu ilede aynı sonuç alınıyor.
Başka bir şey denemek lazım
Data sheet de bir şey dikkatimi çekti bu işlemcinin ADC işleminde Acquistation zamanı 4,7 ms olarak hesaplanmış bu çok uzun bir süre. Normalde diğer işlemcilerde 10-20 us arasındadır bu süre. Sorun bu olabilir.

Ete

M.A.A

İki saattir her şeyi denedim, sonunda yaptığım hatayı buldum. Aslında sorun timer da veya kesmede değilmiş. ADC okuma öncesi
ANSEL =%11111111
ANSELH=%11111111

komutu ile bütün ADC leri aktif ettiğim için çıkışı etkiliyor.  ADC okuması bitince

ANSEL =%00000000
ANSELH=%00000000

yapsam dahi arada geçen süre çıkışın bozulmasına yetiyor. For döngüsü işi uzattığı için daha da bozuluyor.

Sadece ADC sini kullanacağım pinin ADC sini açınca sorun kalmadı.

Aslında 18F4520 de çıkış ayarladığım portun ADC sini aktif etsemde böyle bir sorun olmuyordu.


Not: Similasyonda bende denedim. Aynı sorun oluyordu.

M.A.A


ete

Aldığın bu sonuç beni şaşırttı gerçekten. Hiç bir zaman Analog pinlerin hepsini aktif hale getirip yalnızca birini kullanmayı düşünmem. Ancak bu işlemin başına gelen sorunu yaratacağınıda düşünmem açıkçası. Gerçekten enteresan.
Pinleri aktive etsen bile ancak kullanırsan gerekli gecikmeyi yaratabileceğini düşünürüm ama olabiliyormuş demekki.
Bende deneyeceğim.

Şimdi farkettim ki asıl sorunu yaratan unsur ANSELH registeri 5 nolu biti. Çünki bu bit PORTB.5'i temsil ediyor ve sen oradan çıkış alıyorsun. Çıkış aldığın bir pini aynı zamanda analog pin haline getiriyorsun ki çıkış anında pic o pini önce analog dan kurtarıp digital yapıyor sonra onu çıkış haline getirip senin çıkışını yapmaya çalışıyor bu işi de her kesme oluştuğunda yapıyor. Asıl sorun bu. ANSELH registerinde 5 nolu biti sıfır yap eski kodlarında çalışır.

Ete

M.A.A

Analogların hepsini açtığım için geçikme yaratmıyor. Kesme de terslediğim LED çıkışda RB5/AN13/T1G ye bağlı olduğu için, hepsini aktif ettiğimde AN13 pinine etkisi oluyor. Ben kesmede LOJIK 1 yapsamsa AN13 analog girişe çevrilince LOJIK 0 oluyor, veya tam tersi. 

1 adet analog kullanacağım halde hepsini açma alışkanlığım 18F4520 den geliyor, onda teker teker açma yok, AN0 ile ANx arasını açabiliyorum (ben dahasheet den böyle anladım). Sadece  AN0 ile AN13 ü kullanmak için hepsini açmak gerekiyor. Ama açılan pin çıkış ise herhangi bir etkisi olmuyor diye gözlemlemiştim.

ete

Analog pinlerin hepsini birden açma ve kapatma kötü bir alışkanlık. 18F4520 de tablo yardımı ile analog pinler seçiliyor.
Tablo öyle hazırlanmış ki isterseniz 1 kanal isterseniz 2 isterseniz 3 şeklinde sıra ile gidiyor seçim kabiliyeti. Bu durumda size 1 kanal lazım ise ona ait bit kombinasyonunu seçip bir kereliğine ADCON1 registerine değer verilmesi gerekir. Bu değer program içinde değiştirilmemelidir. Değiştirirseniz işlemciye eziyet etmiş olursunuz. Eziyetten kastım bu işi yapması için bir sürü işlem yapmaktadır. Her seferinde onlarla oynayarak bu işlem adedini artırmış olursunuz.

Basic komutlarının pek çoğunda komutun cinsine göre ilgili pini giriş yapma veya çıkış yapma özelliği bulunur. Bir örnek vereyim.
PORTB.0=1 demek ile HIGH PORTB.0  demek aynı sonucu doğrun iki komuttur. Ancak komutların işleyişi bir birlerinden farklıdır.
PORTB.0=1 komutu ilgili pinin Çıkış olduğunu varsayar ve yalnızca ilgili biti HIGH yapar.
HIGH PORTB.0 komutu ise ilgili bitin girişmi çıkışmı ayarlandığına bakmaksızın ;
- önce TRISB.0=0 yapar
- sonra PORTB.0=1 şeklinde komutu işletir.
Gördüğün gibi ikinci komut ilgili pini otomatik çıkış yapmaktadır.

Ete


M.A.A

Teşekkür ederim hocam.
Öğrencilik yıllarımda ve daha sonrasında ASM dilini çok kullandığım için Basic kullandığım halde bazı şeyleri ASM gibi kullanıyorum. Onun dışında diğer yaptığım hata ve eksikleri de öğrendim sayenizde. Çok teşekkür ederim.

Powered by EzPortal