PWM فرکانس متغیر با AVR، سخت افزاری و نرم افزاری

توسط | 21 آذر, 1398 | میکروکنترلر | 6 دیدگاه ها

تولید موج PWM سخت افزاری و نرم افزاری با AVR، تولید PWM فرکانس متغیر با AVR، نمونه کد PWM در AVR، فرمول Duty Cycle و فرکانس PWM، شبیه سازی PWM فرکانس متغیر در پروتئوس، نحوۀ تغییر فرکانس و Duty Cycle موج PWM، نکات PWM با فرکانس و Duty Cycle متغیر
pwm-فرکانس-متغیر-avr

PWM فرکانس متغیر با AVR هم به صورت سخت افزاری با مدهای PWM تایمر و هم به صورت نرم افزاری با مدهای نرمال، PWM و CTC آن قابل دست یابی است. در نوشتۀ «ساخت PWM با AVR، سخت افزاری و نرم افزاری»، به تولید PWM سخت افزاری و نرم افزاری پرداختیم. در آن نوشته دیدیم که چگونه می توان با تغییر OCRn در یک محدوده، Duty Cycle را تغییر داد. همچنین نکاتی را برای تولید PWM نرم افزاری و سخت افزاری ذکر کردیم. در این نوشته با ایجاد موج PWM با فرکانس متغیر با AVR، بحث تولید PWM در AVR را تکمیل می کنیم. در ادامه ابتدا به محاسبه فرکانس PWM و نحوۀ دست یابی به فرکانس و Duty Cycle دلخواه می پردازیم. خواهیم دید که چگونه با به کار بردن دو فرمول برای مقادیر OCRn و TCNTn به ترتیب Duty Cycle و فرکانس موج PWM را تغییر می دهیم. سپس نمونه کد PWM در AVR را که در نرم افزار اتمل استودیو نوشته شده، بررسی می کنیم. نمونه کدی که در این نوشته بررسی می شود، تکمیل شدۀ نمونه کد همان نوشته ای است که ذکر شد. بنابراین در اینجا تنها به نحوۀ تغییر فرکانس PWM و Duty Cycle آن می پردازیم. همچنین فرکانس و Duty Cycle موج های PWM ساخته شده را در LCD کاراکتری نمایش می دهیم. پروژۀ این نوشته که شامل فایل های اتمل استودیو و کدویژن و شبیه سازی پروتئوس است، در پیوست قرار دارد.

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

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

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

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

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

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

pwm-فرکانس-متغیر-میکروکنترلر-avr

تصویر 1 – موج PWM فرکانس متغیر با AVR

فرمول Duty Cycle و فرکانس موج PWM

برای ایجاد یک موج PWM فرکانس متغیر با AVR یا میکروکنترلرهای دیگر ممکن است روش های متعددی وجود داشته باشد. در نمونه کد این نوشته، سه موج PWM سخت افزاری و یک موج PWM نرم افزاری ایجاد شده است. موج های PWM سخت افزاری با مد شمارۀ 7 تایمر 1 ساخته شده اند. موج PWM نرم افزاری نیز با مد نرمال تایمر صفر ایجاد شده است. برای این که بتوانیم فرکانس این موج های PWM را تغییر دهیم، باید تعداد پله های شمارش را تغییر دهیم. در مدهای  مذکور برای تغییر تعداد پله های شمارش باید به رجیستر TCNTn مقدار بدهیم. در این صورت تایمر همواره از آن مقدار تا TOP که مقداری ثابت است، شمارش می کند. با توجه به تصویر زیر، برای موج PWM ناوارون، فرکانس برابر است با:

فرمول-فرکانس-pwm-تایمر-avr

عبارت tcnt start value مقدار اولیه ای است که باید به TCNTn داده شود. بنابراین رابطۀ مقدار tcnt start value بر حسب فرکانس به صورت زیر است. اگر تایمر همواره از این مقدار تا مقدار TOP شمارش کند، فرکانس PWM خروجی برابر fPWM می شود.

فرمول-مقدار-اولیه-شمارش-تایمر

برای تغییر Duty Cycle نیز باید مقدار رجیستر OCRn را تغییر داد. فرمول Duty Cycle بر حسب درصد به صورت زیر است.

فرمول-duty-cycle-pwm-avr

بنابراین مقدار OCRn به صورت زیر می شود.

فرمول-مقدار-ocr

همان طور که مشاهده می شود، tcnt start value مستقل از Duty Cycle و OCRn است. ولی Duty Cycle و در نتیجه OCRn به tcnt start value وابسته هستند. پس از تغییر فرکانس، مقدار tcnt start value تعیین می شود. این مقدار مستقیماً به TCNTn داده می شود و فرکانس PWM تغییر می کند. این مقدار در فرمول OCRn نیز تأثیرگذار است. بنابراین پس از هر بار تغییر فرکانس باید علاوه بر TCNTn، به OCRn نیز مقدار داد. در این صورت تغییر فرکانس باعث تغییر Duty Cycle نمی شود.

نمودار-تایمر-خروجی-pwm

تصویر 2 – موج PWM وارون از خروجی تایمر در AVR

تولید موج PWM فرکانس متغیر با AVR

در این بخش به شرح نمونه کد PWM با فرکانس متغیر با AVR می پردازیم. در برنامه ای که نوشته ایم، مشخصات موج های PWM توسط کلید تغییر می کنند و در LCD نمایش داده می شوند. با توجه به این که از برد توسعه ATmega64Pin استفاده کرده ایم، کلیدها را به صورت زیر دیفاین می کنیم.

#define next_pwm_change_key			(PINE & (1<<7))
#define duty_cycle_decrease_key		(PINE & (1<<4))
#define duty_cycle_increase_key		(PINE & (1<<5))
#define frequency_decrease_key		(PINE & (1<<6))
#define frequency_increase_key		(PINB & (1<<0))

حداکثر مقدار شمارش تایمرها و همچنین فرکانس کلاک آنها را دیفاین می کنیم.

#define timer1_mode_7_top_value		1023
#define timer0_mode_0_top_value		255
#define timer1_clock_frequency		1000000
#define timer0_clock_frequency		1000000

برای موج های PWMی که آنها را ساخته ایم، چند دیفاین به صورت زیر داریم. در ادامه کاربرد آنها را توضیح می دهیم.

#define oc1a_pwm_channel	0
#define oc1b_pwm_channel	1
#define oc1c_pwm_channel	2
#define pa0_pwm_channel	3

متغیرهای freqn و tcntn start value را به صورت عمومی تعریف می کنیم. این متغیرها به ترتیب برای فرکانس موج PWM مقدار اولیۀ شمارش هستند. در مقداردهی به آنها، از فرمول های بدست آمده استفاده شده است.

unsigned char freq1=5, freq0=5; // frequencies in kHz
unsigned int tcnt1_start_value=  (unsigned int)  (timer1_mode_7_top_value - (timer1_clock_frequency/(freq1*1000)));
unsigned char tcnt0_start_value= (unsigned char) (timer0_mode_0_top_value - (timer0_clock_frequency/(freq0*1000)));

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

ISR(TIMER1_OVF_vect)
{
	TCNT1=tcnt1_start_value;
}

ISR(TIMER0_OVF_vect)
{
	TCNT0=tcnt0_start_value;
	PORTA |= (1<<0);  // set PA.0 at overflow
}

ISR(TIMER0_COMP_vect)
{
	PORTA &=~ (1<<0);  // clear PA.0 at Compare Match
}

در ابتدای تابع main متغیرهایی را به صورت زیر تعریف می کنیم. متغیرهای ocn/pa0 duty cycle برای اختصاص دادن Duty cycle به موج های PWM و متغیرهای ocrn value، مقادیری است که برای رسیدن به آن Duty cycle به رجیسترهای OCRn داده می شود. متغیر pwm channel نیز برای انتخاب کانال PWMی است که با فشردن کلیدها، فرکانس و Duty Cycle آن تغییر می کند. رشتۀ lcd str نیز برای نمایش در LCD کاراکتری 20*4 است.

char oc1a_duty_cycle=10, oc1b_duty_cycle=10, oc1c_duty_cycle=10;
char pa0_duty_cycle=10;
unsigned int ocr1a_value=
(unsigned int) (tcnt1_start_value + ((oc1a_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
unsigned int ocr1b_value=
(unsigned int) (tcnt1_start_value + ((oc1b_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
unsigned int ocr1c_value=
(unsigned int) (tcnt1_start_value + ((oc1c_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
unsigned char ocr0_value=
(unsigned char)(tcnt0_start_value + ((pa0_duty_cycle  * 0.01) * (timer0_mode_0_top_value - tcnt0_start_value)));
	
unsigned char pwm_channel=oc1a_pwm_channel;
char lcd_str[21];

پایه های PB.5 تا PB.7 و همچنین پایۀ PA.0، خروجی های PWM هستند. پایه های PE.4 تا PE.7 و همچنین PB.0 را برای اتصال کلید، به صورت ورودی پول آپ تنظیم می کنیم.

DDRB=(1<<DDB7) | (1<<DDB6) | (1<<DDB5);
DDRA |= (1<<DDA0);
PORTE |= (1<<7)|(1<<6)|(1<<5)|(1<<4);
PORTB |= (1<<0);

پیکربندی تایمرها را به صورت زیر انجام می دهیم. رجیسترهای TCNTn و OCRn را نیز با مقادیر tcntn start value و ocrn value برابر قرار داده ایم.

TCCR1A=(1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (1<<COM1C1) | (0<<COM1C0) | (1<<WGM11) | (1<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);
TCNT1=tcnt1_start_value;
OCR1AH= ocr1a_value >> 8;
OCR1AL= ocr1a_value & 0xFF;
OCR1BH= ocr1b_value >> 8;
OCR1BL= ocr1b_value & 0xFF;
OCR1CH= ocr1c_value >> 8;
OCR1CL= ocr1c_value & 0xFF;
	
TIMSK |= (1<<TOIE1);
	
ASSR=0<<AS0;
TCCR0=(0<<WGM00) | (0<<COM01) | (0<<COM00) | (0<<WGM01) | (0<<CS02) | (1<<CS01) | (0<<CS00);
TCNT0=tcnt0_start_value;
OCR0=ocr0_value;

TIMSK |= (1<<OCIE0) | (1<<TOIE0);

در نهایت وقفه ها و LCD را فعال و عبارت UBOARD.ir را به مدت 1.5 ثانیه نمایش می دهیم.

sei();
	
lcd_init();
lcd_clear();
lcd_puts("UBOARD.ir");
_delay_ms(1500);

pwm-فرکانس-متغیر-avr-پروتئوس

تصویر 3 – موج PWM فرکانس متغیر با AVR در پروتئوس، مقادیر اولیه برای فرکانس و Duty Cycle

تغییر فرکانس و Duty Cycle موج PWM

برای تغییر فرکانس PWM در AVR باید مقدار رجیستر TCNTn را تغییر دهیم. در این صورت تعداد پله های شمارش و در نهایت فرکانس تغییر می کند. برای این کار دو متغیر tcnt1 start value و tcnt0 start value را تعریف کردیم. در برد توسعۀ ATmega6Pin با فشردن کلید بالا (کلید روی PB.0)، شرط زیر اجرا می شود. در این شرط، شرط دیگری چک می شود. اگر مقدار pwm channel برابر یکی از کانال های OC1A تا OC1C باشد، تغییر فرکانس برای تایمر 1 و این سه موج PWM خواهد بود. در غیر این صورت تغییر فرکانس برای کانال PA0 است. در هر کدام از این شرط ها مقدار متغیر freqn تغییر می کند. در سطر بعد، محدوده ای برای فرکانس در نظر گرفته شده است. پس از آن، مقادیر tcntn start value و ocrn value با فرمول ها مقدار می گیرند. رجیستر TCNTn درون وقفۀ سرریز برابر tcntn start value می شود و در اینجا تنها رجیسترهای OCRn مقداردهی می شوند. بدین ترتیب فرکانس موج PWM بدون تاثیر بر Duty Cycle، تغییر می کند. کلید پایین (روی PE.6) نیز برای کاهش فرکانس است و برنامۀ آن به همین شکل نوشته شده است.

else if (!frequency_increase_key)
{
_delay_ms(50);
while (!frequency_increase_key);
if((pwm_channel==oc1a_pwm_channel)||(pwm_channel==oc1b_pwm_channel)||
(pwm_channel==oc1c_pwm_channel))
{
	freq1++;
	if(freq1>10) freq1=10;
tcnt1_start_value=  (unsigned int)  (timer1_mode_7_top_value - (timer1_clock_frequency/(freq1*1000)));
ocr1a_value= (unsigned int) (tcnt1_start_value + ((oc1a_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
ocr1b_value= (unsigned int) (tcnt1_start_value + ((oc1b_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
ocr1c_value= (unsigned int) (tcnt1_start_value + ((oc1c_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
OCR1AH= ocr1a_value >> 8;
OCR1AL= ocr1a_value & 0xFF;
OCR1BH= ocr1b_value >> 8;
OCR1BL= ocr1b_value & 0xFF;
OCR1CH= ocr1c_value >> 8;
OCR1CL= ocr1c_value & 0xFF;
}
else if(pwm_channel==pa0_pwm_channel)
{
freq0++;
	if(freq0>10) freq0=10;
tcnt0_start_value= (unsigned char) (timer0_mode_0_top_value - (timer0_clock_frequency/(freq0*1000)));
ocr0_value= (unsigned char)(tcnt0_start_value + ((pa0_duty_cycle  * 0.01) * (timer0_mode_0_top_value - tcnt0_start_value)));
	OCR0=ocr0_value;
}
}

کلید سمت راست (روی PE.5) برای افزایش Duty Cycle است. در شرط مربوط ابتدا مقدار pwm channel چک می شود. سپس بسته به این که کدام کانال PWM انتخاب شده است، ocn/pa0 duty cycle مربوط به آن، تغییر می کند. در سطر بعد محدوده ای برای Duty Cycle در نظر گرفته شده است. بعد از آن مقدار ocrn value از فرمول بدست می آید. در نهایت رجیستر OCRn مقداردهی می شود. به این ترتیب Duty Cycle موج PWM مورد نظر تغییر می کند. کلید سمت چپ (روی PE.4) برای کاهش Duty Cycle است و برنامۀ آن به همین شکل نوشته شده است.

else if (!duty_cycle_increase_key)
{
_delay_ms(50);
while (!duty_cycle_increase_key);
if(pwm_channel==oc1a_pwm_channel)
{
	oc1a_duty_cycle+=10;
	if(oc1a_duty_cycle>90) oc1a_duty_cycle=90;
ocr1a_value= (unsigned int) (tcnt1_start_value + ((oc1a_duty_cycle * 0.01) *  (timer1_mode_7_top_value - tcnt1_start_value)));
	OCR1AH= ocr1a_value >> 8;
	OCR1AL= ocr1a_value & 0xFF;
}
else if (pwm_channel==oc1b_pwm_channel)
{
	oc1b_duty_cycle+=10;
	if(oc1b_duty_cycle>90) oc1b_duty_cycle=90;
ocr1b_value= (unsigned int) (tcnt1_start_value + ((oc1b_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
	OCR1BH= ocr1b_value >> 8;
	OCR1BL= ocr1b_value & 0xFF;
}
else if (pwm_channel==oc1c_pwm_channel)
{
	oc1c_duty_cycle+=10;
	if(oc1c_duty_cycle>90) oc1c_duty_cycle=90;
ocr1c_value= (unsigned int) (tcnt1_start_value + ((oc1c_duty_cycle * 0.01) * (timer1_mode_7_top_value - tcnt1_start_value)));
	OCR1CH= ocr1c_value >> 8;
	OCR1CL= ocr1c_value & 0xFF;
}
else if (pwm_channel==pa0_pwm_channel)
{
	pa0_duty_cycle+=10;
	if(pa0_duty_cycle>90) pa0_duty_cycle=90;
ocr0_value= (unsigned char)(tcnt0_start_value + ((pa0_duty_cycle  * 0.01) * (timer0_mode_0_top_value - tcnt0_start_value)));
	OCR0=ocr0_value;
}
}

pwm-فرکانس-متغیر-avr-proteus

تصویر 4 – شکل موج PWM فرکانس متغیر با AVR در نرم افزار پروتئوس

انتخاب کانال PWM و نمایش در LCD

برای این که به ازای هر موج PWM، چهار کلید برای تغییر فرکانس و Duty Cycle تعریف نکنیم، متغیر pwm channel را تعریف کرده ایم. برای تعیین کانال نیز مقدار این متغیر را برابر یکی از دیفاین های ocn pwm channel قرار می دهیم. به این صورت که با هر بار فشردن کلید میانی (روی PE.7)، مقدار pwm channel چک و هر بار برابر یکی از مقادیر دیفاین شده، می شود. در شرط های تغییر فرکانس و Duty Cycle، مقدار این متغیر چک می شود. و تغییرات متغیرهای freqn و tcntn start value و همچنین متغیرهای ocn duty cycle و ocrn value مربوط به کانال PWM انتخاب شده تغییر می کنند. بدین صورت توانستیم تنها با اختصاص 5 کلید، Duty Cycle و فرکانس موج های PWM را تغییر دهیم.

if (!next_pwm_change_key)
{
	_delay_ms(50);
	while   (!next_pwm_change_key);
	if      (pwm_channel==oc1a_pwm_channel) pwm_channel=oc1b_pwm_channel;
	else if (pwm_channel==oc1b_pwm_channel) pwm_channel=oc1c_pwm_channel;
	else if (pwm_channel==oc1c_pwm_channel) pwm_channel=pa0_pwm_channel;
	else if (pwm_channel==pa0_pwm_channel)  pwm_channel=oc1a_pwm_channel;
}

پس از این شرط ها در حلقۀ while، LCD کاراکتری در سطر صفرم، کانال انتخاب شده، در سطر یکم، کانال ها و در سطر دوم و سوم، فرکانس و  Duty Cycle آنها را نمایش می دهد.

lcd_clear();
lcd_gotoxy(0,0);
if(pwm_channel==oc1a_pwm_channel) lcd_puts("Change OC1A Values!");
if(pwm_channel==oc1b_pwm_channel) lcd_puts("Change OC1B Values!");
if(pwm_channel==oc1c_pwm_channel) lcd_puts("Change OC1C Values!");
if(pwm_channel==pa0_pwm_channel)  lcd_puts("Change PA0 Values!");
lcd_gotoxy(0,1);
lcd_puts("OC..1A.1B.1C  PA0");		
lcd_gotoxy(0,2);
sprintf(lcd_str,"f=  %.2d %.2d %.2d  %.2d kHz",freq1,freq1,freq1,freq0);
lcd_puts(lcd_str);
lcd_gotoxy(0,3);
sprintf(lcd_str,"DC= %.2d %.2d %.2d  %.2d %%" ,oc1a_duty_cycle,oc1b_duty_cycle,oc1c_duty_cycle,pa0_duty_cycle);
lcd_puts(lcd_str);
_delay_ms(50);

نتیجۀ تولید موج PWM فرکانس متغیر با AVR روی برد توسعۀ AVR یوبرد در تصویر زیر آمده است. LEDهای سبز رنگ روی کانال های OC1x و LED قرمز روی کانال PA.0 است. LCD نیز مقادیر Duty Cycle و فرکانس را برای هر کانال نمایش می دهد. به مقادیر Duty Cycle و شدت نور LEDها توجه کنید.

تغییر-فرکانس-pwm-avr

تصویر 5 – نتیجۀ شکل موج PWM فرکانس متغیر با AVR با مشخصات تصویر قبل

نکات ساخت PWM فرکانس متغیر با AVR

  1. موج های PWM کانال های OC1A و OC1B و OC1C خروجی یک تایمر هستند. بنابراین فرکانس آنها با هم برابر است. (تایمر صفر در AVRتایمر 2 در AVRتایمر 1 و 3 در AVR)
  2. تعداد پله ها در دقت انتخاب فرکانس و Duty Cycle مؤثر است. بنابراین مقدار فرکانس و در نتیجه مقادیر tcntn start value را محدود کرده ایم. که بتوانیم انتخاب Duty Cycle و فرکانس را با دقت به ترتیب 1 درصد و 1 کیلوهرتز انجام دهیم. در برنامۀ نوشته شده، می توانیم Duty Cycle را به جای تغییر 10 درصدی، 1 درصد هم تغییر بدهیم.
  3. در فرمول ها از Type castingبرای تبدیل انواع متغیر استفاده کرده ایم. بنابراین ممکن است فرکانس یا Duty Cycle خاصی، دقیقاً برابر آنچه انتظار داریم، نشود. (انواع متغیر در زبان C)
  4. وجود متغیر tcntn start value در فرمول ocrn value باعث می شود تغییر فرکانس بر Duty Cycle تأثیر نگذارد. باید توجه داشت که پس از هر بار تغییرِ tcntn start value، مقدار ocrn value آپدیت شود.
  5. در مقداردهی به رجیسترهای 16 بیتی میکروکنترلرهای AVR، باید ابتدا به بایت بالا و سپس بایت پایین مقدار داد.
  6. موج PWM روی 0 مقداری عقب تر از موج های روی OC1x است. این موضوع به دلیل این است که تایمر صفر لحظاتی پس از تایمر 1 راه اندازی می شود. همچنین تغییر نرم افزاری وضعیت پایه های IO توسط رجیسترهای آن، زمان بیشتری طول می کشد.

شکل موج های PWM ساخته شده و شدت نور LEDها متناسب با هر یک از آنها در تصویر زیر آمده است.

نتیجه-pwm-فرکانس-متغیر-avr

تصویر 6 – موج PWM با فرکانس متغیر با AVR و نتیجۀ عملی آن

نتایج PWM فرکانس متغیر با AVR، سخت افزاری و نرم افزاری

  1. با به کارگیری مدهای PWM و نرمال و CTC، راه اندازی PWM در AVR به صورت سخت افزاری و نرم افزاری امکان پذیر است. بنابراین می توان گفت برای تولید پالس PWM با AVR محدود به استفاده از پایه های خروجی تایمر نیستیم.
  2. در ساخت PWM در AVR با مد نرمال تایمر و در کل تولید PWM نرم افزاری با AVRبا تایمرها، باید وقفه های سرریز و مقایسه فعال شوند. در این وقفه ها، پایۀ IO تغییر وضعیت می دهد و یک موج PWM ایجاد می شود.
  3. ساخت PWM در AVR با مد PWMتایمر، هم می تواند نرم افزاری باشد و هم سخت افزاری. در تولید PWM سخت افزاری با AVR در مدهای PWM تایمر، نیازی به فعال کردن وقفه ها نیست.
  4. ساخت PWM در AVR با مد CTC تایمر با محدودیت هایی همراه است. زیرا مقدار TOP برابر رجیستر مقایسه است. در تایمرهای 8 بیتی AVR نمی توان PWM نرم افزاری در این مد ساخت. اما در تایمرهای 16 بیتی AVR، این کار امکان پذیر است.
  5. تولید PWM در کدویژن بر خلاف تولید PWM در Atmel Studio، با استفاده از کدویزارد به راحتی با چند کلیک انجام می شود. برای انجام تنظیمات PWM در کدویژن (در بخش کدویزارد)، کافی است مد تایمر را انتخاب و در صورت نیاز، تیک های مربوط به خروجی ها و وقفه ها را بزنیم. همچنین می توانیم مقادیر اولیه را برای رجیسترهای TCNTn و OCRn تعیین و دورۀ تناوب تایمر را با توجه به تعیین مقدار TCNTn مشاهده نماییم.
  6. برای ایجاد PWM با فرکانس متغیر در مد نرمال تایمر، باید به رجیستر TCNTn مقدار بدهیم. طوری که تایمر همواره از آن مقدار تا مقدار TOP شمارش کند. با تغییر این مقدار، تعداد پله های شمارش و در نهایت فرکانس تغییر می کند.
  7. برای ساخت PWM با دیوتی سایکل متغیر باید مقدار رجیستر مقایسه را تغییر دهیم.
  8. در به دست آوردن فرمول محاسبه دیوتی سایکل برای تولید PWM با تایمر، باید به وارون یا ناوارون بودن PWM، مقدار آغاز شمارش و مقدار TOP توجه داشت.
  9. پس از تغییر فرکانس PWM با تغییر TCNTn، باید مقدار OCRn نیز تغییر کند تا دیوتی سایکل ثابت بماند.

نوشته های دیگر مرتبط با موضوع این نوشته در وبلاگ یوبرد:

کنترل دور موتور DC با AVR، موج PWM و Capture

تایمر در میکروکنترلرهای STM32 و کنترل دور موتور

ساخت PWM با LPC1768

رضا اسدی

رضا اسدی

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

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

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

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

آموزش Arduino یوبرد

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

راه-اندازی-dac-stm32

راه اندازی DAC در STM32

راه اندازی DAC در STM32، ویژگی های DAC در میکروکنترلرهای STM32F1، بلوک دیاگرام DAC در STM32، اتصالات راه اندازی DAC در میکروکنترلر STM32F107VC، نمونه کد رجیستری راه اندازی واحد DAC در میکروکنترلرهای STM32F1، ساخت موج سینوسی با STM32، راه اندازی مبدل دیجیتال به آنالوگ STM32 با توابع HAL

راه-اندازی-سون-سگمنت-با-آردوینو

راه اندازی سون سگمنت با آردوینو

راه اندازی سون سگمنت با آردوینو UNO، راه اندازی سون سگمنت 4 تایی آند مشترک با آردوینو، اتصال سون سگمنت به آردوینو، کتابخانۀ سون سگمنت برای آردوینو، نمونه کد راه اندازی سون سگمنت، نمایش اعداد در سون سگمنت 4 تایی، نکات راه اندازی سون سگمنت

راه-اندازی-adc-در-آردوینو

راه اندازی ADC در آردوینو

راه اندازی ADC در آردوینو، راه اندازی LCD گرافیکی KS0108 با کتابخانۀ U8g2، اتصالات لازم برای راه اندازی ADC و LCD گرافیکی KS0108، نمونه کد راه اندازی ADC آردوینو، فرمول محاسبۀ دما با TMP36، راه اندازی سنسور دما با آردوینو، راه اندازی فتوسل (LDR) با آردوینو

6 دیدگاه ها

  1. سلام. من این پروژه رو انجام دادم و نتیجه رو تو اسیلوسکوپ دیدم. توی فرکانس بالا مقدار duty cycle و فرکانس خیلی دقیق نیست. این مشکل از کجاست؟ راهی برای رفعش وجود داره؟ ممنون

    پاسخ
    • سلام. توی فرکانس بالا تعداد پله هایی که تایمر میشمره کم میشه و در نتیجه دیوتی سایکل نمیتونه به صورت دقیق کم و زیاد بشه. مثلاً وقتی که تایمر 100 تا پله میشمره دیوتی سایکل 10 درصد با تعداد 10 پله میتونه با دقت به وجود بیاد. وقتی تعداد پله های شمارش 10 تا میشه، همین دیوتی سایکل با یک پله به وجود میاد. ولی با تعداد 9 پله، دیگه این دیوتی سایکل نمیتونه با دقت خوبی به وجود بیاد. چون وقتی تعداد پله ها 9 تا باشه و توی یه پله مقدار خروجی 1 باشه و توی 8 پلۀ دیگه، خروجی صفر باشه، مقدار دیوتی سایکل میشه یک نهم که میشه حدود 11.11 درصد. فرکانس هم به همین شکل. وقتی تعداد پله های شمارش کم میشه، دقت تغییر فرکانس پایین میاد. مثلاً وقتی تعداد پله های شمارش دو تاست، فرکانس رو که یه مرحله افزایش میدیم، دوبرابر افزایش پیدا میکنه و تعداد پله های شمارش یک واحد کم میشه.

      پاسخ
  2. سلام،توی این پروژه چجوری میتونیم نمودار پالس یکی از خروجی ها رو ببینیم(بقیه رو نشون نده)؟

    پاسخ
    • سلام. اگه منظورتون توی اسیلوسکوپ پروتئوسه، وضعیت کانال مربوط به سیگنال هایی رو که نمیخواید، روی OFF بذارید.

      پاسخ
  3. سلام وقتتون بخیر. آیا بدون میکروکنترلر هم میشه موج PWM ساخت؟

    پاسخ
    • سلام. بله. چرا که نه. حتی با مداراتی که فقط ترانزیستور هم دارن و آی سی ندارن میشه موج PWM ساخت. روش های راحت تر استفاده از اپ امپ ها و استفاده از آی سی LM555 و … است.

      پاسخ

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

نشانی ایمیل شما منتشر نخواهد شد.

ضبط پیام صوتی

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