در جلسه گذشته، به راهاندازی واحد آنالوگ به دیجیتال با استفاده از DMA در میکروکنترلر STM32f103 پرداختیم و یک کد ساده برای راه اندازی آن به وسیلهی کتابخانه HAL نوشتیم. در این جلسه قصد داریم تا به واحد پرکاربرد تایمر بپردازیم و آن را به صورت ساده راه اندازی کنیم.
تایمر چیست؟
یکی از مهمترین بخش های هر میکروکنترلر، واحد تایمر آن می باشد. تایمرها و شمارنده ها به قدری مهم هستند که تقریبا در تمام پروژه های بزرگ از آن ها استفاده می کنند. تایمرها می توانند زمان و تعداد را مشخص کنند. از کاربردهای تایمرها می توان به مواردی مانند کنترل روشنایی LED ها ، کنترل زاویه شافت های سروو ، دریافت داده های سنسور که به صورت PWM(موج مربعی) منتقل می شوند ، ساخت یک تایمر و موارد دیگر اشاره کرد. در واقع کلیه کارهایی که در برنامه مربوط به محاسبات زمانی می شود، زیر نظر واحدی بهنام تایمر انجام می گیرد.
تایمر ها با شمارش به صورت مجزا و مستقل از CPU( شمارش به دلیل عدم ایجاد اختلال در شمارش و دقت به صورت مجزا صورت میگیرد) و بر اساس فرکانس کاری این واحد زمان مورد نیاز برنامه نویس را تعیین کرده و به پردازنده اعلام می دارد. به زبان ساده می توان گفت که نحوه کار تایمر بدین صورت است که با شمارش از مقدار صفر( نه همیشه!!) تا مقدار مورد نظر، که برنامه نویس براساس مد کاری تایمر انتخاب می کند، زمان مورد نظر را به پردازنده اعلام می کند.
ساخت پروژه در نرمافزار CubeMX
در گام اول با استفاده از نرم افزار CubeMX پروژه را می سازیم و در ادامه در بخش تنظیم پایه های میکروکنترلر مانند تصاویر زیر تنظیم می کنیم( تایمر ۳ را فعال کرده و پایه PB15 را تحت نام LED1 به عنوان خروجی تعریف میکنیم).
و تنظیمات آن را در بخش تایمر و به مانند شکل زیر تنظیم می کنیم.
با این کار تایمر۳ را بر اساس کلاک داخلی میکروکنترلر اجرا خواهد کرد. بخش کانالهای این تایمر(channel 1-4) جهت ایجاد موج در خروجی میکروکنترلر براساس تایمر است که در جلسات بعدی به آن پرداخته خواهد شد(در این جلسه به تولید موج به وسیله تایمر نمیپردازیم).
حال در ادامه باید حدود شمارش تایمر را مشخص کنیم تا بر اساس مقدار زمان مورد نیاز ما به پردازنده اینترپت دهد. قبل از این کار ابتدا باید فرکانس کاری واحد تایمر را مشخص کنیم. لذا برای این کار به بخش تنظیمات کلاک رفته و با توجه به اینکه این فرکانس از بخش APB1 timer clock که در شکل زیر مشخص شده است تعیین می گردد، مقدارش را برابر ۷۲ مگاهرتز تنظیم میکنیم.
حال دوباره به سراغ تنظیم تایمر می رویم و در بخش تنظیمات تایمر ۳ مقادیر ( ARR, PSC) را برای ساختن تایمری با اینتراپت هر ۵۰۰ میلی ثانیه تنظیم می کنیم. برای تنظیم ابتدا به نحوه تعیین این مقادیر و فرمول محاسبه آن می پردازیم.
با استفاده از فرمول زیر می توان زمان مورد نیاز برای تایمر را محاسبه نمود:
که در آن F خروجی نهایی مورد انتظار است و صورت همان فرکانس کاری ای که به تقسیم کننده تایمر می آید. ARR بیانگر حد شمارش تایمر می باشد. مثلا زمانیکه این عدد برابر ۱۰۰ قرار داده شود، زمانیکه شمارش تایمر به عدد ۱۰۰ رسید، شمارشگر ریست شده و یک پالس به تایمر برای بیان اتمام یکبار شمارش و رسیدن به عدد ۱۰۰ فرستاده می شود. در ادامه تعداد این پالس با مقدار PSC مقایسه شده و در صورتی که برابر باشد پالس نهایی تایمر به پردازنده ارسال می گردد.با استفاده از CKD نیز می توان فرکانس کاری تایمر را با یک تقسیم کننده کاهش داد. در ادامه مثالی برای تنظیم تایمر بیان روشن تر شدن موضوع بیان می گردد. در این مثال مقادیر را برای تولید زمان یک ثانیه بدست می آوریم
با انتخاب CKD=1 و ARR+1=10000 و PSC+1=7200 معادله بالا برقرار خواهد بود. لذا:
ARR=9999 , PSC=7199 تنظیم می گردند و تقسیم کننده فرکانسی نیز غیرفعال خواهد بود(CKD=1).
حال در صورتی که بخواهیم زمان هر اینتراپت تایمر برابر ۵۰۰ میلی ثانیه باشد، فرکانس برابر ۲ خواهد بود و در نتیجه یکی از این مقادیر فوق نصف میگردد. یعنی با انتخاب ARR+1=10000/2=5000 , PSC+1=7200 خواهیم داشت: ARR=4999, PSC=7200 .
حال مقادیر فوق را در نرم افزار CubeMX وارد کرده و بخش اینتراپت را تیک زده و کد را تولید میکنیم.
تا به حال به دوقسمت آخر از ۵ قسمتی که در تصویر مشخص شده اند اشاره نشده بود. این دو بخش مربوط به تغییرات در رجیسترهاست که در حین فعالیت تایمر صورت می گیرد و با فعال کردن این دو مورد به صورت فوق سبب می شود تا در صورت وقوع تغییراتی در حین اجرای تایمر، این تغییرات بلافاصله تغییر نکنند و بعد از وقوع آخرین اینتراپت تایمر، مقادیر جدید رجیسترها لحاظ گردند. بدین منظور به اشکال زیر و لحظه تغییرات رجیستر ARR توجه فرمایید:
ادامه پروژه در نرمافزار KEIL
فایل پروژه برای نرمافزار KEIL را از مسیر انتخاب شده و واقع در پوشه MDK-ARM پروژه انتخاب کردن و باز میکنیم.
در بخش فانکشن در نوار سمت چپ نرمافزار زیر گروه stm32f1xx_hal_tim.c را باز کرده و توابع مربوط به این کتابخانه را در آن مشاهده می کنید و توضیحات هر تابع در کد هر قسمت موجود است.
در این پروژه باید ابتدا تابع تایمر را فعال کرده و در تابع اینتراپت آن، LED1 را خاموش و روشن کنیم، لذا از دستورات زیر در پروژه استفاده خواهیم کرد:
HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
کدهای فوق به ترتیب از بالا به صورت زیر عمل می کنند:
کد اول تایمر را به صورت تابع اینتراپتی فعال می کند و لذا بعد از فراخوانی این کد دیگر نیازی به فراخوانی دوباره آن نمی باشد(مگر اینکه تایمر را متوقف کرده باشیم!)
کد دوم تابع کالبک مربوط به اینتراپت تایمر می باشد و با هر با رسیدن تایمر به زمان مورد نظر، پردازنده به این تابع مراجعه کرده و دستوراتی که در آن هستند را اجرا می کند.
در کد سوم، همانطور که در جلسات قبل گفته شد، خروجی GPIO معکوس میگردد.
لذا کد زیر را برای روشن و خاموش کردن هر ۵۰۰ میلی ثانیه یک LED که به پایه خروجی میکروکنترلر متصل است می نویسیم:
با نوشتن دستورات بالا در خطوط نشان داده شده، میتوان عملکرد مورد انتظار را مشاهده کرد.
در جلسه بعدی به آموزش بخش دوم تایمر(Timer) در میکروکنترلر STM32f103 خواهیم پرداخت. با ما همراه باشید.
نویسنده: اشکان راکی