मैं बहुत ज्यादा RAM का उपयोग कर रहा हूँ। इसे कैसे मापा जा सकता है?


19

मैं जानना चाहूंगा कि मैं अपने प्रोजेक्ट में कितनी रैम का उपयोग कर रहा हूं, जहां तक ​​मैं बता सकता हूं, वास्तव में उस काम को करने का कोई तरीका नहीं है (बाहर जाने और खुद की गणना करने के अलावा)। मुझे एक बड़ी परियोजना में एक मंच मिला है जहां मैंने निर्धारित किया है कि मैं रैम से बाहर चल रहा हूं।

मैंने इसे निर्धारित किया है क्योंकि मैं एक खंड जोड़ सकता हूं और फिर कोई स्पष्ट कारण के लिए मेरे कोड में सभी नरक कहीं और टूट जाते हैं । अगर मुझे #ifndefकुछ और पता चलता है, तो यह फिर से काम करता है। नए कोड के साथ प्रोग्रामिक रूप से कुछ भी गलत नहीं है।

मुझे थोड़ी देर के लिए संदेह हुआ कि मैं उपलब्ध रैम के अंत तक पहुंच रहा हूं। मुझे नहीं लगता कि मैं बहुत अधिक स्टैक का उपयोग कर रहा हूं (हालांकि यह संभव है), यह निर्धारित करने का सबसे अच्छा तरीका है कि मैं वास्तव में कितना रैम का उपयोग कर रहा हूं?

के माध्यम से जा रहे हैं और इसे बाहर काम करने की कोशिश कर रहा है, मैं जब मैं enums और संरचनाओं के लिए समस्या है; उनकी कितनी मेमोरी है?

पहला संपादित करें: ALSO, मैंने शुरू से ही अपने स्केच को बहुत संपादित किया है, ये वास्तविक परिणाम नहीं हैं जो मुझे शुरू में मिले थे, लेकिन वे वही हैं जो अब मुझे मिल रहे हैं।

  text     data     bss     dec     hex filename
 17554      844     449   18847    499f HA15_20140317w.cpp.elf
 16316      694     409   17419    440b HA15_20140317w.cpp.elf
 17346      790     426   18562    4882 HA15_20140317w.cpp.elf

पहली पंक्ति (पाठ १4५५४ के साथ) काम नहीं कर रही थी, बहुत संपादन के बाद दूसरी पंक्ति (पाठ १६३१६ के साथ) काम कर रही है जैसा कि इसे करना चाहिए।

संपादित करें: तीसरी पंक्ति में सब कुछ काम कर रहा है, धारावाहिक पढ़ना, मेरे नए कार्य आदि, मैंने अनिवार्य रूप से कुछ वैश्विक चर और डुप्लिकेट कोड हटा दिए हैं। मैं इसका उल्लेख करता हूं क्योंकि (संदेह के रूप में) यह प्रति sae इस कोड के बारे में नहीं है, इसे रैम उपयोग के बारे में होना चाहिए। जो मुझे मूल प्रश्न पर वापस लाता है, "इसे सबसे अच्छा कैसे मापें" मैं अभी भी कुछ उत्तरों की जांच कर रहा हूं, धन्यवाद।

मैं वास्तव में उपरोक्त जानकारी की व्याख्या कैसे करूं?

अब तक मेरी समझ है:

`TEXT` is program instruction memory
`DATA` is variables (unitialised?) in program memory
`BSS`  is variables occupying RAM

चूंकि BSS 1024 बाइट्स से काफी कम है, इसलिए दूसरा काम क्यों करता है, लेकिन पहला नहीं है? यदि यह है DATA+BSSतो दोनों 1024 से अधिक पर कब्जा कर लेते हैं।

पुन: संपादित करें: मैंने प्रश्न को कोड शामिल करने के लिए संपादित किया, लेकिन अब मैंने इसे हटा दिया है क्योंकि इसका वास्तव में समस्या से कोई लेना-देना नहीं था (शायद खराब कोडिंग प्रथाओं, चर घोषणाओं और इस तरह के अलावा)। यदि आप वास्तव में इसे देखना चाहते हैं तो आप संपादन के माध्यम से वापस देखकर कोड की समीक्षा कर सकते हैं। मैं प्रश्न को वापस हाथ में लेना चाहता था, जो कि अधिक आधारित था: रैम उपयोग कैसे मापें।


मुझे लगा कि मैं जोड़ दूंगा, मैंने पिछले कुछ हफ्तों में कोड के विभिन्न नए खंड जोड़े हैं, फिर इसे तब तक ऑप्टोमाइज़ किया है जब तक यह काम नहीं करता है, लेकिन अब मैंने केवल आधा
दर्जन

क्या आप Stringअपने कार्यक्रमों में टाइप का उपयोग करते हैं? यह बार-बार गतिशील मेमोरी आवंटन और रिलीज़ करने के लिए जाना जाता है, जो कि उस बिंदु पर ढेर को खंडित कर सकता है जहां आपके पास कोई मेमरी नहीं रह सकती है।
jfpoilpret

@jfilpret मैं Stringओवरहेड के कारण एस से दूर रहता हूं । मुझे खुशी है कि मैं चार सरणियों के साथ काम कर रहा हूं, उन्होंने कहा, मैं हमेशा अपने सभी चार सरणियों को एक निश्चित आकार के साथ परिभाषित करता हूं (फिलहाल, मेरे पास एक बाइट सरणी है जो विशुद्ध रूप से नहीं है क्योंकि मैं विभिन्न recompiles के लिए सामग्री की लंबाई को बदल देता हूं।
Madivad

अपने कोड को यहां पोस्ट करना (या यदि यह बहुत बड़ा है तो पास्टबिन करने के लिए) आपको पता चल सकता है कि आपको मेमोरी से क्या समस्या है।
jfpoilpret

@jfpopret मैं वास्तव में कोड पोस्ट नहीं कर सकता, यह बहुत बड़ा है और दुर्भाग्य से बहुत फूला हुआ है, 16 फाइलों में फैला हुआ है। यह एक ऐसी परियोजना थी जिसे मैं आवश्यकता से परे अच्छी तरह से विकसित करने की अनुमति दे रहा था (यह कई परियोजनाओं को एक साथ मिला दिया गया है)। मैं अब इसे तोड़ने के लिए शुरू कर रहा हूं जो मुझे यकीन है कि समस्या को ठीक करने में मदद करेगा। हालाँकि इसके कुछ हिस्से हैं, जिनकी आवश्यकता मुझे लोगों को देखने (या मेरा मार्गदर्शन करने) पर है, मैं बाद में पोस्ट करूँगा।
मादिवद

जवाबों:


15

आप AVRGCC द्वारा प्रदान किए गए कार्यों का उपयोग कर सकते हैं : निगरानी स्टैक उपयोग

फ़ंक्शन का उद्देश्य स्टैक उपयोग की जांच करना था लेकिन यह रिपोर्ट करता है कि वास्तविक रैम है जिसे कभी भी उपयोग नहीं किया गया है (निष्पादन के दौरान)। यह एक ज्ञात मान (0xC5) के साथ रैम को "पेंटिंग" (भरने) द्वारा करता है, और फिर रैम क्षेत्र की जांच करके गणना करता है कि कितने बाइट्स में अभी भी समान प्रारंभिक मूल्य है।
रिपोर्ट उस रैम को दिखाएगी जिसका उपयोग नहीं किया गया है (न्यूनतम मुफ्त रैम) और इसके बाद आप उपयोग की गई अधिकतम रैम की गणना कर सकते हैं (कुल रैम - रैम की सूचना दी गई है)।

दो कार्य हैं:

  • StackPaint को इनिशियलाइज़ेशन के दौरान स्वचालित रूप से निष्पादित किया जाता है और 0xC5 मान के साथ रैम को "पेंट करता है" (यदि आवश्यक हो तो बदला जा सकता है)।

  • StackCount को किसी भी बिंदु पर उस RAM की गणना करने के लिए कहा जा सकता है जिसका उपयोग नहीं किया गया है।

यहाँ उपयोग का एक उदाहरण है। बहुत कुछ नहीं करता है, लेकिन यह दिखाने का इरादा है कि कार्यों का उपयोग कैसे करें।

// -----------------------------------------------------------------------------
extern uint8_t _end;
extern uint8_t __stack;

void StackPaint(void) __attribute__ ((naked)) __attribute__ ((section (".init1")));

void StackPaint(void)
{
#if 0
    uint8_t *p = &_end;

    while(p <= &__stack)
    {
        *p = 0xc5;
        p++;
    }
#else
    __asm volatile ("    ldi r30,lo8(_end)\n"
                    "    ldi r31,hi8(_end)\n"
                    "    ldi r24,lo8(0xc5)\n" /* STACK_CANARY = 0xc5 */
                    "    ldi r25,hi8(__stack)\n"
                    "    rjmp .cmp\n"
                    ".loop:\n"
                    "    st Z+,r24\n"
                    ".cmp:\n"
                    "    cpi r30,lo8(__stack)\n"
                    "    cpc r31,r25\n"
                    "    brlo .loop\n"
                    "    breq .loop"::);
#endif
} 


uint16_t StackCount(void)
{
    const uint8_t *p = &_end;
    uint16_t       c = 0;

    while(*p == 0xc5 && p <= &__stack)
    {
        p++;
        c++;
    }

    return c;
} 

// -----------------------------------------------------------------------------

void setup() {

Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
Serial.println(StackCount(), DEC);  // calls StackCount() to report the unused RAM
delay(1000);
}

दिलचस्प कोड का टुकड़ा, धन्यवाद। मैंने इसका उपयोग किया था, और यह सुझाव देता है कि वहाँ 600+ बाइट्स उपलब्ध हैं, लेकिन जब मैं दफन करता हूं कि गहरे उप में यह कम करता है, लेकिन मिटा नहीं है। तो मेरी समस्या कहीं और है।
मदिवाड

@ माडिवड ध्यान दें कि जब आप स्टैककाउंट कहते हैं, तो यह 600+ बाइट्स न्यूनतम उपलब्ध मात्रा का प्रतिनिधित्व करता है। इससे वास्तव में कोई फर्क नहीं पड़ता कि आप कॉल को कितनी गहराई से रखते हैं, अगर स्टैककाउंट को कॉल करने से पहले अधिकांश कोड और नेस्टेड कॉल निष्पादित किए गए हैं, तो परिणाम सही होगा। इसलिए उदाहरण के लिए आप अपने बोर्ड को थोड़ी देर के लिए काम करना छोड़ सकते हैं (जब तक कि आपको पर्याप्त कोड कवरेज या आदर्श रूप से प्राप्त करने में समय लगता है जब तक आप उस दुर्व्यवहार का वर्णन नहीं करते) और तब रिपोर्ट की गई रैम को प्राप्त करने के लिए एक बटन दबाएं। यदि पर्याप्त है तो यह समस्या का कारण नहीं है।
अलेक्सां_ए

1
धन्यवाद @alexan_e, मैंने अपने प्रदर्शन पर एक क्षेत्र बनाया है जो अब इसकी रिपोर्ट करता है, इसलिए जैसे ही मैं अगले कुछ दिनों में प्रगति करता हूं, मैं इस संख्या को दिलचस्पी से देखूंगा, खासकर जब यह विफल हो जाए! एक बार फिर धन्यवाद
मदिवाड १।

@ माडिवड कृपया ध्यान दें कि दिए गए फ़ंक्शन सही परिणाम की रिपोर्ट नहीं करेंगे यदि
मॉलोक

उसके लिए धन्यवाद, मैं जागरूक हूं, इसका उल्लेख किया गया है। जहां तक ​​मुझे जानकारी है, मैं इसका उपयोग नहीं कर रहा हूं (मुझे पता है कि इसका उपयोग करने वाला एक पुस्तकालय हो सकता है, मैंने अभी तक पूरी तरह से जांच नहीं की है)।
मड़िवाड़

10

रनटाइम पर मेमोरी के उपयोग के साथ आपके मुख्य मुद्दे निम्न हो सकते हैं:

  • डायनेमिक आवंटन ( या ) के लिए ढेर में उपलब्ध स्मृति नहींmallocnew
  • फंक्शन को कॉल करते समय स्टैक पर कोई जगह नहीं बची

दोनों वास्तव में AVR SRAM (2K on Arduino) के समान हैं, दोनों के लिए उपयोग किया जाता है ( स्थिर डेटा के अलावा जो प्रोग्राम निष्पादन के दौरान आकार कभी नहीं बदलता है)।

आम तौर पर, डायनेमिक मेमोरी एलोकेशन MCUs पर शायद ही कभी उपयोग किया जाता है, केवल कुछ लाइब्रेरी आमतौर पर इसका उपयोग करते हैं (उनमें से एक Stringवर्ग है, जिसका आपने उल्लेख किया है कि आप इसका उपयोग नहीं करते हैं, और यह एक अच्छा बिंदु है)।

ढेर और ढेर (के सौजन्य से नीचे चित्र में देखा जा सकता है Adafruit ): यहां छवि विवरण दर्ज करें

इसलिए, सबसे अधिक अपेक्षित मुद्दा स्टैक ओवरफ्लो से आता है (यानी जब स्टैक ढेर की ओर बढ़ता है और उस पर ओवरफ्लो होता है, और तब -if हीप का उपयोग SRAM के स्टैटिक डेटा ज़ोन पर ऑल-फ़्लो ओवरफ़्लो में नहीं किया जाता था। उस समय) आपके पास या तो उच्च जोखिम है:

  • डेटा भ्रष्टाचार (यानी ढेर ovewrites ढेर या स्थैतिक डेटा), आप बिना समझे व्यवहार दे
  • स्टैक करप्शन (यानी ढेर या स्थैतिक डेटा स्टैक सामग्री को ओवरराइट करता है), आमतौर पर क्रैश के लिए अग्रणी होता है

ढेर के शीर्ष और ढेर के शीर्ष के बीच छोड़ दी गई मेमोरी की मात्रा जानने के लिए (वास्तव में, हम इसे नीचे कह सकते हैं यदि हम ढेर और स्टैक दोनों को एक ही छवि पर दर्शाते हैं जैसा कि नीचे दर्शाया गया है), आप निम्नलिखित समारोह का उपयोग कर सकते हैं:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

ऊपर दिए गए कोड __brkvalमें, ढेर के शीर्ष को इंगित करता है, लेकिन 0जब ढेर का उपयोग नहीं किया गया है, तो उस स्थिति में हम &__heap_startकिस बिंदु का उपयोग करते हैं __heap_start, पहला चर जो कि ढेर के निचले भाग को चिह्नित करता है; &vस्टैक के शीर्ष पर निश्चित रूप से अंक (यह स्टैक पर धकेल दिया गया अंतिम चर है), इसलिए ऊपर दिए गए सूत्र स्टैक के लिए उपलब्ध मेमोरी की मात्रा (या यदि आप इसका उपयोग करते हैं तो ढेर) देता है।

आप इस फ़ंक्शन का उपयोग अपने कोड के विभिन्न स्थानों में करने की कोशिश कर सकते हैं और पता लगा सकते हैं कि यह आकार नाटकीय रूप से कम हो रहा है।

बेशक, यदि आप कभी भी इस फ़ंक्शन को एक ऋणात्मक संख्या में लौटते हुए देखते हैं तो बहुत देर हो चुकी है: आप पहले से ही स्टैक को ओवरफ्लो कर चुके हैं!


1
मॉडरेटर्स के लिए: इस पोस्ट को कम्युनिटी विकी पर डालने के लिए खेद है, मैंने पोस्ट के बीच में टाइप करते समय कुछ गलत कर दिया होगा। कृपया इसे यहां वापस करें क्योंकि यह कार्रवाई अनजाने में हुई थी। धन्यवाद।
jfpoilpret

इस उत्तर के लिए धन्यवाद, मैंने शाब्दिक रूप से केवल एक घंटे पहले कोड के उस टुकड़े को खेल के मैदान पर ( खेल के मैदान के निचले हिस्से पर पाया ।arduino.cc/Code/AvailableMemory# .UycOrueSxfg )। मैंने इसे अभी तक शामिल नहीं किया है (लेकिन मैं करूँगा) क्योंकि मेरे पास मेरे प्रदर्शन पर डिबगिंग के लिए काफी बड़ा क्षेत्र है। मुझे लगता है कि मैं गतिशील रूप से सामान असाइन करने के बारे में उलझन में हूं। है mallocऔर newमैं ऐसा कर सकता हूँ? यदि ऐसा है, तो मेरे पास कुछ भी गतिशील नहीं है। इसके अलावा, मैंने अभी सीखा है UNO में SRAM का 2K है। मुझे लगा कि यह 1K है। इन बातों को ध्यान में रखते हुए, मैं राम से नहीं भाग रहा हूँ! मुझे कहीं और देखने की जरूरत है।
मदीवाड

इसके अलावा, वहाँ भी है calloc। लेकिन आप बिना जान
बूझकर

2
दिलचस्प। केवल "समस्या" यह है कि यह उस बिंदु पर मुफ्त रैम की रिपोर्ट करता है जहां इसे कहा जाता है, इसलिए जब तक कि इसे सही हिस्से में नहीं रखा जाता है आप एक स्टैक ओवररन को नोटिस नहीं कर सकते हैं। मेरे द्वारा प्रदान किए गए फ़ंक्शन से उस क्षेत्र में एक फायदा होता है क्योंकि यह उस बिंदु तक न्यूनतम मुक्त रैम की रिपोर्ट करता है, एक बार जब एक राम पते का उपयोग किया जाता है, तो यह किसी भी लंबे समय तक मुफ्त में रिपोर्ट नहीं किया जाता है (नीचे की ओर कुछ कब्जा किया हुआ रैम हो सकता है बाइट्स जो "पेंट" मान से मेल खाते हैं और मुफ्त में रिपोर्ट किए जाते हैं)। इसके अलावा शायद एक तरीका दूसरे से बेहतर है जो एक उपयोगकर्ता चाहता है पर निर्भर करता है।
एलेक्सन_

अच्छी बात! मैंने आपके उत्तर में इस विशिष्ट बिंदु को नहीं देखा था (और मेरे लिए जो वास्तव में एक बग की तरह दिखता था), अब मैं मुक्त क्षेत्र के ऊपर "पेंटिंग" का बिंदु देखता हूं। हो सकता है कि आप अपने उत्तर में इस बिंदु को अधिक स्पष्ट कर सकें?
jfpoilpret

7

जब आप यह पता लगाते हैं कि अपनी अस्थायी निर्देशिका में उत्पन्न हुई .elf फ़ाइल का पता कैसे लगाया जाए, तो आप SRAM उपयोग को डंप करने के लिए नीचे दिए गए कमांड को निष्पादित कर सकते हैं, जहां project.elfउत्पन्न .elfफ़ाइल के साथ प्रतिस्थापित किया जाना है । इस आउटपुट का लाभ यह निरीक्षण करने की क्षमता है कि आपके SRAM का उपयोग कैसे किया जाता है। क्या सभी चर वैश्विक होने की आवश्यकता है, क्या वे वास्तव में सभी आवश्यक हैं?

avr-objdump -S -j .bss project.elf

project.elf:     file format elf32-avr


Disassembly of section .bss:

00800060 <__bss_start>:
        ...

00800070 <measurementReady>:
        ...

00800071 <cycles>:
        ...

00800073 <measurement>:
  800073:       00 00 00 00                                         ....

00800077 <measurementStart>:
  800077:       00 00 00 00                                         ....

0080007b <timerOverflows>:
  80007b:       00 00 00 00

ध्यान दें कि यह स्टैक या डायनेमिक मेमोरी के उपयोग को नहीं दिखाता है, जैसा कि इग्नासियो वाज़केज़-अब्राम्स ने नीचे टिप्पणी में दिया है।

इसके अतिरिक्त मुझे avr-objdump -S -j .data project.elfजाँच की जा सकती है, लेकिन मेरा कोई भी प्रोग्राम कुछ भी आउटपुट नहीं करता है इसलिए मैं यह सुनिश्चित करने के लिए नहीं बता सकता कि यह उपयोगी है या नहीं। यह 'आरंभीकृत (गैर-शून्य) डेटा' को सूचीबद्ध करने वाला था


या आप बस इस्तेमाल कर सकते हैं avr-size। लेकिन यह आपको गतिशील आवंटन या स्टैक उपयोग नहीं दिखाएगा।
इग्नासियो वाज़केज़-अब्राम्स

@ IgnacioVazquez- डायनामिक्स के बारे में अब्राम, मेरे समाधान के लिए समान है। मेरे उत्तर का संपादन किया।
जिप्पी

ठीक है, यह अब तक का सबसे दिलचस्प जवाब है। मैंने प्रयोग किया है avr-objdumpऔर avr-sizeमैं अपनी पोस्ट को शीघ्र ही संपादित करूंगा। इसके लिए धन्यवाद।
मदिवाड

3

मुझे थोड़ी देर के लिए संदेह हुआ कि मैं उपलब्ध रैम के अंत तक पहुंच रहा हूं। मुझे नहीं लगता कि मैं बहुत अधिक स्टैक का उपयोग कर रहा हूं (हालांकि यह संभव है), यह निर्धारित करने का सबसे अच्छा तरीका है कि मैं वास्तव में कितना रैम का उपयोग कर रहा हूं?

मैन्युअल अनुमान के संयोजन और sizeofऑपरेटर का उपयोग करके उपयोग करना सबसे अच्छा होगा । यदि आपकी सभी घोषणाएं स्थिर हैं, तो यह आपको एक सटीक तस्वीर देनी चाहिए।

यदि आप डायनेमिक एलोकेशन का उपयोग कर रहे हैं, तो मेमोरी को डिस्लोकेट करने के बाद आप एक समस्या में भाग सकते हैं। यह ढेर पर स्मृति विखंडन के कारण है।

के माध्यम से जा रहे हैं और इसे बाहर काम करने की कोशिश कर रहा है, मैं जब मैं enums और संरचनाओं के लिए समस्या है; उनकी कितनी मेमोरी है?

एक एनुम एक के रूप में ज्यादा जगह लेता है int। इसलिए, यदि आपके पास एक enumघोषणा में 10 तत्वों का एक सेट है , तो यह होगा 10*sizeof(int)। इसके अलावा, प्रत्येक चर जो एक एन्यूमरेशन का उपयोग करता है, बस एक है int

संरचनाओं के लिए, यह sizeofपता लगाने के लिए उपयोग करना सबसे आसान होगा । संरचनाएं अपने सदस्यों के योग के बराबर (न्यूनतम) स्थान रखती हैं। यदि संकलक संरचना संरेखण करता है, तो यह अधिक हो सकता है, हालांकि इस मामले में संभावना नहीं है avr-gcc


मैं जहां तक ​​हो सकता है सब कुछ सांख्यिकीय रूप से असाइन करता हूं। मैंने sizeofइस उद्देश्य के लिए उपयोग करने के बारे में कभी नहीं सोचा था । फिलहाल, मेरे पास लगभग 400 बाइट्स पहले से ही (विश्व स्तर पर) हैं। अब मैं एनमोंस (मैन्युअल रूप से) और स्ट्रक्चर्स (जिनमें से मेरे पास कुछ है- और मैं उपयोग करूँगा sizeof) की गणना करके वापस रिपोर्ट करूँगा ।
मदिवाड

निश्चित रूप से आपको sizeofअपने स्थिर डेटा का आकार जानने की आवश्यकता नहीं है क्योंकि यह avrdude IIRC द्वारा मुद्रित होता है।
jfpoilpret

@jfpoilpret यह संस्करण निर्भर है, मुझे लगता है। सभी संस्करण और प्लेटफ़ॉर्म प्रदान नहीं करते हैं। मेरा (लिनक्स, कई संस्करण) एक के लिए मेमोरी उपयोग नहीं दिखाते हैं, जबकि मैक संस्करण करते हैं।
असीर्र

मैंने वर्बोज़ आउटपुट खोजा है, मैंने सोचा कि यह वहाँ होना चाहिए, यह नहीं है
Madivad

@AsheeshR मुझे इस बात की जानकारी नहीं थी कि, मेरा विंडोज पर काम ठीक है।
jfpoilpret

1

Arduino Builder नामक एक प्रोग्राम है जो आपके प्रोग्राम का उपयोग कर रहे फ़्लैश, SRAM और EEPROM की मात्रा का एक साफ-सुथरा दृश्य प्रदान करता है।

Arduino बिल्डर

Arduino बिल्डर CodeBlocks Arduino IDE समाधान का हिस्सा बनाता है । इसका उपयोग या तो स्टैंडअलोन प्रोग्राम के रूप में या कोडब्लॉक अरुडिनो आईडीई के माध्यम से किया जा सकता है।

दुर्भाग्य से Arduino बिल्डर थोड़ा पुराना है, लेकिन इसे अधिकांश कार्यक्रमों और अधिकांश Arduinos, जैसे कि Uno के लिए काम करना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.