Soru:
Arduino kodunu değiştirmeden Arduino çekirdek işlevini değiştirmenin bir yolu var mı?
P.W.
2016-04-22 03:03:50 UTC
view on stackexchange narkive permalink

(Bunun yanlış fikir olduğu ve bir süreliğine kesintiye uğrayacağı yönündeki önerileri atlayalım ...).

digitalWrite () yöntemini değiştirmenin bir yolu var mı ( örneğin) orada olacak bir şey daha ekleyebilmem için? Ancak aşağıdaki kurallara uyulmalıdır:

  • digitalWrite (pin, değer) çağrısı yeni yöntemi çağırmalıdır.
  • Kodumda (örneğin SD.h) bulunan farklı bir kitaplıktan digitalWrite (pin, değer) yeni yöntemi çağırmamalıdır.
  • Hiçbiri Arduino dosyaları değiştirilebilir (bunu her Arduino sürüm yükseltmesinde yapmak istemiyorum).
  • Her şey yeni işlevi kullanmak için ekleyebileceğim bir başlık dosyasında yapılmalıdır.

Bunu denedim ve işe yarıyor, ancak yalnızca kodumda, bu başlıktan sonra eklediğim harici kitaplıklarda değil:

  #include <Arduino.h>class PinsHook { public: statik void digitalWriteHook (uint8_t pin, uint8_t değeri) {digitalWrite (pin, değer); if (pin == 8) {Serial.print ("Pin"); Seri baskı (pin); Serial.print ("değiştirildi"); Serial.println (değer); }}}; # define digitalWrite (pin, değer) PinsHook :: digitalWriteHook (pin, değer)  
[Bu kitaplık] (https://github.com/DannyHavenith/avr_utilities/blob/master/avr_utilities/FastPins.h#L108) bunu şablonları kullanarak yapabiliyor gibi görünüyor.
Yedi yanıtlar:
Majenko
2016-04-22 03:58:18 UTC
view on stackexchange narkive permalink

Arduino IDE'den emin değilim (şu anda onu kurmadım) ancak UECIDE kullanmak, kodunuzda yeni bir digitalWrite işlevi tanımlamak kadar basit. Tüm shebang birbirine bağlandığında, kodunuzdaki işlev kitaplıklardaki işlevi geçersiz kılar.

  void setup () {pinMode (13, OUTPUT);} void loop () {digitalWrite (13 , YÜKSEK); gecikme (100); digitalWrite (13, DÜŞÜK); delay (800);} void digitalWrite (int pin, int level) {// Hiçbir şey yapmayacağım!}  

digitalWrite fonksiyonunu yorumlayın ve LED yanıp söner. Yorumunu kaldırın ve artık yanıp sönmez.

Evet, harici kütüphanelerde de çalıştığını düşünüyorum! Ancak bu şekilde, bu yöntemden orijinal `` digitalWrite () '' i çağıramam çünkü yöntem kendisini çağırıyor (yığın taşması!) Bu çözülebilir mi? Yöntemim bağlantılı olan ise, orijinal yöntemin hiç dahil edilmediğini ve çağrılamayacağını düşünüyorum - haklı mıyım?
Haklısın. Orijinal digitalWrite içeriğini kullanmak için varyantınıza kopyalayıp yapıştırmanız gerekecektir.
Bunu denedim ama derlemiyor. Bazı şeyler eksik. Orijinal yöntemi geçersiz kılarak ve çağırarak (ve cevabınıza ekleyerek) böyle bir yöntemin örnek kodunu oluşturabilirseniz, aradığım cevap bu olacaktır.
Muhtemelen mevcut digitalWrite'da ihtiyacınız olmayan büyük bir miktar vardır. Genel olması için yapılmıştır, ancak yalnızca belirli pinlerle belirli şeyler yapmak istiyorsanız, bu çağrıları PORT kayıtlarına kendiniz kodlayabilirsiniz.
@P.W. tek bir işlevin üzerine yazmak, yalnızca modüldeki tek işlev buysa işe yarar. "Bağlayıcının bildiği en küçük birim nesne modülüdür". Bu nedenle, bağlayıcı kodunuzda eşleşen bir işlev bulursa, bu modülü getirecek ve kod kitaplığındaki diğer yöntemleri yok sayacaktır. Bahsettiğiniz derleyici başarısızlığına neden olan şeyin bu olduğuna inanıyorum. Aşağıdaki cevabımda daha fazla bilgi.
2018: UECIDE ile birkaç saat geçirin, iyi görünüyor ancak tamam değil, birçok hata. Bazı kodları (AVR) değiştirdikten sonra sadece bir kez derler ve IDE'yi yeniden başlattıktan sonra derleme yapmaz (daha önce var olmayan problemi tanımlayın). ESP kodu, kütüphanede uyumsuz tanımlanmış tipler değişti, şimdi çözülemeyen AsyncWebServer sorunu. IDE kitaplık değişikliklerini algılamaz, IDE'yi yeniden başlatması gerekir, vb. Zamanınızı bununla harcamayın, belki birkaç yıl sonra deneyin.
UECIDE ile ilgili sorunlar bulursanız, bunları github havuzunda sorunlar olarak gündeme getirmenizi öneririm. bu şekilde düzeltilme şansı vardır. Belirtilmemiş problemler hakkında sızlarsanız, asla düzeltilmezler. Yine de tahminim, aşırı basitleştirilmiş Arduino ortamına çok alışkın olduğunuz ve menülerde ne yapmak istediğinizi yapmak için doğru seçenekleri bulamadınız - tüm kitaplıkları ve benzerlerini yeniden taramak gibi.
Edgar Bonet
2016-11-29 03:42:54 UTC
view on stackexchange narkive permalink

Bir fikir ortaya atıyorum. Şimdi test etmek için zaman yok.

Düzenleme : Aşağıdaki çözümü test ettim ve hem __wrap_ hem de __real_digitalWrite () , extern "C" olarak bildirilir.

IDE'yi derleme komut satırına fazladan seçenekler eklemeye ikna edebilirseniz, şunları yapabilirsiniz:

  1. __wrap_digitalWrite () uygulamanızı digitalWrite()
  2. içinde __real_digitalWrite () çağırın Arduino çekirdeğinden uygulamayı almak istediğinizde
  3. finallink adımının derleme komutuna -Wl, - wrap = digitalWrite ekleyin
  4. ol>

    Örnek sarmalayıcı:

      extern "C" {void __wrap_digitalWrite (uint8_t, uint8_t); void __real_digitalWrite (uint8_t, uint8_t);} // digitalWrite () 'a yapılan çağrılar buna yönlendirilir. void __wrap_digitalWrite (uint8_t pin, uint8_t değeri) {__real_digitalWrite (pin, değer); // Arduino çekirdeğinden uygulamayı çağırın if (pin == 8) {Serial.print (F ("Pin 8 değiştirildi")); Serial.println (değer); }}  

    Bunu bir sınıfa koymaya çalışmak yardımcı olmaz.

    C.f. gnu ld'nin man sayfası.

Lütfen 3. adımı biraz daha açıklayın: "-Wl, - wrap = digitalWrite` 'ı son bağlantı adımının derleme komutuna nasıl ekleriz?
Igor Stoppa
2016-04-22 03:08:19 UTC
view on stackexchange narkive permalink

Bir C makrosuyla mı denediniz?

  #define digitalWrite (a, b) \ (pre (), digitalWrite (a, b), post ())  

bu, post()

'nin yeniden değerlenmesini sağlar

pre () veya post () işlevleri / makroları.

Bunun, digitalWrite başlığı her eklendiğinde, onu geçersiz kılabilmesi için dahil edildiği bir yere yerleştirilmesi gerekir.

The diğer alternatif ise kütüphane ikili dosyasıyla yaratıcı olmaktır.

Ya da makul olun ve kaynak kodunu değiştirin. İnsanların değiştirebilmesi için özel olarak mevcuttur.

Yanlış tekrar değil her yeni Arduino sürümü olduğunda değişiklik önlenebilir olmalıdır. git kaynaklarından ortamı oluşturursanız, ana dala birleştirerek / yeniden oluşturarak yamanızı koruyabilirsiniz.

Evet, ama bu son çare. Makronuz aynen benim makrom gibi çalışır (kodumun son satırına bakın) - diğer kitaplıklarda çalışmaz. Diğer kitaplıklara dahil etmek için invaziv olmayan bir yol arıyorum. Herhangi bir fikir?
İşlev çağrıları ve kitaplıkları tasarlarken kullanılan her tasarım ilkesine karşı çıkıyorsunuz: - D Yapmak istediğiniz şey, bir programın kaynak kodunu değiştirmekten çok bir ikiliyi hacklemeye daha yakındır. Geriye kalan tek sözde yasal seçenek bağlayıcı ile oynamaktır. Örneğin, orijinal işlevi yeniden adlandırın ve onu ele geçirmek için --wrap kullanın. Bunu başlangıç ​​noktası olarak kontrol edin https://sourceware.org/binutils/docs-2.21/ld/Options.html#Options
Btw, sadece pin seviyesinde neler olup bittiğini izlemek istiyorsanız, mantıksal bir analizör kullanabilirsiniz - bu çok ucuz ve bazı baskılardan daha güvenilirdir. Ayrıca programa sıfır ek yük getirir. Http://arduino.stackexchange.com/questions/22898/how-to-design-and-debug-a-custom-i2c-master-slave- yanıtının ortasındaki "sigrok ve pulseview" bölümüne bakın. sistemi
Biliyorum. Hata ayıklamayı değil, pinleri yeniden yönlendirmeyi düşünüyorum. Ve yeniden yönlendirmekle, onları örneğin orijinal kütüphanelerin yapamayacağı bir genişletici veya kaydıran yazmaç yoluyla göndermeyi kastediyorum. Pinlerim bitti ve standart kitaplıkların kendi sürümlerimi yazmak istemiyorum. Şimdi mantıklı geliyor mu?
RubberDuck
2016-11-29 02:12:08 UTC
view on stackexchange narkive permalink

Arduino, standart kitaplığını bir core.a dosyası halinde derlemek için avr derleyicisini kullanır. avr-gcc bağlayıcısının çalışma şekli ve Arduino'nun sırasına bağlı olarak bağlantı sırasını belirtirse, değiştirmek istediğiniz yöntemi içeren dosyayı projenize kopyalayarak temel işlevlerin davranışını "geçersiz kılabilirsiniz".

Derleyici, tek bir yüksek -düzey dil dosyasını (örneğin C dili) tek bir nesne modülü dosyasına. Bağlayıcı (ld), onları birbirine bağlamak için yalnızca nesne modülleri ile çalışabilir. Nesne modülleri, bağlayıcının birlikte çalıştığı en küçük birimdir.

Tipik olarak, bağlayıcı komut satırında, bir dizi nesne modülü (önceden derlenmiş olan) ve ardından da dahil olmak üzere bir kitaplık listesi belirtirsiniz. Standart C Kütüphanesi. Bağlayıcı, komut satırında belirttiğiniz nesne modülleri kümesini alır ve bunları birbirine bağlar. Daha sonra muhtemelen bir dizi "tanımsız referans" olacaktır. Referans, esasen bir işlev çağrısıdır. Tanımlanmamış bir referans, çağrıyla eşleşecek tanımlı bir fonksiyona sahip olmayan bir fonksiyon çağrısıdır.

Bağlayıcı, tanımlanmamış referansları kütüphanelerde bulunan fonksiyon tanımlarıyla eşleştirmek için kütüphanelerden geçecektir. . Çağrıyla eşleşen işlevi bulursa, bağlayıcı daha sonra işlevin bulunduğu nesne modülüne bağlanır. Bu bölüm önemlidir: bağlayıcı, işlevin bulunduğu TÜM NESNE MODÜLÜNDE bağlantı kurar. Unutmayın, bağlayıcının bir nesne modülünün içindeki işlevler hakkında, sembol adları (işlev adları gibi) dışında hiçbir şey bilmediğini unutmayın. Bağlayıcının birlikte çalıştığı en küçük birim nesne modülleridir.

Artık tanımlanmamış referanslar kalmadığında, bağlayıcı her şeyi bağlamıştır ve yapılır ve son uygulamayı çıkarır.

... .

Bağlayıcı, kitaplıkları üzerinde göründükleri sırayla arayacaktır. Komut satırı. Tanımlanmamış referansla eşleşen önce hangi işlev bulunursa bulunsun, bağlanacaktır.

Arduino'nun bağlantısı şu sırayla gerçekleşir:

  • Proje Dosyaları
  • Kitaplıklar
  • core.a (Arduino std lib)

Yani, dosyayı Arduino kurulum konumundan kopyalamak ( C: \ Program Files (x86) \ Arduino \ hardware \ arduino \ avr \ cores \ arduino ) projenize dahil etmek ve onu değiştirmek, değiştirilmiş uygulamanızı kullanmasıyla sonuçlanacaktır.

Bu, projenizdeki tüm dosyalar için kesinlikle onu geçersiz kılacaktır ve inanıyorum , kullandığınız tüm kitaplıklarda da geçersiz kılacaktır, bu yüzden dikkatli olun bu yaklaşım.

flukee
2017-07-18 03:45:53 UTC
view on stackexchange narkive permalink

Kod modülünüzde, kendi sarmalayıcı işlevinizi tanımlayın ve Arduino işlevine başvurmak için genel kapsam operatörünü kullanın:

  void pinMode (int pin, int pinmode) {/ * my özel işlev? * / if (pin > = MY_OWN_PIN_CODES_BASE) {/ * yapılacak: kendi özel pin erişimim * / example_pinmode (pin, pinmode); } else / * normal Arduino işlevini kullanın * / {/ * genel kapsam operatörünü kullanın :: Arduino kitaplık sürümünü çağırmak için * / :: pinMode (pin, pinmode); }}  

Unutmayın, bağlayıcının referans verdiği kurallar vardır. Global kapsam operatörü, bağlayıcıyı küresel olarak mevcut olanı seçmeye zorlarken, özel sarmalayıcı işlevi modül tarafından özel olarak görülür.

OP'nin gereksinimlerini karşılamak için, sarmalayıcı küresel kapsamda çalışmalıdır. Bu durumda tekniğiniz sonsuz bir döngü oluşturur.
Yahya Tawil
2017-12-07 22:43:47 UTC
view on stackexchange narkive permalink

"Belki" c ++ "işlevlerini geçersiz kılma" özelliğini kullanmak yardımcı olabilir

  void digitalWrite (uint8_t P, int8_t V, bool _wrap) {Serial.print ("wrap digitalwrite"); digitalWrite (P, V);}  

Dolayısıyla, ana uygulamanızı ararsanız:

  digitalWrite (pin_button, 1, 0); 

Sarmalanmış sürüm

olarak adlandırılacaktır ve bunu kullandıysanız:

  digitalWrite (pin_button, 1); 

Orijinal olanın adı


Ayrıca şu tanımı da kullanabilirsiniz:

  void digitalWrite (double P, int8_t V) {Serial.print ("wrap digitalwrite"); // digitalWrite (P, V); Hatta (int) P ile çağırmak yinelemeli bir döngüye neden olur}  

Ancak onu kullanmak için çift tipli bir değişken tanımlamanız gerekir:

  çift pin; pin = 13; digitalWrite (13,1);  
Bu, OP'nin ilk iki gerekliliğini karşılamıyor.
Biliyorum, bunun bir şekilde yardımcı olacağını düşündüm (ve belki de başkalarının yorumlarıyla zenginleştirilebilir).
@EdgarBonet ilgileniyorsanız yeni güncellemeyi görün. Bu talep edilen her şeyi karşılar.
Mevcut bir kütüphaneden arama yapıldığında 2. nokta hariç.
Jan van der Zanden
2018-01-11 06:59:34 UTC
view on stackexchange narkive permalink

The information from Rubber Duck is correct but incomplete.

I need a huge amount of digital PWM output for hobby train control.

So I connected 4 x 74HC595 to my At Mega which must be fed with a 2 kHz bit pattern through 0,5 ms. interrupts.

My serial shift function that shifts 32 bits into the registers takes 562 us per cycle. Impossible.

I made an optimized version of digitalWrite and Read, which takes 328 us. Now it is possible to PWM with 2 kHz. The trick is that my optimized function remembers the last 2 Pins including its bitmasks and outports; and I skip the Timer check. It is thread safe. For a single digitalWrite this takes a tiny bit more time. With repeating writing to datapin and clockpin it improves the standard Arduino digitalWrite with about 42%.

By the way: With the digitalWriteFast library the result is 45,8 µs, a really enormous improvement. But this library handles only writes, if the pin number is known (and thus fixed!) at compile time. That is not the case with my LiquidCrystal library, where either 4 or 8 bits parallel are written to the shield via 4 sequential pins.

I got my optimized digitalWrite only working for my application including the LiquidDisplay when I copied the C:\Users\Dell\Downloads\arduino-1.8.5\hardware\arduino\avr\cores\arduino library to a subfolder in the folder of my application, called

C:\Users\Dell\Google Drive\ …\…..\AppFolder\libraries.

When I replaced in both folders the wiring_digital.c with my optimized version, it worked.

I could not get it at work, when I only replaced the wiring_digital.c in the Arduino library (the LiquidCrystal took the standard function somewhere else).

Adding only wiring_digital.c in de subfolder of my application generated a mass of linking errors.

Thus I copied the whole Arduino folder (which is not that large) to my subfolder in the application and it compiles without any problem. Not a very elegant solution, because there is a replication of the whole library; but it works.

Conclusion to override a core Arduino function:

• Put your changed function(s) (.c and/or .h) in the Arduino library, and copy this library entirely to the subfolder "libraries" in your application folder. Then all other libraries will also use your own changed function.

Conclusion performance digitalWrite in a real 32 bit serial shift :

• An optimized generic digitalWrite and Read easily outperforms the standard one with 42% if 2 pins are used in repetition.• digitalWriteFast (with determined pins at compile time) outperforms the standard digitalWrite in a real 32 bit shift application with 92% (is 12,2 times faster).

Hope this helps other Arduino users…..

//**********************void digitalWrite(uint8_t pin, uint8_t val)//**********************{uint8_t   timer,  bit,  port;volatile uint8_t *out; // volatile because bitmask may be changed by (higher) interruptuint8_t oldSREG;static uint8_t pin1 = 0,               pin2 = 0;static bool    p1   = true; // boolean toggle memorystatic uint8_t // Store 2 sets of port/out adresses static//          timer1, //now exclued. Safety threat?          bit1,          *out1,//          timer2,          bit2,          *out2;   oldSREG = SREG;  // CLI for thread proof function  cli();  if ( (pin == pin1) || (pin == pin2) )  {    if (pin == pin1)   //Compiler optimizes this excellent (see ASM listing)    {      if (val == LOW)       {        *out1 &= ~bit1;      } else       {        *out1 |= bit1;       }     }    else    if (pin == pin2)    {      if (val == LOW)       {        *out2 &= ~bit2;      } else       {        *out2 |= bit2;       }       }    SREG = oldSREG;      }  else  //normal clumsy digitalWrite operation  {
    SREG = oldSREG;   //Enable interrupts again    timer = digitalPinToTimer(pin);    bit = digitalPinToBitMask(pin);    port = digitalPinToPort(pin);    if (port == NOT_A_PIN) return;    // If the pin that support PWM output, we need to turn it off    // before doing a digital write.//    if (timer != NOT_ON_TIMER) turnOffPWM(timer);    out = portOutputRegister(port);    oldSREG = SREG;    cli();    if (val == LOW) {      *out &= ~bit;    } else {      *out |= bit;    }    if (p1)        // Save this port, bit and out, also atomic    {      pin1  = pin;      bit1  = bit;      out1  = out;  // save the pointer, not the value        }    else    {      pin2  = pin;      bit2  = bit;      out2  = out;  // save the pointer, not the value        }    p1 = !p1;    SREG = oldSREG; //enable interrupts  }}//**********************int digitalRead(uint8_t pin)//**********************{uint8_t   oldSREG,  timer,  bit,  port;static uint8_t pin1 = 0;bool           readBit;static uint8_t // Store 2 sets of port/out adresses static//          timer1, //now exclued. Safety threat?              port1,              bit1;  oldSREG = SREG;  cli();  if (pin == pin1)  {    readBit = (*portInputRegister(port1) & bit1);    SREG = oldSREG;    return readBit;             }  else  {    SREG = oldSREG;      timer = digitalPinToTimer(pin);    bit = digitalPinToBitMask(pin);    port = digitalPinToPort(pin);    if (port == NOT_A_PIN) return LOW;    // If the pin that support PWM output, we need to turn it off    // before getting a digital reading.  //  if (timer != NOT_ON_TIMER) turnOffPWM(timer);    oldSREG = SREG;    cli();    pin1 = pin;       //Atomic operation pin - bit combi must be correct    bit1 = bit;    port1 = port;    SREG = oldSREG;    if (*portInputRegister(port) & bit) return HIGH;    return LOW;  }}


Bu Soru-Cevap, otomatik olarak İngilizce dilinden çevrilmiştir.Orijinal içerik, dağıtıldığı cc by-sa 3.0 lisansı için teşekkür ettiğimiz stackexchange'ta mevcuttur.
Loading...