اتصال کلید به میکرو

یکی از ساده ترین و پرکاربرد ترین دستگاههای ورودی کلید است . توسط کلید میتوان منطق 0  یا 1  را به میکرو وارد کرد و بر اساس آن پردازش را انجام داد. برای خواندن منطق کلید از رجیستر PIN  استفاده می شود . نحوه استفاده از رجیستر PIN  به این صورت است که : ”  اگر کلید  زده شد آنگاه کار مورد نظر انجام  شود ” . عبارت اخیر معادل استفاده از دستور شرطی if  به صورتی است که اگر کلید زده شده بود یک منطق و در غیر این صورت منطق دیگری وارد پایه میکرو شود . اتصال کلید به دو صورت PullUp و PullDown انجام می شود که در شکل زیر مشاهده می کنید . در کلید pull up  در حالتی که کلید زده نشده منطق 1  و  در حالت فشردن کلید منطق 0  وارد میکرو می شود . معمولا از مقاومت 10k  برای این کار استفاده می شود .

بنابراین برای فهماندن کلید به میکرو به صورتی که ” اگر کلید زده شد آنگاه کار مورد نظر انجام شود ”  برای کلیدهای فوق به صورت زیر می شود :

if(PINB.0==0) {…} //PullUp

if(PINB.1==1) {…} //PulDown

اما مشکلی که در کلید وجود دارد ، بوجود آمدن لرزش یا bounce  در هنگام قطع و وصل کلید است . در  زمانی که کاربر کلید را فشار می دهد تقریبا 20  میلی ثانیه طول می کشد تا منطق کلید از 0  به 1  ( یا  بالعکس ) ثابت شود تا قبل این بعلت وجود جرقه کلید منطق ثابتی ندارد .  شکل زیر این موضوع را نشان می دهد:

در زمانی که کاربر دست خود را از روی کلید بر می دارد نیز تقریبا 20  میلی ثانیه طول می کشد تا 0  و 1 شدن  های کلید تمام شده و کلید به منطق اولیه خود برگردد . در واقع این مشکل زمانی برای ما مسئله ساز  می شود که زمانی که کاربر کلید را یکبار فشار می دهد و انتظار دارد تا میکرو متوجه یکبار فشار دادن آن شود اما به علت قرار گرفتن if در درون حلقه نامتناهی while  چندین بار شرط PINB.0==0  برقرار شده و کار مورد نظر چندین بار انجام می شود . راه حل این مشکل ساده است و آن هم قرار دادن مقداری delay  در حلقه if است . بنابراین برای حل این مشکل بسته به نوع برنامه یکی از سه روش زیر قابل استفاده است :

کلید نوع 1:

if(PINB.0==0) {

دستورات مربوط به بعد از زدن کلید

delay_ms(200);

}

توضیح : به محض فشار دادن کلید توسط کاربر شرط if  برقرار شده و دستورات مورد نظر اجرا می شود سپس به علت ایجاد تاخیر زیاد توسط تابع delay_ms (  در اینجا 200  میلی ثانیه ) با این کار احتمال اینکه زمانی که برنامه در حلقه while به if  می رسد و شرط برقرار باشد ، کاهش می یابد . مزیت این کلید این است  که در صورتی که کاربر کلید را فشار داده و نگه دارد تقریبا در هر 200  میلی ثانیه یکبار کار مورد نظر صورت می گیرد . عیب این روش نیز این است که هنوز احتمال دارد که زمانی که یک بار کلید زده شود دوبار کار مورد نظر انجام شود .

کلید نوع 2 :

if(PINB.0==0) {

delay_ms(20);

while(PINB.0==0);

دستورات مربوط به بعد از زدن کلید

}

توضیح : به محض فشار دادن کلید توسط کاربر شرط if  برقرار شده و برنامه به مدت 20  میلی ثانیه صبر می کند تا منطق کلید ثابت شود و از منطقه bounce عبور کند سپس توسط حلقه while  با همان شرط برقراری  کلید در این مرحله برنامه تا زمانی که کلید توسط کاربر فشرده شده است در حلقه گیر می کند و هیچ کاری انجام نمی دهد . به محض اینکه کاربر دست خود را بر می دارد ، شرط برقرار نبوده و خط  بعدی یعنی  دستورات مربوطه اجرا می شود . مزیت این روش این است که در هر بار فشردن کلید برنامه تنها یکبار اجرا می شود . معایب این روش این است که تا زمانی که کاربر کلید را نگه داشته اتفاقی نمی افتد و به محض رها کردن کلید کار مورد نظر انجام می شود .

کلید نوع 3 :

if((PINB.0==0 ) && (flag==0)) {

flag=1; start=!start; }

else if ( PINB.0 == 1) flag=0;

if(start){

دستورات مربوط به بعد از زدن کلید

}

توضیح : این کلید به صورت start/stop  عمل می کند یعنی بار اولی که کاربر کلید را فشار می دهد  دستورات مربوط به بعد از زدن  کلید دائما اجرا می شود تا زمانی که کاربر دست خود را از روی کلید رها کرده و دوباره کلید را فشار دهد ، در این صورت دستورات دیگر اجرا نمی شود . دو متغیر از نوع bit با نام های flag و start  با مقدار اولیه 0 برای این کلید باید تعریف شود . زمانی که کاربر برای اول ین بار کلید را فشار می دهد شرط if برقرار شده و flag=1 و start=1 می شود . در این صورت شرط if  دوم برقرار بوده و دستورات مربوطه با هر بار چرخش برنامه درون حلقه نامتناهی while  یکبار اجرا می‌شود . زمانی که کاربر دست خود را از روی  کلید بر می دارد و منطق 1 وارد میکرو می شود flag=0  شده و برنامه دوباره آماده این می شود که کاربر برای بار دوم کلید را فشار دهد . زمانی که کاربر بار دوم کلید را می فشارد start=0  شده و دستوراط مربوطه اجرا  نخواهد شد سپس با برداشته شدن دست کاربر از روی کلید ، همه چیز به حالت اول بر میگردد .  این کلید طوری نوشته شده است که bounce در آن کمترین تاثیر مخرب ممکن را دارد .

مثال عملی شماره 2 : برنامه ای بنویسید که یک کلید روی پورت PA0  و 8 عدد LED روی پورت B  وجود  داشته باشد و با هر بار زدن کلید ، led  های موجود به صورت 1- شمارنده بالا شمار  2- شمارنده پایین شمار  3-شمارنده جانسون  4-شمارنده حلقوی، عمل نماید .  سعی کنید برنامه کمترین عیب ممکن را داشته باشد و کلید به بهترین نحو ممکن کار کند .

 حل : 

مرحله اول : طراحی سخت افزار

مرحله دوم : طراحی نرم افزار

سپس به سراغ نرم افزار CodeVision  رفته و طبق مراحل گفته شده در فصل قبل پروژه جدید را می سازیم و  فرکانس میکرو را روی 1Mhz داخلی قرار می دهیم . برنامه خواسته شده به صورت زیر است .

#include <mega32.h>
#include <delay.h>
unsigned char i,j=0;
bit flag=1;
void main (void) {
DDRB=0xff;
PORTB=0x00;
while(1){
if(PINA.0==0){
delay_ms(25);
i++;
if(i==5) i=0;
j=0;
PORTB=0x00;
flag=1;
while(PINA.0==0);
}
if(i==1){
119
PORTB++;
delay_ms(200);
}
if(i==2){
PORTB--;
delay_ms(200);
}
if(i==3){
PORTB=0x01;
PORTB=PORTB<<j;
delay_ms(200);
if(flag) j++; else j--;
if(j==7) flag=0;
if(j==0) flag=1;
}
if(i==4){
if(flag) PORTB=PORTB+(0x01<<j);
else PORTB=PORTB-(0x01<<j);
delay_ms(200);
if(flag) j++; else j--;
if(j==8) flag=0;
if(j==255) flag=1;
}
}
}

توضیح : متغیر i  حالت کار میکرو را نشان می دهد که با هر باز زدن کلید یک واحد به متغیر i  اضافه می  شود . در حالت پیش فرض مقدار این متغیر0 است و برنامه هیچ کاری انجام نمی دهد تا زمانی که کاربر کلید را فشار دهد . با اولین باری که کلید زده می شود i=1  شده و برنامه مربوط به شمارنده بالاشمار اجرا می‌شود . با دومین باری که کلید زده می شود i=2  شده و برنامه مربوط به شمارنده پایین شمار اجرا می شود . دفعه سوم i=3 شده و برنامه به صورت شمارنده حلقوی و در نهایت زمانی که برای بار چهارم کلید زده شود i=4 شده و برنامه شمارنده جانسون می شود . متغیر flag  از آن جهت ایجاد شده است که زمانی که شمارنده جانسون و حلقوی به آخر رسیدند ، برنامه از آخر به اول شروع به کار کند و زیباتر می‌شود .

نکته : همانطور که مشاهده کردید در برنامه از حلقه for استفاده نکردیم تا برنامه روان تر و حرفه ای تر باشد.