آموزش کدویژن صفر تا صد ( راه اندازی پایه ها )

آموزش کدویژن ( راه اندازی پایه ها )

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

میکروکنترلر AVR سری MEGA رو آموزش میدیم، این میکروکنترلرها هشت بیتی هستند و بسیار کار باهاشون ساده و عالیه.خوب اول سراغ پورتا میریم و انشاءالله تو این جلسه سعی میکنیم پورتارو بصورت کامل آموزش بدیم. یادآور میشم ما با نرم افزار codevision و برنامه نویسی به زبان c کار خواهیم کرد.

اول با این میکرو کار میکنیم میخوایم پایه هاشو راه اندازی کنیم.

ما کلا با ۳ تا رجیستر کار داریم DDR ,PORT,PIN کلا تو کار با پایه ها با این ۳ تا رجیستر کار
داریم.
خوب دیگه بریم سر کار اصلی که همون برنامه نویسی
مثال ۱( میخوایم یه پورت رو به صورت خروجی تبدیل کنیم.)PORTD

#include <mega8.h>
Void main(){
DDRD=0XFF;
PORTD=0XFF;
While(1){
}
}

ببینید ما با دستور DDR.X که X نام پورت مورد نظره تعیین میکنیم که یه پورت به صورت ورودی باشه یا خروجی . تقریبا اکثر پورتا از ۸ پایه تشکیل شده بجز بعضی از
پورت ها مثل پورت c در میکروکنترلر mega8 که ۷ تا پایه داره. خوب اگر تو رجیستر DDR مقدار ۰ بریزیم پایه مورد نظر به صورت ورودی و اگر ۱ بریزیم بصورت
خروجی میشه. توجه به این مثال کنید : DDRD=0B11110000 خوب ما تو اینجا نصف پورت رو بصورت ورودی و نصف پورت بصورت خروجی تعریف می کنیم
چهار بیت اول از راست به صورت ورودی و چهار بیت سمت چپ بصورت خروجی تعریف می کنیم خوب حالا اگه بخوایم بیشتر به این قضیه توجه کنیم که کدوم پایه
بصورت خروجی و کدوم پایه بصورت وردی تعریف شده PORTD.0 تا PORTD.3 به صورت ورودی و PORTD.4 تا PORTD.7 به صورت خروجی تعریف شده.
*نکته : وقتی تو زبان C می خوایم یه کدی رو بصورت هگزادسیمال بنوسیم به صورت ۰X و هر وقت بخوایم کدی رو به صورت باینری تعریف کنیم به صورت ۰B تعریف
میشه.
* نکته : زبان C به بزرگی و کوچکی حروف حساس هست پس به این قضیه توجه کنید.
مثال ۲( هشت عدد LED رو به PORTD وصل کنید و اونارو روشن کنید.

#include <mega8.h>
Void main(){
DDRD=0B11111111;
PORTD=0B11111111;
While(1){
}
}

خوب دستور بعدی دستور PORT.X که X اسم پورت مورد نظره ما با ریختن ۱ تو این رجیستر در اصطلاح این پایه رو روشن کنیم و با ریختن ۰ اونو خاموش می کنیم
که در مثال بالا اگر توجه کنید من تمام پورت رو بصورت خروجی تعریف کردیم و با تمام پایه های اونو روشن کردم.
عکس مدار رو تو شبیه سازی ببینید.
خوب دوستان یک نکته : اگه همین مدار رو تو عمل ببندین LED ها خیلی عالی میسوزن  چرا؟چونکه ولتاژ LED نهایتا ۳٫۳V و ولتاژ خروجی میکروکنترلر AVR
۵V هستش پس باید به LED ها مقاومت وصل کرد.
حالا من نحوه محاسبه مقاومت رو برای LED توضیح میدم
مثال: با فرض اینکه ولتاژ LED ما ۱٫۷ ولت باشه و جریانش ۱۰ میلی آمپر باشه حالا اگه بخوایم این LED رو مستقیم به میکروکنترلر وصل کنیم که ولتاژش ۵V
هستش مقدار مقاومت رو محاسبه کنیم.
پس مدار برای تست عملی به این شکل تغییر پیدا می کنه
خوب یه سوال پیش میاد اگه بخوایم این پایه ها چشمک بزنن تکلیف چیه؟جواب اینه که باید با یه دستور جدید آشنا بشیم اونم دستور تاخیر هست. دستور تاخیر به این
صورت هست که تاخیر به ثانیه و تاخیر به میکرو ثانیه داریم که دستوراتش به این صورت هستش
delay_ms(x);
delay_us(x);
که X می تونه مقداری از ۰ تا ۵۶۶۳۶ می تونه باشه.
مثال ۳( برنامه ای بنویسید)برنامه نویس شدید ها !(که PORTD رو بصورت خروجی تعریف کنید و تمام پایه هاش به فاصله یک ثانیه روشن و خاموش شن و این کار
به صورت مداوم انجام بشه.

#include <mega8.h>
#include <delay.h>
Void main(){
DDRD=0B11111111;
PORTD=0B00000000;
While(1){
PORTD=0B11111111;
delay_ms(1000);
PORTD=0B00000000;
delay_ms(1000);
}
}

خوب بریم سراغ تشریح برنامه :
ببینید هر کتابخونه ای که بخوایم از دستوراتش استفاده کنیم باید اول هدر اونو فراخونی کنیم این به چه معناست یعنی این که اگر بخواییم از دستورات تاخیر که همون
delay_ms و delay_us استفاده کنیم باید اول هدرش که #include <delay.h> هست رو باید اول برنامه فراخونی کنیم.حالا اگه توجه کرده باشین گفتیم این
کارو به صورت مداوم انجام بدیم ، دوستان توجه کنن که تمام دستورات داخل تابع )با توابع بعدا بصورت کامل آشنا میشیم( main فقط یکبار اجرا می شه و دستورات
داخل حلقه while(1) به صورت مداوم.
خوب حالا در مثال بعدی ما میخوایم پایه هارو یکی یکی روشن کنیم، به این صورت که اول PIND.0 بعد PIND.1 تا PIND.7 و یک تاخیری ۱۰۰ میلی ثانیه ای هم
ایجاد کنیم.

#include <mega8.h>
#include <delay.h>
Void main(){
DDRD=0XFF;
PORTD=0X00;
While(1){
PORTD.0=1;
delay_ms(100);
PORTD.1=1;
delay_ms(100);
PORTD.2=1;
delay_ms(100);
PORTD.3=1;
delay_ms(100);
PORTD.4=1;
delay_ms(100);
PORTD.5=1;
delay_ms(100);
PORTD.6=1;
delay_ms(100);
PORTD.7=1;
delay_ms(100);
}
}

خوب حالا این برنامه بالا رو به یه سبک دیگه می نویسم

#include <mega8.h>
#include <delay.h>
Void main(){
DDRD=0XFF;
PORTD=0X00;
While(1){
PORTD=0b00000001;
delay_ms(100);
PORTD=0b00000011;
delay_ms(100);
PORTD=0b00000111;
delay_ms(100);
PORTD=0b00001111;
delay_ms(100);
PORTD=0b00011111;
delay_ms(100);
PORTD=0b00111111;
delay_ms(100);
PORTD=0b01111111;
delay_ms(100);
PORTD=0b11111111;
delay_ms(100);
}
}

این برنامه دقیقا شبیه برنامه بالاست
حالا ی برنامه بنویسیم که عکس برنامه بالا باشه یعنی اول PORTD.7 و بعد PORTD.6 روشن بشه تا برسه به PORTD.0 و این کار ادامه پیدا کنه.

#include <mega8.h>
#include <delay.h>
Void main(){
DDRD=0XFF;
PORTD=0X00;
While(1){
PORTD=0b10000000;
delay_ms(100);
PORTD=0b11000000;
delay_ms(100);
PORTD=0b11100000;
delay_ms(100);
PORTD=0b11110000;
delay_ms(100);
PORTD=0b11111000;
delay_ms(100);
PORTD=0b11111100;
delay_ms(100);
PORTD=0b11111110;
delay_ms(100);
PORTD=0b11111111;
delay_ms(100);
}
}

تمرین ۱: حالا برنامه بنویسید که اول PORTD.0 تا PORTD.7 روشن بشن بعد PORTD.7 تا PORTD.0 روشن بشن )تلفیق دو برنامه بالا(
تمرین ۲ : تمرین ۱ رو بصورتی بنویسید که LED ها یکی یکی روشن بشن و با روشن LED بعدی LED قبلی خاموش بشه.
خوب اگه توجه داشته باشین کدهای برنامه بالا خیلی زیاده باید در برنامه نویسی تا اونجا که می تونیم حجم کدها رو کم کنیم اما چطور؟
باید با یه دستور جدید آشنا بشیم، دستور SHIFT به چپ و SHIFT به راست.
<< شیفت به چپ و >> شیفت به راست
ساختار کلی دستور شیفت :
تعداد شیفت >> متغیری که می خواهیم شیفت دهیم
مثال : عدد یک رو ۱۸ بار به چپ شیفت بدید.
۱>>18
مثال : عدد سه رو ۶ بار به راست شیفت بدید.
۳<<6
خوب حالا که با دستور SHIFT به طور مختصر آشنا شدیم برنامه فلاشرمون رو با دستور شیفت بنویسیم
مثال( برنامه ای بنویسید که پورت D رو یکی یکی روشن کنه با تاخیر ۳۰۰ میلی ثانیه .

#include <mega8.h>
#include <delay.h>
Int i=0b00000001; //0x01
Void main(){
DDRD=0XFF;
PORTD=0X00;
While(1){
PORTD=i;
delay_ms(300);
i=i<<1;
}
}

دیدین حجم کد چقد کمتر شد و برنامه چقد اصولی تر شد.
تمرین ۳ : برنامه بالا رو طوری بنویسید که برنامه برعکس عمل کنه .
خب اگه توجه کرده باشین برنامه بالا یه مشکلی داره مشکلشم اینه که فقط یه مرحله انجام میشه، چرا؟
دلیلش اینه که وقتی متغیر i داره شیفت پیدا میکنه در مرحله آخر که میشه ۰b100000000 اگر این عدد رو ی بار دیگه شیفت به چپ بدیم میشه ۰b00000000
پس راه حل چیه؟
باید با ی دستور جدید آشنا بشیم دستور if که بگیم اگر متغیر ما برابر ۰b10000000 حالا اول خود این متغیر رو بریزه تو پورت D بعد ی تاخیر ایجاد کنه بعد
بیاد متغیر رو به ۰b00000001 تغیر بده تا برنامه بصورت مداوم این کار رو انجام بده
خوب حالا با دستور if اشنا می شیم
{)شرط( if
}
مثال ( برنامه ای بنویسید که اگر متغیر i برابر یک شد PORTD.0 یک بشه

if(i==1) { 1(
PORTD.0=1;
}
if(i){ 2(
PORTD.0=1;
}
if(i==1) PORTD.0=1; 3(
if(i) PORTD.0=1; 4(

دوستان من برنامه بالا رو به چهار طور مختلف نوشتم که همه برنامه ها مثل همه، دقیقا مثل هم.
حالا مثال بعدی
مثال( برنامه ای بنویسید که اگر متغیر i برابر یک شد PORTD.0=1 و اگر در غیر این صورت PORTD.1=1 بشه
if(i==1) PORTD.0=1; 1(
else PORTD.1=1;
من باید همین جا یه نکته رو به دوستان متذکر بشم برنامه نویسی فقط با کار و تلاش و تمرین و صرف وقت زیاد به دست میاد.
خوب حالا که تقریبا با دستور if اشنا شدیم برنامه بالا رو بنویسیم
مثال ( برنامه بالا رو طوری بنوسید که بطور مدام این چشمک زدن ادامه پیدا کنه.

#include <mega8.h>
#include <delay.h>
Int i=0b00000001; //0x01
Void main(){
DDRD=0XFF;
PORTD=0X00;
While(1){
PORTD=i;
delay_ms(300);
i=i<<1;
If(i==0b100000000){
PORTD=i;
delay_ms(300);
i=0b000000001;
}
}
}

حالا من می خوام برنامه بالا رو قشنگ تر بنویسم:

#include <mega8.h>
#include <delay.h>
int i=1;
Void main(){
DDRD=0XFF;
PORTD=0X00;
While(1){
if(i==256) i=1;
PORTD=i;
delay_ms(300);
i=i<<1;
}
}

خب حالا تو مثال بعدی من می خوام برنامه بالا برعکس عمل کنه

#include <mega8.h>
#include <delay.h>
int i=128;//0b10000000;
Void main(){
DDRD=0XFF;
PORTD=0X00;
While(1){
if(i==0) i=128;
PORTD=i;
delay_ms(300);
i=i>>1;
}
}

تمرین ۴ : دوستان برنامه ای بنوییسید که تلفیق دو برنامه بالا باشه.
خوب دوستان نوبت اون رسیده که دستور PIN و وصل کردن کلید به میکرو رو آموزش بدیم. دوستان با استفاده از دستور PIN ما می تونیم مقداری که روی پین های
میکروکنترلر هستش رو بخونیم.
دوستان الان ما به یکی از پایه های میکروکنترلر ی کلید وصل کردیم خوب حالا می خوایم بگیم که اگه کلید زده شد LED روشن بشه در غیر این صورت خاموش بشه.

#include <mega8.h>
#include <delay.h>
Void main(){
DDRC.0=0;
DDRD.0=1;
PORTD.0=0;
While(1){
If(PINC.0==0)
PORTD.0=1;
else
PORTD.0=0;
}
}

خوب حالادوستان جرا ما از مقاومت بالاکش)پول آپ( و یا مقاومت پایین کش )پول داون( استفاده میکنیم. اول بخاطر اینکه نویز از بین بره و به مدارمون غلبه نکنه تا
اطلاعات اشتباه نشن، دوم اینکه صفر و یکی که به میکرو میدیم اطمینان بالایی داشته باشن، به طور مثال من وقتی که میگم این پین رو چک کن اگر برابر صفر منطقی
شد فلان کارو انجام بده باید اول خودش در وضعیت یک منطقی باشه امیدوارم که جا افتاده باشه تو تصاویر زیر پول آپ و پول داون کردن یک کلید رو میبینید.
پول آپ پول داون
توجه کنن که مقدار مقاومت می تونه از ۳۳۰R تا ۱۰K یا حتی بیشتر هم باشه که معمولا از ۱۰K استفاده می کنیم.
فقط یه نکته رو هم باید به دوستان متذکر بشم اونم اینه که میکروکنترلر AVR سری MEGA مقاومت بالاکش )پول آپ( داخلی داره اما مقاومت پایین کش)پول داون(
نداره که بعدا توضیح میدیم چطوری باید راه اندازیش کنیم.
خوب حالا اینقد مثال می زنیم که جا بی افته.
مثال( یک کلید به میکرو وصل کنید که با زدن اون کلید تمام PORTD روشن و دوباره با زدن همون کلید خاموش بشه.

#include <mega8.h>
#include <delay.h>
bit f=0;
Void main(){
DDRC.0=0;
DDRD=0XFF;
PORTD=0;
while(1){
if(PINC.0==0) {
While(PINC.0==0);
f=!f;
}
if(f==1)
PORTD=0XFF;
else
PORTD=0X00;
}
}

خوب دوستان من گفتم اگه کلیدی که PINC.0 وصله زده شه متغیر F که نوع bit هستش)متغیر نوع bit یا صفر یا یک می تواند باشد( تاگل بشه، یعنی اگه مقدارش
صفره یک بشه و برعکس اینکارو من با دستور f=!f; انجام دادم. خوب دوستان شاید الان همه بپرسین این دستور while(PINC.0==0); چیه. قبل از اینکه به این
سوال پاسخ بدیم دوستان یبار این دستور رو پاک کنن و برنامه رو اجرا کنن و بعد از اون این دستور رو اجرا کنن و عملکرد مدار رو ببینن. چونکه کلید یه ابزار مکانیکی و
سرعت پردازش میکرو هم خیلی بالاست وقتی دستمون رو کلیده لرزش های کوچیک باعث میشه کلید هی مقدارش عوض بشه و میکرو هم داره این مقدارو با سرعت
بالامیخونه و همونطور که دیدین برنامه نمی دونهباید چیکار کنه. ما با این دستور while(PINC.0==0); می گیم میکرو تا زمانی که دست من روی کلید هست تو هیچ
کاری نکن )در اصل تو این حلقه گرفتار شده( وقتی دستمونو برداشتیم و شرط داخل حلقه نقض شد میکرو میره به خط بعد و حالا مقدار f رو معکوس حالت قبل می
کنه. امیدوارم که جا افتاده باشه.
خو حالا میخوایم همین مثال بالا را دوباره بنویسیم اما با این تفاوت که از مقاومت پول آپ داخلی خود میکرو استفاده کنیم.

#include <mega8.h>
#include <delay.h>
bit f=0;
Void main(){
DDRC.0=0; PORTC.0=1;
DDRD=0XFF;
PORTD=0;
while(1){
if(PINC.0==0) {
While(PINC.0==0);
f=!f;
}
if(f==1)
PORTD=0XFF;
else
PORTD=0X00;
}
}

تنها تفاوتش اون خط زرد رنگه. پس وقتی یه پین رو به صورت ورودی پیکره بندی کنیم برای فعال کردن پول آپ داخلی باید به اون پین عدد یک منطقی بفرستیم. به
مثال زیر توجه کنن دوستان
مثال( پین C.0 رو بصورت ورودی در نظر گرفته و پول آپ داخلی را فعال کنید
DDRC.0=0;
PORTC.0=1;
مثال( تمام پایه های PORTB را ورودی و مقاومت بالاکش این پورت را فعال کنید.
DDRB=0X00;
PORTB=0XFF;
اینم از نحوه راه اندازی مقاومت بالاکش داخلی فقط دوستان توجه کنن در این حالت دیگه نیازی به مقاومت خارجی نیست مدار زیر رو ببینید
اینجا جا داره که یک نکته مهم رو متذکر بشم:
اگر مدارتون می خواد در یک محیط پر نویز صنعتی استفاده بشه حتما از مقاومت
بالاکش خارجی استفاده کنید.
خو ی مثال دیگه میزنیم و به سراغ برنامه نویسی یه فلاشر مشتی میریم.
مثال( برنامه ای بنویسید که با استفاده از یک دیپ سویچ هشت تایی اطلاعات رو از PORTB خوانده و همان اطلاعات را روی PORTD نشان دهد.

#include <mega8.h>
#include <delay.h>
Void main(){
DDRB=0X00;
PORTB=0XFF;
DDRD=0XFF;
PORTD=0X00;
While(1){
PORTD=PINB; {
}

ممنون از دوست عزیز محسن فیض الهی
یا علی

پاسخ دهید

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