در برنامهنویسی پروژههای مختلف ممکن است خطاهایی ایجاد شوند که از آن بیخبر باشیم. یا اینکه به هر دلیل دیگری در حین اجرا برنامه دچار اشکال شود یا گیر کند. برای این موقعیت یک مکانیسم در نظر گرفتهشده که تایمر نگهبان مستقل IWDG است، و با ریست کردن میکروکنترلر، روند اجرای برنامه را به روال عادی برمیگرداند. در این بخش میخواهیم نحوه کارکرد IWDG و چگونگی راهاندازی آن در بورد Blue Pill را شرح دهیم.
با ما همراه باشید.
واحد IWDG شامل یک شمارنده نزولی 12 بیتی است که با کلاک داخلی کمسرعت میکرو (LSI) و مستقل از کلاک سیستم کار میکند. همچنین یک تقسیمکننده کلاک در این واحد وجود دارد که میتوان بهوسیله آن به نرخ کلاک موردنیاز دست پیدا کرد.
پس از فعالسازی این واحد، امکان غیرفعالسازی آن توسط برنامه وجود ندارد و در صورتی که قبل از صفر شدن شمارنده آن، مقدار شمارش بازنویسی نشود، میکروکنترلر ریست خواهد شد. از این قابلیت برای خلاص کردن میکروکنترلر هنگام وقوع اشکالات پیشبینی نشده استفاده میشود. کاربرد دیگر آن نیز، استفاده برای زمان Time_out توابع است.
در ادامه تایمر نگهبان مستقل IWDG را در یک پروژه ساده راهاندازی میکنیم.
ایجاد پروژه
مثل بخشهای قبلی قسمت دیباگ و کلاک و USART1 را تنظیم میکنیم. بعدازآن باید پین PA5 را روی ورودی و در حالت pull-up تنظیم کنیم. سپس IWDG را فعال میکنیم و تقسیمکننده کلاک آن را روی یک عدد دلخواه (مثلاً 16) تنظیم و مقدار شمارنده آن را 4095 میکنیم.
اکنون تنظیمات درایورها را نیز مانند قبل انجام میدهیم و وارد بخش کدنویسی میشویم.
نوشتن کد پروژه IWDG
برای این پروژه نیز اعمال مربوط به ریدایرکت را انجام میدهیم و از همان کد استفاده میکنیم. سپس تابعی برای نمایش منبع ریست میکرو، بهصورت زیر مینویسیم:
void show_reset_sources (void) { if(LL_RCC_IsActiveFlag_SFTRST()) printf("reset source was software reset\r\n"); else if(LL_RCC_IsActiveFlag_LPWRRST()) printf("reset source was Low Power reset\r\n"); else if(LL_RCC_IsActiveFlag_PORRST()) printf("reset source was POR\r\n"); else if (LL_RCC_IsActiveFlag_WWDGRST()) printf("reset source was WWDG or pin\r\n"); else if (LL_RCC_IsActiveFlag_IWDGRST()) printf("reset source was IWDG or pin\r\n"); else if(LL_RCC_IsActiveFlag_PINRST()) printf("reset source was reset pin\r\n"); printf("Reset sources:\r\nPIN: %d\r\nIWDG: %d\r\nWWDG: %d\r\nSFT: %d\r\nLPW: %d\r\nPOR: %d\r\n", LL_RCC_IsActiveFlag_PINRST(), LL_RCC_IsActiveFlag_IWDGRST(), LL_RCC_IsActiveFlag_WWDGRST(), LL_RCC_IsActiveFlag_SFTRST(), LL_RCC_IsActiveFlag_LPWRRST(), LL_RCC_IsActiveFlag_PORRST() );
در تابع ()int main ابتدا با تابعی که نوشتیم منبع ریست را نمایش میدهیم و سپس همه پرچمهای ریست را پاک میکنیم؛
show_reset_sources(); LL_RCC_ClearResetFlags();
سپس یک شمارنده با مقدار اولیهی صفر تعریف میکنیم و مقدار شمارنده IWDG را بازنشانی میکنیم؛
int count = 0; LL_IWDG_ReloadCounter(IWDG);
حالا باید در حلقه while(1)، یک شرط برای بازنشانی مقدار شمارندهی IWDG تعریف کنیم (که فشرده شدن کلید PA5 است)، که در صورت عدم وقوع شمارنده به صفر رسیده و ریست اتفاق افتد، همچنین مقدار شمارندهای که تعریف کردیم را در هر بار اجرای حلقه افزایش میدهیم و چاپ میکنیم؛
/* if PA5 is pressed, then IWDG counter will be reset */ if (((LL_GPIO_ReadInputPort(GPIOA)) & (1<<5)) == 0) { LL_IWDG_ReloadCounter(IWDG); LL_mDelay(250); printf("IWDG counter reset\r\n"); LL_IWDG_ReloadCounter(IWDG); } /* print the count value*/ printf("count: %d\r\n", count++); LL_mDelay(250);
اکنون باید یک کلید یا push-button به پایه PA5 متصل کنیم و برنامه را روی میکرو دانلود کنیم. نتیجه اجرا را در ترمینال سریال میبینیم؛
میبینیم که اگر کلید PA5 را فشار ندهیم، میکرو بعد از شمارش تا عدد 6، ریست خواهد شد و درصورتیکه قبل از رسیدن شمارنده تایمر نگهبان به عدد صفر، کلید را فشار دهیم، اجرای برنامه و شمارش ادامه خواهد داشت. در قسمت بعدی در مورد تایمر نگهبان پنجرهای یا WWDG صحبت خواهیم کرد.
منبع: سیسوگ