در قسمت قبل از سری آموزش STM32 با توابع HAL، در مورد نحوه Redirect کردن توابع کتابخانه stdio صحبت شد. در این قسمت می خواهیم به معرفی تایمر ها بپردازیم به نوعی، تایمرهای میکروکنترلر STM32F103C8 را معرفی میکنیم و در مورد کاربردهای آنها صحبت خواهیم کرد. همچنین یک کاربرد نمونه تایمر را با توسعه یک پروژه ساده نشان میدهیم. با سیسوگ همراه باشید.
در میکروکنترلرهای STM32 انواع مختلفی از تایمرها وجود دارد که دارای تفاوتهای سختافزاری با یکدیگر هستند. هرکدام از این تایمرها را میتوان در حالتهای مختلف تنظیم کرد و برای منظورهای متفاوتی بهکار برد. به دلیل همین گستردگی کاربرد و جزییات تایمرها، چندین قسمت از این سری آموزش، به تایمرها اختصاص دادهشده است. در این قسمت به معرفی کلی تایمرها کفایت میکنیم و به مفاهیم اساسی آنها میپردازیم. سپس به توسعه یک پروژه نمونه برای نشان دادن کاربرد تایمر در حالت ابتدایی آن میپردازیم. در قسمتهای آینده حالتهای دیگر و پیشرفتهتر تایمرها را نیز بررسی خواهیم کرد.
ساز و کار تایمرها
هر ماژول تایمر در سادهترین حالت کاری خود، یک مدار دیجیتالی است که با هر سیکل کلاک، یک شمارش (افزایشی یا کاهشی) انجام میدهد. همچنین تایمرها معمولاً از امکاناتی مثل یک Prescaler برای تقسیم فرکانس کلاک ورودی، مدار مختص input capture، قابلیت تولید موج PWM و… بهره میبرند.
برای نمونه، یک تایمر 16 بیتی مانند شکل زیر را در نظر میگیریم. این تایمر امکان شمارش از 0 تا عدد 65535 را دارد. در هر سیکل کلاک مقدار ذخیرهشده در تایمر، 1 واحد افزایش مییابد. همانطور که در شکل نیز مشخصشده است، عمل شمارش با فرکانس Fsys (فرکانس کلاک سیستم) صورت نمیگیرد، بلکه فرکانس کلاک سیستم، قبل از ورود به شمارنده تایمر توسط واحد Prescaler تقسیم (بر یک عدد مشخص و انتخابی) خواهد شد.
در این حالت کاری ساده و بالا شمار، تایمر در هر سیکل کلاک با فرکانس (Fsys/PSC) شمارش میکند. بهطوریکه اگر بهعنوانمثال Fsys یا همان فرکانس کلاک سیستم برابر با 80MHz و تقسیمکننده (PSC) در حالت 1:1024 باشد، شمارنده تایمر یا همان TCNT، در هر 12.8 میکروثانیه، شمارش میکند.
بنابراین، درصورتیکه این تایمر، از مقدار 0 شروع به شمارش کند، مدتزمان شمارش تا عدد 65535 (و overflow درنتیجه روی داد)، 0.839 ثانیه خواهد بود. پس در صورت فعال بودن وقفه، این تایمر در هر 0.839 ثانیه یک بار، وقفه تولید میکند. حال، سؤالی که ممکن است پیش بیاید این است که اگر بخواهیم دوره تناوب این تولید وقفه، بهجای 0.839 ثانیه،1 ثانیه باشد، چه تغییراتی باید صورت گیرد؟ برای این مسئله، چندراه حل وجود دارد، که یکی از آنها استفاده از یکی از امکانات سختافزاری تایمر، یعنی رجیستر Preload، است. این رجیستر میتواند باعث شود که تایمر شمارش خود را بهجای صفر، از یک مقدار مشخص انتخابی آغاز کند و تا مقدار سرریز ادامه دهد. بدین طریق میتوان به بازههای زمانی موردنظر دستیافت. یک راه دیگر نیز تغییر مقدار سرریز یا سقف شمارش بهوسیله تغییر رجیستر بازنشانی خودکار (Auto-reload Register) است.
یک شمارنده 16 بیتی بالا شمار به همراه رجیستر auto-reload را میتوان بهعنوان بخش اصلی یک تایمر قابلبرنامهریزی، برشمرد. همچنین اشاره شد که کلاک تایمر، بهوسیله یک Prescaler قابل تنظیم است. نکته دیگر این است که رجیسترهای شمارنده، auto-reload و Prescaler بهوسیله نرمافزار، قابلخواندن و نوشتن هستند. این عمل در هرزمانی، حتی حین شمارش شمارنده، قابل انجام است.
واحد time-base شامل قسمتهای زیر میشود:
- Counter Register (TIMx_CNT)
- Prescaler Register (TIMx_PSC)
- Auto-Reload Register (TIMx_ARR)
به این حالت کاری تایمر، که در آن منبع کلاک، توسط کلاک سیستم تنظیم میشود، Timer mode نیز گفته میشود. اما در بعضی کاربردها ممکن است نیاز باشد که منبع کلاک دیگری انتخاب شود. در حالت counter mode، از یک سیگنال خارجی بهعنوان منبع کلاک استفاده میشود. بهعنوانمثال یک push button میتواند تولیدکننده این سیگنال باشد و با هر لبه بالارونده یا پایینروندهای که ایجاد میشود، شمارنده یک واحد افزایش و یا کاهش یابد. این حالت کاری یکی از حالتهای پرکاربرد استفاده از تایمر است. در شکل زیر دیاگرام استفاده از سیگنال خارجی بهعنوان منبع کلاک تایمر نشان دادهشده است:
همانطور که در این تصویر دیده میشود، سیگنال کلاک ابتدا توسط منبع خارجی (push button) تولیدشده و پس از رد شدن از Prescaler وارد ورودی کلاک تایمر شده است. با این تنظیمات همچنین میتوان تعداد دفعات فشرده شدن کلید یا همان push button را بهسادگی با خواندن مقدار رجیستر شمارش (TCNT) بهدست آورد.
انواع تایمر
پیشتر اشاره کردیم که ماژولهای تایمر، ازنظر سختافزاری تفاوتهایی با یکدیگر دارند که سبب میشود هر یک، برای کاربردهای خاصی مناسب باشند. در میکروکنترلرهای STM32، بهطورمعمول از هرکدام از انواع تایمر، تعدادی تعبیهشده است. بااینحال ممکن است برخی از مدلهای این میکروکنترلرها، فاقد یک یا چند نوع از تایمرها باشند. در این بخش میخواهیم برخی از انواع این ماژولها و کاربرد آنها را معرفی کنیم. بهاینترتیب میتوان براساس نوع مسئله و کاربرد موردنظر سختافزار مناسب را انتخاب نمود. سری میکروکنترلرهای STM32F103xC/D/E (میکروکنترلر مورداستفاده در این آموزش) میتوانند تا 11 تایمر داشته باشند که این 11 تایمر شامل دو تایمر advanced-control، 4 تایمر general-purpose، 2 تایمر basic، 2 تایمر watchdog و 1 تایمر SysTick میشود.
در جدول زیر ویژگیهای سه نوع تایمر advanced-control، general-purpose و basic، مقایسه شدهاند:
همانطور که این مقایسه ساده نشان میدهد، تایمرهای advanced-control نسبت به انواع دیگر از امکانات بیشتری برخوردار است. در ادامه ویژگیهای هرکدام از انواع تایمرهای موجود در میکروکنترلهای STM32f103 را بررسی میکنیم.
تایمرهای Advanced-control (TIM1 و TIM8)
دو تایمر TIM1 و TIM8، از نوع تایمرهای advanced-control هستند. به این تایمرهای پیشرفته، میتوان به چشم PWM های 3-فازه نگاه کرد که هرکدام به 6 کانال multiplex شدهاند. تایمرهای advanced-control، دارای خروجیهای PWM متمم هستند. به این معنی که برخلاف PWM تایمرهای عادی که تنها یک شکل موج خروجی دارند، این PWM ها دارای دو شکل موج خروجی هستند که در هر بازه زمانی متمم منطقی یکدیگرند. علاوه بر این، در خروجیهای مکمل این PWM ها، امکان تنظیم dead-time ها نیز وجود دارد.
دو موج متمم تولید شده توسط PWM.
Dead-Time زمانی است که در سیگنالهای PWM بهکار میرود تا مدارات سوییچینگ مثل H-Bridge، به دلیل تاخیرات ذاتی، دچار اتصال کوتاه و Shoot through (و درنتیجه آسیب) نشوند.
علاوه بر اینها، تایمرهای advanced-control را میتوان بهعنوان تایمرهای کاربرد عمومی یا general-purpose نیست استفاده کرد. چهار کانال مستقل در این تایمرها، کاربردهای زیر رادارند:
- Input capture
- Output compare
- PWM generation (edge or center-aligned modes)
- One-pulse mode output
درصورتیکه این تایمرها بهعنوان تایمر استاندارد 16 بیتی تنظیم شوند، کاربردشان مشابه تایمرهای عمومی (TIMx) خواهد بود. همچنین در صورت تنظیم بهعنوان تولیدکننده موج PWM 16 بیتی، این ماژول، امکان مدولاسیون در تمام بازه 0 تا 100% را خواهد داشت.
بلاک دیاگرام تایمر advanced-control.
شمارنده تایمرهای advanced-control، در حالت دیباگ، امکان freeze شدن را دارند. علاوه بر این، امکان غیرفعالسازی خروجیهای PWM و در نتیجه غیرفعال کردن سوییچینگ تغذیه این خروجیها، وجود دارد.
اشاره کردیم که تایمرهای پیشرفته، ویژگیهای مشترک زیادی با تایمرهای عمومی دارند. دلیل این امر هم یکسان بودن معماری این دو نوع تایمر است. به همین دلیل، تایمرهای advanced-control، به وسیله استفاده از ویژگی Timer Link امکان به کارگیری به همراه تایمرهای عمومی، برای همگامسازی (synchronization) یا Event chaining را دارند.
تایمرهای همه منظوره یا General-purpose (TIMx)
در سری میکروکنترلرهای STM32F103xC، STM32F103xD و STM32F103xE، تا 4 تایمر general-purpose وجود دارد که عبارتند از TIM2، TIM3، TIM4 و TIM5. این تایمرها برپایه یک شمارنده 16بیتی بالا/پایین شمار به همراه auto-reload طراحی شدهاند. همچنین دارای یک prescaler 16بیتی هستند و از 4 کانال مستقل پیشتیبانی میکنند. کاربرد این 4 کانال عبارت است از input capture، output compare، PWM و one-pulse mode output. به این ترتیب و با وجود 4 تایمر همه منظوره (یا همان کاربرد عمومی)، در پکیجهای بزرگ میکروکنترلرها، میتوان تا 16 کانال برای input capture، ouput compare و یا PWM، در اختیار داشت.
بلاک دیاگرام تایمر general-purpose.
تایمرهای general-purpose، بهوسیله قابلیت Timer Link، امکان کار با تایمرهای advanced-control، برای همگامسازی یا event chaining رادارند. شمارنده این تایمرها امکان freeze شدن در حالت Debug را دارد.
همه تایمرهای general-purpose، قابلیت تولید شکل موجهای PWM رادارند و همچنین همگی آنها داری امکان تولید درخواست DMA بهصورت مستقل هستند.
علاوه بر اینها، تایمرهای همهمنظوره، امکان کار با سیگنال quadrature (Incremental) encoder یا همان سنسور تشخیص جهت حرکت و همچنین قابلیت کار با خروجی 1 تا 3 سنسور اثر هال رادارند
.
ماژولهای تایمر ساده یا Basic (TIM6 و TIM7)
تایمر basic از یک شمارنده 16 بیتی با بازنشانی خودکار (auto-reload) تشکیلشده است که کلاک آن از خروجی یک Prescaler قابلبرنامهریزی تأمین میشود. این تایمرها میتوانند برای کاربردهای مختلفی استفاده شوند. اما کاربرد خاص آنها، بهعنوان کنترلکننده واحد مبدل دیجیتال به آنالوگ (DAC) است. به این صورت که این نوع تایمر، بهصورت داخلی به واحد DAC متصل است و بهوسیله خروجی trigger خود قادر به کنترل DAC هستند. بااینحال، تایمرهای basic به طول کامل مستقلاند و از منابع سختافزاری مشترکی با واحد دیگر استفاده نمیکنند.
بلاک دیاگرام تایمر basic.
ویژگیهای تایمر basic عبارتاند از:
- یک شمارنده بالا شمار 16 بیتی با auto reload
- یک Prescaler 16 بیتی قابل تنظیم که برای تقسیم کردن فرکانس کلاک شمارنده بر اعداد 1 تا 65536 استفاده میشود.
- مدار همگام سازی (Synchronization) که برای کنترل DAC به کار میرود.
- قابلیت فعال سازی سیگنال درخواست Interrupt و DMA در زمان update event (که در اینجا همان overflow شدن شمارنده است)
تایمر نگهبان مستقل (Independent Watchdog)
Indepenent watchdog یا تایمر نگهبان مستقل، بر اساس یک شمارنده پایین شمار 12 بیتی و یک Prescaler 8 بیتی، طراحیشده است. کلاک این تایمر، توسط یک مدار RC داخلی مستقل با فرکانس 40KHz تأمین میشود و ازآنجاییکه عملیات آن مستقل از کلاک اصلی سیستم است، میتواند در حالتهای Stop و Standby نیز کار کند. کاربرد اصلی Independent watchdog، ریست کردن دستگاه در زمان وقوع مشکل است. کاربرد دیگر آن، استفاده از آن در حالت free running، برای مدیریت timeout های مختلف برنامه است. همچنین این ماژول از راه سختافزاری و نرمافزاری و بهوسیله option bytes قابل تنظیم است. همچنین شمارنده آن در حالت Debug، امکان freeze شدن رادارند.
بلاک دیاگرام Independent watchdog.
تایمر نگهبان پنجرهای (Window Watchdog)
Window watchdog یا تایمر نگهبان پنجرهای، بر اساس یک شمارنده پایین شمار 7 بیتی طراحیشده است. window watch dog نیز میتواند به در حالت free running یا برای ریست کردن دستگاه در زمان موقع مشکل، استفاده شود و کلاک آن توسط کلاک اصلی سیستم تأمین میشود. window watchdog دارای قابلیت early warning interrupt است و همچنین شمارنده آن میتواند در حالت دیباگ freeze شود.
بلاک دیاگرام Window watchdog.
تایمر SysTick
تایمر SysTick یا System Tick Time، مخصوص استفاده در سیستمهای بلادرنگ (Real-time) است. بااینحال این تایمر میتواند بهعنوان یک شمارنده پایین شمار استاندارد نیز استفاده شود. از امکانات و ویژگیهای اصلی این تایمر، میتوان به موارد زیر اشاره کرد:
- یک شمارنده 24 بیتی پایین شمار
- قابلیت autoreload
- قابلیت تولید وقفه سیستم هنگام به صفر رسیدن شمارنده، با امکان Mask شدن.
- قابلیت برنامه ریزی کلاک.
بلاک دیاگرام SysTick.
تعریف پروژه نمونه برای راهاندازی تایمر
تا این مرحله، با جزییات تایمر، نحوه عملکرد و انواع مختلف آن آشنا شدیم. البته سختافزارهای تایمر دیگری نیز وجود دارند که کاربردهای خاص خود رادارند و در این مقاله به آنها اشاره نکردیم. ازجمله تایمرهای کممصرف (Low-Power)، تایمرهای دقت بالا (High-Resolution). همچنین، به برخی قابلیتها و حالتهای کاری مختلف تایمرها اشاره کردیم که البته شامل تمامی حالتها و قابلیتهای ممکن نمیشوند. بااینحال اکنون میتوانیم پروژه نمونهای تعریف کنیم و کاربردهای سادهای از تایمر را در عمل بررسی کنیم. در این پروژه ابتدا با استفاده از تایمر و بدون تابع آماده تأخیر، یک چشمکزن را راهاندازی میکنیم و همچنین زمان را اندازه میگیریم (Timer mode). سپس در حالت Counter mode، تعداد فشرده شدنهای یک کلید و درنتیجه لبههای سیگنال تولیدشده بهوسیله کلید را شمارش میکنیم.
ایجاد پروژه
در این پروژه مانند گذشته تنظیمات دیباگ و منبع کلاک را انجام میدهیم و کلاک سیستم را روی 72MHz تنظیم میکنیم. همچنین واحد USART1 را برای نمایش پیام، مانند پروژه بخش قبلی، فعال میکنیم. اکنون باید به سراغ TIM2 برویم که یک تایمر general-purpose است؛
تنظیم TIM2.
واحد TIM2 را مطابق شکل بالا، تنظیم میکنیم. دلیل انتخاب این مقادیر برای Prescaler و Auto reload (Counter Period) این است که میخواهیم زمان سرریز شدن رجیستر Auto reload و درنتیجه تولید Update Event، 0.5 ثانیه باشد. پس بدین منظور انتخاب این پارامترها طبق رابطه زیر انجامشده است:
پس از تنظیم این پارامترها، باید وقفه TIM2 را نیز فعال کنیم. بدین منظور به تب NVIC Settings میرویم و TIM2 global interrupt را فعال میکنیم؛
فعال سازی وقفه TIM2.
در این مرحله تنظیم پروژه انجام شده است و میتوانیم به سراغ نوشتن کد برویم.
نوشتن کد پروژه
در این پروژه، برای ایجاد امکان استفاده از printf و نمایش پیام روی ترمینال سریال، کدهای نوشتهشده در قسمت قبل را از طریق کپی کردن پوشه stdio_usart به این پروژه منتقل میکنیم. همچنین تنظیم مربوط بهاضافه کردن مسیر این پروژه به لیست include های پروژه را انجام میدهیم. سپس فایل main.c را باز میکنیم و در اولین قدم، کتابخانههای موردنیاز را اضافه مینماییم؛
1 2 3 4 | /* USER CODE BEGIN Includes */ #include "stdio_usart.h" #include <stdbool.h> /* USER CODE END Includes */ |
پس از آن، باید متغیرهای گلوبال مورد نیاز را تعریف کنیم؛
1 2 3 4 | /* USER CODE BEGIN 0 */ uint16_t counter = 0; bool inrpt_sgnl_lvl = false, state_update = false; /* USER CODE END 0 */ |
در این مرحله، وارد فایل stm32f1xx_it.c میشویم و به سراغ تابع روال وقفه گلوبال TIM2 میرویم:
1 2 3 4 5 6 7 8 9 10 | void TIM2_IRQHandler(void) { /* USER CODE BEGIN TIM2_IRQn 0 */ /* USER CODE END TIM2_IRQn 0 */ HAL_TIM_IRQHandler(&htim2); /* USER CODE BEGIN TIM2_IRQn 1 */ /* USER CODE END TIM2_IRQn 1 */ } |
سپس به سراغ تعریف تابع HAL_TIM_IRQHandler میرویم. در این تابع باید بخش مربوط به TIM Update event را پیدا کنیم؛
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* TIM Update event */ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->PeriodElapsedCallback(htim); #else HAL_TIM_PeriodElapsedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } } |
در این بخش میبینیم که در زمان وقوع Update event، تابع HAL_TIM_PeriodElapsedCallback فراخوانی میشود. پس باید این تابع را طوری تعریف کنیم که عمل مورد نظر ما را انجام دهد. به فایل main.c بازمیگردیم و این تابع را به صورت زیر تعریف میکنیم:
1 2 3 4 5 6 7 | /* USER CODE BEGIN 4 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { inrpt_sgnl_lvl = !inrpt_sgnl_lvl; state_update = true; } /* USER CODE END 4 */ |
اکنون در بدنه int main و قبل از حلقه while(1) کد زیر را مینویسیم:
1 2 3 4 5 6 | /* USER CODE BEGIN 2 */ RetargetInit(&huart1); // initializing the stdio retargetting HAL_TIM_Base_Start_IT(&htim2); printf("%s\n\r", "Start!\r\n"); /* USER CODE END 2 */ |
در اولین خط، تابع راهاندازی ریتارگت فراخوانی شده و در خط بعد تایمر فعال شده است. سپس یک پیام برای نشان دادن شروع شمارش، چاپ میشود.
اکنون در آخرین مرحله، در بدنه حلقه while(1) کد زیر را مینویسیم تا در هر ثانیه متغیر Counter یک واحد افزایش یابد و چاپ شود و همچنین LED، یک بار خاموش و روشن شود:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if(state_update) { if(inrpt_sgnl_lvl) { counter++; HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); } else if(!inrpt_sgnl_lvl) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); printf("Elapsed Time (sec): %d\r\n", counter); } state_update = false; } /* USER CODE END WHILE */ |
حالا کد را کامپایل و روی میکروکنترلر دانلود میکنیم. پورت سریال را نیز متصل و ترمینال را باز میکنیم تا نتیجه اجرای کد را ببینیم؛
نتیجه اجرای کد در ترمینال سریال.
مشاهده میکنیم که با شروع به کار میکروکنترلر، LED شروع به چشمک زدن میکند و همچنین اندازهگیری زمان، در ترمینال نمایش داده میشود.
Counter mode
اکنون میخواهیم با استفاده از تایمر تعداد دفعات فشرده شدن یک push button را شمارش کنیم. بدین منظور از سیگنال خارجی تولیدشده بهوسیله push button بهعنوان منبع کلاک تایمر، استفاده میکنیم. پس ابتدا به تنظیمات پیکربندی پروژه برمیگردیم تا تغییرات موردنیاز را اعمال کنیم. برای این قسمت پروژه، تایمر 1 (TIM1) را بهصورت زیر تنظیم میکنیم:
تنظیم TIM1.
همانطور که در تصویر نشان دادهشده است، منبع کلاک تایمر، در حالت ETR2 تنظیمشده است و بدینصورت از طریق پایه PA12، میتوان سیگنال کلاک خارجی را به مدار اعمال کرد. پس کلید یا push-button را به این پایه متصل میکنیم. اکنون تغییرات موردنیاز در پیکربندی برنامه انجامشده است، پس مجدداً به سراغ کد میرویم.
در فایل main.c، درون بدنه تابع int main و قبل از حلقه while(1)، کد زیر را برای راهاندازی تایمر 1 مینویسیم:
1 | HAL_TIM_Base_Start(&htim1); |
در همین بخش، یک متغیر برای شمارش تعداد دفعات فشرده شدن push-button، تعریف میکنیم:
1 | uint16_t push_counter = 0; |
اکنون کد زیر را در حلقه while(1) برای شمارش تعداد دفعات فشرده شدن push-button و همچنین چاپ این شمارش در ترمینال سریال، مینویسیم:
1 2 3 4 5 | if(push_counter != __HAL_TIM_GetCounter(&htim1)) // check if the (button)counter has changed { push_counter = __HAL_TIM_GetCounter(&htim1); // store the new (button)counter value printf("button is pushed! push count: %d\r\n", push_counter); // print the value of (button)counter value } |
برنامه را روی میکرو میریزیم تا نتیجه اجرای آن را در ترمینال سریال بررسی کنیم. مشاهده میکنیم که شمارش ثانیههای سپریشده، مثل قسمت قبل بهدرستی انجام میشود. اما با فشردن push-button، میبینیم که شمارش دفعات فشرده شدن، بهدرستی انجام نمیشود و با هر بار فشار دادن کلید، بیش از یک شمارش انجام میشود؛
نتیجه شمارش فشرده شدن کلید در ترمینال سریال.
این اتفاق به این دلیل رخ میدهد که با فشرده شدن کلید سیگنالی که تولید میشود موج مربعی یا هر موج مشابهی نبوده و مانند بخش پایینی شکل زیر، دارای نوسانات زیادی است که موجب میشود بیش از یک لبه توسط میکرو دریافت شود. در نتیجه تعداد پالسهای کلاک دریافت شده نیز بیش از یک خواهد بود.
دیبانس کرد سیگنال کلید
برای رفع مشکل پیشآمده، یک مدار ساده برای دیبانس کردن کلید به مدار قبلی اضافه میکنیم. در شکل زیر یک نوع نمونه از چنین مداری نشان دادهشده است:
مدار Debounce.
اکنون میکرو را ریست میکنیم تا مجدداً نتیجه اجرای برنامه را بررسی کنیم. در ترمینال سریال شمارش فشرده شدن کلید را میبینیم:
نتیجه شمارش فشرده شدن کلید در ترمینال سریال.
همانطور که در تصویر بالا دیده میشود، این بار با هر دفعه فشرده شدن کلید، تنها یک شمارش انجام میشود.
در این قسمت از سری آموزش STM32 با توابع HAL، تایمرها و کاربردهای نمونهای از آنها را بررسی کردیم. در قسمت بعدی در مورد نحوه اتصال تایمرها به هم و ساخت تایمر بزرگتر را بررسی خواهیم کرد. با ما همراه باشید.
آقا سیاوش واقعا نکات خوبی رو نوشتی بودی.
کمتر سایتی به این خوبی و کاملی توضیح داده بود.
ممنون از شما
چقدر خوب توضیح دادین.
واقعاً همیشه به بهترین نحو سیسوگ توضیح میده. کلی وقت save میشه با این زحماتی که شما میکشید، مرسی. -یه سوال هم بپرسم، راه دیگه ای برای تشخیص اینکه کلید فشرده شده(به جز مقایسه با مقدار قبلی) هست؟ البته منظورم اینتراپت هم نیست. نحوه کدزنی دیگه ای به ذهنتون میرسه یا برای اینکه توی تایمر اون فشار کلید رو بسنجیم همین کدی که نوشتین متداوله؟
if(push_counter != __HAL_TIM_GetCounter(&htim1))