Sıfır geçiş etkinleştirilmiş röle


13

Sıfır geçiş gücüne neden olan bir anahtarın (katı hal rölesine veya bir triyaka dayalı olarak) nasıl programlanacağı hakkında?

Konuya aşina olmayanlar için: Güç hattının sinüs dalgası sıfıra ulaştığında 230V gücü açın - sonuç, akımdaki hızlı artıştan kaynaklanan elektromanyetik bozuklukları en aza indirir.

Özellikle, mümkün olduğunca yazılıma geçmeyi tercih ederim. Seviyeleri ve akımları kontrol altında tutmak için küçük bir transformatör, bir diyot ve bir çift dirençten oluşan algılama devresi, AC giriş gücü pozitif yarıda, negatif olarak "0", bir giriş GPIO pinine bağlı olduğunda "1" sağlar. Çıktı, çıkış GPIO pinlerine bağlı olan birkaç katı hal rölesi ve onları çalışır durumda tutmak için temel gerekliliklerden oluşur (pull-up vb.).

Sorun zamanlamadır: 50Hz AC ile saniyede 100 sıfır geçiş alırız, bir yarım döngü 10 ms'dir. Söz konusu EMI'yi düşük tutmak için sıfır geçişten makul mesafeye ulaşmak için, çıkışı sıfır geçiş durumunda% 10'dan fazla (veya daha önce) etkinleştirmemeliyiz, yani + -1 ms tolerans anlamına gelir. Bu, 1ms reaksiyon süresi anlamına gelmez - bir sonraki sıfır geçişinin ilkinden 10ms sonra veya dördüncü - 40ms'den sonra olmasını bekleyebiliriz. Ayrıntı ile ilgilidir - reaksiyon için 20 ms'ye izin verirsek, 18 ila 22 değil, 19 ila 21 ms arasında olmalıdır.

Giriş böyle bir zamanlayıcı - tetikleyici çıkış GPIO'yu 1ms içinde ya da o zamandan beri bir kenar algıladığında ya da o zamandan bu yana 10ms'lik sabit bir katmanda nasıl uygulayabilirim - tercihen bazı negatif sapmalara izin vererek (örneğin, transformatör ve röle 1.6ms gecikme sağlar; Bu yüzden giriş darbesinden bu yana tetikleme 8.4+ (n * 10) ms sönmesini istiyorum, bu şekilde sapma devrenin getirdiği gecikmeyi önler.) - Tabii ki "kullanıcı talebi üzerine", kullanıcı yazar "1 "a / sys / class / ... dosyasına ve en yakın (kabaca) fırsata çıktı" devam eder ". Kullanıcı "0" yazar ve sıfır geçiş geldiğinde belirli röle devre dışı kalır.

Bunun bir çekirdek modülü yazmayı veya hacklemeyi gerektireceğine inanıyorum. Beni çekirdekteki Raspberry Pi'nin GPIO pinlerini neyin ele aldığını ve bu tür bir işlevsellik elde etmek için ne tür zamanlayıcılar ekleyebilirim (zaten bir tane yoksa).


bahsettiğiniz oldukça ilginç bir proje! Sadece kaba bir tahminde bulunmak için: İlk önce sinüs dalgasını 50Hz orijinal sinyalden bazı schmitt tetikleyici mantık yoluyla GPIO'ya bağlayacağım. Oradan sinyalin yükselen veya düşen kenarında bir kesinti oluşturun. 50Hz AC'de kilitli durumdasınız ve bir sonraki sıfır geçişinin ne zaman gerçekleşeceğini 'tahmin edebiliyorsunuz'. Kesinlikle bu bazı çekirdek sürücü programlamayı içerir. Google arkadaşın :-)
sparkie

Bir göz atın Inmojo AC sönük modülü . Bunu açık kaynak belgelerini kullanarak bir proje için başarıyla klonladım. Kodunuzun mantığında size yardımcı olabilecek bazı Arduino örnek kodları da vardır.
Butters

@Butters: Arduino'yu programlama ve Linux Çekirdek modülü programlama arasındaki boşluğun yazılım tarafını benim için işe yaramaz hale getireceğinden korkuyorum, ancak donanım şemaları ihtiyacım olanın% 100'ünü kaplıyor - teşekkürler, işimden biraz tasarruf ettiniz - iki proje arasındaki fark sadece yazılımdadır (dimmer triyak'ı döngüsel olarak değiştirmelidir, anahtar ise her anahtar için bir kez açar / kapatır.)
SF.

... donanım tarafının% 100'ü elbette.
SF.

Yanıtlar:


6

Çekirdeği hacklemenize gerek yok. İşlemi zamanlayıcı kuyruğunun dışına taşımanız yeterlidir.

    #include<sched.h>

    struct sched_param param;               
    param.sched_priority = sched_get_priority_max(SCHED_FIFO);
    if( sched_setscheduler( 0, SCHED_FIFO, &param ) == -1 )
    {
            perror("sched_setscheduler");
            return -1;
    }

Şu andan itibaren sürecimiz cat /proc/sys/kernel/sched_rt_runtime_usher cat /proc/sys/kernel/sched_rt_period_usmilisaniye zaman diliminden milisaniye, bu süre zarfında önceden boşaltma riski olmadan kesintisiz yürütme alır (pratikte, BerryBoot'ta varsayılan olarak: her saniyenin 0,95'i.) Daha fazlasına ihtiyacınız varsa, karışıklık ama buradaki amacım için daha fazlasına ihtiyacım yok.

clock_gettime()Gecikmelerimi azaltmak için milisaniye (ihtiyaç duyduğum hassasiyet hakkında) bir zamanlayıcı işlevi kullanıyorum .

Arama timer(1)sıfırlanır, timer(0)sıfırlamadan bu yana geçen süre döndürülür.

    #include<time.h>
    typedef unsigned long long ulong64;

    ulong64 timer(unsigned char reset)
    {
            struct timespec t;
            static struct timespec lt={0,0};
            clock_gettime(CLOCK_REALTIME, &t);
            if(reset)
            {
                    lt.tv_sec = t.tv_sec;
                    lt.tv_nsec = t.tv_nsec;
            }

            int r = ((ulong64)(t.tv_sec - lt.tv_sec))*1000 + (t.tv_nsec - lt.tv_nsec)/1000000;

            return r;
    }

Bunun rtderlenmesi için kütüphaneye bağlanmanız gerekir - -lrtgcc komutunuza ekleyin .

Şimdi, ana döngü için. "Kullanıcı isteği" için bir anahtar girişi kullanıyorum, ancak ağ, zamanlayıcı veya her şeyi kullanabilirsiniz. Tek ihtiyacınız olan boolean değerini elde etmektir in.

    while(1)
    {
            //when idle, return a lot of CPU time back to the system. 
            //A call every 100ms is perfectly sufficient for responsive reaction.
            usleep(100000); 

            in  = bcm2835_gpio_lev(SWITCH_PIN);
            out = bcm2835_gpio_lev(TRIAC_PIN);

            if(in==out) continue;   //nothing to do; wait user input, return control to system.

            //The output needs to be changed.
            //First, let's wait for zero-crossing event.
            timer(TIMER_RESET);
            zx = bcm2835_gpio_lev(ZEROXING_PIN);

            //We don't want to freeze the system if the zero-xing input is broken.
            //If we don't get the event within reasonable time, 
            // (like three half-sines of the power; ZEROXING_TIMEOUT = 70)
            // we're going to bail.
            while(timer(TIMER_READ) < ZEROXING_TIMEOUT)
            {
                    if(zx != bcm2835_gpio_lev(ZEROXING_PIN))
                    {
                            //Event detected.                  
                            timer(TIMER_RESET);
                            break;
                    }
            }
            if(timer(TIMER_READ) >= ZEROXING_TIMEOUT) continue;     //Zero-crossing detection is broken, try again soon.

            //Now we are mere milliseconds after zero-crossing event arrived
            // (but it could have taken some time to arrive) so let's wait for the next one, making adjustments for the system delay.
            // This is to be worked out using an oscilloscope and trial and error.
            // In my case BIASED_DELAY = 19.

            while(timer(TIMER_READ)<BIASED_DELAY) ;

            //We can reasonably expect if we perform this right now:
            bcm2835_gpio_set_pud(TRIAC_PIN, in);
            //the signal will reach the output right on time.

            // The 100ms delay on return to start of the loop should be enough 
            // for the signals to stabilize, so no need for extra debouncing.
    }

Bu, ana şebeke için pi kontrollü bir kısma anahtarının uygulanması için işe yarar mı? Sadece ayarlamak yerine) I) 1 zorunda yerine her 100ms çok daha küçük bir şey () ve 2'ye çözünürlüğünü değiştirmek hayal TRIAC_PINetmek in, ben ayarlamak zorunda kalacak TRIAC_PIN, 1 ile orantılı olarak zaman belirli bir miktarda (bekle istenen sönük düzeyi) ve ardından TRIAC_PIN0'a geri ayarlayın. Bu işe yarar mı?
rinogo

Ben ana döngüde varsayalım, ben de çizgiyi değiştirmek istediğimiz if(in==out) continue;için if(out==0) continue;sağ? Aslında, pi için programlamada tamamen yeniyim, bu yüzden belki de gerekli değil - sanırım bunların hepsi eşzamanlı olarak gerçekleşiyor (yani iç içe döngüler hala yürütülürken çağrılan ana döngü hakkında endişelenmek zorunda değiliz)
rinogo

(Bunların tümü, yukarıda bahsedilen Inmojo dimmer modülünü kullanıyor, tabii ki: inmojo.com/store/inmojo-market/item/… )
rinogo

2
Bununla ilgili bir sorun var. Kararlı sistem etkinliği için sisteme periyodik olarak kontrol vermeniz GEREKİR ve gerçekten 20ms kadar kısa bir sürede geri yükleyeceğinizden şüpheliyim. Böylece, bu verimler atım atımlarına neden olur ve sonuç olarak ampul yanıp söner. Bununla ilgili bir soru sordum ama cevap alamadım. Sistemin önceden kullanılmasını tamamen devre dışı bırakmak için sched_rt_runtime_us ve sched_rt_period_us öğelerini -1 olarak ayarlayabilirsiniz;
SF.

2
Şudur: SCHED_FIFO ile bir zaman dilimini başladıktan sonra, bu gönüllü verim dek kesintisiz sürer (veya sched_rt_runtime_us geçen edilir) ancak sistem size mutlaka zaman o zaman dilim olsun. Benim durumumda normal çalışmada fark ettim (çağrılara zaman dilimleri vererek) çağrılar arasındaki süre maksimum CPU yükü ile 0.1 saniyeye kadar uzayabilir. Belki o dönem ince ayar yapıp daha kısa sürebilir ama nasıl yapacağımı bilmiyorum.
SF.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.