روش کنترل دور موتور DC با PWM و Capture تایمر میکروکنترلر AVR

توسط | 22 آذر, 1398 | AVR, میکروکنترلر, وبلاگ | 4 دیدگاه ها

کنترل-دور-موتور-dc-avr

آموزش AVR یوبرد

شاهکار 8بیتی اتمل

آموزش های رایگان AVR

فیلم های آموزش AVR

آموزش خصوصی AVR

اخبار جدید یوبرد در اینستاگرام

PWM یکی از قابلیت های تایمر است که می تواند وسیله ای برای کنترل دور موتور DC باشد. PWM در AVR هم می تواند روی پایه های خروجی تایمر ایجاد شود و هم با کدنویسی و استفاده از وقفه های سرریز و مقایسۀ تایمر روی دیگر پایه های پورت I/O به وجود بیاید. با استفاده از موج PWM می توانیم دور یک موتور DC را کنترل کنیم. در این نوشته می خواهیم به بررسی نمونه کد کنترل دور موتور DC با PWM و Capture بپردازیم. در این نمونه کد یک موج PWM ساخته می شود و همچنین مقدار دور موتور بر حسب RPM از موتور DC توسط Capture خوانده می شود. کنترل دور موتور DC با میکروکنترلر AVR شامل استفاده از تایمرهای AVR برای ساختن موج PWM و شمارش پالس های فیدبک موتور توسط تایمر دیگری از AVR است.

برنامۀ نوشته شده برای تولید موج PWM در نرم افزار اتمل استودیو می باشد. همچنین از یک LCD گرافیکی برای نمایش پارامترهای موج PWM و دور موتور استفاده شده است. یک نمونه کد دیگر هم در فایل پیوست وجود دارد که با نرم افزار کدویژن نوشته شده است و در آن از LCD کاراکتری استفاده شده است. در ویدئوی این نوشته هر دو نمونه کد روی بورد توسعۀ ATmega 64pin امتحان می شوند. با استفاده از چهار کلید مقدار Duty Cycle و فرکانس موج PWM خروجی تغییر می کند. همچنین با استفاده از Capture مقدار زمان یک دور موتور اندازه گیری می شود. برای اندازه گیری دور موتور روی شفت موتور یک پره قرار داده ایم و این پره هنگام چرخش موتور از روی یک سنسور عبور می کند. با هر بار عبور پره از روی سنسور، خروجی سنسور از سطح منطقی یک به سطح منطقی صفر تغییر وضعیت می دهد. با هر بار تغییر وضعیت از سطح منطقی یک به سطح منطقی صفر، یک Capture در تایمر اتفاق می افتد. در ادامه به تحلیل بیشتر این موضوع می پردازیم.

در نوشتۀ «موج PWM با مد نرمال تایمر با Duty Cycle متغیر» دربارۀ موج PWM و همچنین ساخت PWM با تایمر در AVR صحبت کردیم. و دیدیم که چگونه می توانیم یک موج PWM روی یکی از پایه های پورت I/O ایجاد کنیم. همچنین توانستیم Duty Cycle این موج PWM را تغییر دهیم. برای یادگیری روش برنامه نویسی در اتمل استودیو نیز می توانید به نوشتۀ «مهاجرت از کدویژن به اتمل استودیو» مراجعه نمایید.

فیلم آموزش تایمر در STM32                         (فیلم آموزش ARM STM32 مقدماتی)

فیلم آموزش تایمر پیشرفته در STM32

فیلم آموزش تایمر در AVR                             (فیلم آموزش میکروکنترلرهای AVR مقدماتی)

فیلم آموزش تایمر پیشرفته در AVR

فیلم آموزش تایمر در آردوینو                          (فیلم آموزش آردوینو مقدماتی)

فیلم آموزش تایمر پیشرفته در آردوینو

نحوۀ کنترل دور موتور DC با PWM

کنترل دور موتور هم می تواند بدون فیدبک باشد و هم با فیدبک. کنترل بدون فیدبک دور موتور به این صورت که ما یک موج PWM با Duty Cycle مشخص به موتور می دهیم و موتور با یک دور مشخص شروع به چرخش می کند و به چرخش ادامه می دهد. اگر در حین چرخش وزنه یا باری روی شفت (Shaft) موتور قرار گیرد، سرعت چرخش موتور تغییر می کند. ما انتظار داشتیم با اعمال یک موج PWM با Duty Cycle مشخص، دور موتور مشخص داشته باشیم. ولی دور موتور با وزنۀ روی شفت تغییر کرد.

حال اگر به روشی بتوانیم کنترل دور موتور DC با فیدبک داشته باشیم، می توانیم حین تغییرات دور موتور، با تغییر Duty Cycle موج PWM، دور موتور را ثابت نگه داریم و میزان تغییرات را تا حد زیادی کم کنیم. کنترل دور موتور با فیدبک به این صورت است که ابتدا یک دور موتور مشخص برای آن تعیین می کنیم. در خروجی یک موج PWM با یک Duty Cycle پیش فرض ایجاد می شود. سپس موتور شروع به چرخش می کند. همچنان که موتور در حال چرخش است، از آن فیدبک گرفته می شود و دور موتور توسط سنسور خوانده می شود. اگر بعد از زمانی (این زمان توسط برنامه نویس تعیین می شود) دور موتور خوانده شده کمتر از مقدار تعیین شدۀ آن باشد، مقدار Duty Cycle موج PWM بیشتر می شود. اگر بعد از گذر همان زمان، مقدار دور موتور بیشتر از مقدار تعیین شده باشد، Duty Cycle موج PWM  کم می شود. مقدار Duty Cycle موج PWM آن قدر تغییر می کند و کم یا زیاد می شود که دور موتور به میزانی که تعیین کرده بودیم برسد.

تصویر 1 – روش کلی کنترل دور موتور با فیدبک

یک نوع دیگر کنترل دور موتور با فیدبک این است که وقتی دور موتور تعیین می شود، بلوک تولید کنندۀ موج PWM، یک موج PWM با Duty Cycle کم ایجاد کند و با گذر زمان رفته رفته آن را افزایش دهد. در همین حین نیز از موتور فیدبک گرفته شود. به محض رسیدن دور موتور به مقدار تعیین شده، افزایشِ Duty Cycle موج PWM متوقف شود. در این روش کاهش دور موتور نیز به همین صورت است. یعنی اگر دور موتور را بخواهیم کم کنیم، مقدار Duty Cycle موج PWM با گذر زمان رفته رفته کم شود. هنگامی که دور موتور خوانده شده به مقدار تعیین شده رسید، کاهش Duty Cycle موج PWM متوقف شود.

یک نکتۀ مهم در کنترل دور متور با فیدبک، زمان های فیدبک گیری است. ممکن است برای مثال هر 10 ثانیه یک بار فیدبک گرفته شود. ممکن است با هر چرخش موتور زمان یک چرخش آن محاسبه شود. اگر فواصل زمانی فیدبک گیری زیاد باشد، ممکن است دور موتور از آنچه برایش تعیین شده عبور کرده باشد. پس باید دوباره Duty Cycle موج PWM تغییر کند تا دور موتور به حد تعیین شده برسد. این روند تا زمانی ادامه می یابد که دور موتور به مقدار تعیین شده برسد.

به تصویر زیر توجه کنید. دور موتور 200 دور در دقیقه تنظیم شده است. مقدار Duty Cycle موج PWM طوری زیاد می شود که دور موتور از 200 دور در دقیقه بیشتر می شود. سپس فیدبک گرفته می شود. دوباره دور موتور با PWM کم می شود. دوباره فیدبک گرفته می شود. دور موتور از 200 دور در دقیقه کمتر شده است. دوباره دور موتور با PWM زیاد می شود. این روند تا زمانی ادامه پیدا می کند که دور موتور به مقدار تعیین شده برسد.

تصویر 2 – روند رساندن دور موتور به مقدار دلخواه

در این نوشته از خروجی برای کنترل دور موتور فیدبک گرفته نمی شود. مقدار دور موتور تنها برای نمایش در LCD اندازه گیری می شود.

قابلیت Capture در AVR و کنترل دور موتور DC با AVR

در تایمر شمارۀ یک میکروکنترلر ATmega64A یک قابلیت وجود دارد به اسم Input Capture. توضیح مختصر قابلیت Capture (کپچر در AVR) این است که یک پایۀ میکروکنترلر (پایۀ ICP1) برای تایمر شمارۀ یک ورودی می شود. اگر یک لبۀ بالا رونده (یا پایین رونده) روی این پایه به وجود بیاید، مقدار رجیستر تایمر یعنی  رجیستر TCNT1 در رجیستری به نام ICR1 ریخته می شود. بنابراین می توانیم بفهمیم که آن لبۀ بالا رونده (یا پایین رونده) در چه زمانی از شمارش تایمر رخ داده است.

کاربرد Capture در کنترل دور موتور DC

با استفاده از قابلیت Captuer می توان دور یک موتور را اندازه گرفت. در این روش خروجی سنسورِ روی موتور به پایۀ ICP1 متصل می شود. هر وقت موتور یک دور بزند، یک پالس در خروجی سنسور ایجاد می شود. با دور بعدی پالس دیگری ایجاد می شود. با استفاده از قابلیت Capture می توان زمان بین دو لبۀ بالا رونده (یا پایین رونده) این موج را اندازه گرفت. بنابراین می توان زمان یک دور موتور را اندازه گرفت. اگر عدد 60 را بر زمان بین دو لبۀ پالس تقسیم کنیم، مقدار دور موتور بر حسب RPM به دست می آید.

خروجی سنسور چگونه به پایۀ ICP1 متصل می شود؟

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

این پالس را اگر به پایۀ ICP1 بدهیم می توانیم زمان بین دو پالس یعنی یک دور موتور را اندازه بگیریم. یک نکته را در نظر داشته باشید. اگر از پره ای استفاده کنیم که تنها یک لبه (blade) داشته باشد با هر بار دور زدن این لبه، موتور یک دور زده است. اگر چند لبه داشته باشد، باید تعداد لبه ها در مقدار زمان اندازه گیری شده ضرب شود تا زمان یک دور به دست بیاید. مثلاً اگر پره ای با سه لبه به موتور متصل کنیم، با عبور هر لبۀ این پره از فضای خالی سنسور، یک پالس ایجاد می شود. و میکروکنترلر زمان بین هر چرخش لبه را اندازه گیری می کند. یعنی یک سومِ دور موتور. بنابراین زمان اندازه گیری شده باید در سه ضرب شود تا زمان یک چرخش کامل به دست بیاید.

تصویر 3 – سنسور دور موتور و پرۀ موتور در حال چرخش

این که سنسور چگونه بایاس شود و یا خروجی آن پول آپ شود مهم نیست. زیرا در خروجی تنها لبه های پالس ایجاد شده مهم هستند. هر لبۀ بالا رونده (یا پایین رونده) یک بار باعث Capture در تایمر می شود. اگر وقفۀ Capture را فعال کرده باشیم، کدهای روتین وقفۀ Capture اجرا می شود. کدهای روتین وقفۀ Capture نیز باید طوری نوشته شوند که فرق بین پالس اول و دوم تشخیص داده شود. در ادامۀ نوشته این مورد بحث می شود.

بررسی برنامۀ نوشته شده برای کنترل دور موتور DC

همان طور که گفته شد یک نمونه کد در اتمل استودیو و یک نمونه کد در کدویژن برای کنترل دور موتور DC نوشته ایم. در نمونه کد اتمل استودیو LCD گرافیکی KS108 و در نمونه کد کدویژن LCD کاراکتری راه اندازی شده است. در ادامه نمونه کد اتمل استودیو را بررسی می کنیم.

Defineها و کتابخانه های برنامه

پس از تعیین فرکانس میکروکنترلر چند کتابخانه به برنامه اضافه شده است.

#ifndef F_CPU
#define F_CPU 8000000UL // You can enter the frequency you want for the processor here
#endif

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include "MyLib/Gpio.h"
#include "MyLib/GlcdKs108.h"

برای استفاده از وقفه های تایمر لازم است کتابخانۀ interrupt.h از پوشۀ avr فراخوانی شود. کتابخانۀ Gpio.h نیز دارای توابعی است که پایه های پورت I/O را کنترل می کند. توابع این کتابخانه در کتابخانۀ GlcdKs108.h استفاده شده اند. توابع کتابخانۀ Gpio.h در نوشتۀ «روش راه اندازی ADC در AVR و LCD گرافیکی KS108» شرح داده شده اند.

متغیرهای عمومی و وقفه های استفاده شده

برای کنترل دور موتور DC و همچنین ساخت موج PWM با فرکانس و Duty Cycle متغیر لازم است چند متغیر تعریف شود.

volatile unsigned char TcntStartPoint=0, DutyCycle=50, LcdRefCounter=0;

volatile float RpmIn=0;
volatile char Counter=0 ;

روتین وقفه های تایمر صفر به صورت زیر هستند.

ISR (TIMER0_OVF_vect)
{
	LcdRefCounter++;
	TCNT0=TcntStartPoint;
	PORTF &=(~(1<<0));
}

ISR (TIMER0_COMP_vect)
{
	PORTF|=(1<<0);
}

در روتین وقفۀ سرریز تایمر صفر به متغیر LcdReCounter یک واحد اضافه می شود. این متغیر برای این است که LCD دائماً رفرش نشود. در حلقۀ while شرطی گذاشته ایم که هرگاه مقدار این متغیر از عددی بزرگ تر شد آنگاه LCD رفرش شود. به این طریق LCD دائماً در حلقۀ while رفرش نمی شود. مقدار TCNT0 نیز از متغیر TcntStartPoint گرفته می شود. دربارۀ این دو موضوع در نوشتۀ «روش ساخت موج PWM در AVR با Duty Cycle و فرکانس متغیر» توضیح داده ایم.

در سطر آخر نیز پایۀ صفرم پورت F صفر می شود. این پایه در وقفۀ مقایسۀ تایمر صفر یک می شود. بنابراین روی پایۀ PF0 یک موج PWM خواهیم داشت. با توجه به این که این پایه در روتین وقفۀ سرریز، صفر و در روتین وقفۀ مقایسه یک می شود، موج PWM ساخته شده روی پایۀ PF0 شبیه موج PWM در حالت inverted PWM مد fast PWM است.

روتین وقفه های تایمر یک نیز به صورت زیر هستند.

// Timer1 overflow interrupt service routine
ISR (TIMER1_OVF_vect)
{
	// Place your code here
	Counter = 0 ;
}

// Timer1 input capture interrupt service routine
ISR (TIMER1_CAPT_vect)
{
	static unsigned int PULSE1=0 , PULSE2=0 ,PULSES=0 ;
	static float one_encoder_period_pulse_time=0 ,one_route_time=0;
	
	if (Counter == 0)
	{
		PULSE1 = ICR1;
		Counter = 1 ;
	}
	else if (Counter == 1)
	{
		PULSE2 = ICR1;
		PULSES = PULSE2 - PULSE1 ;
		one_encoder_period_pulse_time = PULSES * 0.00032 ;
		one_route_time =  one_encoder_period_pulse_time  ;
		RpmIn = 60 / one_route_time  ;
		Counter = 0 ;
	}
	
}

در وقفۀ سرریز تایمر یک، متغیر Counter صفر می شود. در ادامه به توضیح عملکرد این متغیر می پردازیم. در روتین وقفۀ Capture تایمر یک، ابتدا چند متغیر تعریف شده است. پس از آن شرط هایی آورده شده که مقدار متغیر Counter را بررسی می کنند. با توجه به مقدار Counter دو حالت به وجود می آید.

اگر برای اولین بار پرۀ روی موتور از جلوی سنسور عبور کند، با لبۀ پایین روندۀ آن (با توجه به مقدار بیت ICES1 در رجیستر TCCR1B) یک Capture و نیز وقفۀ آن اتفاق می افتد. مقدار اولیۀ Counter نیز صفر است. بنابراین مقدار ICR1 (که در واقع مقدار تایمر است) در PULSE1 ریخته می شود. متغیر Counter نیز 1 می شود. با عبور دوم پره و ایجاد پالس دوم و لبۀ پایین روندۀ پالس یک بار دیگر Capture و وقفۀ آن اتفاق می افتد. با توجه به این که مقدار Counter برابر 1 است، شرط دوم اجرا می شود. مقدار جدید ICR1 (که مقدار جدید تایمر است) در متغیر PULSE2 ریخته می شود.

الآن دو مقدار داریم. یکی PULSE1 که دربرگیرندۀ زمانی است پالس اول روی خروجی سنسور ایجاد شده و دیگری PULSE2 است که شامل زمانی است که پالس دوم به وجود آمده است. یعنی تایمر یک در حال شمارش بوده است. وقتی لبۀ پایین روندۀ پالس اول اتفاق افتاده مقدار تایمر در PULSE1 قرار گرفته. سپس تایمر به شمارش خود ادامه داده و وقتی لبۀ پایین روندۀ پالس دوم اتفاق افتاده، مقدار جدید تایمر در PULSE2 قرار گرفته است. بنابراین فاصلۀ زمانی بین لبه های پایین روندۀ دو پالس ایجاد شده برابر است با مقدار متغیر PULSE2 منهای PULSE1 که در ادامه حاصل این تفریق در متغیر PULSES قرار گرفته است.

با توجه به فرکانس کاری تایمر که توسط بیت های CS12 تا CS10 در رجیستر TCCR1B تعیین شده است، هر پله از تایمر برابر 32 میکرو ثانیه است. بنابراین زمان بین لبه های پایین روندۀ دو پالس بر حسب ثانیه برابر مقدار PULSES ضرب در 32 میکروثانیه است. این مقدار در متغیر one_encoder_period_pulse_time قرار گرفته است. در ادامه مقدار این متغیر در متغیر one_route_time ریخته شده است. در سطر بعدی مقدار دور موتور بر حسب دور در دقیقه (RPM) محاسبه شده است. اگر عدد 60 را بر زمان بین دو پالس که بر حسب ثانیه است، تقسیم کنیم، مقدار دور موتور بر حسب دور در دقیقه به دست می آید.

برای مثال فرض کنیم هنگام ایجاد لبۀ پایین روندۀ پالس اول مقدار تایمر برابر 1000 است. این مقدار در PULSE1 ریخته می شود. وقتی لبۀ پایین روندۀ پالس دوم ایجاد می شود، مقدار تایمر به 2000 رسیده است. این مقدار در PULSE2 ریخته می شود. مقدار PULSE2 منهای PULSE1 که برابر 1000 است، تعدا پله های شمارش شده به ازای یک چرخش موتور است. در ادامه دور موتور با در نظور گرفتن این مقدار محاسبه می شود.

در سطر بعدی مقدار متغیر Counter صفر شده است. برای این که دفعۀ بعدی که روی پایۀ ICP1 لبۀ پایین روندۀ یک پالس ایجاد شد، شرط اول روتین وقفۀ Capture اتفاق بیفتد. کاربرد متغیر Counter همین است. در وقفۀ Captuer برای این که تفکیک کنیم که الآن کدام پالس ایجاد شده، به متغیر Counter مقدار داده ایم. اگر پالس اول ایجاد شده باشد، شرط اول اجرا می شود و مقدار آن را 1 می کنیم برای این که دیگر شرط اول اجرا نشود. در ادامه اگر پالس دوم ایجاد شود، شرط دوم اجرا می شود. در این شرط مقدار آن را صفر می کنیم. تا دفعۀ بعد وارد شرط اول شود. به همین ترتیب این روند ادامه خواهد داشت.

نکته ای که باید به آن توجه داشت این است که تایمر همیشه در حال شمارش است و هرگاه که مقدار ماکزیمم خود برسد، سرریز می شود. مقدار ماکزیمم تایمر 1 با توجه به این که یک تایمر 16 بیتی است، برابر 65535 است. تایمر از صفر تا این مقدار می شمارد و پس از این مقدار سرریز می شود و دوباره از صفر می شمارد. حال فرض کنید در هنگامی که تایمر مقدار زیادی دارد، مثلاً 65530، پالس اول ایجاد شود. این مقدار در PULSE1 ریخته می شود. در ادامه تایمر به ماکزیمم خود می رسد و سرریز می شود. در هنگام ایجاد پالس دوم مقدار تایمر مثلاً 500 می شود. این مقدار در PULSE2 ریخته می شود. با توجا به این دو مقدار، متغیر PULSES که نتیجۀ تفریق این دو مقدار است، منفی می شود. علاوه بر منفی بودن این مقدار، تعدا پله های شمارش شده صحیح نیست. 500 منهای 65530 می شود -65030  که هم منفی است و هم مقداری است اشتباه.

برای رفع این مشکل کافی است در هنگام سرریز تایمر یک، مقدار متغیر Counter را صفر کنیم که اگر مقدار آن با ایجاد پالس اول (در هنگامی که مقدار تایمر نزدیک سرریز شدن بوده) یک شده بود، دوباره صفر شود. به این ترتیب پالس که ایجاد شده بود در نظر گرفته نمی شود و پالس بعدی به عنوان پالس اول در نظر گرفته خواهد شد. مقدار متغیر Counter در روتین وقفۀ سرریز تایمر یک به همین منظور صفر شده است.

بررسی تابع main

در این تابع پس از معرفی متغیر LcdSTR و Freq، که به ترتیب برای نمایش در LCD و فرکانس هستند، رجیسترها مقداردهی شده اند.

int main(void)
{
	char LcdStr[16];
	static int Freq = 1000;
	
	DDRB = (1<<4); PORTB= (1<<4); // LED Blue
	DDRG = (1<<1); PORTG= (1<<1); // LED Green
	DDRB |= (1<<7); PORTB|= (1<<7); // LED Red


	PORTE= (1<<6)|(1<<5)|(1<<4);
	PORTB|=(1<<0);

	DDRF=0X01;


	// Timer/Counter 0 initialization
	TCCR0=(1<<CS02) | (1<<CS01) | (1<<CS00);
	TcntStartPoint= (unsigned char) (255-(7813/Freq));
	TCNT0=TcntStartPoint;
	OCR0 = (unsigned char)(((DutyCycle * 0.01) * (255-TcntStartPoint)) + TcntStartPoint);
	
	// Timer/Counter 1 initialization
	TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<COM1C1) | (0<<COM1C0) | (0<<WGM11) | (0<<WGM10);
	TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (1<<CS12) | (0<<CS11) | (0<<CS10);

	// Timer(s)/Counter(s) Interrupt(s) initialization
	TIMSK= (1<<TICIE1) | (1<<TOIE1) | (1<<OCIE0) | (1<<TOIE0);

	asm ("sei");

	glcd_on();
	glcd_clear(); . . . . . . .}

ابتدا به رجیسترهای پورت های I/O مقدار داده ایم. پایه هایی را که به LED متصل هستند، خروجی کرده ایم و به آنها مقدار 1 داده ایم تا LEDها خاموش باشند. روی بورد توسعۀ ATmega 64pin یک LED RGB آند مشترک به سه پایۀ PB4، PG1 و PB7 متصل است. برای خاموش کردن این LED باید پایه های آن را یک کرد. در ادامه پایه های PE4، PE5، PE6 و PB0 ورودی و به صورت داخلی پول آپ شده اند. این پایه ها روی بورد توسعه به چهار کلید متصل اند. پایۀ PF0 نیز خروجی شده است. زیرا موج PWM خروجی را روی این پایه ساخته ایم.

در ادامه به رجیسترهای تایمر صفر مقدار داده ایم. موج PWM روی پایۀ PF0 با این تایمر به وجود می آید. برای درک عملکرد این موضوع به نوشتۀ «روش ساخت موج PWM در AVR با Duty Cycle و فرکانس متغیر» مراجعه کنید. در نوشتۀ مذکور مقدار دهی به رجیسترهای این تایمر و همچنین روش ساختن موج PWM با Duty Cycle و فرکانس متغیر به طور مفصل بحث شده است. در اینجا از تکرار مباحث گذشته اجتناب می کنیم.

رجیسترهای تایمر 1 نیز به این صورت مقداردهی شده اند که تایمر در مد نرمال با تقسیم فرکانسی 256 کار کند. با توجه به این که مقدار F_CPU برابر 8 مگاهرتز است، مقدار فرکانس کلاک تایمر برابر است با 8 مگاهرتز تقسیم بر 256 که می شود 31250 هرتز. پس زمان هر پلۀ تایمر برابر است با 1 تقسیم بر این مقدار که می شود 32 میکروثانیه. مقدار بیت ICES1 نیز صفر است. با این مقدار اگر لبۀ پایین رونده روی پایۀ Capture یعنی ICP1 ایجاد شود، Capture اتفاق می افتد. اگر این بیت یک می شد، Capture با لبۀ بالا رونده اتفاق می افتاد.

رجیستر TIMSK هم طوری مقداردهی شده که وقفه های سرریز و مقایسۀ تایمر صفر و وقفه های سرریز و Capture تایمر یک فعال شوند. در سطرهای بعدی نیز LCD گرافیکی و پرچم کلی وقفه ها فعال شده اند.

برنامۀ نوشته شده در حلقۀ while

در حلقۀ while چهار شرط اول برای تغییر فرکانس و Duty Cycle موج PWM خروجی است. شرط اول برای کاهش Duty Cycle، شرط دوم برای افزایش Duty Cycle و شرط های سوم و چهارم به ترتیب برای کاهش و افزایش فرکانس موج PWM خروجی هستند. توضیح این چهار شرط را در نوشتۀ «روش ساخت موج PWM در AVR با Duty Cycle و فرکانس متغیر» مطالعه نمایید.

while (1)
	{
		if ( (PINE & (1<<4)) == 0 )
		{
			if (DutyCycle>10)
			{
				while ( (PINE & (1<<4)) == 0 );
				DutyCycle -=10;
				OCR0 = (unsigned char)(((DutyCycle * 0.01) * (255-TcntStartPoint)) + TcntStartPoint);
				if ( OCR0<=TcntStartPoint )
				{
					DutyCycle +=10;
					OCR0 = (unsigned char)(((DutyCycle * 0.01) * (255-TcntStartPoint)) + TcntStartPoint);
				}
			}
		}
		else if ( (PINE & (1<<5)) == 0 )
		{
			if ( DutyCycle<90 )
			{
				while ( (PINE & (1<<5)) == 0 );
				DutyCycle +=10;
				OCR0 = (unsigned char)(((DutyCycle * 0.01) * (255-TcntStartPoint)) + TcntStartPoint);
			}
		}
		
		if ( (PINE & (1<<6)) == 0 )
		{
			if ( Freq>300 )
			{
				while ( (PINE & (1<<6)) == 0 );
				Freq -=300;
				TcntStartPoint= (unsigned char) (255-(7813/Freq));
				TCNT0=TcntStartPoint;
				OCR0 = (unsigned char)(((DutyCycle * 0.01) * (255-TcntStartPoint)) + TcntStartPoint);
			}
			
		}
		else if ( (PINB & (1<<0)) == 0 )
		{
			if ( Freq < 3600 )
			{
				while ( (PINB & (1<<0)) == 0 );
				Freq +=300;
				TcntStartPoint= (unsigned char) (255-(7813/Freq));
				TCNT0=TcntStartPoint;
				OCR0 = (unsigned char)(((DutyCycle * 0.01) * (255-TcntStartPoint)) + TcntStartPoint);
			}
		}
		
		if (LcdRefCounter >= 200)
		{
			glcd_clear();
			sprintf(LcdStr,"Fr=%d", Freq );
			glcd_puts((uchar*)LcdStr,0,0,0,1,0);
			sprintf(LcdStr,"Du=%d",(char)DutyCycle );
			glcd_puts((uchar*)LcdStr,0,10,0,1,0);
			sprintf(LcdStr,"RPM=%d",(int)RpmIn );
			glcd_puts((uchar*)LcdStr,0,20,0,1,0);
			LcdRefCounter=0;
		}
	}

در شرط آخر مقدار متغیر LcdRefCounter بررسی می شود. هرگاه مقدار این متغیر بزرگتر یا مساوی 200 شود، کدهای درون آن اجرا می شوند. ابندا LCD گرافیکی پاک می شود سپس مقدار فرکانس، مقدار Duty Cycle و مقدار دور موتور در LCD گرافیکی نمایش داده می شود. مقادیر فرکانس و Duty Cycle موج PWM خروجی را کاربر انتخاب کرده است اما مقدار دور موتور با قابلیت Capture تایمر یک از سنسور روی موتور خوانده می شود.

مشابه همین نمونه کد را برای میکروکنترلرهای ARM در دورۀ آموزشی ARM TSM32 و  دورۀ آموزشی ARM LPC1768 بررسی کرده ایم.

راه اندازی موتور DC با L293D

ما نمی توانیم موتور را مستقیماً به میکروکنترلر متصل کنیم. زیرا موتور جریانی بیش از حد جریان یک پایۀ میکروکنترلر می کشد. پایۀ میکروکنترلر می تواند حداکثر 40 میلی آمپر جریان بدهد که حتی یک پنجم این جریان هم نباید از پایۀ آن بکشیم. برای راه اندازی موتور می توانیم از درایورهای موتور استفاده کنیم. درایورهای موتور DC انواع مختلفی دارند. می توانیم برای موتور با استفاده از تعدادی ترانزیستور یک درایور بسازیم. اما استفاده از درایورهایی به صورت آی سی راحت تر است. یکی از آی سی درایورهای مناسب برای موتورهای معمولی (یعنی با جریان کم) آی سی L293D می باشد. تصویر زیر ترتیب و عملکرد پایه های این آی سی را نشان می دهد.

تصویر 4 – ترتیب پایه های L293D و نحوۀ اتصال آن به موتور

همان طور که در تصویر مشاهده می شود، L293D دو منبع تغذیه دارد. یکی برای قسمت دیجیتال و کنترل و دیگری برای موتور. اگر ما یک PWM با سطوح ولتاژ صفر و 5 ولت یا صفر و 3.3 ولت به L293D بدهیم، این آی سی می تواند PWM با سطوح ولتاژ صفر و Vs به موتور بدهد. یعنی لزومی ندارد ما از ولتاژی که به میکروکنترل داده ایم استفاده کنیم. همچنین می توان دو موتور را به این آی سی متصل کرد. برای اطلاعات بیشتر دربارۀ L293D می توانید دیتاشیت آن را مطالعه کنید.

PWM و کنترل دور موتور DC را در عمل ببینیم

در عمل از یک آی سی L293D استفاده کرده ایم. موتور استفاده شده در این پروژه دارای یک پرۀ یک لبه است. منبع تغذیۀ موتور (که به آی سی داده می شود) یک منبع 12 ولت است. لازم به ذکر است که افزایش و کاهش فرکانس اگر از محدوده ای خارج شود بر دور موتور تأثیر دارد. مثلاً اگر با Duty Cycle برابر 50 درصد فرکانس را آن قدر کم کنیم که موتور در لحظاتی طولانی خاموش شود و دوباره روشن شود، زمانی که موتور خاموش است دور آن کم می شود و زمانی که روشن است دورش زیاد می شود. و یک دور ناپایدار خواهیم داشت.

تصویر 5 – اتصال موتور به بورد توسعۀ ATmega 64pin با آی سی L293D

روی این بورد سه موتور وجود دارد. یک موتور سروو یک موتور استپر و یک موتور DC. یک پره (سبز رنگ) روی موتور DC شد متصل است. این پره یک لبه دارد که از فضای خالی سنسور عبور می کند. خروجی این سنسور با پین هدر به برد بورد و از آنجا با سیم به بورد توسعه و میکروکنترلر متصل است. خروجی L293D هم روی برد بورد با سیم به پین هدرهای بورد موتورها متصل شده است. در تصویر زیر موتور را در حال چرخش و همچنین مشخصات موج PWM و دور موتور را روی LCD مشاهده می کنید.

تصویر 6 – موتور در حال چرخش و نمایش مشخصات موج PWM و دور موتور در LCD

به عنوان تمرین می توانید یک برنامه بنویسید که کنترل دور موتور با فیدبک باشد. طوری که وقتی دور موتور تعیین می شود، مقدار Duty Cycle طوری تغییر کند که دور موتور به مقدار تعیین شده برسد. هر وقت که بار روی شفت موتور زیاد می شود، دور موتور تغییر نکند. برای این که بار روی شفت موتور را تغییر دهید، پره هایی با وزن های متفاوت استفاده کنید. یا روی لبه های پره وزنه هایی بچسبانید. این تمرین می تواند یک پروژۀ کنترل موتور DC با AVR باشد. می توان کنترل PWM با ولوم نیز انجام داد. با استفاده از ADC مقدار ولتاژ ولوم خوانده شود و مقدار OCRx با توجه به مقدار ADC تغییر کند. بنابراین می توان دور موتور DC را با ولوم تغییر داد.

در فایل شبیه سازی، برنامۀ اتمل استودیو شبیه سازی شده است. به جای فیدبک از موتور نیز به پایۀ ICP1 یک سیگنال ژنراتور متصل شده است.

از کنترل دور موتور DC با PWM و Capture نتیجه می گیریم:

  1. قابلیت Capture در تایمر وسیله ای برای اندازه گیری زمان، Duty Cycle، فرکانس، دور موتور و … است
  2. تغییر دور موتور DC معمولاً با PWM انجام می شود. برای کنترل بهتر دور موتور باید از آن فیدبک گرفت.
  3. یکی از راه های اندازه گیری دور موتور، استفاده از سنسورهای مادون قرمز است. این سنسور در جایی قرار می گیرد که با چرخش موتور مسیر بین فرستنده و گیرندۀ مادون قرمز باز و بسته شود. به این ترتیب گیرندۀ مادون قرموز در لحظاتی اشعۀ مادون قرمز را دریافت می کند و در لحظاتی دریافت نمی کند.
  4. یکی از روش های اندازه گیری دور موتور اندازه گیری فاصلۀ زمانی یک چرخش شفت موتور است. یکی دیگر از روش ها شمارش پالس های خروجی سنسور در یک زمان (مثلاً یک ثانیه) است.

برای راه اندازی موتور DC با میکروکنترلر لازم است از درایورها استفاده کنیم. درایورها می توانند به صورت آی سی مثل L293 و L298 باشند. همچنین می توانند به صورت ترانزیستوری مثل پل H باشند.



 

رضا اسدی

رضا اسدی

مدیر یوبرد، خالق و توسعه دهندۀ پلتفرم یوبرد، مجری پروژه های الکترونیکی، فعال در صنعت آسانسور، سابقه فعالیت در صنعت خودرو و همکاری در صنعت پزشکی و صنایع دیگر، آموزگار آموزش های یوبرد

سفارش پروژه میکروکنترلر یوبرد

زیرساخت مطمئن صنعت

جدیدترین تاپیک های AVR

برنامه-نویسی-میکروکنترلر-ویژوال-استودیو

برنامه نویسی میکروکنترلرها با ویژوال استودیو

نصب VisualGDB روی ویژوال استودیو، ساخت پروژه برای برنامه نویسی میکروکنترلرها با ویژوال استودیو، ساخت پروژه برای STM32 در ویژوال استودیو، کدنویسی STM32 در ویژوال استودیو، ساخت پروژه برای AVR در ویژوال استودیو، ساخت پروژه برای LPC در ویژوال استودیو، ساخت پروژۀ آردوینو در ویژوال استودیو

رله-relay

رله، سوییچ تحریک پذیر

تعریف رله، تاریخچه، طرز کار رلۀ الکترومکانیکی، اصطلاحات، انواع الکترومکانیکی، رلۀ حالت جامد، رلۀ هیبریدی، رلۀ حرارتی و انواع تحریک شونده با عوامل غیر الکتریکی، انواع موجود در صنعت برق و برق صنعتی، رلۀ ایمنی و برخی انواع حفاظتی، رلۀ دیجیتال، لزوم استفاده و راه اندازی رله، مشخصات الکتریکی

پروتکل-i2c-protocol

پروتکل I2C، ادغامی از USART و SPI توسط Philips

پروتکل I2C، تاریخچه I2C، ویژگی ها و کاربردهای I2C، عبارات و اصطلاحات I2C، باس، اتصالات و گسترش شبکه I2C، سیگنال های I2C، قالب داده و آدرس در I2C، انتقال داده در I2C، آدرس دهی 10 بیتی، قابلیت Multi-master، حکمیت، مشخصات الکتریکی و زمانی، مقدار مقاومت های پول آپ، Clock Stretching

سون-سگمنت-seven-segment

سون سگمنت، نمایشگر هفت قسمتی

سون سگمنت چیست؟ انواع 7-segment، تاریخچه 7-segment، ساختار 7-segment و نمایش در آن، تعداد ارقام و 7-segmentهای مالتی پلکس، کاربردها، انواع اندازه ها و رنگ ها و مدار راه اندازی 7-segment، بایاس 7-segment، مقدار مقاومت در راه اندازی 7-segment، درایور سون سگمنت، پایه های 7-segment

4 دیدگاه ها

  1. سلام.دمت گرم.دمت گرم.دمت گرم
    پرچمت همیشه بالا باشه

    پاسخ
  2. سلام
    من میخوام 4 تا موتور dc رو که ولتاژ شون بین 8 تا 18 ولته رو از طریق زمان بندی کنترل کنم و همین طور از طریق بلوتوث بتونم 4 تا 6 برنامه مجزا زمان بندی رو داشته باشم ک هر زمان خواستم تغییر بدم و همینطور از طریق بلوتوث قابل تنظیم باشه
    ممنون میشم راهنمایی ام کنید

    پاسخ
    • سلام وقت بخیر. شما بطور کلی یک پروژه را تعریف کردید. ما دقیقا متوجه نیاز شما نشدیم. می توانید با شماره تماس وبسایت تماس بگیرید. درصورت نیاز برای مشاوره یا آموزش یا انجام پروژه راهنمایی خواهید شد.

      پاسخ

یک دیدگاه بنویسید

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

دیگر آموزش های یوبرد

آموزش زبان C و MISRA-C یوبرد

گام نخست دنیای میکروکنترلر

آموزش طراحی PCB و نویز یوبرد

تجسم دنیای الکترونیک

آموزش لحیم کاری و IPC-A-610 یوبرد

ساخت دنیای الکترونیک

آموزش میکروکنترلرهای ARM STM32 یوبرد

شروع بازی ST

آموزش آردوینو یوبرد

جادۀ آسفالت میکروکنترلر

آموزش FreeRTOS یوبرد

زمان واقعی در میکروکنترلر و پردازنده های کوچک با FreeRTOS

آموزش ماژول های SIM800 یوبرد

تلفن همراه صنعت

آموزش زبان ++C و ++MISRA-C یوبرد

لمس شی گرایی در میکروکنترلرها

آموزش میکروکنترلرهای LPC یوبرد

یادگار فیلیپس

آموزش های شاخص

دانلود

لطفا برای دریافت لینک دانلود اطلاعات خواسته شده را وارد نمایید
ضبط پیام صوتی

زمان هر پیام صوتی 4 دقیقه است