12F675 hardware ADC interrupt?

Başlatan Maxim, 24 Mart 2015, 09:57:19

Maxim

adc için tam interrupt kullanmaya çalışıyorum
yani istiyorumki arka planda adc ölçümü yapsın, adin komutu olmadan.

bir hata var ama çözmedim
pic, intterupt bölümüne uğramıyor.
daha önce hard adc interrupt deneyen varmı?


Device 12F675
Declare Xtal=4
Config CPD_OFF,CP_OFF,BODEN_ON,MCLRE_OFF,PWRTE_ON,WDT_OFF,INTRC_OSC_NOCLKOUT

TRISIO=%00000010
ADCON0=%10000101
ANSEL =%00110010
CMCON=7


    Symbol GO_DONE = ADCON0.1
    Dim AD_RESULT As ADRESL.Word

    Dim RAW_adc As Word
    Dim HAKAN As Word

    Symbol GIE = INTCON.7
    Symbol PEIE = INTCON.6
    Symbol ADIE  = PIE1.6
    Symbol ADIF  = PIR1.6
   
    While GIE=1 : GIE=0 : Wend
    On_Interrupt GoTo INT
    PEIE=1
    ADIE=1
    GIE=1
     
   
    LOOP:
    Inc HAKAN
    DelayMS 50
    GoTo LOOP
   
   
    INT:
    Context Save
   
    If ADIF=1 Then
    GO_DONE = 1
    While GO_DONE =1 :Wend
    RAW_adc = AD_RESULT
    EndIf
   
    ADIF = 0
    Context Restore


ete

ADCIN komutunu kullanmadan ADC okumanın iki yolu mevcut. Bunların ikisinde de kesme özelliği kullanılıyor. Ancak birinde Global kesmeleri aktif ediyorsunuz diğerinde etmiyorsunuz. Genelde Global kesmeleri açmadan kesme kullanılır. Çünki kesmeyi aktif ettiğiniz andan itibaren yaklaşık 20us sonra kesme oluşacaktır. Bunun için genel kesme kullanmaya gerek yoktur ki çoğu kişide bunu böyle yapar. Onun yerine yalnızca Kesme bayrağına bakmak yeterlidir.
İŞlem sırası Şöyle;
1. Önce ADCON0 registerini kullanarak Hem REF girişlerini  hemde kanal seçimini ayarlamak gerekiyor.
Diyelimki AN0 dan ADC okuması yapacağız.
ADCON0=%10000000 vererek ,
Okunan değeri sağa yaslı alacağız. (Bit7)
Voltaj Ref pini olarak VDD yi kullanacağız (Bit6)
Canal-0 (AN0) okuyacağız (Bit3-2)
2. Daha sonra ANSEL regisyterine ANSEL=%00010001 değerini vererek,
CLK olarak Fosc/8 , seçmiş olduk (Bit6-4)
Analog kanal olarak AN0 seçmiş olduk (3-0)
3.Şimdi ADC okumasını aktive etmek için ADON bitini set ediyoruz. ADCON0.0=1 (veya direk ADON=1)
4. Çevirim başladı kondansatörün önce şarj olması gerek. Bunun için Acquistation zamanı kadar beklemek gerekiyor. Bu data sheet de 19,72us olarak verilmiş biz 20us bekliyoruz. Delayus 20
5. Şimdi Asıl okuma çevrimini başlatmak gerekiyor. Bunuda Go/DONE bitini set ederek yapıyoruz. ADCON0.1=1 veya GO/DONE=1
Bu aşamada kesmeleri aktive etmiş isek çevrim tamamlandığında ADIF biti 1 olarak kesme oluşur. 
Burada iki sistemden bahsetmiştik. İki sistem bu noktada bir birinden ayrılıyor işte.
GIE=0 ve PEIE=0 ise yani Global kesmeleri aktive etmemiş isem yapacağım şey yalnızca,
GODONE bitinin LOW olmasını beklemek yada ADIF bitinin set olmasını beklemek olacaktır.
WHILE ADIF=0:WEND şeklinde bir komut dizisi kullanıp ardından AdresH ve AdresL değerlerini okumak sonuca ulaşmak açısından yeterli olacaktır.
Şayet  GIE=1 ve PEIE=1 ise o zaman kesme oluşmasını bekleyip kesme içinde AdresL ve AdresH değerlerini almanız gerekecektir.

Hepsi bu kadar.
Ete


Maxim

ete usta, bu şekilde kararlı bir şekilde çalışıyor
delayus 10 beklemeye isis hata vermiyor
hiç beklemez isem "adc wait time expired ......." diye bir hata veriyor bilirsiniz.
teşekkürker istediğim oldu.

not:
aslında interrupt bölümünde delay komutu kullanmak hoş karşılanmıyor
acaba başka bir çözüm olabilirmi sizin aklınıza gelen?



Device 12F675
Declare Xtal=4
Config CPD_OFF,CP_OFF,BODEN_ON,MCLRE_OFF,PWRTE_ON,WDT_OFF,INTRC_OSC_NOCLKOUT

TRISIO=%00000010
ANSEL =%00010010
ADCON0=%10000111
CMCON=7

    Symbol GO_DONE = ADCON0.1
    Dim AD_RESULT As ADRESL.Word

    Dim RAW_adc As Word
    Dim HAKAN As Word

    Symbol GIE = INTCON.7
    Symbol PEIE = INTCON.6
    Symbol ADIE  = PIE1.6
    Symbol ADIF  = PIR1.6
   
    While GIE=1 : GIE=0 : Wend
    On_Interrupt GoTo INT
    PEIE=1
    ADIE=1
    GIE=1
     
   
    LOOP:
    Inc HAKAN
    DelayMS 50
    GoTo LOOP
   
   
    INT:
    Context Save

    While GO_DONE =1 :Wend
    DelayUS 10
    RAW_adc = AD_RESULT

    ADIF = 0
    GO_DONE=1
    Context Restore


ete

İnterrupt bölümünde bana göre kısa gecikmelerin mahsuru yoktur. Uzun gecikmeler sorun olabilir. Özellikle zamanlayıcı tipi kesme işlemlerinde bu mahsur görülür. Ama ADC kesmesi ve benzeri zamana etkisi olmayan işlerde bence mahsur yoktur. Sizinki ihmal edilecek kadar kısa zaten.
Kesmede mahsurlu olan şey başka bir alt programa Gosub ile gitmektir.

Ete

Maxim

hocam sorun var
yukarıdaki isis te çalışan program gerçek devrede çalışmıyor
şu an onunla uğraşıyorum

ete

Sen çalışıyor dedğin için programa bakmamıştım ama bakınca gördümki isiste nasıl çalışıyor hayret dedim kendi kendime.
Sıralı bir çalışma algortiması vermiştim. Programın buna uymuyor.
Üstelik kesme aktif etmişsin ama kesme bayrağını kesme içinde test ediyorsun. Buda yanlış.

Doğru program aşağıdaki şekilde olmalı bence;
Device 12F675
Declare Xtal=4
Config CPD_OFF,CP_OFF,BODEN_ON,MCLRE_OFF,PWRTE_ON,WDT_OFF,INTRC_OSC_NOCLKOUT

TRISIO=%00000010
ANSEL =%00010010
ADCON0=%10000100
CMCON=7

    Symbol GO_DONE = ADCON0.1
    SYMBOL ADON    = ADCON0,0
    Dim AD_RESULT As Word


    Dim RAW_adc As Word
    Dim HAKAN As Word

    Symbol GIE = INTCON.7
    Symbol PEIE = INTCON.6
    Symbol ADIE  = PIE1.6
    Symbol ADIF  = PIR1.6
   
    While GIE=1 : GIE=0 : Wend
    On_Interrupt GoTo INT
    PEIE=1
    ADIE=1
    GIE=1
     
   
    LOOP:
    adon=1
    DELAYUS 20
    GO_DONE=1
    'bu noktadan sonra adc ölçümü başlar ve ADIF=1 oluncya kadar devam eder.
    WHILE ADIF=0:wend
   
    Inc HAKAN
    DelayMS 50
    GoTo LOOP
     
    INT:
    Context Save

    AD_RESULT.BYTE0=ADRESL
    AD_RESULT.BYTE1=ADRESH

    ADIF = 0
    Context Restore

Aynı programı kesme kullanmadan da çalıştırabilirsin. Şöyle;
Device 12F675
Declare Xtal=4
Config CPD_OFF,CP_OFF,BODEN_ON,MCLRE_OFF,PWRTE_ON,WDT_OFF,INTRC_OSC_NOCLKOUT

TRISIO=%00000010
ANSEL =%00010010
ADCON0=%10000100
CMCON=7

    Symbol GO_DONE = ADCON0.1
    SYMBOL ADON    = ADCON0,0
    Dim AD_RESULT As Word


    Dim RAW_adc As Word
    Dim HAKAN As Word

'    Symbol GIE = INTCON.7
'    Symbol PEIE = INTCON.6
    Symbol ADIE  = PIE1.6
    Symbol ADIF  = PIR1.6
   
   
    LOOP:
    adon=1
    DELAYUS 20
    GO_DONE=1
    'bu noktadan sonra adc ölçümü başlar ve ADIF=1 oluncya kadar devam eder.
    WHILE ADIF=0:wend
    ADIF=0 'program buraya geçerse ADIF=1 olur hemen ardından onu sıfırlarız.
    AD_RESULT.BYTE0=ADRESL
    AD_RESULT.BYTE1=ADRESH 
    ADON=0 
   
    Delayms 50
    GOTP LOOP


Ete


Maxim

ete hocam
normal döngü içerisinden adc kanal komutu kullanırsam interruptın bir önemi kalmıyorki
zaten o zaman adin komutunu kullanırım

benim sıkıntı şu
döngü içerisinde 3 saniye + 3 adet 1.2 saniye + 0.4 + 0.4 saniyelik beklemeler vardı.
amacım, bu beklemeler sırasında adc girişi değişirse program en başa gidip tekrar sıfırdan başlasın.
adc girişine pot bağlı, yani pot ile oynarsam program baştan başlasın.

normalde adin komutu kullanırsam böyle birşey mümkün değil
program bütün bu beklemeleri yapıp tekrar adin komutuna gelene kadar sürmek zorundaydı.

bende interrupt kullanmaya karar verdim
bekleme komutlarını for-next döngüsü şekline çevirdim
yani delayms 3000 yerine
for say=0 to 3000
delayms 1
if rawadc<>rawadctemp goto basla
next
diyerek bekleme-sayma sırasında adc kesmesi oluşursa en başa gitmesini sağladım.

program dediğim gibi proteusta güzel güzel çalışıyor
ama gerçek devrede interrupt oluşmuyor bende buna şaşırdım.
acaba 12F675 konusunda atladığım bir detaymı var.

ete

Proteus da çalışıyor dediğin programda kesme nasıl oluşacak anlamış değilim. Zira bir ADC işlemi başlatmıyorsun. Başlatmayınca kesmede olmaz gerçek devren bu mantığa uyuyor. Senin amacını anlıyorum ADC de bir değişiklik olursa başa gitsin diyorsun. Kısaca ben döngü içinde bekleyeyim bir adc farklılığı olursa başa gideyim diyorsun. Bunu anlamak için bile sürekli ADC nin okunması gerekemez mi?. Zira ancak ADC yi okursan farkı anlayabilirsin. Okumadığın şeyin karşılaştırması olmaz.
Simulasyon nasıl ve neden çalışıyor onu da anlamış değilim. Ama işin doğrusu ADC çevrimini başlat değeri oku eskisi ile farklılık var ise ne yapacaksan yap şeklindedir. Başka türlü olmaz.
Senin sisteminde ADC kanalı zaten sabit programın başında bir kereliğine seçiyorsun. Yapman gerek tek şey;

    ADON=1        '....ADC modülünü aktif ediyorsun
    DELAYUS 20   '...dahili kondansatörün şarj olmasını bekliyorsun
    GO_DONE=1  '...ADC çevrimini başlatıyorsun

komutlarını verip beklemek böylece adc değerini kesme içinde okuyup geri geleceksin ve orada ESKI=YENI ise aynı şeyleri yeniden yap diyebilirsin.
Başka bir şeyda aklıma gelmiyor maalesef.

Ete

F®T

#8
50 uS Tmr1 kesmesi kullanıyorum.Kesme dışına çıktığım anda 50 uS içinde Adc okumam lazım.
Aşağıda kesme dışında okuma ile ilgili verilen örneğe göre en kısa sürede okumaya çalışıyorum.
Fakat proteuse simülasyonunda  While ADIF=0:Wend bu noktada program takılıp kalıyor.ADIF bir türlü 1 pozisyonuna geçmiyor.

 ADCON0=%00000100 '1 NOLU ADC DEN OKUMA YAPAR
ADCON1=0
ADCON2=%10111111
ADON=1
DelayUS 20
GO_DONE=1
While ADIF=0:Wend
AKIMHOLD.Byte0=ADRESL
AKIMHOLD.Byte1=ADRESH 
ADIF=0
ADON=0
"Hakk" şerleri hayr eyler Zannetme ki gayr eyler Ârif anı seyreyler Mevlâ görelim neyler Neylerse güzel eyler.

Hattuşa


ADCON0=%00000100


adcon0 in 0. biti adc okumasını aktif ettiği iiçin adcon0.0 =1 olmalı bence sorun bundan kaynaklı

ete

BU hangi işlemci? 12f675 değil herhalde.!!
Normalda ADC nin bittiğini Go_done biti ile kontrol ediyoruz aslında.
Go_Done bitini 1 yapıp ardından
while Go_done=1:wend şeklinde komut yapıp aynı bitin işlemci tarafından sıfırlanmasını beklemek gerekiyor. Bu anda hem bu bit sıfırlanır hemde  ADIF biti set edilir.  Sende bu bitin set edilmemesinin sebebi döngüye başlarken aynı biti sıfırlamamış olmandan kaynaklanıyor olabilir.
While döngüsünden önce ADIF=0 deyip döngüye girmen gerekir. Çünki önceki işlemlerden birinde aynı bit set edilmiş olabilir ve yazılımla sıfırlanmadıkça o bit set edilmiş olarak kalır.
Gerçi işlem sonunda sen sıfırlamışsın biti ama doğrusu döngüye girmeden önce sıfırlanmasıdır.
Ete

F®T

#11
Selami hocam haklısın 1 olması lazım.Ama sorunum o değil.ADON=1 bu zaten dediğin bit.
Ete hocam işlemci tahmin ettiğiniz gibi 12f675 değil 18f46k22.
sıkıntım şu 50us kesmede işim bitince adc okumak zorunluluğum var.Ama okuyamıyorum.Yada proteuse beni yanıltıyor.Bayrak kurmayınca takılıp kalıyor.Kart ile deneme şansım olmadı Kart ile az bir işim kaldı bitince deneme yapıcam.Ama takılma olunca ve adc okuma süresi 120 us gibi çıkınca daha kısa sürede nasıl bir yöntem olur diye araştırıyorum.

Program satırları aşağıdaki gibi

'
ADCON0=%00000100 '1 NOLU ADC DEN OKUMA YAPAR
ADCON1=0
ADCON2=%10111000
ADON=1
DelayUS 10
GO_DONE=1
' 'bu noktadan sonra adc ölçümü başlar ve ADIF=1 oluncya kadar devam eder.
While ADIF=0:Wend
  ADIF=0 'program buraya geçerse ADIF=1 olur hemen ardından onu sıfırlarız.
AKIMPEAK.Byte0=ADRESL
AKIMPEAK.Byte1=ADRESH 
ADON=0

"Hakk" şerleri hayr eyler Zannetme ki gayr eyler Ârif anı seyreyler Mevlâ görelim neyler Neylerse güzel eyler.

ete

Aşağıdaki kodu bir denermisin.
Senin yukarıda yazdıklarını çıkartıp yerine bunları yazman yeterli olacak.
 ADCON2=%10101111
ADCON1=0
TRISA.1=1
ANSELA.1=1
ADCON0=%00000001
ADCON0.1=1
WHILE ADCON0.1=1:wend
AKIMPEAK.Byte0=ADRESL
AKIMPEAK.Byte1=ADRESH


Data sheet şöyle söylemiş,
Analog kanal seçimi clk ve ref voltaj seçimlerini yaptıktan sonra ve özellikle Go_Done bitini set etmeden önce acquistition (kondansatör şarj süresi) kadar beklemen gerek demiş. Bu işi aslında ADCON2 registeri ayarlıyor. Bu registerde 5-3 bitleri bunu ayarlamakta sen burada 20 Tad seçmişsin bu yüksek bir değer. Örnek ASM kodunda bu süre 4 TAD olarak seçilmiş bende öyle yaptım. Kod içinde ayrıca bir bekleme vermeye gerek yok diye düşünüyorum. Kendiside vermemiş zaten. Böylece işlem epeyce kısalacaktır diye düşünüyorum. Dene de görelim.

Ete



F®T

Tamamdır hocam deniyorum.Teşekkürler.
"Hakk" şerleri hayr eyler Zannetme ki gayr eyler Ârif anı seyreyler Mevlâ görelim neyler Neylerse güzel eyler.

F®T

@Ete hocam simülasyonda 9.375 uS sürede adc yi okuyorum.Şimdilik bu hız iyi.Sanırım simülasyonla alakalı sıkıntı oluyor.Adım adım çalışmada kesmeye giriyor çıkıyor adc alt programına girip çıkıyor bir sorun yok.Fakat normal çalışmada adc alt programına girmiyor.Bazen girip çıkıyor.Simülasyon kaçırıyor bazı durumları.Sanırım gerçekte sorun oluşmuyacak diye düşünüyorum.Teşekkürler.
"Hakk" şerleri hayr eyler Zannetme ki gayr eyler Ârif anı seyreyler Mevlâ görelim neyler Neylerse güzel eyler.

Powered by EzPortal