پروژه ماشین حساب ساده با وقفه در AVR

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

خب برای شروع،در پروتیوس مدار زیر رو طراحی میکنیم و بقیه ی کارمونو در  کدویژن ادامه میدیم.

پروژه ماشین حساب

پروژه ی جدیدی رو ایجاد کرده و در قسمت کدویزارد باید int1 و LCD رو فعال کنیم و پول آپ بودن بعضی از پایه های مورد استفاده رو نیز تعیین کنیم که بصورت زیر عمل میکنیم:

وقفه اینتراپت int

در قسمت وقفه ها،int1 رو فعال کرده و مد مربوطه رو انتخاب میکنیم.در این پروژه بخاطر اینکه من پایه int1یعنی پایه ی D.3 رو پول آپ انتخاب کردم پس نمیتونم از Rising Edge استفاده کنم که حالت حساس به لبه پایین رونده رو انتخاب کردم.

lcd کدویزارد codewizard

در این قسمت همونطور که در شکل بالا مشخصه،چون از LCD 2*16 استفاده کردم برای همین Characters رو 16انتخاب کردمو پایه های LCD رو بنابه شماتیک به پایه های مربوطه اش  وصل میکنیم.

پورت پایه PORT پین pull up

در این قسمت هم پورت A که به LCD وصله همه ی پایه هارو خروجی باید در نظر بگیریم و در پورت D  چون فقط ازپایه ی وقفه استفاده کردم باید این پایه رو بعنوان ورودی در نظر بگیرم و این پایه رو پول آپ و حساس به لبه پایین رونده در نظر میگیرم تا با آمدن صفر منطقی این پایه تحریک بشه و روال سرویس وقفه رو اجرا کنه.

در پورت C هم چهار پایه ی ورودی به کیپد رو بعنوان خروجی در نظر میگیریم و پایه های خروجی از کیپد رو بعنوان ورودی در نظر گرفته و پول آپ داخلی این پایه هارو فعال میکنیم.

تا اینجا کار با کدویزارد تموم شد وGenerate Save and Exit  رو میزنیم که کد های زیر ایجاد میشن.

سورس کد source cod اینتراپت interrupt

#include <mega32.h>
#include <alcd.h>
#include <delay.h>
#include <stdio.h>
char lcd_buffer[33],halat,adad;
char shift[4]={0XFE,0XFD,0XFB,0XF7};
int key;
int i,j,a,b,c;
void display ();
void process ();
interrupt [EXT_INT1] void ext_int1_isr(void)
{
for (i=0;i<4;i++)
{
j=0;
PORTC=shift[i];
if(PINC.4==0) j=1;
if(PINC.5==0) j=2;
if(PINC.6==0) j=3;
if(PINC.7==0) j=4;
if (j!=0) key=i*4+j;
delay_ms (50);
}
display ();
while (PIND.3==0) {}
PORTC=0XF0;
}
void display ()
{
switch (key)
{
case 1: lcd_puts("7"); if (adad==0) {a=a*10+7;} else {b=b*10+7;} break;
case 2: lcd_puts("8"); if (adad==0) {a=a*10+8;} else {b=b*10+8;} break;
case 3: lcd_puts("9"); if (adad==0) {a=a*10+9;} else {b=b*10+9;} break;
case 5: lcd_puts("4"); if (adad==0) {a=a*10+4;} else {b=b*10+4;} break;
case 6: lcd_puts("5"); if (adad==0) {a=a*10+5;} else {b=b*10+5;} break;
case 7: lcd_puts("6"); if (adad==0) {a=a*10+6;} else {b=b*10+6;} break;
case 9: lcd_puts("1"); if (adad==0) {a=a*10+1;} else {b=b*10+1;} break;
case 10: lcd_puts("2"); if (adad==0) {a=a*10+2;} else {b=b*10+2;} break;
case 11: lcd_puts("3"); if (adad==0) {a=a*10+3;} else {b=b*10+3;} break;
case 14: lcd_puts("0"); if (adad==0) {a=a*10+0;} else {b=b*10+0;} break;
case 4: lcd_puts("/"); halat=1; adad=1; break;
case 8: lcd_puts("*"); halat=2; adad=1; break;
case 12: lcd_puts("-"); halat=3; adad=1; break;
case 16: lcd_puts("+"); halat=4; adad=1; break;
case 15: lcd_puts("="); process (); break;
case 13: lcd_clear (); a=0; b=0; halat=0; adad=0; break;
}
}

void process ()
{
switch (halat)
{
case 1: c=a/b; break;
case 2: c=a*b; break;
case 3: c=a-b; break;
case 4: c=a+b; break;
}
sprintf(lcd_buffer,"%d",c);
lcd_puts(lcd_buffer);
}
void main(void)
{
DDRA=0XFF;
PORTA=0X00;
DDRB=0X00;
PORTB=0X00;
DDRC=0X0F;
PORTC=0XF0;
DDRD=0X00;
PORTD=0X08;
// External Interrupt(s) initialization
// INT0: Off
// INT1: On
// INT1 Mode: Falling Edge
// INT2: Off
GICR|=(1<<INT1) | (0<<INT0) | (0<<INT2);
MCUCR=(1<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
MCUCSR=(0<<ISC2);
GIFR=(1<<INTF1) | (0<<INTF0) | (0<<INTF2);
lcd_init(16);
// Global enable interrupts
#asm("sei")
while (1)
{
}
}
خطوط 1 تا 4:

معرفی توابع هدر موردنیاز

خطوط 5 و 8:

تعریف متغیرهای مورد نیاز
متغیر shift،چهارتا آرایه داشته که ازینا در شیفت دادن پایه های کیپد استفاده میشه.یعنی ابتدا یکی از پایه های ورودی کیپد رو صفر میکنیم و بقیه ورودی هارو یک میکنیم و در مرحله دوم پایه ی دوم رو صفر کرده و بقیه پایه هارو یک میکنیم و به همین صورت ادامه میدید م تا پایه پهارم صفر بشه ولی با پایه های 4و5و6و7کاری نداریم که دائما یک هستش و با فشرده شدن کلید کیپد صفر میشه.

خطوط 10 و 9:

چون توابع display و process بعد از خطوطی که فراخوانی میشن،تعریف شدن یعنی تابع display در خط26فراخوانی میشه درحالیکه تو خط 31 تعریف شده پس باید این تابع قبل از خط 26 تعریف اولیه بشه.

خطوط 11 تا 27:

در این خطوط روال سرویس وقفه نوشته شده که ابتدا همونطوری که گفتم،یه پایه ورودی رو صفر میکنیم و بقیه یک میمونه و این کارو برا هر چهارتا ورودی انجام میدیم تا اینکه دکمه ایی فشرده بشه،بطورییکه قبل از فشرده شدن j=0 و اگه ذکمه ایی فشرده بشه مقدار j عوض شده (خطوط 19تا21)و با اینکار میفهمیم که دکمه یی فشرده شده(خط 22) که اگه دکمه ایی فشرده شده باشه،موقعیت دکمه رو پیدا کرده و در key ذخیره میکنه.
البته اینو هم بگم که این تابع هنگامی که دکمه ایی فشرده بشه و پایه وقفه تحریک بشه،اجرا میشه.

خط 24:

تو این خط تابع display رو فراخوانی کرده و اجرا میکنه.به این ترتیب که بعد از بدست آوردن موقعیت دکمه و ذخیره در key،تابع display رو اجرا کرده و برحسب مقدار key به case موردنظر رفته و بعد از چاپ عدد در LCD، عدد مورد نظر رو در a یا b ذخیره میکنه.این ذخیره کردن عددها به این صورته که که قبل از فشرده شدن دکمه عملگر،عدد اول نام داشته و با adad=0 مشخص میشه و تو متغیر ش ذخیره میشه و عددی که بعد از فشرده شدن دکمه عملگرها تو متغیر b ذخیره میشه با adad=1 مشخص م یشه.

خط 25:

هنگامی که دکمه ایی فشرده میشه میکرو ممکنه چندین بار برنامه رو اجرا کنه و چندین بار  عدد دکمه رو چاپ کنه درحالیکه ما میخواستیم فقط با یک بار فشرده شدن دکه،فقط ک بار عدد چاپ کنه که برای این کار  از حلقه ی while باید استفاده کنیم تا به میکرو بگیم که تا زمانی که کلید رو رها نکردیم فقط یکبار عدد رو چاپ کن نه بیشتر.

خط 26:

این خط وضعیت پایه های ورودی و خروجی کیپد رو به حالت اول برمیگرد ونه.

خطوط 28تا49:

تو این خطوط تابع display تعریف شده و اساس کارش به این صورته که موقعیت دکمه ها که تو متغیر key ذخیره شده،برحسب مقدار key،به case موردنظر رفته و بعد از چاپ عدد تو LCD،همون عدد رو تو متغیر a یا b ذخیره میکنه.

اگه بخوام بیشتر  طرز کار این تابع رو بگم به اینصورته که مقدار اولیه adad برابر صفره پس اگه عددی رو کیپد بزنیم موقعیت این دکمه میاد تو case مربوطه اش و بلافاصله چاپ میشه و چون adad=0 این عدد تو متغیر a ذخیره میشه و هنگامی که دکمه ی عملگرازده بشه میاد تو case مربوطه اش و متغیر halat مقدارگرفته و مقدار adad برابر یک میشه که پس ازین هربار دکمه ای فشرده بشه چون adad=1 عدد تو متغیر bذخیره میشه.

خط 49:

این خط که مربوط به عملگر تساویه،بافشرده شدن دکمه اش،تابع process رو اجرا میکنه.

خطوط 53 تا 59:

تو این خطوط بنابه مقدار متغیر halat،عملیات مربوطه شو انجام داده و برای چاپ،تو متغیر c ذخیره میکنه.

خط 60:

چون متغیر c رو int تعریف کردم،برا همین LCD نمیتونه چاپ کنه که برای اینکار c رو باید به کاراکتر تبدیل کنیم که از دستور sprintf استفاده میکنیم که کتابخانه اش stdio هستش.

خطوط 65 تا 72:

تعریف کردن پورت ها و پایه ها که توسط کدویزارد اینکارو انجام دادیم.

خطوط 78 تا 81:

این دستورات مربوط به فعال سازی وقفه خارجی(int1) و انتخاب مد هستش که توسط کدویزارد این کد ها نوشته شده.

خط 84:

این دستور وقفه ی عمومی رو فعال میکنه.

دانلود نمونه فایل نهایی


توسط

برچسب‌ها:

دیدگاه‌ها

3 پاسخ به “پروژه ماشین حساب ساده با وقفه در AVR”

  1. […] ساده با وقفه در AVR رو براتون آماده کردم،برای مشاهده اینجا کلیک […]

  2. مائده نیم‌رخ
    مائده

    با سلام خسته ونباشید
    ببخشید من کدشو تو codevisionavr نوشتم بعد دقیقا مشابه چیزی که شما نوشتین هست
    ولی بهم ارور میده که void display و void process باید اول در بلوک اعلام شود. میشه هرچه زودتر راهنماییم کنید ممنونم

  3. Sadaf نیم‌رخ
    Sadaf

    برنامتون توی کدویژن جواب نمیده…

دیدگاهتان را بنویسید

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