Hall Sensörlerin Kesmelerle Okunması.

Başlatan mr.selim, 01 Mayıs 2017, 21:14:50

mr.selim

İyi günler iyi çalışmalar herkese. Soru gayet basit ama ben işin içinden bir türlü çıkamadım. özetliyeyim hemen.

FDAM hall sensörlerinden aldığım bilgileri if yapılarıyla okuyup pwm veriyordum. Ancak fonskiyon çıkışında 1 ms lik bekleme süresi ekliyordum aksi halde motor ciddi anlamda güçsüzleşiyor nedenini hala çözemedim. Yani Hall bilgilerini devamlı okumak yerine OKU-PWM VER-1MS BEKLE-ÇIK-OKU-PWM VER-1MS BEKLE-ÇIK şeklinde yapıyordum.

Bu işi kesmelerle yapmak istedim. Beklemeye gerek duymicak sadece tetiklenme gelirse okuyacaktı. Bana gayet mantıklı geldi ama bildiğim bişeyler var. Ben kesmeleri, Düşen kenar, yükselen kenar ve (düşme-yükselme) değişim olarak biliyorum ancak sadece değişim kullanarak bi yere kadar gelebildim ondan sonrasına kafam basmadı. Sebebi Tablodan yola çıkarak söylemek istiyorum.

Şimdi birinci sorum: A, B, C sensörlerinin başlangıç değerlerini 0 0 0 olarak ekledim. Motor Hall konumları da 1 0 1 olsa, kesme ile okumada bakicak ki A değişmiş o zaman fonksiyona gideyim ancak C de değişmiş? Gidip gelicek ve aynı adım için tekrar mı fonksiyona gidecek? Bu bir sorun oluşturmaz mı ?

İkinci sorum ise 3 tane sensöü kesmelerle okumak yerine 2 tanesiyle de bu işlem yapılabilir mi ? Veya daha başka tavsiyeleriniz var mı. Çünkü ben konuya sadece değişim olursa tetiklensin diye bakmıştım.

Şimdiden teşekkür ederim.



matador

Ben senin yerinde olsam şöyle yapardım.

Her kesme için bir değişken tanımla. Bir de global değişkenin olsun. Her değişimde değişkenlerini güncelle ve global değişkenine toplam değer olarak yaz.

Örneğin; 1 0 1 = 5 bu değer için çıkışlarını oluştur. Her bir değer senin motorunun konumuna ait. Buna göre de çıkışlar sabit olacak.

Son olarak, ister her sayısal değerin için select - case kullan. İster if'ler ile yap. Bana kalırsa select - case daha uygun. Her bir değerin için çıkışların belli olduğundan döngü sabit kalacak.

ilyas KAYA

İşlemcinin RB değişiklik kesmesini kullanın. 3 encoder ı dan herhangi birinde değişiklik olduğunda kesme rutini çalışır. İşlemciye göre bu kesme değişiklik gösterir. Kimisi b0-b7 kimisi b4-b7 olarak değişiklik kesmesini destekler.

mr.selim

@matador Bu benim yaptığım mantıkla aynı değil mi ? Yani ben döngünün sürekli dönmesinden yana değilim. Mesela 1 0 1 oldu diyelim pwm verdi ve akış bitti ancak motor konumu geç kaldı ve tekrar 1 0 1 e geçti. Ben bunu istemiyorum. Program 1 0 1 e geçsin orda takılsın değişim olduğunda 1 0 0 vs ona geçsin orda kalsın istiyorum. Bu mantıkla diyorsanız biraz daha açmanızı isterim.

@cezeri  Hocam özel bir ismi var mı onun. Şuan da arduino kullanıyorum orada yok herhalde ya. Ben onu daha detaylı araştırıyım.

Tagli

dsPIC30F2010 için yazdığım kesme kodu aşağıda. Belki fikir verir. PWM dağıtımını maskeleme ile özelliği ile yapmıştım. Burada soft switching yapılıyor, yani sadece üst taraflara PWM veriliyor, altlar doğrudan aç kapa yapılıyor.
#include <xc.h>
#include "global.h"
#include "data.h"

// Local Variables
uint8_t hall; // will be initialized by soft interrupt during initialize()
uint8_t oldHall = 0xff; // A dummy initial value

/**
 * Change notification ISR
 * Updates the hall variable and switches to the next commutation
 */
void __interrupt(auto_psv) _CNInterrupt(void) {
    hall = PORTB & 0b111;
    if (hall == oldHall) errFlags.falseCnInt = 1;
    oldHall = hall;

    // Hall: 3 2 1
    // Out: H3 L3 H2 L2 H1 L1
    if (sFlags.dirDes == 0) { // Clockwise rotation
        switch (hall) {
            case 0b001:
                OVDCON = (0b000010 << 8) + 0b010000;
                LATE &= 0xffc0;
                LATE += 0b010000;
                break;
            case 0b101:
                OVDCON = (0b000010 << 8) + 0b000100;
                LATE &= 0xffc0;
                LATE += 0b000100;
                break;
            case 0b100:
                OVDCON = (0b100000 << 8) + 0b000100;
                LATE &= 0xffc0;
                LATE += 0b000100;
                break;
            case 0b110:
                OVDCON = (0b100000 << 8) + 0b000001;
                LATE &= 0xffc0;
                LATE += 0b000001;
                break;
            case 0b010:
                OVDCON = (0b001000 << 8) + 0b000001;
                LATE &= 0xffc0;
                LATE += 0b000001;
                break;
            case 0b011:
                OVDCON = (0b001000 << 8) + 0b010000;
                LATE &= 0xffc0;
                LATE += 0b010000;
                break;
            default:
                errFlags.invHall = 1;
        }
    } else { // Counter-Clockwise Rotation
        switch (hall) {
            case 0b001:
                OVDCON = (0b100000 << 8) + 0b000001;
                LATE &= 0xffc0;
                LATE += 0b000001;
                break;
            case 0b101:
                OVDCON = (0b001000 << 8) + 0b000001;
                LATE &= 0xffc0;
                LATE += 0b000001;
                break;
            case 0b100:
                OVDCON = (0b001000 << 8) + 0b010000;
                LATE &= 0xffc0;
                LATE += 0b010000;
                break;
            case 0b110:
                OVDCON = (0b000010 << 8) + 0b010000;
                LATE &= 0xffc0;
                LATE += 0b010000;
                break;
            case 0b010:
                OVDCON = (0b000010 << 8) + 0b000100;
                LATE &= 0xffc0;
                LATE += 0b000100;
                break;
            case 0b011:
                OVDCON = (0b100000 << 8) + 0b000100;
                LATE &= 0xffc0;
                LATE += 0b000100;
                break;
            default:
                errFlags.invHall = 1;
        }
    }
    _CNIF = 0;
}

Kod gözüktüğü kadar karmaşık değil. LATE &= 0xffc0; satırlarının olayla ilgisi yok mesela, aynı porta bağlı bir LED'in yanlışlıkla sönmesini engellemek için yazmıştım sadece.
Gökçe Tağlıoğlu

mr.selim

@Tagli flaglar dışında anladım sayılır hocam. dspic de interupt olayı daha kolay gibi. Şimdi sizin yaptığın tüm portu son 3 bit ile eşleyip, eski hall ile yeni hall de kıyaslama yapması mı ? Birde neden switch case, tüm yapı if ile olsa ( hall 1, 2, 3 için tabloya göre yazılsa) bir sorun teşkil edermi. Mesela gecikmelerin yaşanması gibi?

Tagli

Aslında burada önceki ile kıyaslama yok. Onu olası bir kesme kaçırma durumu olursa fark edeyim diye koydum. Normal çalışmada gerekmiyor. Switch yapısının çok sayıda seçenek olduğu durumlarda if bloklarından daha iyi performans verdiği söylenir. Ama sanırım modern derleyiciler için çok da fark etmiyor. dsPIC'lerde destekleyen bacakların istediklerinde değişim kesmesini açabiliyorsun. Aslında yeni PIC16 ve PIC18'lerde de var bu özellik. Ancak eski PIC16 ve PIC18'lerde maalesef 4 bacağı aynı anda açıp kapamak mümkün oluyor sadece.
Gökçe Tağlıoğlu

mr.selim

@Tagli Tamamdır hocam çoğunu anladım. Şimdi kaçırma durumunu fark ediyosunuz burası tamam peki şöyle olursa nasıl olacak. Hall bacakları 0 0 0 ile başladı ve ilk değerimiz 1 0 1 oldu. Burda hem 1. bacak hemde 3. bacak değişti. Yani kesmeden çıkıp tekrar kesmeye girmeyecek herhalde. Bunu da aynı şekilde mi çözdünüz ?

Tagli

Aslında normal çalışmada böyle bir durum ortaya çıkmamalı çünkü komşu fazlar arasında sadece 1 bit oynar. Benim kodumda doğrudan bununla ilgili bir önlem yok.

Normalde iki bit tam olarak aynı anda değişemez. Bir bit değiştiği anda zaten kesme tetiklenir. Kesme içinde hall değişkeni atandıktan sonra bir bir daha değişirse kesme kodu bunu umursamayacaktır. Ayrıca bu durum ikinci bir kesmeye de sebep olmaz ve motor çalışmasında olumsuzluklar ortaya çıkabilir. Ancak böyle bir durum oluşması işlemci hızının motor hızına yetişememesi anlamına geliyordur büyük ihtimalle.

Kodu yazalı epey oldu ve hall değişmediği halde kesme gelmesi durumuyla neden karşılaşmıştım da böyle bir uyarı mekanizması koyma ihtiyacı duymuştum hatırlamıyorum. Sorunu nasıl çözdüğümü de hatırlamıyorum ancak galiba sorun kendini hall sensör üzerinden hız okumaya çalışırken belli etmişti. Ama tamamen yanlış hatırlıyor da olabilirim.
Gökçe Tağlıoğlu

mr.selim

@Tagli Anlam karmaşası olmuş sanrıım. Başlangıçta biz bunların hepsini 0 0 0 olarak atadık. şimdi İlk gelen değer 1 0 1 olursa nolur diye merak ediyorum. iki bit burda aynı anda değişmiş oluyor o zaman ? 0 0 0 dı 1 0 1 oldu. ilk kesmesini yaptı sonra baktı ki diğeri de değişmiş. Birşeyi mi atlıyorum ben acaba anlayamadım.

Ayrıca son dediğinizi de yapmak istiyordum. Hall dan hız okumak sorun çıkaracak mıdır bana ?

Tagli

Ben programın başında bir yerde elle sahte bir kesme oluşturup komütasyon kodunu tetikliyorum. Yani başta 000 değil, hall neyse o geliyor. Ayrıca, senin başta değişkene ne atadığının bir önemi de yok. Dediğim gibi, değişim kesmesi kullanınca önceki değer gerekmiyor zaten. O andaki (değişimden sonraki) hall değeri ve hangi yöne dönmek istediğin bilgisi yeterli. Kesme fonksiyonu 3 girişten biri değişince tetikleniyor. Tetikleme olunca hall değerleri neymiş diye bakıp bu yeni değerlere göre çıkışları güncelleyip kesmeden çıkıyorum.

Hall'dan hız okumayla ilgili son durum neydi hatırlamıyorum. Uygulamamda zaten encoder olduğu için şu anda o özelliği kullanmıyorum. Ama hall ile hız tespiti kapalı çevrim hız kontrolü için pek uygun değil. Düşük çözünürlük nedeniyle hız güncellemesini 1 Hz gibi düşük bir frekansta alabilirsin ancak. Bu hızla da doğru düzgün bir kapalı çevrim hız kontrolü yapılmaz (ya da epey uğraştırır).
Gökçe Tağlıoğlu

mr.selim

@Tagli Hocam anladım tamam siz pin değişimi değil de port değişimine bakıyonuz değil mi ben olaya pin pin bakıyordum. Şimdi şöyle sorsam:



elle sahte bir kesme oluşturma kısmını çözemedim bir örnek verebilir misiniz. Birde sizin kodda eski hall konumu 0xff buda 111 olmuş olmuyor mu hocam başka bişey mi ifade ediyor acaba ?


Hız tesbiti için benim düşündüğüm fonksiyona saydıracağım ek bir değer atamaktı. 60 saniyede bir kaç değer alıyor buna bakıcaktım. Sonuçta 1 turda 6 kere fonksiyona gittiğini biliyoruz (ıskalamaz sanırsam) . 60 saniyede toplam sonucu 6 ya bölsem çok mu mantıksız olur ?

Tagli

Sahte kesme oluşturmak elle kesme bayrağını 1 yapmaktan ibaret. Kart ilk çalıştığında ilk komütasyona karar vermek için kesme kodunun çalışması gerekiyor ama motor durmakta olduğu için kesme oluşmuyor. Bu sebeple kodda kesme bayrağını bir kereye mahsus olmak üzere elle 1 yapıp kesme kodunun çalışmasını sağlıyorum.

Eski hall konumuna takılma, o önemsiz bir ayrıntı. Kodun çalışması için şart değil. 0xff demek 0b111 demek değil. Hall'ın normalde alamayacağı bir değer verdim ki ilk okunan hall değeri ne olursa olsun algoritma bir değişim olduğu sonucuna vardın ve hata bayrağını 1 yapmasın diye.

Uzun aralıklarla hız okuyacaksan bir sorun yok, dediğin şekilde düşünebilirsin. Ancak motorun bir turunda 6'dan fazla faz olabilir ki bu aslında iyi bir şey, daha yüksek çözünürlük demek. Elektriksel tur ile mekanik tur birbirinden farklı. Bir mekanik turda birden fazla elektriksel tur olabilir. Eğer örneğin 10 ms'de bir çalışan bir kontrol döngün olsaydı hall sensör bir işine yaramazdı. Çünkü birkaç 10 ms'lik döngü boyunca hall değişmeyeceği için hız 0 gibi görünür, sonra da tek bir 10 ms içinde birden değişeceği için anlamsız bir zıplama yapıp bir sonraki turda yine sıfırlanırdı.
Gökçe Tağlıoğlu

mr.selim

@Tagli Şimdi hocam belki aynı soru etrafında sizi döndürüyor olucam ama anlamadığım nokta motor duruyorken bile biz hall sinyallerini okuyabiliyoruz ? Elle çalıştırmaktaki amaç, kesmenin ilk durumunun belli olmaması mı ? Birde elle kesme yapmayı basit bir kodla ifade edebilir misiniz. Diğer kontrol kartlarında Araştırmam için.


111 dememdeki amaç hall konumu 111 olmasıydı. Demek aynı mantık sadece değişim var diyebilsin diye.


Hız konusunda da gözümden kaçmış bir turda kaç tane elektriksel tur olduğunu hall sensörlerin adc ile okunmasıyla saysam. Elle çevirip. Sonra bölü bulduğum tur sayısı desem bu sefer mantıklı olur herhalde. Şöyle ki okuduğum yüksek lisans tezlerinde encoder kullanmadan yapmışlar. Demekki bu sensörler kapalı çevrimde kullanılabilmiş. Benim asıl kafama takıla konu şu oldu. Hem motor kontrolü yapmak hemde devir saydırmak bir mcu içinde ne kadar verimli ? Bizim yaptığımız deneylerde akım, gerilim devir okuma aynı bir mcu dan olurdu hep.

Tagli

Alıntı yapılan: mr.selim - 03 Mayıs 2017, 15:06:22
@Tagli ...motor duruyorken bile biz hall sinyallerini okuyabiliyoruz ?
Doğru, ama ben okumuyorum. Sadece değişim kesmesi gelirse bakıyorum ne olmuşlar diye. Sürücü ilk çalışmaya başladığında da bu hall sensörlerinin okunması ve buna göre komütasyona karar verilmesi gerekiyor. Aynı kodu tekrar yazmayayım, kesme içinde yazılmışları kullanayım diye yazılım üzerinden bir kereye mahsus olmak üzere kendim tetikliyorum kesmeyi. Yaptığım şey _CNIF = 1; yazmaktan ibaret.

Hall çıkışları dijitaldir. Belki motoru yavaş yavaş elle çevirerek bile sayabilirsin. Benim kullandığım bir motorda mekanik turda 24 faz geçiyordu, yani 4 elektriksel tur. Veya deneme yanılma yap. 60 rpm'i kabaca gözle tespit edebilirsin. Açık çevrim ile hızı kabaca 60 rpm'e ayarla. Bunu yazılımının raporlayacağı sayı ile karşılaştır, duruma göre katsayıyı değiştirip tekrar denersin.

Alıntı YapHem motor kontrolü yapmak hemde devir saydırmak bir mcu içinde ne kadar verimli ?
Bu iki işlemin öyle ya da böyle aynı yerde yapılması gerekir. Amacın kapalı çevrim kontrol ise, zaten sayılan devir sayısına göre motorun kontrol edilmesi gerekiyor. Ben dsPIC30F2010 ile bunu yaptım. Ama kullandığım motorda yüksek çözünürlüklü quadrature encoder vardı ve devir sayma işini bu işlemcinin içindeki dahili quadrature encoder interface ile yaptım.
Gökçe Tağlıoğlu