آموزش Atmel studioآموزش میکروکنترلر AVRپروژهپروژه های AVRتازه هامیکروکنترلرهمه ی مطالب

ساعت دیجیتال با AVR و سون سگمنت

سلام با یک پروژه دیگر در الکترولب در خدمتتون هستیم این پروژه از چند لحاظ اهمیت داره یک اولین پروژه ای است که در محیط atmel studio کار شده دو کار با سون سگمنت در این پروژه و نحوه برنامه نویسی اون به طور کامل شرح داده شده به طوری که می تونید از کدهای مربوط به سون سگمنت در پروژه در میکروکنترلر های مختلف و پروژه ای مختلف استفاده کنید. سعی کردم کد رو به صورت خط به خط و کامل توضیح بدم باز اگر جایی نامفهوم بود بگید تا بیشتر توضیح بدم.

عملکرد ساعت دیجیتال طراحی شده:

عملکرد این مدار به این صورت است که با وصل شدن برد به منبع تغذیه ساعت از “00:00:00” شروع به کار می کند. به وسیله 2 دکمه فشاری می توان ساعت و دقیقه را تنظیم کرد. دکمه SW1 برای تنظیم دقیقه و دکمه ی SW2 برای تنظیم ساعت به کار می رود.

شماتیک لازم برای راه اندازی ساعت دیجیتال با AVR و سون سگمنت:

این برنامه به صورت صحیح و بدون تغییر در میکروکنترلر های ATmega32 و ATmega16 کار می کند.

Digital Clock_1توجه مهم: برای کارکرد صحیح مدار باید اسیلاتور داخلی میکروکنترلر روی 4MHZ تنظیم شده باشد.

برنامه ی ساعت دیجیتال با ATmega32:

/*
 * DigitalClock.c
 * Written in AVR Studio 5
 * Compiler: AVR GNU C Compiler (GCC)
 *
 * Created: 12/10/2011 1:17:19 PM
 * Author:	AVR Tutorials
 * Website:	www.AVR-Tutorials.com
 */ 
#define F_CPU	4000000UL
#include <avr/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
#define SegDataPort		PORTB
#define SegDataPin		PINB
#define SegDataDDR		DDRB
 
#define SegCntrlPort	PORTC
#define SegCntrlPin		PINC
#define SegCntrlDDR		DDRC
 
 
/*Global Variables Declarations*/
unsigned char hours = 0;
unsigned char minutes = 0;
unsigned char seconds = 0;
 
 
/*Function Declarations*/
/*****************************************************************************/
/*Decimal Digit (0-9) to Seven Segment Values Encoder*/
unsigned char DigitTo7SegEncoder(unsigned char digit, unsigned char common);
 
/*Timer Counter 1 Compare Match A Interrupt Service Routine/Interrupt Handler*/
ISR(TIMER1_COMPA_vect);
 
 
/*Main Program*/
/*****************************************************************************/
int main(void)
{
    SegDataDDR = 0xFF;
	SegCntrlDDR = 0x3F;
	SegCntrlPort = 0xFF;
 
	TCCR1B = (1<<CS12|1<<WGM12);
	OCR1A = 15625-1;
	TIMSK = 1<<OCIE1A;
	sei();
 
 
	while(1)
    {
        /* Set Minutes when SegCntrl Pin 6 Switch is Pressed*/
		if((SegCntrlPin & 0x40) == 0 )
		{	
			_delay_ms(200);
			if(minutes < 59)
				minutes++;
			else
				minutes = 0;
		}
        /* Set Hours when SegCntrl Pin 7 Switch is Pressed*/			
		if((SegCntrlPin & 0x80) == 0 )
		{	
			_delay_ms(200);
			if(hours < 23)
				hours++;
			else
				hours = 0;
		}			
 
		SegDataPort = DigitTo7SegEncoder(seconds%10,1);
		SegCntrlPort = ~0x01;
		SegDataPort = DigitTo7SegEncoder(seconds/10,1); 
		SegCntrlPort = ~0x02;
		SegDataPort = DigitTo7SegEncoder(minutes%10,1);
		SegCntrlPort = ~0x04;
		SegDataPort = DigitTo7SegEncoder(minutes/10,1); 
		SegCntrlPort = ~0x08;
		SegDataPort = DigitTo7SegEncoder(hours%10,1); 
		SegCntrlPort = ~0x10;
		SegDataPort = DigitTo7SegEncoder(hours/10,1);
		SegCntrlPort = ~0x20;
 
    }
	return 0;
}
 
/*
* Function Description:
* Encode a Decimal Digit 0-9 to its Seven Segment Equivalent.
*
* Function Arguments:
* digit - Decimal Digit to be Encoded
* common - Common Anode (0), Common Cathode(1)
* SegVal - Encoded Seven Segment Value 
*
* Connections:
* Encoded SegVal is return in the other G-F-E-D-C-B-A that is A is the least
* significant bit (bit 0) and G bit 6.
*/
unsigned char DigitTo7SegEncoder(unsigned char digit, unsigned char common)
{
	unsigned char SegVal;
 
	switch(digit)	
	{	
		case 0:	if(common == 1)	SegVal = 0b00111111;
				else			SegVal = ~0b00111111;
				break;
		case 1:	if(common == 1)	SegVal = 0b00000110;
				else			SegVal = ~0b00000110;
				break;
		case 2:	if(common == 1)	SegVal = 0b01011011;
				else			SegVal = ~0b01011011;
				break;
		case 3:	if(common == 1)	SegVal = 0b01001111;
				else			SegVal = ~0b01001111;
				break;
		case 4:	if(common == 1)	SegVal = 0b01100110;
				else			SegVal = ~0b01100110;
				break;
		case 5:	if(common == 1)	SegVal = 0b01101101;
				else			SegVal = ~0b01101101;
				break;
		case 6:	if(common == 1)	SegVal = 0b01111101;
				else			SegVal = ~0b01111101;
				break;
		case 7:	if(common == 1)	SegVal = 0b00000111;
				else			SegVal = ~0b00000111;
				break;
		case 8:	if(common == 1)	SegVal = 0b01111111;
				else			SegVal = ~0b01111111;
				break;
		case 9:	if(common == 1)	SegVal = 0b01101111;
				else			SegVal = ~0b01101111;		
	}		
	return SegVal;
}
 
/*Timer Counter 1 Compare Match A Interrupt Service Routine/Interrupt Handler*/
ISR(TIMER1_COMPA_vect)
{
	seconds++;
 
	if(seconds == 60)
	{
		seconds = 0;
		minutes++;
	}
	if(minutes == 60)
	{
		minutes = 0;
		hours++;		
	}
	if(hours > 23)
		hours = 0;
}

توضیح خط به خط برنامه ساعت دیجیتال با AVR و سون سگمنت:

خط 10:

#define F_CPU	4000000UL

این خط برای مشخص شدن فرکانس کاری میکروکنترلر نوشته شده است و شما باید فیوزبیت های میکروکنترلر را طوری تنظیم کنید تا در 4MHZ کارکند.

خط 11:

#include <avr/delay.h>

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

_delay_ms(x)

می توان تاخیر مورد نظر را ایجاد کرد. به جای X زمان مورد نظر را قرار داد.

خط 13:

برای استفاده از وقفه ها در میکروکنترلر های AVR باید این کتابخانه به برنامه اضافه شود.

#include <avr/interrupt.h>

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

خط 15 تا 21:

این خطوط پورت ها و پین های متصل یه سون سگمت را مشخص میکند. به طور مثال:

#define SegDataPort		PORTB

مشخص می کنیم که پایه های a تا g سون سگمنت به پورت B وصل شوند. می توانید با تغییر عبارت PORTB از پورت دلخواه خود استفاده کنید.

خط 25 تا 27:

در این خطوط متغییرهایی که مقدار ساعت دقیقه و ثانیه در آن ها ذخیره می شود تعریف شده است. این متغییر ها به صورت سراسری تعریف شده است. و در همه توابع برنامه شناخته می شوند.

خط 33:

unsigned char DigitTo7SegEncoder(unsigned char digit, unsigned char common);

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

خط 36:

این خط معرفی تابع روتین وقفه به برنامه است.

خط 41:

int main(void)

شروع تابع اصلی برنامه می باشد.

خط 43:

خروجی کردن پورت های مربوط به پایه های دیتای سون گمنت منظور همان پایه های غیر مشترک.

خط 44:

خروجی کردن پایه های مربوط به پایه های کنترل سون سگمت (پایه های مشترک سون سگمت) و وردی کردن دو پین از پورت برای وصل کردن کلید برای تنظیم ساعت.

خط 47 تا 49:

تنضیمات مربوط به تایمر 1 میکروکنترلر ATmega32 برای ایجاد زمان 1 ثانیه ای

خط 50:

	sei();

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

خط 56 تا 72:

دو دستور if تعریف شده در این خطوط برای تنظیم ساعت و دقیقه کاربرد دارند با هر بار فشرده شدن کلید بک واحد به مقدار ساعت یا دقیقه اضافه می شود ساعت بعد از رسیدن به 23 و دقیقه بعد از رسیدن به 59 صفر می شوند.

خطوط 74 تا 85:

قبل از توضیح عملکرد این خطوط باید عملکرد تابع DigitTo7SegEncoder توضیح داده شود.

عملکرد تابع DigitTo7SegEncoder:

این تابع از خط 104 شروع شده و تا سطر 141 ادامه دارد. نکته ی مهم در مورد این تابع این است که می توانید از این تابع در برنامه ی مختلف خود نیز استفاده کنید. این تابع اعداد ده دهی را به کد سون سگمنت تبدیل می کند. منظور از کد سون سگمنت کدهایی است که می توانید در جدول زیر آن ها را مشاهده کنید.

Segment-ASCII-table-character-Set

این تابع دو ورودی دارد ورودی اول digit نام دارد و عددی است که باید به کد سون سگمنت تبدیل شود. ورودی دوم common نام دارد و نوع پایه مشترک سون سگمنت را مشخص می کند در صورت آند مشترک بودن باید صفر مقدار دهی شود و در کاتد مشترک 1

unsigned char DigitTo7SegEncoder(unsigned char digit, unsigned char common)
{
	unsigned char SegVal;
 
	switch(digit)	
	{	
		case 0:	if(common == 1)	SegVal = 0b00111111;
				else			SegVal = ~0b00111111;
				break;
		case 1:	if(common == 1)	SegVal = 0b00000110;
				else			SegVal = ~0b00000110;
				break;
		case 2:	if(common == 1)	SegVal = 0b01011011;
				else			SegVal = ~0b01011011;
				break;
		case 3:	if(common == 1)	SegVal = 0b01001111;
				else			SegVal = ~0b01001111;
				break;
		case 4:	if(common == 1)	SegVal = 0b01100110;
				else			SegVal = ~0b01100110;
				break;
		case 5:	if(common == 1)	SegVal = 0b01101101;
				else			SegVal = ~0b01101101;
				break;
		case 6:	if(common == 1)	SegVal = 0b01111101;
				else			SegVal = ~0b01111101;
				break;
		case 7:	if(common == 1)	SegVal = 0b00000111;
				else			SegVal = ~0b00000111;
				break;
		case 8:	if(common == 1)	SegVal = 0b01111111;
				else			SegVal = ~0b01111111;
				break;
		case 9:	if(common == 1)	SegVal = 0b01101111;
				else			SegVal = ~0b01101111;		
	}		
	return SegVal;
}

در این تابع از ساختار switch case استفاده شده است. ورودی digit یا case های مختلف مقایسه شده و در صورت برابر بودن کد مربوز به هر کدام توسط دستور return SegVal به خروجی تابع ارسال می شود.

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

توضیح خطوط 74 تا 85:

SegDataPort = DigitTo7SegEncoder(seconds%10,1);
SegCntrlPort = ~0x01;
SegDataPort = DigitTo7SegEncoder(seconds/10,1); 
SegCntrlPort = ~0x02;

کدهای مربوط به قسمت ثانیه شرح داده می شود دقیقه و ساعت هم دقیقا مثل همین مورد است.

برای کنترل سون سگمنت از دو پورت segdataport و segcntrlport استفاده شده است. برای نشان دادن یک عدد بر روی سون سگمنت باید دیتای لازم بر روی پایه های a تا g قرار بگیرد علاوه بر این پایه مشترک نیز با توجه به نوع آند مشترک بودن یا کاتد مشترک بودن به منبع تغذیه وصل شود. segdataport  پایه های a تا g را کنترل می کند و segcntrlport  پایه ی مشترک را

برای نشان دادن دو رقم ثانیه از روش زیر استفاده می کنیم به عنوان مثال عدد 23 را بررسی می کنیم برای بدست آوردن یکان عدد 23 از باقی مانده تقسیم آن بر عدد ده استفاده می کنیم. برای بدست آوردن باقی مانده در زبان C می توان از عملگر % استفاده کرد.

SegDataPort = DigitTo7SegEncoder(seconds%10,1);

عبارت seconds%10 عدد 3 را نتیجه می دهد. و تابع DigitTo7SegEncoder کد سون سگمنت آن را تولید می کند برای نمایش این کد برروی سون سگمنت باید پایه مشترک نیز به تغذیه وصل شود که این عمل نیز توسط دستور زیر انجام می شود.

SegCntrlPort = ~0x01;

برای نمایش دهگان عدد کافی است نتیجه تقیم صحیح عدد بر 10 را بدست آوریم.

SegDataPort = DigitTo7SegEncoder(seconds/10,1);

خط 144 تا 160:

در پایان برنامه مربوط به تابع وقفه نوشته شده است که با هر بار وقوع وقفه یک ثانیه به مقدار متغببر ثانیه شمار افزوده می شود. تا به مقدار 60 برسد. و با شصت شدن متغییر ثانبه یک واحد به متغییر دققیه اضافه می شود. ومتغییر ثانیه صفر می شود. نحوه عملکرد متغییر ساعت نیز به همین ترتیب است.

فیلم عملکرد مدار ساعت دیجیتال با AVR و سون سگمنت:


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

 

 

علی عزتی

علی عزتی هستم. رشته ی مهندسی برق الکترونیک رو خوندم. علاقه ی من به یادگیری و به اشتراک گذاشتن چیز هایی که یاد گرفتم. باعث شد تا الکترولب ایجاد بشه. علاقه ی زیادی به الکترونیک دارم. و دوست دارم چیزهای جدید یادبگیرم و بسازم ... :))

نوشته های مشابه

24 دیدگاه

  1. سلام و خسته نباشید
    من این پروژه را ساختم ولی کار نکرد
    میشه بگید که سون سگمنت از چه نوعی است؟فیوزبیت ها هم میشه بگید که چه طوری است؟

    1. با هر دو نوع کاتد مشترک یا آند مشترک میشه از این کد استفاده کرد توی توضیحات نوشتم ولی اگر از کد بالا استفاده می کنید کاتد مشترک هستش برای فیوزبیت هم باید روی 4 مگاهرتز داخلی تنظیم بشه می تونید از این مقادیر استفاده کنید low:C3 و high:D9

        1. توجه مهم: برای کارکرد صحیح مدار باید اسیلاتور داخلی میکروکنترلر روی 4MHZ تنظیم شده باشد.

  2. سلام من نو اموز الکترونیک هستم اموزش کار با مولتی متر دیجیتال دارید ویا جایی تو نت هست که برم دان کنم ویاد بگیرم .با سپاس

    1. بهتره در انجمن بپرسید من خودم راهنمایی تون می کنم بابت دیر جواب دادن هم معذرت می خوام مدتی بود به سایت سر نزده بودم

  3. سلام آقای عزتی عزیز خسته نباشید ممنون بابت سایت بسیار خوبتون
    یک سوال هست که خدمت شما دارم و ممنون میشم که پاسخ این سوال رو بدهید
    همون طور که خود شما بهتر میدانید برای میکروکنترلر های AVR و ARM از زبان C استفاده میکنند
    بذارید سوالم رو این طوری مطرح کنم برای مثال پروژه ساعت دیجیتال شما
    شما برای میکروکنترلر AVR که در برد ساعت به کار رفته یک سری کد نوشته اید آِیا میشود عین همین کد ها رو در میکروکنترلر ARM در محیط keil به کار برد؟
    منظورم اینه که در کدهای C نوشته شده برای AVR رو میشود در ARM هم به کار برد؟(و نه نیاز به تغییر اساسی دارند؟)
    ممنون و بسیار سپاس گذارم

    1. شرمنده بابت تاخیر در جواب دادن به جز قسمت هایی که به رجیسترهای AVR مربوط میشه بقیه قسمت ها رو میشه در هر میکروکنترلری استفاده کرد. منظور اینه با تغییر جزئی رجیستر ها میشه از این برنامه در هر میکروکنترلر دیگه ای هم استفاده کرد.

  4. این برناه کو نوشتی به درد نمی خوره پر از اررور ه درستش کن یا مزد تموم یا منت تموم

  5. سلام این دستورو من چجوری باید بنویسم {if(400>gas>200) {PORTD.1=1
    الان این اجراع نمیشه

    1. سلام آقای مهندس
      برای درایو کردن سگمنت ها و تبدیل انها به سگمنت های بزرگ با ULN نیاز هست پولاپ بشن
      اگر ترانزیستور استفاده کنم چی
      مرسی

  6. سلام جناب آقای عزتی . چطور میشه برای سون سگمنت توی سی مثل آردینو لایبری نوشت.

  7. سلام خیلی تلاش کردی و خوب از روی سایت های خارجی کپی کردی.خوب فایل هگزش رو قرار میدادی که یه کاری کرده باشی…
    =

    1. دوست عزیز شما زحمت همین کپی کاری هم نمیکشی و فایل هگز آماده میخوای کافیه یه پروژه ایجاد کنی و برنامه کپی کنی توش

      1. مهندس جان
        این مدار
        سگمنت هارو بدون مقاوت نمیسوزونه ؟
        فکر تقسیم ولتاژو جریانم کردی شما ؟

      2. مهندس جان
        این مدارو بستم فایل هکز هم جای گذاری کردم تو پروتئوس ولی سگمنت ها ساعتو نشون نمیدادن هی جشمک میزدن مشکل چیه

  8. آقا عزتی جان
    یه سوال داشتم خدمتتون
    برای برنامه نویسی میکروکنترلر چه سطحی از زبان C لازمه ؟
    منظورم اینه که مبتدی یا متوسط یا پیشرفته
    در ضمن دستت درد نکنه کسایی هم که میگن فقط کپی و پیست بوده بد نیست از مغزتون استفاده کنید
    خط به خط توضیح داده شده
    جای تشکرتونه دیگه

    1. سلام

      تسلط به زبان C صد در صد لازمه ولی لازم نیست C رو مثل یک دانشجوی نرم افزار یاد بگیرید اگر میخواهید یک منبع خوب داشته باشید من کتاب برنامه نویسی به زبان c
      برای دانشجویان الکترونیک و سخت افزار Embeded C مهندس سپاس یار رو پیشنهاد میکنم از اینجا هم میتونید تهیه کنید. https://bit.ly/2IHkBpK هرچی لازم میشه رو از این کتاب می تونید یاد بگیرید

  9. با سلام و ارزوی سلامتی
    من میخواهم این مدار رو برای استفاده شخصی ام بسازم. دوتا سوال داشتم خدمتتون
    اولا میخوام سگمن ثانیه شمار حذف بشه بهش احتیاج ندارم . همون دقیقه برای من کافیه. میخوام بدونم اگه 77 سگمنت ثانیه شمار رو نگذارم مشکلی پیش میاد یا نه؟
    سوال دوم اینکه می تونم آیا بجای پورت c از پورت A استفاده کنم؟ البته با تغییر در ابتدای برنامه

  10. سلام مهندس
    اگه i2c رو فعال کنم با ای سی ساعت مشکل پیش نمیاد یا کدوم کدها باید حذف بشن

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

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

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

دکمه بازگشت به بالا