در قسمت یازدهم از آموزش STM32 با توابع LL، در رابطه با DAC صحبت کردیم و ویژگیهای مهم DAC در میکروکنترلرهای STM32 را بررسی کردیم و درنهایت با استفاده از DAC، دو سیگنال پالس و مثلثی را ایجاد کرده و بر روی اسیلسکوپ نمایش دادیم. در این قسمت میخواهیم در رابطه با Timer در میکروکنترلرهای STM32 صحبت بکنیم. بهجرئت میتوان گفت که بحث Timer در میکروکنترلرها و مشخصاً در میکروکنترلرهای STM32، گستردهترین مبحث است. بهعلاوه Timer از آن مواردی است که تقریباً در تمامی پروژهها بهوفور استفاده میشود و اهمیت بسیار مهمی دارد. به همین دلیل هم ما تصمیم گرفتیم که چندین قسمت را به بحث تایمرها اختصاص بدهیم.
Timer چیست و چگونه ساخته میشود؟
بهعنوان یک تعریف ساده و کلی میگوییم که Timer ابزاری است که زمان را برای ما میسنجد، و سنجش زمان میتواند با استفاده از سیستمها و روشهای مختلفی ساخته شود. مثلاً زمان میتواند با استفاده از یک سیستم مکانیکی، پنوماتیکی و یا الکترونیکی ساخته شود. اما روش ساختی که در این مقاله مدنظر ما است، روش الکترونیکی و مشخصاً الکترونیک دیجیتال است. ساعت مچی نمونهی خوبی از یک سیستم الکترونیکی-مکانیکی که زمان را برای ما میسنجد و معمولاً مبنای عملکرد آن بر اساس یک کریستال کوارتز با فرکانس 32.768KHz است.
در میکروکنترلر هم معمولاً با استفاده از کریستال یا یک روش مشابه دیگر، یک سیگنال کلاک تولید میشود و ما با استفاده از همین سیگنال کلاک، زمان را میسنجیم. ما در این مقاله بااینکه سیگنال کلاک چگونه ساخته میشود و سایر مقدمات آن کاری نداریم و فرض میکنیم که یک سیگنال کلاک با فرکانس مشخص داریم و میخواهیم با استفاده از ادوات دیجیتالی که در اختیارداریم، یک Timer بسازیم.
ساخت Timer دیجیتال
قبل از اینکه نحوهی ساخت Timer دیجیتال را توضیح بدهیم باید با یک مفهوم دیگر به اسم Counter یا شمارنده و ارتباط آن با Timer آشنا بشویم. اصول ساخت Timer بر اساس یک شمارنده است. یعنی ما برای سنجش زمان، یک شمارنده داریم که عمل شمارش را انجام میدهد و برای محاسبهی زمان، باید عدد شمارششده توسط شمارنده را در مدتزمان هر شمارش ضرب کنیم.
فرض کنید یک شمارنده 4 بیتی داریم که کلاک این شمارنده از یک منبع کلاک با فرکانس 1KHz تأمین میشود. این شمارنده 4 بیتی میتواند از عدد 0 تا 15 را شمارش کند و با توجه به فرکانس 1KHz، میزان هر شمارش 1ms است. پس با استفاده از یک شمارنده توانستیم تایمری بسازیم که میتواند زمان را با پایه زمانی 1ms بسنجد و برای زمانهای دیگر هم میتوانیم عدد 1 تا 16 (با احتساب عدد 0 بهعنوان اولین عدد شمارش) را در 1ms ضرب کنیم.
تا اینجا با Timer و روش ساخت آن با استفاده از کانتر و همچنین با نحوهی عملکردش آشنا شدیم. در ادامه میخواهیم Timer در میکروکنترلرهای STM32 را بررسی کنیم.
Timer در میکروکنترلرهای STM32
تعداد Timer در میکروکنترلرهای STM32 درمجموع 14 عدد است که این 14 عدد به انواع زیر تقسیم میشوند:
- Advanced-control timers
- General-purpose timers
- Basic timers
تایمرهای 1 و 8 از نوع Advanced-control، تایمرهای 2 تا 5 و 9 تا 14 از نوع General-purpose و درنهایت تایمرهای 6 و 7 از نوع Basic هستند. تفاوت عمدهی Timer در میکروکنترلرهای STM32 در امکاناتی که دارند، میباشد. بهعنوانمثال در تایمرهای Advanced-control، مُدهایی برای اینترفیس انکودر و سنسور هال وجود دارد که در سایر تایمرها موجود نیست یا در تایمرهای General-purpose، قابلیت PWM و Input capture وجود دارد که این امکانات در تایمرهای Basic موجود نیست.
قابلذکر است که با توجه به میکروکنترلر، نوع و تعداد تایمرهای موجود در میکروکنترلر میتواند متفاوت باشد. مثلاً در میکروکنترلر STM32F103C8T6 که ما با آن کار میکنیم، تایمر نوع Basic وجود ندارد. همانطور که قبلاً هم گفتیم Timer در میکروکنترلرهای STM32 بسیار گسترده است و دارای قابلیتها و امکانات بسیار زیادی میباشد، از همین جهت ما در این مقاله و چند مقالهی آتی، مهمترین قابلیتهای تایمرها و مواردی که کاربردیتر هستند را موردبررسی قرار خواهیم داد.
همچنین ما در مقالات مربوط به Timer، تنها Advanced-control timer را راهاندازی خواهیم کرد به این دلیل که تمامی امکانات سایر تایمرها را دارد و برای راهاندازی سایر تایمرها کافی است تا از همین اصولی که در Advanced-control timer خواهیم گفت پیروی کنید و آنها را راهاندازی کنید. سایر قابلیتها کاربرد خاص دارند و اینگونه نیست که بهصورت روزمره با آنها سروکار داشته باشیم، پس هر موقع نیاز شد مقدمات آنها را مطالعه کرده و با توجه به اصولی که در این مقالات خواهیم گفت آنها را راهاندازی کنید.
Timer در میکروکنترلرهای STM32 دارای یک Counter یا شمارنده 16 بیتی است (در سریهای متفاوت این عدد تا 32 بیت هم میرسد) که این شمارنده میتواند بهصورت بالا شمار، پایین شمار و بالا-پایین شمار، شمارش کند. همانطور که میدانید نکته مهم این است که این شمارنده 16 بیتی با چه فرکانسی میتواند شمارش کند. حداکثر فرکانس واحد همهی تایمرها در میکروکنترلر مدنظر ما، 72MHz است که از طریق باسهای مربوطه تأمین میشود.
حال ما میتوانیم این فرکانس 72MHz را مستقیماً به شمارنده 16 بیتی بدهیم و یا اینکه این فرکانس را با استفاده از Prescaler به فرکانسهای کوچکتری تبدیل کرده و سپس آن را به شمارنده بدهیم. Timer در میکروکنترلرهای STM32 دارای یک Prescaler با طول 16 بیت است که فرکانس ورودی واحد تایمر را به عددی بین 1 تا 65536 تقسیم میکند.
پس ما علاوه بر اینکه با استفاده از Prescaler ها و ضربکنندههای فرکانسی که قبل از واحد تایمر قرار دارند، میتوانیم فرکانس ورودی واحد تایمر را تعیین کنیم، با استفاده از Prescaler که در خودواحد تایمر قرار دارد هم این انعطاف راداریم که فرکانس را تا حد بسیار زیادی، و تقریباً به هر عددی که بخواهیم تغییر بدهیم. توجه کنید که هم Prescaler و هم Counter هر دو 16 بیتی هستند و Prescaler دقیقاً قبل از Counter قرار دادهشده است و کلاک متصل به Counter، دقیقاً همان کلاکی است که از خروجی Prescaler گرفته میشود. کلاک ورودی به واحد Timer در میکروکنترلرهای STM32 میتواند از روشهای مختلفی مانند کلاک داخلی میکروکنترلر، پینهای خارجی و از طریق یک تایمر دیگر تأمین بشود.
تصویر زیر منابع مختلف کلاک تایمر را نشان میدهد:
همانطور که در تصویر بالا مشاهده میکنید، کلاک از هر منبعی که تأمین بشود، قبل از رفتن به شمارنده، ابتدا توسط Prescaler تقسیم فرکانسی میشود و درنهایت به شمارنده متصل خواهد شد.
قبلاً گفتیم که کلاک تایمر میتواند از طریق یک تایمر دیگر هم تأمین بشود. در این حالت یک تایمر بهعنوان Master و تایمر دیگر بهعنوان Slave در نظر گرفته میشود.
در تصویر بالا تایمر اول به عنوان Prescaler تایمر دوم عمل میکند.
کاربرد Timer در میکروکنترلرهای STM32
تایمری که در میکروکنترلرهای STM32 قرار دادهشده است کاربردهای بسیار زیادی دارد، اما کاربردهایی که مهم هستند و ما میخواهیم به آنها بپردازیم شامل پایه زمانی، PWM و Input capture است. همچنین هرکدام از این تایمرها دارای 4 کانال مختلف هستند که میتوان از این کانالها برای تولید PWM یا خواندن سیگنال ورودی (Input capture) و … استفاده کرد. ما در ادامه میخواهیم با استفاده از تایمر، قابلیت پایه زمانی را راهاندازی و مدتزمان 1 ثانیه را اندازهگیری بکنیم.
تایمر را در حالت بالا شمار راهاندازی کرده و پسازاینکه اعداد شمارششده توسط شمارنده معادل 1 ثانیه شد، وقفه واحد تایمر را فعال کرده تا متوجه سپری شدن زمان 1 ثانیه بشویم و متناسب با آن عملیات موردنظر را انجام بدهیم. اما چگونه متوجه بشویم که اعداد شمارششده توسط شمارنده، معادل 1 ثانیه است؟
خب همانطور که قبلاً گفتیم با استفاده از منبع کلاک و Prescaler، کلاک ورودی Counter واحد تایمر را مشخص میکنیم. بهعنوانمثال منبع کلاک را از نوع داخلی انتخاب کرده و مقدار آن را بر روی 8MHz و Prescaler را بر روی 7999 (به این دلیل 8000 قرار ندادیم چونکه شمارش از 0 شروع میشود) تنظیم میکنیم. خب با این تنظیمات منبع کلاک بر عدد Prescaler تقسیمشده و درنهایت به ورودی کلاک Counter متصل میشود. یعنی 8MHz بر عدد 8000 تقسیمشده و درنهایت فرکانس 1KHz به ورودی کلاک Counter متصل میشود.
با این تنظیمات با اضافه شدن هر عدد به شمارنده، مدتزمان 1ms سپری میشود. حال باید شمارنده تا عدد 1000 بشمارد تا ما بتوانیم مدتزمان 1 ثانیه را بهدست بیاوریم. اما چگونه؟ یک رجیستر به اسم ARR یا Auto-reload وجود دارد و زمانی که مقدار شمارنده به مقدار این رجیستر رسید، تایمر یک وقفه به ما میدهد و ما متوجه سپری شدن زمانی که مدنظرمان بود میشویم و عملیات دلخواه را در روتین وقفه انجام میدهیم.
ابتدا به تصویر زیر توجه کنید:
در تصویر بالا مقدار رجیستر Auto-reload عدد 36 است و زمانی که مقدار شمارنده به عدد 36 برسد شمارنده ریست و یک وقفه (Update interrupt flag) هم ایجاد خواهد شد.
همچنین توجه کنید که شمارنده یک کلاک پس از فعال کلاک ورودی شمارنده (CNT_EN) شروع به شمارش میکند. این یعنی اگر قرار باشد تا 1000 بشماریم باید مقدار Auto-reload را عدد 999 تنظیم کنیم چرا که عدد 0 هم با توضیحی که اکنون دادیم شمارش خواهد شد. به نرمافزار STM32CubeMX میرویم تا همین مثال بالا، یعنی اندازهگیری زمان 1 ثانیه را با استفاده از Timer در میکروکنترلرهای STM32 راهاندازی کنیم.
ابتدا مقادیر مثال بالا را مانند تصویر زیر برای TIM1 تنظیم میکنیم:
همچنین در قسمت NVIC Setting وقفه مربوطه را نیز فعال میکنیم:
تنظیمات Clock Configuration را هم به نحوی تنظیم میکنیم که کلاک ورودی تایمر 8MHz باشد:
یک پین از میکروکنترلر را هم بر روی حالت خروجی قرار میدهیم تا هر 1 ثانیه یک بار در روتین وقفه آن را Toggle کنیم.
پس از انجام تنظیمات بالا به نرمافزار Keil میرویم تا کد این برنامه را بنویسیم.
تنها کاری که باید در main برنامه انجام بدهیم، فعال کردن Counter و وقفه است که این کار را با استفاده از کد زیر انجام میدهیم:
1 2 | LL_TIM_EnableCounter(TIM1); LL_TIM_EnableIT_UPDATE(TIM1); |
حال باید به فایل stm32f1xx_it.c برویم و در تابع TIM1_UP_IRQHandler که مربوط به وقفه است کد زیر را بنویسیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void TIM1_UP_IRQHandler(void) { /* USER CODE BEGIN TIM1_UP_IRQn 0 */ if(LL_TIM_IsActiveFlag_UPDATE(TIM1) == 1) { /* Clear the update interrupt flag*/ LL_TIM_ClearFlag_UPDATE(TIM1); LL_GPIO_TogglePin(GPIOC, LL_GPIO_PIN_13); } /* USER CODE END TIM1_UP_IRQn 0 */ /* USER CODE BEGIN TIM1_UP_IRQn 1 */ /* USER CODE END TIM1_UP_IRQn 1 */ } |
ما در تابع وقفه بررسی کردیم که اگر Flag وقفه فعال شد، ابتدا Flag را پاک و سپس پین 13 از PORTC را Toggle کن. پین 13 بر روی برد Blue Pill به یک LED متصل است که با برنامه بالا هر 1 ثانیه یک بار خاموش و روشن میشود.
توجه کنید که Flag وقفه بهصورت سختافزاری پاک نمیشود و باید خودمان با استفاده از کد بهصورت نرمافزاری Flag وقفه را پاککنیم.
در قسمت سیزدهم دوباره در رابطه با تایمرها و در مورد حالت Input capture صحبت خواهیم کرد.
عالی، مرسی واقعا.
کاش آموزش ها ادامه پیدا کنه و کامل بشه.
stm32f103c8t6 چندتا pwm داره؟ برای راه اندازی اینورتر 6 تا pwm لازم هست، میشه از همین میکرو استفاده کرد؟
سلام و درود بر شما
آموزش ها ادامه خواهد داشت 🙂
سلام اموزش بعدی چه زمانی ارائه میدید؟ ممنون
سلام ممنون از زحمتی که میکشید .لطفا اگه امکانش هست مبحث i2c رو هم بعد از تایمر ارائه دهید.اکثر سنسور ها و حافظه های eprom از i2c استفاده میکنند ممنون
سلام محسن جان، خواهش میکنم. بعد از مبحث تایمر به پروتکلها میپردازیم که یکیش همین I2C است.
بسیار عالی
تشکر
سپاس از نظر مثبتتان.