सामान्य ISR की तरह AVR वॉचडॉग का उपयोग करें


17

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

क्या WDT का उपयोग करने का कोई तरीका है जैसे आप TIMER1_COMPA_vect या इसी तरह का होगा। मैंने देखा कि इसमें 1 सेकंड का टाइमआउट मोड है और मैं वास्तव में इसका उपयोग करने में सक्षम होना पसंद करूंगा कि मेरे कोड में हर 1 सेकंड में कुछ हो सके (और बीच में अधिमानतः सो जाओ)।

विचार?

* अद्यतन: * चूंकि यह पूछा गया था, मैं जो बात कर रहा हूं वह ATTinyX5 डेटाशीट के खंड 8.4 है । ऐसा नहीं है कि मैं इसे पूरी तरह से समझता हूं, जो मेरी समस्या है ...


1
बॉक्स के बाहर सोचने के लिए +1। यदि आप AVR के लिए डेटा पत्रक के लिए एक लिंक जोड़ते हैं, तो अतिरिक्त अंगूठे।
जिप्पी

जवाबों:


23

आप सबसे निश्चित रूप से कर सकते हैं। डेटाशीट के अनुसार, वॉचडॉग टाइमर को MCU को रीसेट करने के लिए सेटअप किया जा सकता है या ट्रिगर होने पर एक बाधा पैदा कर सकता है। ऐसा लगता है कि आप रुकावट की संभावना में अधिक रुचि रखते हैं।

WDT वास्तव में एक सामान्य टाइमर की तुलना में सेटअप करना आसान है उसी कारण से यह कम उपयोगी है: कम विकल्प। यह आंतरिक रूप से कैलिब्रेटेड 128kHz घड़ी पर चलता है, जिसका अर्थ है कि MCU की मुख्य घड़ी की गति से इसका समय प्रभावित नहीं होता है। यह जागृत स्रोत प्रदान करने के लिए गहरी नींद मोड के दौरान भी जारी रह सकता है।

मैं डेटशीट के उदाहरणों के एक जोड़े के साथ-साथ कुछ कोड भी इस्तेमाल करूंगा जो मैंने (सी में) उपयोग किए हैं।

शामिल फ़ाइलें और परिभाषाएँ

शुरू करने के लिए, आप संभवतः काम करने के लिए निम्नलिखित दो हेडर फ़ाइलों को शामिल करना चाहेंगे:

#include <avr/wdt.h>        // Supplied Watch Dog Timer Macros 
#include <avr/sleep.h>      // Supplied AVR Sleep Macros

इसके अलावा, मैं मैक्रो <_BV (BIT)> का उपयोग करता हूं, जिसे मानक AVR हेडर में से एक के रूप में परिभाषित किया गया है (जो आपके लिए अधिक पारिवारिक हो सकता है):

#define _BV(BIT)   (1<<BIT)

कोड की शुरुआत

जब MCU पहली बार शुरू किया जाता है, तो आप आम तौर पर I / O को इनिशियलाइज़ करेंगे, टाइमर सेट करेंगे, आदि कहीं न कहीं यह सुनिश्चित करने के लिए एक अच्छा समय है कि WDT को रीसेट करने का कारण नहीं बने क्योंकि यह फिर से कर सकता है, आपके प्रोग्राम को ध्यान में रखते हुए। एक अस्थिर लूप।

if(MCUSR & _BV(WDRF)){            // If a reset was caused by the Watchdog Timer...
    MCUSR &= ~_BV(WDRF);                 // Clear the WDT reset flag
    WDTCSR |= (_BV(WDCE) | _BV(WDE));   // Enable the WD Change Bit
    WDTCSR = 0x00;                      // Disable the WDT
}

WDT सेटअप

फिर, आपके द्वारा बाकी चिप को सेटअप करने के बाद, WDT को फिर से करें। WDT को सेट करने के लिए "समयबद्ध अनुक्रम" की आवश्यकता होती है, लेकिन यह करना आसान है ...

// Set up Watch Dog Timer for Inactivity
WDTCSR |= (_BV(WDCE) | _BV(WDE));   // Enable the WD Change Bit
WDTCSR =   _BV(WDIE) |              // Enable WDT Interrupt
           _BV(WDP2) | _BV(WDP1);   // Set Timeout to ~1 seconds

बेशक, इस कोड के दौरान आपके इंटरप्ट को अक्षम किया जाना चाहिए। बाद में उन्हें फिर से सक्षम करना सुनिश्चित करें!

cli();    // Disable the Interrupts
sei();    // Enable the Interrupts

WDT इंटरप्ट सर्विस रूटीन चिंता की अगली बात WDT ISR संभाल रही है। यह इस प्रकार किया जाता है:

ISR(WDT_vect)
{
  sleep_disable();          // Disable Sleep on Wakeup
  // Your code goes here...
  // Whatever needs to happen every 1 second
  sleep_enable();           // Enable Sleep Mode
}

MCU नींद

WDT ISR के अंदर सोने के लिए MCU लगाने के बजाय, मैं बस ISR के अंत में स्लीप मोड को सक्षम करने की सलाह देता हूं, फिर MAIN प्रोग्राम को MCU को सोने के लिए रखा है। इस तरह, कार्यक्रम वास्तव में आईएसआर छोड़ने से पहले सो रहा है, और यह जाग जाएगा और सीधे डब्ल्यूडीटी आईएसआर में वापस चला जाएगा।

// Enable Sleep Mode for Power Down
set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // Set Sleep Mode: Power Down
sleep_enable();                     // Enable Sleep Mode  
sei();                              // Enable Interrupts 

/****************************
 *  Enter Main Program Loop  *
 ****************************/
 for(;;)
 {
   if (MCUCR & _BV(SE)){    // If Sleep is Enabled...
     cli();                 // Disable Interrupts
     sleep_bod_disable();   // Disable BOD
     sei();                 // Enable Interrupts
     sleep_cpu();           // Go to Sleep

 /****************************
  *   Sleep Until WDT Times Out  
  *   -> Go to WDT ISR   
  ****************************/

   }
 }

वाह ... बहुत विस्तृत। धन्यवाद! मैं स्लीप सेक्शन से थोड़ा भ्रमित हूँ जहाँ आप मुख्य लूप दिखाते हैं (यदि (MCUCR और _BV (SE)) {// यदि स्लीप सक्षम है ... आदि) मैं उलझन में हूँ कि आप मुख्य लुक में क्यों हैं लगातार अक्षम और सक्षम व्यवधान। और उस भाग के शीर्ष पर (set_sleep_mode (SLEEP_MODE_PWR_DOWN);) वह भाग कहाँ होना चाहिए?
एडम हैले

ठीक है, "set_sleep_mode (MODE)" भाग मुख्य मुख्य लूप में होना चाहिए, आदर्श रूप से अन्य इनिशियलाइज़ेशन कोड में जहाँ आप I / O पोर्ट, टाइमर आदि सेटअप करते हैं, आपको वास्तव में enable_leepep () की आवश्यकता नहीं है; उस बिंदु पर, क्योंकि यह आपके पहले डब्ल्यूडीटी ट्रिगर के बाद किया जाएगा। मुख्य लूप के अंदर, वह स्लीप कोड केवल निष्पादित करेगा यदि स्लीप को सक्षम किया गया है, और यह पूरी तरह से निष्क्रिय करने / पुन: प्रयोज्य करने के लिए आवश्यक नहीं है, केवल तभी जब आप स्लीप_बोड_डिसिबल () कर रहे हों; वह संपूर्ण IF स्टेटमेंट किसी अन्य कोड के बाद MAIN लूप के निचले (लेकिन अभी भी अंदर) तल पर हो सकता है।
कर्ट ई। क्लोथियर

ठीक है ... जो अब अधिक समझ में आता है। केवल आखिरी बात मैं फजी हूँ, यह "समयबद्ध अनुक्रम" क्या है ...
एडम हैले

साइड नोट: मुझे पता है कि आप क्यों सोना चाहते हैं, लेकिन मैं मानता हूं कि आपको WDT का उपयोग करते समय नहीं करना है?
एडम हैले

डेटाशीट के इस छोटे से भाग पर एक नज़र डालें: 8.4.1। मूल रूप से, WDT रजिस्टर को बदलने के लिए, आपको परिवर्तन बिट सेट करना होगा और फिर इतने सारे घड़ी चक्रों में उचित WDTCR बिट्स सेट करना होगा। WDT सेटअप सेक्शन में जो कोड मैंने दिया था, वह पहले WD चेंज बिट को इनेबल करके करता है। और नहीं, आपको डब्ल्यूडीटी के साथ नींद की कार्यक्षमता का उपयोग करने की आवश्यकता नहीं है। यह जो भी कारण आप चाहते हैं के लिए एक मानक समयबद्ध बाधा स्रोत हो सकता है।
कर्ट ई। क्लोथियर

1

डेटशीट के अनुसार यह संभव है। आप एक अवरोध और रीसेट दोनों को भी सक्षम कर सकते हैं। यदि दोनों सक्षम हैं, तो पहला वॉचडॉग टाइमआउट उस रुकावट को ट्रिगर करेगा जो इंटरप्ट इनेबल बिट को परेशान करने में सक्षम बनाता है (व्यवधान अक्षम)। अगला टाइमआउट तब आपके CPU को रीसेट करेगा। यदि आप इंटरप्ट को सीधे निष्पादित करने के बाद सक्षम करते हैं, तो अगली टाइमआउट (फिर से) केवल एक बाधा को ट्रिगर करेगा।

आप केवल व्यवधान को सक्षम कर सकते हैं और रीसेट को बिल्कुल भी सक्षम नहीं कर सकते। जब भी व्यवधान उत्पन्न हो, आपको हर बार WDIE बिट सेट करना होगा।


हम्मम .... मुझे लगता है कि समझ में आता है। मैं इसे एक शॉट दूँगा। मैं हमेशा उन चीजों का उपयोग करना पसंद करता हूं जो वे इरादा नहीं थे :)
एडम हैले

वास्तव में मुझे लगता है कि यह एक चतुर डिजाइन है। वॉचडॉग कार्यक्षमता रखते हुए आपको एक टाइमर बचाता है।
टॉम एल।

2
डब्लूडीटी का यह शुरुआती समय और उसके बाद का व्यवधान कुछ अनुप्रयोगों के लिए लाभ के लिए भी इस्तेमाल किया जा सकता है जो वास्तविक हैंगअप वसूली के लिए डब्लूडीटी को सक्षम कर रहे हैं। WDT ISR में स्टैक किए गए रिटर्न एड्रेस को देखने के लिए यह पता लगाने की कोशिश करता है कि "अनपेक्षित टाइमआउट" होने पर कोड क्या करने की कोशिश कर रहा था।
माइकल करस

1

यह ऊपर और अन्य जगहों पर सुझाए गए की तुलना में बहुत आसान है।

जब तक WDTONफ्यूज को प्रोग्राम नहीं किया जाता है (यह डिफ़ॉल्ट रूप से प्रोग्राम नहीं किया जाता है), तब तक आपको केवल ...

  1. वॉचडॉग सेट को सक्षम करें और वॉचडॉग नियंत्रण रजिस्टर में टाइमआउट सक्षम करें।
  2. बीच में सक्षम करें।

यहां एक कोड उदाहरण दिया गया है जो 16ms के अनुसार एक बार ISR निष्पादित करेगा ...

ISR(WDT_vect) {
   // Any code here will get called each time the watchdog expires
}

void main(void) {
   WDTCR =  _BV(WDIE);    // Enable WDT interrupt, leave existing timeout (default 16ms) 
   sei();                                           // Turn on global interrupts
   // Put any code you want after here.
   // You can also go into deep sleep here and as long as 
   // global interrupts are eneabled, you will get woken 
   // up when the watchdog timer expires
   while (1);
}

वाकई ऐसा है। चूंकि हम वॉचडॉग रीसेट को कभी भी सक्षम नहीं करते हैं, हमें इसे अक्षम करने के लिए समयबद्ध दृश्यों के साथ गड़बड़ नहीं करना है। जब ISR कहा जाता है, तो वॉचडॉग बाधा ध्वज स्वचालित रूप से साफ़ हो जाता है।

यदि आप हर 1 सेकंड से अलग अवधि चाहते हैं, तो आप इन मानों का उपयोग यहां किए जा सकने वाले बिट्स में सेट करने के लिए कर सकते हैं WDTCR...

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

ध्यान दें कि आपको टाइमआउट बदलने के लिए समयबद्ध अनुक्रम निष्पादित करने की आवश्यकता है। यहाँ कोड है जो 1 सेकंड का समय निर्धारित करता है ...

   WDTCR = _BV(WDCE) | _BV(WDE);                   // Enable changes
   WDTCR = _BV(WDIE) | _BV( WDP2) | _BV( WDP1);    // Enable WDT interrupt, change timeout to 1 second

सेटअप के दौरान समयबद्ध अनुक्रम का प्रदर्शन नहीं करना कोड की एक पंक्ति को बचाता है - एक रीड-संशोधित-राइट ऑपरेशन। डेटशीट में प्रारंभिक अनुक्रम की सिफारिश की जाती है "यदि वॉचडॉग गलती से सक्षम है, उदाहरण के लिए एक रनवे पॉइंटर या ब्राउन-आउट स्थिति" और मेरे बाकी कोड स्लीप मोड के साथ संयोजन में WDT का उपयोग करने के लिए विशिष्ट है, जैसा कि अनुरोध किया गया है। ओ.पी. आपका समाधान सरल नहीं है, आपने केवल अनुशंसित / आवश्यक बॉयलर प्लेट कोड की उपेक्षा की है।
कर्ट ई। क्लोथियर

@ KurtE.Clothier क्षमा करें, बस सबसे सरल काम उदाहरण देने की कोशिश कर रहा है!
बिगजॉश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.