माइक्रोकंट्रोलर में मल्टीटास्किंग के बारे में थोड़ा सा

मल्टीटास्किंग के बारे में थोड़ा सा


हर कोई जो दिन-प्रतिदिन, या केस-केस से, माइक्रोकंट्रोलर प्रोग्रामिंग में लगा हुआ है, जल्दी या बाद में इस सवाल का सामना करेगा: क्या मुझे मल्टी-टास्किंग ऑपरेटिंग सिस्टम का उपयोग करना चाहिए? नेटवर्क पर उनमें से बहुत सारे हैं, और उनमें से बहुत सारे मुफ्त (या लगभग मुफ्त) हैं। बस चुनो।


इसी तरह की शंकाएँ तब होती हैं जब आप एक ऐसी परियोजना में आते हैं जिसमें माइक्रोकंट्रोलर को एक साथ कई अलग-अलग क्रियाएं करनी होती हैं। उनमें से कुछ दूसरों के साथ नहीं जुड़े हैं, जबकि बाकी, इसके विपरीत, एक दूसरे के बिना नहीं कर सकते। इसके अलावा, दोनों के बहुत सारे हो सकते हैं। "बहुत अधिक" क्या इस बात पर निर्भर करता है कि कौन मूल्यांकन करेगा या कौन विकास करेगा। ठीक है, अगर यह एक ही व्यक्ति है।


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


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


लेकिन अगर आप माइक्रोकंट्रोलर के लिए तैयार ऑपरेटिंग सिस्टम का उपयोग करते हैं तो क्या होगा? ज़रूर, कई करते हैं। यह एक अच्छा विकल्प है। लेकिन इन पंक्तियों के लेखक, अब तक, इस विचार से रोका और जारी रखा गया है कि यह समझने के लिए आवश्यक होगा कि, बहुत समय बिताने के बाद, उस चीज़ को चुनें जो हम प्राप्त करने में कामयाब रहे और केवल उसी से उपयोग करें जो वास्तव में इस से जरूरी है। और यह सब, तुम मन करो, किसी और के कोड में delving! और कोई निश्चितता नहीं है कि छह महीने में इसे दोहराना नहीं होगा, क्योंकि यह भूल जाएगा।


दूसरे शब्दों में, यदि आपको एक साइकिल संग्रहीत और उपयोग की जाती है, तो आपको उपकरण और जुड़नार के पूर्ण गेराज की आवश्यकता क्यों है?


इसलिए, केवल कॉर्टेक्स-एम 4 (ठीक है, शायद एम 3 और एम 7 के लिए भी) के लिए एक सरल "स्विच" कार्य करने की इच्छा थी। लेकिन पुरानी, ​​अच्छी इच्छा बहुत तनाव नहीं गायब हो गई।


तो, हम सबसे सरल करते हैं। कार्यों की एक छोटी संख्या समान रूप से निष्पादन समय को साझा करती है। जैसा कि नीचे चित्र 1 में, चार कार्य यह करते हैं। मुख्य को शून्य होने दें, क्योंकि दूसरे की कल्पना करना मुश्किल है।



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


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


और कार्य को करने दें, अगर इसका अब तक कोई लेना-देना नहीं है, तो टिक से बचे हुए समय को अपने साथियों को दे दें, जो सबसे अधिक संभावना है, अपनी पूरी शक्ति के साथ।


दूसरे शब्दों में, साझा करना आवश्यक है। कार्य 2 को चित्र 2 की तरह ही करें।



और क्यों हमारे बैकग्राउंड टास्क मेन को बाकी समय देने की अनुमति नहीं दी जानी चाहिए, अगर आपको अभी भी इंतजार करना है? चलिए इजाजत देते हैं। जैसा कि चित्र 3 में दिखाया गया है।



और अगर आप जानते हैं कि कुछ कार्यों को जल्द ही आपको फिर से कुछ जांचने या बस काम करने की आवश्यकता नहीं होगी? और वह खुद को थोड़ा सोने की अनुमति दे सकती थी, और इसके बजाय समय बर्बाद करती और अपने पैरों के नीचे हो जाती। आदेश नहीं, इसे ठीक करने की आवश्यकता है। कार्य 3 को उसके समय के एक टुकड़े (या एक हजार) को याद करने दें। जैसा कि चित्र 4 में दिखाया गया है।



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


स्टैक के लिए, हम रैम के एक सामान्य क्षेत्र का चयन करते हैं, जो मेमोरी एड्रेस को कम करने की दिशा में भर देगा। क्यों? सिर्फ इसलिए कि यह अलग तरह से काम नहीं करता है। हम इस महत्वपूर्ण क्षेत्र को अपने कार्यों की घोषित अधिकतम संख्या के अनुसार मानसिक रूप से समान वर्गों में विभाजित करेंगे। चित्र 5 इसे चार कार्यों के लिए दिखाता है।



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


संभवतः, यह कहना अतिश्योक्तिपूर्ण होगा कि कतार में टास्क 3 के बाद अगला मुख्य होगा। और निश्चित रूप से, यह याद रखना अतिश्योक्तिपूर्ण नहीं है कि Cortex-M4 में पहले से ही SysTick टाइमर और उससे एक विशेष रुकावट है, और कई माइक्रोकंट्रोलर निर्माता इसके बारे में जानते हैं। हम इसे और इस रुकावट के रूप में उपयोग करेंगे।


इस सिस्टम टाइमर को शुरू करने के लिए, साथ ही साथ सभी आवश्यक तैयारी और जांच करें, आपको इसके लिए इच्छित प्रक्रिया का उपयोग करना चाहिए।


U8 main_start_task_switcher(void); 

यह रुटीन 0 हो जाता है यदि सभी चेक पास हो गए हैं, या कुछ गलत हो गया है तो त्रुटि कोड। यह जांच की जाती है, मूल रूप से, क्या स्टैक सही ढंग से गठबंधन किया गया है और क्या इसके लिए पर्याप्त जगह है, और हमारे सभी विशेष स्थान प्रारंभिक मानों से भरे हुए हैं। संक्षेप में, बोरियत।


यदि कोई कार्यक्रम के पाठ को देखना चाहता है, तो कथन के अंत में वह आसानी से ऐसा कर पाएगा, उदाहरण के लिए, व्यक्तिगत मेल के माध्यम से।


हां, मैं पूरी तरह से भूल गया जब हम उसके जीवन में पहली बार भंडारण से अगले कार्य के रजिस्टरों को लेते हैं, यह आवश्यक है कि उन्हें सार्थक मूल मूल्य मिले। और जब से, वह उन्हें ढेर के अपने खंड से उठाएगा, आपको उन्हें पहले से वहां रखना होगा और उसके स्टैक पॉइंटर को स्थानांतरित करना होगा ताकि इसे लेना सुविधाजनक हो। इसके लिए हमें एक प्रक्रिया की आवश्यकता है


  U8 task_run_and_return_task_number(U32 taskAddress); 

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


प्राथमिकताओं के बारे में कुछ शब्द। मुख्य प्राथमिकता थी और अनावश्यक विवरणों के साथ पाठक को अधिभार न देना।


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


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


मैं बात नहीं करना चाहता था, लेकिन मुझे करना पड़ा। हमारे प्रोसेसर के दो ऑपरेटिंग मोड हैं: विशेषाधिकार प्राप्त और गैर-विशेषाधिकार प्राप्त। और स्टैक पॉइंटर के लिए भी दो रजिस्टर:
मुख्य एसपी और एसपी प्रक्रिया। इसलिए, हम trifles के लिए विनिमय नहीं करेंगे, हम केवल विशेषाधिकार प्राप्त मोड और केवल मुख्य स्टैक पॉइंटर का उपयोग करेंगे। इसके अलावा, यह सब पहले से ही नियंत्रक की शुरुआत में दिया गया है। इसलिए, हम अपने जीवन को जटिल नहीं करेंगे।


यह याद है कि हर कार्य, निश्चित रूप से, हर चीज को नरक में फेंकने और आराम करने के लिए कैसे सक्षम होना चाहिए। और यह हमारे टिक के दौरान, कार्य दिवस के दौरान किसी भी समय हो सकता है। कॉर्टेक्स-एम 4 ऐसे मामलों के लिए एक विशेष कोडांतरक कमांड एसवीसी प्रदान करता है, जिसे हम अपनी स्थिति के अनुकूल बनाएंगे। यह एक रुकावट की ओर ले जाता है जो हमें लक्ष्य तक ले जाएगा। और हम कार्य को न केवल दोपहर के भोजन के बाद कार्यस्थल छोड़ने की अनुमति देंगे, बल्कि कल नहीं आने देंगे। क्यों, इसे छुट्टियों के बाद आने दो। और यदि आवश्यक हो, तो मरम्मत पूरी होने पर उसे आने दें या बिल्कुल न आएं। ऐसा करने के लिए, एक प्रक्रिया है जो कार्य स्वयं का कारण बन सकती है।


  void release_me_and_set_sleep_period(U32 ticks); 

इस दिनचर्या को केवल यह इंगित करने की आवश्यकता है कि कितने टिक्स को आराम करने की योजना है। यदि 0 है, तो आप केवल शेष वर्तमान टिक को आराम कर सकते हैं। यदि 0xFFFFFFFF है, तो कार्य तब तक "सो" जाएगा जब तक कि कोई जाग न जाए। अन्य सभी संख्याएं उन टिकों की संख्या को इंगित करती हैं जिनके दौरान कार्य नींद की स्थिति में होगा।


किसी और के पक्ष में जागने या उसे नींद लाने में सक्षम होने के लिए, मुझे ऐसी प्रक्रियाओं को जोड़ना पड़ा।


  void task_wake_up_action(U8 taskNumber); void set_task_sleep_period(U8 taskNumber, U32 ticks); 

और, बस मामले में, यहां तक ​​कि इस तरह के एक सबरूटीन।


  void task_remove_action(U8 taskNumber); 

मोटे तौर पर, वह कर्मचारियों की सूची से एक कार्य को पार कर जाती है। ईमानदारी से, मुझे अभी तक पता नहीं है कि मैंने इसे क्यों लिखा है। अचानक काम आ गया?


यह दिखाने का समय है कि किस तरह से एक कार्य को दूसरे द्वारा प्रतिस्थापित किया जाता है, अर्थात, स्विच खुद ही दिखता है।


बस मामले में, आइए याद करते हैं कि कुछ रजिस्टरों, जब एक बाधा में प्रवेश करते हैं, तो हमारी भागीदारी के बिना स्टैक पर सहेजे जाते हैं, स्वचालित रूप से (जैसा कि कॉर्टेक्स-एम 4 में प्रथागत है)। इसलिए, हमें केवल बाकी को बचाने की आवश्यकता है। इसे नीचे देखा जा सकता है। आप जो देखते हैं, उससे चिंतित न हों, ये कॉर्टेक्स-एम 4 एसेंबलर निर्देश (एम 3, एम 7) हैं, जैसा कि आईएआर एंबेडेड वर्कबेंच द्वारा उल्लिखित है।


जिन लोगों को अभी तक विधानसभा निर्देशों का सामना नहीं करना पड़ा है, बस मेरा विश्वास करो, वे वास्तव में इस तरह दिखते हैं। ये वे अणु हैं जो एआरएम कोर्टेक्स-एम 4 के तहत कोई भी कार्यक्रम बनाते हैं।


 SysTick_Handler STMDB SP!,{R4-R11} ;   LDR R0,=timersTable ;    LDR R1,=stacksTable ;    LDR R2,[R0] ;R2   ()  STR SP,[R1,R2,LSL #2] ;   SP (R2 * 4) __st_next_check ADD R2,R2,#1 ;   CMP R2,#TASKS_LIMIT ;R2-TASKS_LIMIT  BLO __st_no_border_yet ;   MOV R2,#0 ;    (main) LDR R3,[R1] ; main SP MOV SP,R3 B __st_timer_ok __st_no_border_yet ;; LDR SP,[R1,R2,LSL #2] ;    (errata Cortex M4) ;; CMP SP,#0 ; LDR R3,[R1,R2,LSL #2] ;  SP      CMP R3,#0 ; =0     BEQ __st_next_check MOV SP,R3 LDR R3,[R0,R2,LSL #2] ;  suspend timer CBZ R3,__st_timer_ok ; 0    ,   ; CMP R3,#0xFFFFFFFF ; ,   BEQ __st_next_check SUB R3,R3,#1 ;  1 STR R3,[R0,R2,LSL #2] ;  suspend timer B __st_next_check __st_timer_ok STR R2,[R0] ;     LDMIA SP!,{R4-R11} ;  R4-R11 BX LR 

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


 SVC_Handler LDR R0,__sysTickAddr ; SysTick  MOV R1,#6 ;   CSR ,   STR R1,[R0] ;Stop SysTimer MOV R1,#7 ; ,   STR R1,[R0] ;Start SysTimer ; STMDB SP!,{R4-R11} ;   LDR R0,=timersTable ;    LDR R1,=stacksTable ;    LDR R2,[R0] ;R2   ()  STR SP,[R1,R2,LSL #2] ;   SP (R2 * 4) LDR R3,=tmpTimersTable ;   tmpTimers LDR R3,[R3,R2,LSL #2] ;tmpTimer    STR R3,[R0,R2,LSL #2] ; timer  __svc_next_check ADD R2,R2,#1 ;   CMP R2,#TASKS_LIMIT ;R2-TASKS_LIMIT  BLO __svc_no_border_yet ;   MOV R2,#0 ;    (main) LDR R3,[R1] ; main SP MOV SP,R3 B __svc_timer_ok __svc_no_border_yet ;; LDR SP,[R1,R2,LSL #2] ;Restore SP does not work (errata Cortex M4) ;; CMP SP,#0 ; LDR R3,[R1,R2,LSL #2] ;  SP      CMP R3,#0 ; =0     BEQ __svc_next_check MOV SP,R3 LDR R3,[R0,R2,LSL #2] ;  suspend timer CBZ R3,__svc_timer_ok ; 0    ,   B __svc_next_check __svc_timer_ok STR R2,[R0] ;     LDMIA SP!,{R4-R11} ; R4-R11 BX LR 

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


  DATA SECTION .taskSwitcher:CODE:ROOT(2) __topStack DCD sfe(CSTACK) __botStack DCD sfb(CSTACK) __dimStack DCD sizeof(CSTACK) __sysAIRCRaddr DCD 0xE000ED0C __sysTickAddr DCD 0xE000E010 __sysSHPRaddr DCD 0xE000ED18 __sysTickReload DCD RELOAD ;******************************************************************************* ; Task table for concurrent tasks (main is number 0). ;******************************************************************************* SECTION TABLE:DATA:ROOT(2) DS32 1 ;stack shift due to FPU mainCopyCONTROL DS32 1 ;Needed to determine if FPU is used mainPSRvalue DS32 1 ;Copy from main ;******************************************************************************* 

यह सुनिश्चित करने के लिए कि उपरोक्त सभी सामान्य ज्ञान है, लेखक को आईएआर एंबेडेड वर्कबेंच के तहत एक छोटी परियोजना लिखना था, जहां वह विस्तार से सब कुछ जांचने और छूने में कामयाब रहा। सब कुछ STM32F303VCT6 नियंत्रक (ARM Cortex-M4) पर परीक्षण किया गया था। या बल्कि, STM32F3DISCOVERY बोर्ड का उपयोग कर। प्रत्येक कार्य को अलग-अलग एलईडी के साथ अलग-अलग चमक देने के लिए पर्याप्त एल ई डी हैं।


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


  U32 get_task_stack_empty_space(U8 taskNum); 

मैं एक और समारोह का उल्लेख करना चाहूंगा। यह कार्य के लिए खुद को सूची में अपना नंबर पता करने का अवसर है। आप किसी को बाद में बता सकते हैं।


 ;******************************************************************************* ; Example: U8 get_my_number(void); ;     (). ..    . ;******************************************************************************* get_my_number LDR R0,=timersTable ;    (currentTaskNumber) LDR R0,[R0] ;  BX LR ;============================================================== 

फिलहाल शायद यही सब है।

Source: https://habr.com/ru/post/hi454874/


All Articles