I / O pin soyutlaması için C ++ sınıfları


13

Donanım I / O noktaları veya pimleri için C ++ soyutlama arıyorum. İn_pin, out_pin, inout_pin, belki open_collector_pin vb.

Kesinlikle böyle bir soyutlama kümesi ortaya çıkarabilirim, bu yüzden 'hey, bu şekilde yapabilirsin' tür cevaplar aramıyorum, daha ziyade 'bu ve bu kitapta kullanılan bu kütüphaneye bakın ve bu proje'.

Google, başkalarının bunu nasıl arayacağını bilmediğim için bir şey açmadı.

Amacım bu noktalara dayanan ancak aynı zamanda bu noktaları sağlayan G / Ç kitaplıkları oluşturmaktır, bu nedenle örneğin bir HD44780 LCd'yi çipin IO pinlerine veya bir I2C'ye (veya SPI) bağlamak kolay olacaktır. LCD sınıfında herhangi bir değişiklik yapmadan G / Ç genişletici veya bir şekilde kontrol edilebilen başka herhangi bir nokta.

Bunun elektronik / yazılım kenarında olduğunu biliyorum, eğer buraya ait değilse üzgünüm.

@leon: kablolama Bu büyük bir yazılım çantası, daha yakından bakmam gerekecek. Ama öyle görünüyor ki benim istediğim gibi bir pin soyutlaması kullanmıyorlar. Örneğin tuş takımı uygulamasında görüyorum

digitalWrite(columnPins[c], LOW);   // Activate the current column.

Bu, bir G / Ç pinine nasıl yazılacağını bilen bir işlev (digitalWrite) olduğunu gösterir. Bu, digitalWrite işlevini yeniden yazmadan yeni bir tür G / Ç pini (örneğin, MCP23017'de bulunan bir tane eklemeyi imkansız hale getirir).

@Oli: Bir Arduino IO örneğini araştırdım, ancak Wiring kütüphanesi ile aynı yaklaşımı kullanıyor gibi görünüyor:

int ledPin = 13;                 // LED connected to digital pin 13
void setup(){
    pinMode(ledPin, OUTPUT);      // sets the digital pin as output
}

Burada hangi mikrodenetleyici hakkında konuşuyoruz?
Majenko

Bu alakasız; belirli bir mikrodenetleyici için bu uC'nin io pinleri uygun arayüzleri uygulayacaktır. Ancak bu C ++ içindir, bu yüzden ARM, Cortex ve MIPS gibi 32 bit yongaları düşünün.
Wouter van Ooijen

1
Hiç kullanmadım ama Arduino tüm pimleri bu şekilde soyutlamıyor mu? Bazı şeyleri yaptıklarına bakarak yararlı bilgiler edinebilirsiniz (ya da edemeyebilirsiniz).
Oli Glaser

1
Ve digitalWrite fonksiyonunu yeniden yazmak için - C ++ 'da "aşırı yüklenmeye" bakın. Birkaç dakika önce Arduino için bir IO genişletici kartı için aşırı yüklü bir digitalWrite işlevi yazdım. Farklı parametreler kullandığınız sürece (ilk "int" i "struct" ile değiştirdim), digitalWrite öğenizi varsayılan olarak seçecektir.
Majenko

1
Berlin'deki C ++ ile bu konudaki çalışmalarım hakkında bir konuşma yaptım. Youtube'da bulunabilir: youtube.com/watch?v=k8sRQMx2qUw O zamandan beri biraz farklı bir yaklaşıma geçtim, ancak konuşma yine de ilginç olabilir.
Wouter van Ooijen

Yanıtlar:


3

Kısa cevap: ne yazık ki, istediğinizi yapacak bir kütüphane yok. Kendimi defalarca yaptım ama her zaman açık kaynaklı olmayan projelerde. Github'a bir şey koymayı düşünüyorum ama ne zaman yapabileceğimden emin değilim.

Neden C ++?

  1. Derleyici, dinamik kelime boyutu ifade değerlendirmesini kullanmakta serbesttir. C, int. Bayt maskeniz / vardiyanız daha hızlı / daha küçük yapılabilir.
  2. Satır içine almak.
  3. Templatize etme işlemleri, kelime güvenliği ve diğer özellikleri, tip güvenliği ile değiştirmenize olanak tanır.

5

Açık kaynak projemi utanmadan takmama izin ver https://Kvasir.io . Kvasir :: Io kısmı pim manipülasyon fonksiyonları sağlar. Önce PIN kodunuzu bir Kvasir :: Io :: PinLocation kullanarak şöyle tanımlamanız gerekir:

constexpr PinLocation<0,4> led1;    //port 0 pin 4
constexpr PinLOcation<0,8> led2;

Bunun gerçekte RAM kullanmadığına dikkat edin, çünkü bunlar constexpr değişkenleridir.

Kodunuz boyunca bu pin konumlarını makeOpenDrain, set, clear, makeOutput ve benzeri 'action factory' işlevlerinde kullanabilirsiniz. Bir 'eylem fabrikası' eylemi gerçekte yürütmez, bunun yerine Kvasir :: Register :: Apply () kullanılarak gerçekleştirilebilen bir Kvasir :: Register :: Action döndürür. Bunun nedeni, Apply () yönteminin, bir ve aynı kayıt üzerinde hareket ettiklerinde kendisine iletilen eylemleri birleştirmesi ve böylece bir verimlilik kazancı sağlamasıdır.

apply(makeOutput(led1),
    makeOutput(led2),
    makeOpenDrain(led1),
    makeOpenDrain(led2));

Eylemlerin oluşturulması ve birleştirilmesi derleme zamanında yapıldığından, bu tipik el kodlu eşdeğeri ile aynı birleştirici kodunu vermelidir:

PORT0DIR |= (1<<4) | (1<<8);
PORT0OD |= (1<<4) | (1<<8);

3

Wiring projesi aşağıdaki gibi soyutlamaları kullanır:

http://wiring.org.co/

ve derleyici C ++ ile yazılmıştır. Kaynak kodda çok sayıda örnek bulmalısınız. Arduino yazılımı Kablolama üzerine kuruludur.


soru gövdesinde cevaplandı
Wouter van Ooijen

2

C ++ 'da, bir sınıf yazmak mümkündür, böylece G / Ç bağlantı noktalarını değişkenmiş gibi kullanabilirsiniz, örn.

  PORTB = 0x12; / * 8 bit bağlantı noktasına yazma * /
  (RB3) LATB4 = 1 ise; / * Bir G / Ç bitini okuma ve koşullu olarak başka bir yazma yazma * /

temel uygulama dikkate alınmadan. Örneğin, bit düzeyi işlemleri desteklemeyen ancak bayt düzeyi kayıt işlemlerini destekleyen bir donanım platformu kullanılıyorsa, (muhtemelen bazı makroların yardımıyla) satır içi okuma yazma özelliğine sahip statik bir sınıf IO_PORTS tanımlanabilir yukarıdaki son ifadeye dönüşecek şekilde bbRB3 ve bbLATB4 olarak adlandırılan özellikler

  eğer (IO_PORTS.bbRB3) IO_PORTS.bbLATB4 = 1;

bu da şu şekilde işlenir:

  eğer (!! (PORTB & 8)) (1? (PORTB | = 16): (PORTB & = ~ 16));

Bir derleyici?: İşlecindeki sabit ifadeyi fark edebilmeli ve sadece "doğru" kısmı içermelidir. Makroların aşağıdakilere genişlemesini sağlayarak oluşturulan özelliklerin sayısını azaltmak mümkün olabilir:

  eğer (IO_PORTS.ppPORTB [3]) IO_PORTS.ppPORTB [4] = 1;

veya

  eğer (IO_PORTS.bb (addrPORTB, 3)) IO_PORTS.bbPORTB (addrPORTB, 4) = 1;

ama bir derleyici kodu güzel satır içi mümkün olacak emin değilim.

Hiçbir şekilde G / Ç bağlantı noktalarını değişkenmiş gibi kullanmanın mutlaka iyi bir fikir olduğunu ima etmek istemiyorum, ancak C ++ 'dan bahsettiğiniz için bilmek yararlı bir numara. C veya C ++ 'daki kendi tercihim, yukarıda belirtilen stili kullanan kodla uyumluluk gerekli değilse, muhtemelen her G / Ç biti için bir tür makro tanımlamak ve daha sonra "readBit", "writeBit" için makrolar tanımlamak, "setBit" ve "clearBit", bu makrolara iletilen bit tanımlama bağımsız değişkeninin, bu tür makrolarla kullanılması amaçlanan bir G / Ç bağlantı noktasının adı olması şartıyla. Yukarıdaki örnek, örneğin,

  (readBit (RB3)) setBit (LATB4);

ve olarak çevrildi

  eğer (!! (_ PORT_RB3 & _BITMASK_RB3)) _PORT_LATB4 | = _BITMASK_LATB4;

Bu önişlemci için C ++ stilinden biraz daha fazla iş olurdu, ancak derleyici için daha az iş olurdu. Ayrıca birçok I / O uygulaması için en uygun kod üretimine ve neredeyse herkes için iyi kod uygulamasına izin verir.


3
Şu sorudan bir alıntı: "Hey, bu şekilde yapabilirsin" şeklinde cevaplar "...
Wouter van Ooijen

Ne aradığınızı pek bilmiyorum. Kesinlikle I / O pin rekonstrüksiyonu için sınıflarla ilgilenen birçok insanın, özelliklerin kullanılmasının, bir I / O stili için yazılan kodun hemen hemen her şeyi kullanabileceğini bilmek isteyeceğini umuyorum. Ben "LATB3 = 1;" gibi bir ifade yapmak için özellikleri kullandım TCP akışına bir G / Ç isteği gönderin.
supercat

Sorumda net olmaya çalıştım: IO pinlerini kullanan kodu yeniden yazmadan IO pinlerinin yeni tiplerini karşılamak istiyorum. Kesinlikle ilginç olan kullanıcı tanımlı tür dönüşümleri ve atama operatörleri hakkında yazıyorsunuz, bunları her zaman kullanıyorum, ama sorunuma bir çözüm değil.
Wouter van Ooijen

@Wouter van Ooijen: Hangi "yeni G / Ç pimleri" türünü beklersiniz? Kaynak kodu "if (BUTTON_PRESSED) MOTOR_OUT = 1;" gibi bir sözdizimi ile yazılmışsa, işlemcinin bir düğme kontrolünü okuyabileceği herhangi bir mekanizma veya bir motorun yukarıdaki kaynak için bir kütüphane yazabileceğini beklerim. düğmeye basılırsa kod motoru açar. Böyle bir kütüphane motoru çalıştırmanın en etkili yolunu göstermeyebilir, ancak çalışması gerekir.
supercat

@Wouter van Ooijen: Kaynak kodunun herhangi bir girdiyi okumadan bir süre önce UPDATE_IO () veya UPDATE_INPUTS () makrosunu çağırması gerekiyorsa ve girdilerin semantiği, bunları okuyan kodda veya önceki UPDATE_INPUTS () / UPDATE_IO () çağrısında örneklenebilir. Benzer şekilde çıktılar hemen meydana gelebilir veya ertelenebilir. Bir G / Ç bir kaydırma yazmacı gibi bir şey kullanılarak uygulanırsa, erteleme eylemleri birden çok işlemin birleştirilmesine izin verir.
supercat

1

Donanımı soyutlamak için gerçekten harika bir şey arıyorsanız ve C ++ becerilerinize güveniyorsanız, bu modeli denemelisiniz:

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

Bir Cortex-M0 yongası için donanımı soyutlamak için kullandım. Bu deneyim hakkında henüz bir şey yazmadım (bir gün yapacağım), ama bana inanın statik polimorfik doğası nedeniyle çok yararlı oldu: farklı yongalar için aynı yöntem (ücretsiz olarak polimorfizm ile karşılaştırıldığında).


Bu yazıyı izleyen yıllarda pin_in, pin_out, pin_oc ve pin_in_out için ayrı "sınıflar" üzerine oturdum. Optimum performans (boyut ve hız) için şablon parametreleri olarak iletilen statik sınıflar kullanıyorum. Bunu Berlin'deki C ++ Toplantısında konuştum
Wouter van Ooijen
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.