آموزش STM32 با توابع HAL, توصیه شده

آموزش STM32 با توابع HAL قسمت 12: ساخت تایمر بزرگ‌تر

ساخت تایمر بزرگ‌تر

در قسمت قبل از سری آموزش STM32 با توابع HAL، در مورد تایمرها و کاربردهای و نمونه‌ای از آن‌ها صحبت شد. در این قسمت، نحوه اتصال تایمرها به هم و ساخت تایمر بزرگ‌تر را بررسی می‌کنیم. همچنین یک کاربرد نمونه چنین تایمری را با توسعه یک پروژه ساده نشان می‌دهیم. با سیسوگ همراه باشید.

همه‌ی تایمرهایی که معرفی کردیم و در میکروهای مورداستفاده در این سری آموزشی وجود دارند (به‌جز SysTick)، 16 بیتی هستند. اما در این قسمت، می‌خواهیم نحوه ساخت تایمرهای 32 بیتی و 64 بیتی را بررسی کنیم. همان‌طور که احتمالاً می‌دانید، در میکروکنترلرهای مورداستفاده در این آموزش، همه تایمرها (به‌جز SysTick) 16 بیتی هستند. که البته ممکن است این مسئله مشکل‌ساز نباشد. اما گاهی پیش می‌آید که برای اندازه‌گیری طول یک پالس با دقت بالا، نیاز پیدا کنیم که تایمری با تعداد بیت‌های بیشتری در اختیار داشته باشیم. یا اینکه اگر قصد شمارش تعداد پالس‌ها یا لبه‌های یک سیگنال خارجی را داشته باشیم که تعداد آن‌ها از ۶۵۵۳۶ بیشتر باشد، تایمرهای 16 بیتی کارساز نیستند. پس در این موقعیت‌ها، راه‌حل چه خواهد بود؟ آیا لازم است که از خانواده‌ای از میکروکنترلر استفاده کرد که تایمرهایی با دقت بالا دارند؟ یا می‌شود به شکل دیگری این مسئله را حل کرد؟ البته باید گفت که راه‌های نرم‌افزاری برای حل این مشکل‌ها وجود دارد. اما در این قسمت یک راه‌حل ساده سخت‌افزاری برای عبور کردن از این محدودیت، معرفی خواهیم کرد.

 

ساخت تایمر 64 بیتی

همان‌طور که می‌دانید، در میکروکنترلر STM32F103C8T6 که در بورد Blue Pill به‌کاررفته است، تنها تایمرهای 16 بیتی وجود دارد. اگر برای کاربرد خاصی نیاز به تایمر بزرگ‌تری داشته باشیم (مثلاً برای اندازه‌گیری فرکانس‌های بالا یا شمارش‌های طولانی یک واقعه یا گذر زمان)، باید با استفاده از این تایمرهای 16 بیتی، و اتصال آن‌ها به‌صورت سخت‌افزاری، عمل موردنظرمان را انجام دهیم. به عبارت دقیق‌تر اگر تایمرها را جوری متصل کنیم که هر بار سرریز تایمر1 به‌عنوان کلاک تایمر 2 عمل کند، بدین گونه یک تایمر 32 بیتی ساخته‌ایم. به همین ترتیب اگر 3 یا 4 تایمر را به هم متصل کنیم، تایمرهای 48 و 64 بیتی در اختیار خواهیم داشت.

برای اینکه مسئله موردنظر را بهتر درک کنیم، می‌توانیم به یک حالت ساده‌تر این موضوع نگاه کنیم؛ زمانی که می‌خواهیم به‌وسیله اتصال چند شمارنده، یک شمارنده بزرگ‌تر بسازیم، می‌توانیم با استفاده از پایه سرریز یا پایه پرارزش یک شمارنده، کلاک یک شمارنده پرارزش‌تر را کنترل کنیم. بدین‌وسیله هرگاه شمارش به حداکثر مقدار خود در شمارنده اول می‌رسد، شمارنده پرارزش‌تر یک واحد شمارش می‌کند. به همین ترتیب شمارنده دوم نیز می‌تواند کلاک شمارنده سوم را کنترل کند و این روند ادامه پیدا کند. همچنین می‌دانیم که تایمرهای میکروکنترلرها نیز درواقع شمارنده هستند. پس احتمالاً به روش مشابه می‌توان تایمرها را برای ساخت تایمر بزرگتر نیز، به یکدیگر متصل کرد.

 

تایمر 64 بیتی

 

قبلاً گفته شد که برای هر تایمر، منبع کلاک می‌تواند به‌صورت داخلی یا خارجی تنظیم می‌شود. همچنین، برای هر تایمر یک منبع تریگر می‌توان تعریف کرد. این تریگر می‌تواند از منبع‌های مختلفی فرستاده شود. در حالتی که تایمر روی حالت Slave Mode و External Clock Mode1 تنظیم‌شده باشد، منبع تریگر به‌عنوان منبع کلاک در نظر گرفته می‌شود. بنابراین با این روش می‌توان کلاک یک تایمر را توسط یک تایمر دیگر تأمین نمود. در ادامه برای ساخت تایمر بزرگ‌تر (32 و 64 بیتی) یک پروژه ایجاد می‌کنیم.

 

ایجاد پروژه

روال معمول ایجاد پروژه ساخت تایمر بزرگتر را تا مرحله تنظیم کلاک و دیباگ طی می‌کنیم و سپس تایمرها را به‌صورت زیر تنظیم می‌نماییم:

ساخت تایمر بزرگ‌تر

تنظیم TIM1

 

همان‌طور که در تصویر بالا دیده می‌شود، منبع کلاک تایمر1، در حالت ETR2 و از طریق سیگنال خارجی و پایه PA12 تأمین می‌گردد. همچنین Trigger Event برای این تایمر در حالت Update Event انتخاب‌شده است. در ادامه، TIM2، ‌TIM3 و TIM4 مشابه هم و به‌صورت زیر تنظیم می‌شوند:

 

ساخت تایمر بزرگ‌تر

تنظیم TIM2

 

 

ساخت تایمر بزرگ‌تر

تنظیم TIM3

 

 

ساخت تایمر بزرگ‌تر

تنظیم TIM4

 

بدین ترتیب هر تایمر با update event یا سرریز کردن یک تایمر دیگر، شمارش می‌کند و عملاً هر 4 تایمر را به هم متصل کرده‌ایم. کلاک تایمر اول نیز از منبع خارجی تأمین می‌شود تا بتوانیم تعداد پالس یک سیگنال خاص را بشماریم.

 

دستورات مورد نیاز

برای استفاده از تایمرهای متصل شده (برای ساخت تایمر بزرگ‌تر ) به‌عنوان شمارنده یک سیگنال خارجی، می‌توان به‌سادگی هر چهار تایمر را فعال کرده و سپس مقدار شمارنده آن‌ها را چاپ می‌کنیم. بدیهی است که قبل از آن باید کدهای مربوط به ریدایرکت stdio را نیز به این پروژه اضافه کنیم.

بنابراین کد زیر را در بدنه تابع int main و قبل از حلقه while(1) می‌نویسیم:

   سپس مقدار شمارنده‌ها را در حلقه while(1)، چاپ می‌کنیم:

برای اینکه نتیجه شمارش و اتصال تایمرها را بتوانیم به‌سرعت بررسی کنیم، مقدار سرریز یا همان Counter Period (Auto-Reload Register) را روی عدد کوچکی مثل 2 تنظیم می‌کنیم.

 

اندازه‌گیری فرکانس با تایمر 32 بیتی

به‌عنوان یک کاربرد نمونه برای تایمر 32 بیتی، می‌خواهیم فرکانس یک سیگنال ورودی (که دوره تناوب کوچک و فرکانس بالایی دارد) را اندازه‌گیری کنیم. بدین منظور تایمرهای 1 و 2 را طبق شکل‌های بالا (مربوط به ساخت تایمر 64 بیتی)، تنظیم می‌کنیم و پارامتر Counter Period را برای آن‌ها روی عدد 65535 قرار می‌دهیم. سپس تنظیم تایمر 3 را برای اندازه‌گیری زمان 1 ثانیه، طبق شکل زیر انجام می‌دهیم:

 

ساخت تایمر بزرگ‌تر

تنظیم TIM3

 

 

ساخت تایمر بزرگ‌تر

فعال‌ سازی وقفه TIM3

 

 

اکنون مجدداً وارد فایل کد می‌شویم و در بدنه int main کد مربوط به فعال‌سازی تایمرها را به شکل زیر تغییر می‌دهیم:

سپس متغیرهای زیر را تعریف می‌کنیم:

در این مرحله، تابع HAL_TIM_PeriodElapsedCallback  که مربوط به روال وقفه Update event است و در پروژه قبل نیز استفاده شد را به‌صورت زیر می‌نویسیم:

در مرحله آخر، کد قبلی نوشته‌شده در حلقه while(1) را کامنت می‌کنیم و کد زیر را در بدنه این حلقه می‌نویسیم:

در این کد، می‌بینیم که ابتدا پرچم read_flag صفر شده است تا اجرای کد به‌درستی و در هر وقفه یک ثانیه یک بار اتفاق بیافتد. سپس بخش کم‌ارزش و پرارزش شمارش، که به ترتیب توسط تایمرهای TIM1 و TIM2 شمارش‌شده است، خوانده می‌شود. همان‌طور که می‌دانید هر تایمر/شمارنده 16 بیتی، قابلیت شمارش تا عدد 65535 را دارد. حال اگر بخواهیم فرکانس سیگنالی را اندازه بگیریم که در هر ثانیه بیش از 65535 نوسان می‌کند (فرکانس آن بیش از 65535Hz باشد)، یک تایمر 16 بیتی کارساز نخواهد بود و باید عمل شمارش را با یک تایمر 32 بیتی یا 2 تایمر 16 بیتی متصل‌به‌هم انجام دهیم.

پس از نوشتن کدهای گفته‌شده، پروژه را Build و روی میکرو دانلود می‌کنیم. سپس یک سیگنال با فرکانس حدود 10 مگاهرتز را با Signal Generator تولید می‌کنیم و به پایه PA12 میکروکنترلر می‌دهیم. نتیجه اجرا و اندازه‌گیری فرکانس سیگنال را می‌توانیم در ترمینال سریال ببینیم؛

 

ساخت تایمر بزرگ‌تر

نتیجه اندازه‌گیری فرکانس در ترمینال سریال

 

 

در این قسمت از سری آموزش STM32 با توابع HAL، نحوه اتصال تایمرها به هم و ساخت تایمر بزرگ‌تر و کاربرد نمونه‌ای از آن را بررسی کردیم. در قسمت بعدی در مورد حالت‌های Input capture و Output compare در تایمرها صحبت خواهیم کرد. با ما همراه باشید.

لینک این پروژه در گیت‌هاب

انتشار مطالب با ذکر نام و آدرس وب سایت سیسوگ، بلامانع است.

شما نیز میتوانید یکی از نویسندگان سیسوگ باشید.   همکاری با سیسوگ

بازگشت به لیست

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

2 دیدگاه در “آموزش STM32 با توابع HAL قسمت 12: ساخت تایمر بزرگ‌تر

  1. مهران گفت:

    ممنون نمیخاد توضیح بدین خودم فهمیدم 🙂

  2. مهران گفت:

    ممنون از مطلب عالی ای که منتشر کردین
    میشه لطفا راجع این فرمول کمی بیشتر توضیح دهید
    frequency = (float)((counterMS * __HAL_TIM_GetAutoreload(&htim1)) + counterLS) / 1000000;