چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
PWM یا Pulse Width Modulation یا Pulse Duration Modulation ( مدولاسیون عرض پالس یا مدولاسیون مدت زمان پالس ) نام تکنیکی در الکترونیک است که استفاده گسترده ای در صنایع الکترونیک و مخابرات دارد. از این روش برای کارهایی مانند کدینگ پیام های مخابراتی ، کنترل توان دستگاه های الکتریکی ، شارژ باتری و … استفاده می شود.
در میکروکنترلر ها نیز PWM برای مصارف مختلفی مانند کنترل نور LED ها ( Fade کردن نور LED ) ، کنترل سرعت موتور های DC , انتقال پیام ، مبدل های ولتاژ و …. استفاده می شود.
در اصل PWM موجی مربعی است که در برخی زمان ها ۰ و برخی زمان ها ۱ است و این ۰ و ۱ شدن ها با فرکانس مرتبی تکرار می شود. همانگونه که در شکل بالا مشاهده می کنید PWM مانند سایر امواج ، دارای دامنه یا Amplitude ، دور تناوب یا Period و فرکانس است. عبارت دیگری که در PWM مورد استفاده قرار می گیرد Duty Cycle است. دیوتی سایکل مدت زمان ۱ بودن به مدت زمان کل پریود در هر سیکل موج است که معمولا بر حسب درصد ( % ) نمایش داده می شود. به فرض مثال اگر Duty Cycle یک موج PWM برابر با ۴۰% باشد بدان معنی است که در هر سیکل ۴۰% ولتاژ برابر VCC و در ۶۰% اوقات ولتاژ برابر ۰ است. همانگونه که می دانید در چنین حالتی ولتاژ موثر یا Vrms برابر با ۴۰% VCC خواهد بود. به فرض مثال شما اگر با یک میکرو با تغذیه ۵V ، موج PWM با دیوتی سایکل ۵۰% ایجاد نمایید ولتاژ RMS شما برابر ۵۰% VCC یا به عبارتی ۲٫۵ ولت خواهد بود. در شکل زیر تعدادی موج PWM با فرکانس ثابت و دیوتی سایکل متفاوت نمایش داده شده است.
من امروز میخوام PWM نرم افزاری رو به شما معرفی کنم
چون خیلی از دوستان دیدم که گذرشون به این کارها میخوره همون طور که میدونید اکثر میکروهای AVR هشت بیتی PWM سخت افزاری محدودی دارند و اگر بخواهیم که آنها را به کار بگیریم باید از همون پایه ای که مشخص شده PWM بگیریم بنابراین اگر کسی بخواهد که از پایه های دیگه PWM بگیرد باید به صورت نرم افزاری تعریف کند تا پایه دلخواه را PWM کند همانطور که می دانید برای هر PWM نیاز به یک تایمر دارد . البته در بعضی از تایمرها هستند که 3تا PWM تولید میکنند . اما در این برنامه ای که میخواهم برای شما معرفی کنم تنها یک تایمر بکار رفته است . تایمر صفر رو انتخاب کردم که امکاتاتش کمه و به کارمون میاد دلیل اینکه چرا از تایمر های دیگه استفاده نکردم اینه که گفتم شاید کسی از تایمر های دیگه که خیلی امکاناتش بالاتره بخواهد استفاده کند .
با استفاده از تایمر 0 میکروهای 128-64-ATmega16-32 این قابلیت را دارند که انجام مقایسه ای مقدار تایمر را انجام دهد(در بعضی از تایمر0 میکرو ها فقط این قابلیت رو دارند که Overflow کنند مثل ATmega8 ) . پس میتوانیم در این تایمر فرکانس را کم و زیاد کنیم . اگر فرکانس را بالا ببریم (مقدار OCR0 را کم کنیم) پردازش زیادتر میشود و دقت پایین می آید و اگر فرکانس رو کم کنیم دقت زیاد میشود . ما در این پروژه نیازی به این دو داریم ولی تا یک حدی این تایمر در مد CTC تنظیم شده است .
اگر برایتان فرکانس زیاد مهم نیست مقدار OCR0 را زیادتر کنید تا پردازش کمتر شود . دلیل اینکه روی بحث پردازش تاکید میکنم این هست که روی دستورات تاخیری تاثیر میگذارد و این باعث میشود که تاخیرات نرم افزاری دیرتر صورت بگیرد .
یک توضیح مختصر در مورد برنامه :
برنامه طوری طراحی شده که با استفاده از آرایه میتوانیم مقدار تک تک PWM ها را تغییر بدهیم آرایه ای که []pwm نام دارد را میتوانید اندیس آن را برای PWM دلخواهتان تنظیم کنید بازه مقدار آرایه PWM از 0 تا 99 است که نشانگر دیوتی سایکل است این آرایه یه جورایی میشه گفت که مثل رجیستر عمل میکنه . یعنی اینکه تا مقدار به آن بدهیم PWM تنظیم میشود .
برنامه ATmega64-128 :
در این دو میکرو به دلیل اینکه دستور PORTx.y فقط برای پورتهای A,B,C,D کاربرد دارد گفتم چه بهتر که همه رو با استفاده از دستورات کتابخانه ای خود کدویژن به کار بگیرم .
از لحاظ پردازش هم با این فرکانس و این تقسیم کننده فرکانس در تایمر ، در میکروی اتمگا 16 و 32 تقریبا 15.75% و در میکرو های اتمگا 64 و 128 تقریبا 24.67% پردازش میکرو را میگیرد . (البته این محاسبات در بدترین شرایط در نظر گرفته شده است .)
اگر بخواهید از تمام PWM های نرم افزاری استفاده نکنید میتوانید یکسری تنظیمات را تغییر دهید …
البته که اگر PWM های کمتری را به کار بگیرید پردازش کمتری خواهد گرفت .
سورس کد برای میکروهای ATmega16-32 به زبان C در کدویژن
/***************************************************** This program was produced by the CodeWizardAVR V2.05.3 Standard Automatic Program Generator © Copyright 1998-2011 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.com Project : 32-channel PWM (Rain LED) Version : 2.1 Date : 2/27/2014 Author : Saman.Asadi www.ECA.ir Chip type : ATmega16 Program type : Application AVR Core Clock frequency: 8.000000 MHz Memory model : Small External RAM size : 0 Data Stack size : 256 *****************************************************/ #include <mega16a.h> #include <delay.h> #define led1 PORTA.0 #define led2 PORTA.1 #define led3 PORTA.2 #define led4 PORTA.3 #define led5 PORTA.4 #define led6 PORTA.5 #define led7 PORTA.6 #define led8 PORTA.7 #define led9 PORTC.7 #define led10 PORTC.6 #define led11 PORTC.5 #define led12 PORTC.4 #define led13 PORTC.3 #define led14 PORTC.2 #define led15 PORTC.1 #define led16 PORTC.0 #define led17 PORTD.7 #define led18 PORTD.6 #define led19 PORTD.5 #define led20 PORTD.4 #define led21 PORTD.3 #define led22 PORTD.2 #define led23 PORTD.1 #define led24 PORTD.0 #define led25 PORTB.7 #define led26 PORTB.6 #define led27 PORTB.5 #define led28 PORTB.4 #define led29 PORTB.3 #define led30 PORTB.2 #define led31 PORTB.1 #define led32 PORTB.0 #define byte unsigned char #define max_var_PWM 99 #define factor byte a = max_var_PWM; byte pwm[35]; flash byte rain1[25]={99,70,40,20,10,5,4,3,2,1,0}; flash byte rain2[40]={0,1,2,3,4,5,10,20,40,70,99,70,40,20,10,5,4,3,2,1,0}; flash byte rain3[35]={0,1,2,3,4,5,10,20,40,70,99}; flash byte rain4[40]={1,2,3,4,5,10,20,40,70,99,70,40,20,10,5,4,3,2,1,0}; // Timer 0 output compare interrupt service routine interrupt [TIM0_COMP] void timer0_comp_isr(void) { if(a) { if(a == pwm[1] )led1=1; if(a == pwm[2] )led2=1; if(a == pwm[3] )led3=1; if(a == pwm[4] )led4=1; if(a == pwm[5] )led5=1; if(a == pwm[6] )led6=1; if(a == pwm[7] )led7=1; if(a == pwm[8] )led8=1; if(a == pwm[9] )led9=1; if(a == pwm[10])led10=1; if(a == pwm[11])led11=1; if(a == pwm[12])led12=1; if(a == pwm[13])led13=1; if(a == pwm[14])led14=1; if(a == pwm[15])led15=1; if(a == pwm[16])led16=1; if(a == pwm[17])led17=1; if(a == pwm[18])led18=1; if(a == pwm[19])led19=1; if(a == pwm[20])led20=1; if(a == pwm[21])led21=1; if(a == pwm[22])led22=1; if(a == pwm[23])led23=1; if(a == pwm[24])led24=1; if(a == pwm[25])led25=1; if(a == pwm[26])led26=1; if(a == pwm[27])led27=1; if(a == pwm[28])led28=1; if(a == pwm[29])led29=1; if(a == pwm[30])led30=1; if(a == pwm[31])led31=1; if(a == pwm[32])led32=1; } if(--a == 255) { a = max_var_PWM; PORTA=0; PORTB=0; PORTC=0; PORTD=0; } } void main(void) { byte x1,x2,x3; //Config all //Config timers //Config PORTS { DDRA=255; DDRB=255; DDRC=255; DDRD=255; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 1000.000 kHz // Mode: CTC top=OCR0 // OC0 output: Disconnected TCCR0=0x0A; OCR0=150; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x02; // Global enable interrupts #asm("sei") } //End Config ...... while(1) { ///////////////////////////////////////// for(x1=0;x1<25;x1++) { pwm[1]=rain1[x1]; for(x2=17;x2>0;x2--)pwm[x2+1]=pwm[x2]; delay_ms(40); } for(x1=0;x1<35;x1++) { pwm[1]=rain2[x1]; for(x2=17;x2>0;x2--)pwm[x2+1]=pwm[x2]; delay_ms(40); } for(x1=0;x1<25;x1++) { pwm[1]=rain3[x1]; for(x2=17;x2>0;x2--)pwm[x2+1]=pwm[x2]; delay_ms(40); } ///////////////////////////////////////// for(x1=0;x1<25;x1++) { pwm[17]=rain1[x1]; for(x2=0;x2<17;x2++)pwm[x2]=pwm[x2+1]; delay_ms(40); } for(x1=0;x1<35;x1++) { pwm[17]=rain2[x1]; for(x2=0;x2<17;x2++)pwm[x2]=pwm[x2+1]; delay_ms(40); } for(x1=0;x1<25;x1++) { pwm[17]=rain3[x1]; for(x2=0;x2<17;x2++)pwm[x2]=pwm[x2+1]; delay_ms(40); } ////////////////////////////////////////// for(x3=0;x3<3;x3++) for(x1=0;x1<14;x1++) { for(x2=0;x2<8;x2++)pwm[x2]=pwm[x2+1]; for(x2=17;x2>9;x2--)pwm[x2]=pwm[x2-1]; pwm[8]=rain1[x1]; pwm[9]=rain1[x1]; delay_ms(40); } for(x3=0;x3<3;x3++) for(x1=0;x1<14;x1++) { for(x2=8;x2>00;x2--)pwm[x2]=pwm[x2-1]; for(x2=9;x2<17;x2++)pwm[x2]=pwm[x2+1]; pwm[0]=rain1[x1]; pwm[17]=rain1[x1]; delay_ms(40); } ////////////////////////////////////////// for(x3=0;x3<4;x3++) for(x1=0;x1<19;x1++) { for(x2=0;x2<8;x2++)pwm[x2]=pwm[x2+1]; for(x2=17;x2>9;x2--)pwm[x2]=pwm[x2-1]; pwm[8]=rain4[x1]; pwm[9]=rain4[x1]; delay_ms(40); } for(x3=0;x3<4;x3++) for(x1=0;x1<19;x1++) { for(x2=8;x2>00;x2--)pwm[x2]=pwm[x2-1]; for(x2=9;x2<17;x2++)pwm[x2]=pwm[x2+1]; pwm[0]=rain4[x1]; pwm[17]=rain4[x1]; delay_ms(40); } ////////////////////////////////////////// } }
مطلب اصلی در انجمن: https://www.eca.ir/forums/thread48596.html
کاشکی بیشتر توضیح می دادین یا یه شبیه سازی تو پروتئوس می زاشتین