معماری

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

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

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

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

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

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

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

lcd کدویزارد codewizard

در این قسمت همونطور که در شکل بالا مشخصه،چون از LCD 2*16 استفاده کردم برای همین Characters رو ۱۶انتخاب کردمو پایه های 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,"%f",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)
{
}
}
خطوط ۱ تا ۴:

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

خطوط ۵ و ۸:

تعریف متغیرهای مورد نیاز
متغیر shift،چهارتا آرایه داشته که ازینا در شیفت دادن پایه های کیپد استفاده میشه.یعنی ابتدا یکی از پایه های ورودی کیپد رو صفر میکنیم و بقیه ورودی هارو یک میکنیم و در مرحله دوم پایه ی دوم رو صفر کرده و بقیه پایه هارو یک میکنیم و به همین صورت ادامه میدید م تا پایه پهارم صفر بشه ولی با پایه های ۴و۵و۶و۷کاری نداریم که دائما یک هستش و با فشرده شدن کلید کیپد صفر میشه.

خطوط ۱۰ و ۹:

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

خطوط ۱۱ تا ۲۷:

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

خط ۲۴:

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

خط ۲۵:

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

خط ۲۶:

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

خطوط ۲۸تا۴۹:

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

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

خط ۴۹:

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

خطوط ۵۳ تا ۵۹:

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

خط ۶۰:

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

خطوط ۶۵ تا ۷۲:

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

خطوط ۷۸ تا ۸۱:

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

خط ۸۴:

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

 

یک دیدگاه

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

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

قالب وردپرس