Şimdi Ara

Beyler şu kodu yazın paranızı alın (pic programlama)

Daha Fazla
Bu Konudaki Kullanıcılar: Daha Az
2 Misafir - 2 Masaüstü
5 sn
20
Cevap
0
Favori
1.568
Tıklama
Daha Fazla
İstatistik
  • Konu İstatistikleri Yükleniyor
0 oy
Öne Çıkar
Sayfa: 1
Giriş
Mesaj
  • Arkadaşlar Merhaba,

    Aralarında zaman farkı olan iki dalga arasındaki bu zaman farkını 16f877 mcu'su ile ölçüp ekrana yazabilir misiniz?

    Elimde iki adet +-5V, 50Hz sinüs dalgası var. Bu dalgaların negatifini opamplarla doğrulttum. Sonuçta elimde 0-5V, 100 Hz ac dalgalar oldu. Bunların arasında faz farkı var. Sıfır geçiş dedektörü ile lojik hale getirdiğimiz sinyali mcu ya verip timer zamanlayıcısı ile faz farkını ekrana yazmayı çok istedim. Yapamadım.

    Amacım Reaktif Güç Kontrol Rölesi yapmak. Ancak programlama ve mcu konularında çok yeniyim. Ccs c ve 16f877 üzerinde çalıştım. Mplab'a girmeye çalıştım ancak gerçekten çok derin bir dünya var o tarafta.

    Mümkünse Ccs c de, 16f877 üzerinde, kesme fonksiyonlarına hiç girmeden, sıfır geçişinden devresinden faydalanıp timer'ı başlatıp durdurarak zaman farkını sade bir şekilde ölçebilirseniz çok iyi olur.

    Yapabilecek olan pm den ulaşabilir.







  • Merhaba istediğiniz şartları karşılayan şu şekilde bir mantık kurgulanabilir. Farklı yaklaşımlar ve çözüm yöntemleride olabilir. Ama kesme kullanmadan aklıma gelen en sade çözüm aşağıdaki gibi. Gerekli açıklamaları kodun içerisinde yapmaya çalıştım.

    Not 1: Sadece not defterinde yazıldı. Syntax hataları veya farklı hatalarda olabilir. Ama size yol göstereceğini tahmin ediyorum.


    Not 2: Kodlar işinize yararsa benim adıma bir hayır kurumuna bağışda bulunabilirsiniz.



    #define SIN_A PIN_B0
    #define SIN_B PIN_B1


    float faz_olc()
    {
    int16 tm = 0;
    int8 in_state;
    float tempa,tempb;

    // faz farkının olmadığı durum kontrolü
    in_state = input_b();
    in_state = in_state && 0b00000011; //0 ve 1. bitler maskeleniyor.

    if (in_state == 3) return(0); // faz farkı yok

    while (!input(SIN_A)) { delay_cycles(1);} // yükselen kenar bekle SIN A
    tm = 0; // ölçüm sayacın sıfırla

    while (!input(SIN_B)) // yükselen kenar bekle SIN B
    {
    tm++;
    delay_us(100); // faz farkı yaklaşık 100us lik adımlar ile ölçülüyor.
    }

    // skalalandırma isterseniz
    tempa = (float)tm;

    // Tam dalga doğrultulmuş işaret 100Hz için Peryot 10ms = 10000us
    // ölçüm Step 100us olduğu için aşağıdaki formülde
    // bölen 10000/100 = 100;
    tempb = (tempa * 180 ) / 100;

    return (tempb); // derece olarak faz farkı

    }


    void main()
    {
    float olc;

    while(TRUE)
    {
    olc = faz_olc();

    // printf("Faz farki : %f\r",olc);
    // LCD ye yazdırma rutinleri
    //....
    // varsa diğer işlemler
    //....
    delay_ms(1000);

    }

    }



    < Bu mesaj bu kişi tarafından değiştirildi rafet32 -- 10 Haziran 2020; 9:34:13 >




  • rafet32 kullanıcısına yanıt
    Hocam çok teşekkür ediyorum cevabınız için. Zamanlayıcı olarak timer kullanıp başlatıp/durdurarak yapmak amacındaydım.

    Yazdığınız kod hata verince aynı mantıkla şöyle yazdım:

    Beyler şu kodu yazın paranızı alın (pic programlama)Beyler şu kodu yazın paranızı alın (pic programlama)

    Sinyalin periyodu 100Hz. 10ms. Mcu'nun a4/TOCKI pinine verdiğim sinyale 45 derece faz verdim. Yani a0 pinine verdiğim sinyale göre daha erken sıfırdan geçecek ve kesme fonksiyonuna dallanacak. Bu fonksiyonda 45 derecenin zaman farkı 2.5ms olarak olarak ölçülecek. Yani 2500us. 10us de bir sayacı arttırdığım için sayaç değeri 250 olmalı. Ancak 119 gösteriyor.Kesme fonksiyonundaki algoritmada sıkıntı var ama çözemedim.

    Beyler şu kodu yazın paranızı alın (pic programlama)




  • rafet32 kullanıcısına yanıt
    Hocam TOCKI timer0 kesmesini kullanarak doğru bir hesaplama yapamadım. Timer0 kesmesindeki kodları RB kesme fonksiyonuna yazdım ve RB kesmesini kullanarak doğru bir ölçüm yapabildim. 45 derece verdiğim faz açısını 43 derece görüyorum.

    Bu hesaplamayı timer zamanlayıcısını iki sıfır geçiş arasında başlatıp durdurarak hesaplayacak bir kod parçası yazabilir misiniz?
  • Yukarida kullandiginiz tmr0 kesme kullanimi hatali bir kullanim şekli.

    Genis bir zamanda uzerine kafa yoralim.

    Siz ilk mesajinizda kesme kullabmadan basit sekilde diye şartlari belirleyince buna göre bir şablon hazirladim.

    Şablon kodda ne gibi bir hata aldiniz?

    < Bu ileti mobil sürüm kullanılarak atıldı >
  • rafet32 kullanıcısına yanıt
    6 adet hata almıştım. ilki float faz_olc() olarak gösteriyordu biraz kurcaladım çözemedim ama problem değil sonuçta yazdığınız kod da zaman farkını hesaplama mantığı en basitiyle delay komutuyla sayacı arttırmak. Tabi bugüne kadar timer ve kesmeleri öğrenmeye çalışıp bunlarla yapmaya endekslendiğim için bu şekilde düşünmedim. Hocam kabul eder mi, tabi etmek zorunda. Çünkü anladığım kadarıyla tam olarak mcu'ların çalışma mantığını anlayıp hakim olmak ve istediğini yapabilmek için assembly den başlamak gerekiyor.

    Kesme kullanmadan sadece timer'ı (timer0 yada timer1) çalıştırıp-durdurarak sade bir kod istemiştim. 16f877 de araştırdığım kadarıyla timer0 durdurulamıyor, timer1'in T1CON registerin'de ise TMR1ON bit'i çalıştırılıp durdurulabileceğini gösteriyor.
    Hocamla konuştuğumda '16f877 ile de çalıştım ben ve timer çalıştırılıp durdurulabiliyor' dedi.

    Daha sonra bir iki gün önce timer1 için;

    setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
    set_timer1(0);
    delay_us(40); deyip ardından;
    setup_timer_1(T1_DISABLED); time=get_timer1(); ile timer1'i durdurup ekranda '40' ı görmüştüm. Hatta devamında;

    setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
    delay_us(40);
    setup_timer_1(T1_DISABLED); time=get_timer1(); deyip ekranda '80' görmüştüm yanlış hatırlamıyorsam. Yani başlatıp durdurabiliyordum. Timer0'ında içindeki değeri durduramadan anlık olarak alabildim. Gel gör ki bunlar beni ne kadar sevindirse de iki sıfır geçiş arasını doğru hesaplatamadım. Gerçi yanlış hatırlamıyorsam sinyalleri doğrultup sonra da offset verip (2.5v-5v arası) ve adc ye verip 2.5V ta takabül eden adc değeri 500 ise oku=read_adc() den oku değerini 'if' komutuyla 500 ise timer1'i çalıştır vs yapmıştım ama ortalık feci karışmıştı. Sıfır değerini adc den değilde şimdiki gibi pulse olarak dışarıdan alsam ki bunu da denemişimdir ama hatırlamıyorum.




  • quote:

    Orijinalden alıntı: rafet32

    Yukarida kullandiginiz tmr0 kesme kullanimi hatali bir kullanim şekli.

    Genis bir zamanda uzerine kafa yoralim.

    Siz ilk mesajinizda kesme kullabmadan basit sekilde diye şartlari belirleyince buna göre bir şablon hazirladim.

    Şablon kodda ne gibi bir hata aldiniz?
    Bu arada MCU'ya iki adet sinyali a0 ve a1 pininden verdiğimizde (lojik sinyal veriyorum, adc kapalı) birini algılayıp diğerini hiç okumuyor. Bunun için birini sıfır geçişte algılayıp kesmeye dallanması, kesme fonksiyonunda ise diğer sinyali okuyabildiği için kesme kullanmak zorunlu gibi görünüyor.
  • Fırsat bulmuşken konuya kısa bir katkı daha yapayım.

    Tasarım veya problem çözerken birden fazla çözüm yöntemi olabilir. Sizin önemli olan ölçümü doğru şekilde yapmakmı? Yoksa illa A0 ve Timer0 ı kullanmak zorundamısınız?

    İkinci şekilde bir talep varsa çok saçma bir durum!

    + Zaman veya peryot ölçümlerinde yazılan kodların çok iyi şekilde optimize edilmesi gerekir. Çünkü yazılan kodların cpuda işlenmeside bir zaman almaktadır. Hassas ve doğru sonuçlar için bu gecikmelerinde hesaba katılması gerekir.

    + Harici kesme ile ilgili donanımı iyi tanımanız gerekmektedir. 877 nin A0 ve A1 pinleri kesme için kullanılamaz!

    + Proteus dosyanızı ekleyin, fırsat bulunca denemeleri onun üzerinde yapmaya çalışırım.

    + ADC ile peryot ölçümü yapmak yanlış bir tercih. (ADC çevrim zamanı ve hesaplama, karar verme rutinleri nedeniyle hassas ve tekrarlanabilir sonuçlar alamazsınız)



    < Bu mesaj bu kişi tarafından değiştirildi rafet32 -- 11 Haziran 2020; 11:22:15 >




  • rafet32 kullanıcısına yanıt
    Şöyle diyeyim, bu benim yıllık ödevim olduğu için geçen dönemde hocadan adc, kesme ve zamanlayıcıları öğrenin diye tavsiyelerini duyduğum için, bir de hani ödevin adı Reaktif güç kontrol rölesi iken timer falan kullanmayıp delay kullanmak ödevin içini boşaltmış gibi bir algı oluştuğu için bende içim rahat etmiyor. Yoksa hocanın kesin timer ve kesme kullanacaksın diye bir söylemi yok.

    'Harici kesme ile ilgili donanımı iyi tanımanız gerekmektedir. 877 nin A0 ve A1 pinleri kesme için kullanılamaz!' Nasıl yani RB kesme fonksiyonu içinde bu pinleri kullanamam mı?

    Proteus dosyalarını burdan ekleyemedim, sadece resim kabul ediyor.
  • quote:

    Bu arada MCU'ya iki adet sinyali a0 ve a1 pininden verdiğimizde (lojik sinyal veriyorum, adc kapalı) birini algılayıp diğerini hiç okumuyor. Bunun için birini sıfır geçişte algılayıp kesmeye dallanması, kesme fonksiyonunda ise diğer sinyali okuyabildiği için kesme kullanmak zorunlu gibi görünüyor.


    Ben bu cümlenize binaen a0 ve a1 i kesme olarak kullanamazsınız demiştim. RB kesmenini kullandığınızı/ nasıl kullandığınızı siz yazmazsanız takdir edersinizki bizim bilmemiz mümkün değildir. Kullanmanızın bir mantığı varsa tabiki kullanabilirsiniz.

    Bir problem ile uğraşan arkadaşlarımız, genelde kendi yaptıklarını / denediklerini cevap veren arkadaşlarında bildiği izlenimine kapılıyorlar. Sonrasında ise konu genelde, soru/cevap şeklinde ilerliyor.

    Konuyu okuyacak diğer arkadaşlarımız için bir tavsiye; probleminizi, ne yaptığınızı/yapacağınızı, ne gibi hatalar aldığınızı detaylı şekilde yazarsanız daha isabetli cevaplar alırsınız, konuya cevap vermek için vakitlerini ayıranlan kişilerede saygı göstermiş olursunuz.

    Lütfen yukarıda yazdıklarımı size karşı bir sitem olarak almayın, sadece yapılacak iş veya sorun ne kadar net tarif edilirse daha kaliteli cevaplar / içerikler üretilebilir, gereksiz zaman israfıda önlenmiş olur düşüncesindeyim.

    Gelelim asıl meselemize:

    Şablon kod olarak sabah paylaştığım kodları gerçek uygulamada derledim ve denedim sorun görünmüyor. Siz ne gibi bir hata aldınız?

    Diğer alternatif bir öneri:

    Sizin projeniz için aklıma gelen daha kısa ve kararlı sonuç üretecek alternatif diğer bir öneriyi aşağıda paylaştım.
    Yapmanız gereken 16F877 yerine birebir pin uyumlu 18F452 kullanmak. (harici 3 adet kesmeye destek verdiği için)

    Gelelim işin mantığına:

    + 2 adet harici kesme farklı faz açısı girişlerinin yükselen kenarını yakalamak için kullanıldı (INT1 ve INT2) {Toplamda 452de 3 tane var biz ikisini kullandık. 877 de 1 tane var bu mantık için yeterli gelmiyor}

    + Timer1 1us lik adımlarla çalışacak şekilde ayarlandı. Max ölçülebilecek süre 65535us = 65ms
    (Bu ayarlar ile Faz farkı 5ms ise ekranda 5000 e yakın bir değer görürsünüz)

    + Sonuçlar Seri port ile ekrana basıldı. Siz LCD kullanabilirsiniz.

    + Girişdeki NOT kapısı ve kapasitörler aklınızı karıştırmasın, deneme yapmak için basit şekilde faz farkı oluşturmak için kullandığım bir teknik. Gerçek uygulamada siz kendi sıfır geçiş devrenizin çıkışını buraya bağlayacaksınız.

    Başarılar...

    Test Devresi:

    Beyler şu kodu yazın paranızı alın (pic programlama)

    Header:

    Beyler şu kodu yazın paranızı alın (pic programlama)

    Kodlar:

    Beyler şu kodu yazın paranızı alın (pic programlama)

    İlk resimdeki terminalde görünen 5005 değerinin karşılığı olan işaret ölçümü:

    Beyler şu kodu yazın paranızı alın (pic programlama)



    < Bu mesaj bu kişi tarafından değiştirildi rafet32 -- 11 Haziran 2020; 18:41:32 >




  • rafet32 kullanıcısına yanıt
    Haklısınız hocam.

    18f452 biraz uğraştırdı. 16f877'de 5V bağlamasakta çalışıyordu simülasyonda :).
    Bir de bu not kapısı olayını pek anlamadım;

    Kesme aldığımız iki porta da not kapısı bağlamadığımda 5ms'de 4910 civarı,
    Portlardan birine bağladığımda 5ms'de 4995-5000 arası,
    Her iki porta da bağladığımda 5ms'de 5080 civarı değer görüyorum.

    Ayrıca çok teşekkür ediyorum hocam bu uygulama için.

    Bir de mesela 16f877'de lcd bağlantısı, izlediğim videolardan dolayı elimde hazır olarak vardı. 18f452'de lcd bağlantısı nasıl olacak kısmında takıldım. Biraz temel bilgiler eksik bende hocam. Yani kullandığımız derleyicinin bir lcd kütüphanesi var ve orada bağlantıların nasıl yapılacağı yazıyor ve derleyici değişmediği sürece bu bağlantılar işlemciden işlemciye değişmiyor. Dolayısıyla 16f877'de lcd nasıl bağlıysa yine öyle bağladım.


    Beyler şu kodu yazın paranızı alın (pic programlama)




  • rafet32 kullanıcısına yanıt
    Bir de Reaktif güç kontrol rölesi faz farkını azaltmak için şebekeye röleler vasıtasıyla kapasiteler ekler. Gayet mantıklı kodlar yazsam da röleleri çalıştıramadım.
    Beyler şu kodu yazın paranızı alın (pic programlama)

    Basit bir if komutuyla x değişkeni şu eğerler arasındaysa output_high(pin_c0) gibi kodlar yazdım ama olmadı.
  • Yukarıdaki mesajdada belirtmiştim. "Not kapısına takılmayın diye". Yazdığım kodları test etmek için en basit faz farkı oluşturma devresi olarak kullandım. Sizin devrenizde o kısım haliyle farklı olacak. AC işaretleri bir şekilde alıp, sıfır geçişlerinde "Pals" olarak elde etmeniz / elde etmiş olmanız gerekir.

    LCD ile ile ilgili 877 de olan portlar ve pinler 452 dede var. Aynı şekilde bağladığınızda sorun olacağını tahmin etmiyorum.

    quote:

    Bir de Reaktif güç kontrol rölesi faz farkını azaltmak için şebekeye röleler vasıtasıyla kapasiteler ekler. Gayet mantıklı kodlar yazsam da röleleri çalıştıramadım.
    Basit bir if komutuyla x değişkeni şu eğerler arasındaysa output_high(pin_c0) gibi kodlar yazdım ama olmadı.


    Yukarıdaki uzun mesajda ifade etmeye çalıştığım gibi ne yazdığınızı görmeden / bilmeden birşey demek imkansız. Demekki sizin gayet mantıklı dediğiniz şey ile yazdığınız kodlar bir birine uymuyor




  • rafet32 kullanıcısına yanıt
    Not kapısını sizin uygulamanızdan bağımsız olarak sormak istedim. Bağlamadığımda 2400 civarı bir değer görüp, not kapısını eklediğimde görmem gereken 2500 değerini görünce şaşırdım anlayamadığım için sizin uygulamanızdan bağımsız olarak sormak istedim. Ancak çözdüm.

    Beyler şu kodu yazın paranızı alın (pic programlama)

    Kesme yükselen kenarda gerçekleştiği için, benim sıfır geçişin palsinin yükselen kenarı, not kapısının yükselen kenarına göre bir önceki palse daha yakın. Not kapısını kaldırdım ve sıfır geçiş palsinin düşen kenarında tetikledim ve 2500 gördüm (45 derecede);

    (enable_interrupts(INT_EXT2_H2L);


    Röle mevzusunu da çözdüm. Çalıştıramadığım röleyi ayrı bir simülasyonda basit olarak çalıştırmaya çalıştım ancak çalışmadı. Basitçe Relay yazıp çıkan ilk röleyi seçtim ve çalıştı.

    Beyler şu kodu yazın paranızı alın (pic programlama)

    Hocam şuan en çok aciliyeti olan diğer konu 555 entegresi. Bu konuda bilginiz varsa çok ikrama geçer. Hocamız sinüs dalgasını 555 entegresinden almamızı istedi.

    Beyler şu kodu yazın paranızı alın (pic programlama)

    5v'tan biraz fazlası var. Amacım 5v, 50Hz bir sinüs almak. Çıkış dalgasını 50Hz almak için aylar önce uğraşmıştım ancak yapamamıştım. Birkaç güne teslim etmem gerekiyor ödevi. Eğer bilgin varsa hocam çok ama çok makbule geçer.




  • Röle konusunda yaşadığınız sıkıntı: Proteusda seçtiğiniz elemanın "VSM modelinin" olduğundan emin olunuz. Bazı bileşenlerin simülasyon/animasyon modelleri olmuyor, sadece şematik ve baskı devre çiziminde kullanılıyorlar.

    555 ile ilgili tavsiyem; problem genliğin fazla olması ise, basitce 2 direç ile gerilim bölücü yapabilirsiniz.

    Başarılar....



    < Bu mesaj bu kişi tarafından değiştirildi rafet32 -- 13 Haziran 2020; 9:8:59 >
  • rafet32 kullanıcısına yanıt
    Anladım.

    Hocam çok ama çok teşekkür ediyorum. Çok faydalı oldunuz. Beşiktaşlıysanız sizin niyetinize kampanyaya bağışta bulunabilirim. Aksi halde camiye verebilirim.
  • Önemli değil. Bağış yapmak zorundada değilsiniz.
    Ama yapmak isterseniz size en az zahmet verecek yeri tercih edebilirsiniz.
    Tekrar başarılar...



    < Bu mesaj bu kişi tarafından değiştirildi rafet32 -- 13 Haziran 2020; 12:52:12 >
  • rafet32 kullanıcısına yanıt
    Tamamdır hocam, eyvallah
  • 
Sayfa: 1
- x
Bildirim
mesajınız kopyalandı (ctrl+v) yapıştırmak istediğiniz yere yapıştırabilirsiniz.