जब कोई इनपुट बदलता है, तो क्या किसी फ़ंक्शन को स्वचालित रूप से कहा जा सकता है?


21

वर्तमान में, मेरा स्केच हर बार मुख्य लूप के चक्कर में एक इनपुट पिन की जाँच कर रहा है। यदि यह किसी परिवर्तन का पता लगाता है, तो यह प्रतिक्रिया करने के लिए एक कस्टम फ़ंक्शन को कॉल करता है। यहाँ कोड (आवश्यक के लिए छंटनी की गई है):

int pinValue = LOW;

void pinChanged()
{
    //...
}

void setup()
{
    pinMode(2, INPUT);
}

void loop()
{
    // Read current input
    int newValue = digitalRead(2);

    // Has the input changed?
    if (newValue != pinValue) {
        pinValue = newValue;
        pinChanged();
    }
}

दुर्भाग्य से, यह हमेशा इनपुट (जैसे संक्षिप्त दालों) पर बहुत कम बदलावों के लिए ठीक से काम नहीं करता है, खासकर अगर loop()थोड़ा धीरे चल रहा है।

क्या Arduino को इनपुट परिवर्तन का पता लगाने और मेरे फ़ंक्शन को स्वचालित रूप से कॉल करने का एक तरीका है?


1
आप इसके लिए एक बाहरी अवरोधन
बट्ज़के

जवाबों:


26

आप बाहरी रुकावटों का उपयोग करके ऐसा कर सकते हैं। हालांकि ज्यादातर Arduinos सीमित संख्या में पिनों पर इसका समर्थन करते हैं। पूर्ण विवरण के लिए, दस्तावेज़ीकरण देखें attachInterrupt()

मान लें कि आप एक यूनो का उपयोग कर रहे हैं, तो आप इसे इस तरह कर सकते हैं:

void pinChanged()
{
    //...
}

void setup()
{
    pinMode(2, INPUT);
    attachInterrupt(0, pinChanged, CHANGE);
}

void loop()
{
}

pinChanged()जब भी बाहरी व्यवधान पर परिवर्तन का पता चलता है तो यह कॉल करेगा । Uno पर, जो GPIO पिन से मेल खाती है। 2. अन्य बोर्ड पर बाहरी अवरोध नंबरिंग अलग है, इसलिए संबंधित दस्तावेज की जांच करना महत्वपूर्ण है।

हालांकि इस दृष्टिकोण की सीमाएँ हैं। कस्टम pinChanged()फ़ंक्शन का उपयोग इंटरप्ट सर्विस सर्विस (ISR) के रूप में किया जा रहा है। इसका मतलब है कि loop()कॉल निष्पादित होते समय बाकी कोड (सब कुछ ) अस्थायी रूप से बंद हो जाता है। किसी भी महत्वपूर्ण समय को बाधित करने से रोकने के लिए, आपको आईएसआर को यथासंभव तेज बनाने का लक्ष्य रखना चाहिए।

यह भी ध्यान रखना महत्वपूर्ण है कि आपके ISR के दौरान कोई अन्य व्यवधान नहीं चलेगा। इसका मतलब है कि कुछ भी बाधित होने पर (जैसे कि कोर delay()और millis()फ़ंक्शन) इसके अंदर ठीक से काम नहीं कर सकते हैं।

अंत में, यदि आपके ISR को स्केच में किसी भी वैश्विक चर को बदलने की आवश्यकता है, तो उन्हें आमतौर पर घोषित किया जाना चाहिए volatile, जैसे:

volatile int someNumber;

यह महत्वपूर्ण है क्योंकि यह संकलक को बताता है कि मूल्य अप्रत्याशित रूप से बदल सकता है, इसलिए यह सावधान रहना चाहिए कि इसकी कोई भी आउट-ऑफ-डेट प्रतियां / कैश का उपयोग न करें।


प्रश्न में उल्लिखित "संक्षिप्त दालों" के बारे में, क्या पिन को बाधित करने के लिए एक न्यूनतम समय होना चाहिए? (जाहिर है कि यह मतदान से बहुत कम होगा, जो इस बात पर निर्भर करता है कि लूप में और क्या हो रहा है)
सैचलेन

1
@ साचलेन वह तब तक काम करेगा जब तक कि वह ISR फ़ंक्शन के निष्पादन के दौरान नहीं होता (जैसा कि उत्तर में समझाया गया है); इसलिए pinChanged()जितना संभव हो उतना कम होना चाहिए। इसलिए आमतौर पर न्यूनतम समय pinChanged()फ़ंक्शन को निष्पादित करने का समय होना चाहिए ।
jfpoilpret

2
इस बहुत विस्तृत जवाब के लिए +1 जिसमें सभी अहितकर सामान शामिल हैं, एक का उपयोग करते समय ध्यान रखना चाहिए!
jfpoilpret

3
साझा किए गए ग्लोबल्स को घोषित करने के अलावा volatile, अगर वैश्विक चर 1 बाइट से अधिक व्यापक है, जैसा कि कुछ नॉनम्बर है, तो आपको प्रोग्राम द्वारा बाइट एक्सेस के बीच होने वाले पिन-चेंज रुकावट से बचाव करना चाहिए। someNumber +=5;कम बाइट्स को शामिल करने और कैरी के साथ हाई बाइट्स को जोड़ने जैसा बयान शामिल है। इन दो (अधिक, व्यापक चर के लिए) को एक व्यवधान से विभाजित नहीं किया जाना चाहिए। ऑपरेशन से पहले और बाद में (बीच में) पर्याप्त होने पर उन्हें बाधित करना और उन्हें बहाल करना पर्याप्त है।
JRobert

@ साचलेन - न्यूनतम पल्स आकार के बारे में। डेटशीट में एक निश्चित उत्तर ढूंढना कठिन है, लेकिन पिन-चेंज इंटरप्ट के लिए समय से देखते हुए, उन्हें आधे घड़ी के चक्र के भीतर लगाया जाता है। एक बार जब बाधा को "याद" किया जाता है, तो यह तब तक याद किया जाता है जब तक कि ISR किक नहीं मारता और इससे निपटता है।
निक गैमन

5

डिजिटल इनपुट के रूप में कॉन्फ़िगर किए गए किसी भी पिन पर परिवर्तन की कोई भी स्थिति एक रुकावट पैदा कर सकती है। INT1 या INT2 के कारण अवरोधक के लिए अद्वितीय वैक्टर के विपरीत PinChangeInt सुविधा इस वेक्टर के लिए एक आम वेक्टर और फिर इंटरप्ट सर्विस सर्विस (उर्फ ISR) का उपयोग करती है, फिर यह निर्धारित करने के लिए कि पिन बदल गया है।

सौभाग्य से PinChangeInt लाइब्रेरी इसे आसान बनाती है।

PCintPort::attachInterrupt(PIN, burpcount,RISING); // attach a PinChange Interrupt to our pin on the rising edge
// (RISING, FALLING and CHANGE all work with this library)
// and execute the function burpcount when that pin changes

0

इस घटना में कि आप केवल उच्च या कम होने के बजाय एक दहलीज से गुजरने वाले वोल्टेज का पता लगाना चाहते हैं , आप एनालॉग तुलनित्र का उपयोग कर सकते हैं। उदाहरण स्केच:

volatile boolean triggered;

ISR (ANALOG_COMP_vect)
  {
  triggered = true;
  }

void setup ()
  {
  Serial.begin (115200);
  Serial.println ("Started.");
  ADCSRB = 0;           // (Disable) ACME: Analog Comparator Multiplexer Enable
  ACSR =  bit (ACI)     // (Clear) Analog Comparator Interrupt Flag
        | bit (ACIE)    // Analog Comparator Interrupt Enable
        | bit (ACIS1);  // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on falling edge)
   }  // end of setup

void loop ()
  {
  if (triggered)
    {
    Serial.println ("Triggered!"); 
    triggered = false;
    }

  }  // end of loop

यह प्रकाश-डिटेक्टरों जैसी चीजों के लिए उपयोगी हो सकता है, जहां आपको इनपुट पर (कह) 1 वी से 2 वी के बदलाव का पता लगाने की आवश्यकता हो सकती है।

उदाहरण सर्किट:

यहां छवि विवरण दर्ज करें

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

समय-महत्वपूर्ण अनुप्रयोगों के लिए, यह कुछ हद तक सटीकता दे सकता है।

उदाहरण आवेदन: अपने Arduino को संधारित्र परीक्षक में बदल दें

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