کارگاه عملی - شماره 2 : کار با واحد LM35 + ADC + سون سگمنت [18]
دومین قسمت از آموزش برنامه نویسی،تحت عنوان "کار با واحد ADC" رو مورد ارزیابی قرار می دهیم.
پس با ما در ادامه مطلب همراه باشید...
به نام خدا
سلام ...
حالتون چطوره ؟!
خوب هستید ؟
بزارید اول تشکر کنم از اون دسته از دوستانی که با نظراتشون به بنده دلگرمی میدند و لطف دارند !
و البته گله کنم از اونایی که بی تفاوت از کنار مطالب رد میشند.عزیزم نظر بزار ...
اون زمانی که این وبلاگ رو راه انداختم نمیدونستم دقیقا میخوام چقدر مطلب بزارم و کلا تا چه سطحی پیش برم.اما همونطور که میبینید بخش 18 آموزش رو هم شروع کردیم و با دعای خیر شما دوستان ایشالا میریم تا بخش 1018 !!!
خوشحال میشم بتونم روز به روز هم خودم پیشرفت کنم،هم شما پیشرفت کنید و هم وبلاگ پیشرفت کنه !
بنابر این شما هم اگه کمکی از دستتون برمیاد،کوتاهی نکنید و اگه نظری دارید و یا میتونید به طریقی مدد کنید،منتظر یاری سبزتان هستم ...
دوستانی که تازه و جدیدا دارن بحث ها رو پیگیری میکنند،لطفا اول از همه پستهای :
مبدل آنالوگ به دیجیتال ADC در AVR ؟ [12]
بهتره که هنگام مطالعه این قسمت از آموزش،صفحه مبدل آنالوگ به دیجیتال ADC در AVR ؟ [12] رو هم باز کنید و همزمان پیگیر بحث باشید.
بریم سراغ برنامه نویسی و مقدار دهی رجیسترها :
فرکانس کاری میکروکنترلر را 8 مگاهرتز در نظر میگیریم.
#include <mega32.h> #include <delay.h> void adc_configuration(){} unsigned int temp(){} void main(){}
دو تا تابع تعریف میکنیم با نام های : adc_configuration و temp .(توجه : انتخاب نام توابع کاملا اختیاری است.)
در تابع adc_configuration تنظیمات پیکربندی واحد ADC رو انجام میدیم.
تابع temp هم وظیفه قرائت مقدار دما رو داره.
اول شروع میکنیم به کانفیگ کردن واحد ADC ؛ یعنی نوشتن تابع adc_configuration بصورت گام به گام :
رجیستری داشتیم با نام ؛ ADMUX :
کانال مورد نظر ما ADC0 هست و ولتاژ مرجعمون رو هم به دلخواه روی 2.56 ولت داخلی قرار میدیم :
void adc_configuration(){ ADMUX |= (1<<REFS1)|(1<<REFS0); }
رجیستر دیگه ای هم بود با نام ؛ ADCSRA :
ضریب تقسیم رو 64 میگیریم و فلگ ADEN رو هم یک میکنیم تا واحد ADC فعال بشه :
void adc_configuration(){ ADMUX |= (1<<REFS1)|(1<<REFS0); ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADEN); }
تا اینجا پیکربندی ADC تموم شد.
تابع بعدی که مورد بحثمونه،تابع تعریفیه temp ـه ! :
unsigned int temp(){}
کاری که باید در این قسمت انجام بدیم،اول از همه،فرمان برای شروع تبدیله ،که با یک کردن فلگ ADSC انجام میشه !
unsigned int temp(){ ADCSRA |=(1<<ADSC); }
با صدور فرمان شروع تبدیل،باید منتظر بمونیم تا تبدیل انجام بشه و پس از پایان یافتن تبدیل،مقدار رجیستر ADC رو بخونیم !
حالا از کجا بفهمیم که تبدیل تموم شده ؟
قبلنا براتون گفتم که یه فلگی داریم با نام ADIF که اصل کارش همینه !
وقتی یک بشه،یعنی تبدیل تموم شده و وقتی صفر باشه یعنی واحد ADC در حال انجام عملیات تبدیله.
پس باید منتظر موند تا این فلگ یک بشه.
بعد هم که یک شد،با نوشتن یه یک دیگه روش دوباره صفرش میکنیم (جل الخالق ).
unsigned int temp(){ ADCSRA |=(1<<ADSC); while ((ADCSRA & (1<<ADIF))==0); ADCSRA |=(1<<ADIF); }
الان دیگه تبدیل انجام شده و رجیسترهای ADCL و ADCH که وظیفه نگهداری مقدار ADC رو دارند،پر شدند و حاوی مقدار ADC هستند.
نکته ای که باید بگم اینه که به مجموع دو تا رجیستر ADCL و ADCH میگند ADCW که در واقع قراره یه عدد 10 بیتی رو به ما تحویل بده ! (توضیحاتشو قبلن دادم.نکنه میخواین دوباره بگم ؟! )
unsigned int temp(){ ADCSRA |=(1<<ADSC); while ((ADCSRA & (1<<ADIF))==0); ADCSRA |=(1<<ADIF); return ADCW; }
تا اینجای کار،دو تا تابع اصلیمون رو نوشتیم که وظیفه عملیات های واحد ADC رو بر عهده داشتند.
اما قرارمون این بود که مقدار دما رو بخونیم و روی سون سگمنت نمایش بدیم.
پس میریم سراغ ادامه آموزش و توضیح تابع اصلی main :
void main(){}
روند کار به این صورته که :
1.دما رو میخونیم.
2.داخل متغیری با نام T میریزیم.
3.چون دما چند رقمیه (اینجا دو رقم) باید تفکیک به دو عدد تک رقمی بشه.
4.اعداد تفکیک شده از آرایه مربوط به اعداد (seg) انتخاب میشند.
5.اعداد با یه تکنیک خاص روی سون سگمنت نمایش داده میشند.
الان میخوایم مقدار دما رو بخونیم :
مقدار برگردونده شده از تابع temp رو داخل متغیر T میریزیم.
با توجه به فرمولی که در بخش 12 آموزش های وبلاگ دادم بهتون،مقدار T جدید رو محاسبه میکنید.
این مقدار جدید،مساوی با اندازه دما در واحد درجه سلسیوس است.
لازم بذکره که دلیل اضافه شدن عبارت (100*) اینه که سنسور مقدار رو به میلی ولت به ما تحویل میده !
T = temp(); T = (((T*2.56)*100)/1023);
قبل از همه،اعداد مورد نظرمون رو برای نمایش رو سون سگمنت میسازیم.
نرم افزارهای مختلفی برای اینکار وجود داره که میتونید ازشون استفاده کنید.
برای راحتی کار،اعداد 0 تا 9 + علامت درجه + حرف C رو در قالب کد براتون آماده گذاشتم :
به نحوی که که عضو صفرم از آرایه seg معادل عدد 0 و عضو یکم معادل عدد 1 و ... و عضو دهم معادل علامت درجه و عضو یازدهم معادل حرف C .
(دقت کنید که شمارش اعضای آرایه از صفر شروع میشه).
کاتد مشترک :
unsigned char seg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x63,0x39};
آند مشترک :
unsigned char seg[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x1C,0x46};
برای اینکه برنامه نویسیمون مرتب تر در بیاد،یه تابع دیگه هم تعریف میکنیم به اسم : seg_display و کلیه مسائل مربوط به نمایش سون سگمنت رو در اون انجام میدیم.
void seg_display (unsigned int temp){}
این تابع مقدار دما رو میگیره و با عملیاتی که روش انجام میده،برای نمایش روی سون سگمنت آمادش میکنه.
void seg_display (unsigned int temp){ unsigned char seg[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x1C,0x46}; unsigned char data[4]; DDRB=0xFF; DDRD=0x0F; data[0]=seg[temp/10]; data[1]=seg[temp%10]; data[2]=seg[10]; data[3]=seg[11]; for (i = 0; i < 4; i++) { PORTB=data[i]; PORTD=0x00; PORTD=1<<i; delay_us(500); } }
ایندفعه یکباره همه کدهای تابع رو یه جا نوشتم تا بهتر متوجه بشید.
unsigned char data[4];
از این آرایه بعنوان یک بافر استفاده میکنیم که قراره مقادیری رو از آرایه seg در خودش بریزه !
DDRB=0xFF; DDRD=0x0F;
در این قسمت هم پورت B رو که بعنوان خطوط کنترلی abcdefg+dot سون سگمنت،استفاده شدند رو بعنوان خروجی و همچنین 4 پین اول پورت D رو بعنوان خروجی که در واقع خطوط کنترلی 1234 سون سگمنت ها هستند،انتخاب کردیم.
data[0]=seg[temp/10];
این قسمت به بعد رو خیلی خوب یاد بگیرید،چون برای کار با سون سگمنت بصورت کلیشه ای باید این کار ها رو همیشه انجام بدید.
فرض کنید که دمای اندازه گیری شده 27 درجه سانتی گراده و میخوایم روی سون سگمنت عدد رو نمایش بدیم.
عدد مورد نظر برای نمایش روی سون سگمنت بصورت کاملترش به این شکله :
که تشکیل شده از عدد دهگان (2) و عدد یکان (7) و علامت ثابت (°) و حرف (C) !
اگر یادتون باشه،برای نمایش روی سون سگمنت باید بصورت تک تک اعداد رو روی هرکدوم از سون سگمنتها نمایش بدیم.
که اینجا سون سگمنت ما از نوع مالتی پلکس 4 تایی آند مشترکه !
پس باید روی سون سگمنت 1 عدد 2 - روی سون سگمنت 2 عدد 7 - روی سون سگمنت 3 علامت ° - روی سون سگمنت 4 حرف C نمایش داده بشه.
پس در اولین مرحله باید اعداد رو از هم تفکیک کنیم.
پس میریم یخورده ریاضیات پیش دبستانی رو با هم دوره میکنیم :
عدد مورد نظر از : یکان-دهگان-صدگان-هزارگان تشکیل شده.
حالا اگه این عدد رو بر 1000 تقسیم کنیم،خارج قسمت میشه : 1 (هزارگان)
باقی ماندش هم میشه : 453
اگه 453 رو بر 100 تقسیم کنیم،خارج قسمت میشه : 4 (صدگان)
باقی مونده هم میشه : 53
اگه 53 رو بر 10 تقسیم کنیم،خارج قسمت میشه : 5 (دهگان)
باقی مونده هم میشه : 3 (یکان)
ما هم دقیقا از همین تکنیک برای تفکیک اعداد از همدیگه استفاده میکنیم !
ولی در این پروژه ای که ما روش کار میکنیم با اعداد 2 رقمی کار داریم پس کار ساده تر میشه !
data[0]=seg[temp/10];
اینجا اومدیم و عدد دهگان رو با تقسیم عدد بر 10 مشخص کردیم،بعد مقدار متناظرش رو از آرایه seg انتخاب کردیم و اونو ریختیم در عضو صفرم آرایه data.
data[1]=seg[temp%10];
تو این مرحله باقی مانده عدد مورد نظرمون رو بر 10 که میشه همون یکان رو مشخص کردیم و مقدار متناظرش از آرایه seg هم انتخاب شده و در عضو یکم آرایه data ریخته شده.
تا این مرحله عدد دو رقمی رو با تفکیک به دوتا عدد تک رقمی تبدیل کردیم.
data[2]=seg[10]; data[3]=seg[11];
گفتیم که؛اعضای دهم و یازدهم آرایه seg علامت ° و حرف C رو شامل میشند که بصورت ثابت در خانه های 2 و 3 آرایه data قرار میگیرند.
از اینجا به بعد وظیفه ما نمایش اعضای : 0و1و2و3 آرایه data بر روی سون سگمنتهای 1و2و3و4 به ترتیبه .
for (i = 0; i < 4; i++) { PORTB=data[i]; PORTD=0x00; PORTD=1<<i; delay_us(500); }
اومدیم و یه حلقه ایجاد کردیم که طبق همون تکنیک اثر فلیکر با یه تاخیر 500 میکروثانیه ای،به ترتیب مقادیر سون سگمنتهای 1و2و3و4 رو نمایش بدیم.
PORTB=data[i];
اطلاعات مورد نمایش رو بر روی پورت B قرار میدیم.
PORTD=0x00; PORTD=1<<i;
از طریق این بخش پایه های کنترلی 1و2و3و4 سون سگمنت رو کنترل میکنیم.
بصورت خیلی خلاصه براتون توضیح میدم که چجوری 27 درجه سانتی گراد،روی سون سگمنت 4 تایی نمایش پیدا میکنه(باتوجه به کد نوشته شده) :
بعدش انتخاب میکنیم که باید سون سگمنت 1 این عدد رو نمایش بده.
پس از اون باید عدد 7 رو نمایش بدیم.
اینجا هم بهش میگیم که باید سون سگمنت 2 مسئول نمایش این عدد باشه.
و به همین ترتیب برای علامت درجه و حرف C و همچنین سون سگمنتهای 2 و 3 !
اینم از شماتیک :
در پایان هم کل کدی که نوشته شده رو یه جا قرار میدم براتون :
#include <mega32.h> #include <delay.h> unsigned int i,T; // ADC Configuration Function void adc_configuration(){ ADMUX |= (1<<REFS1)|(1<<REFS0); ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADEN); } // ADC Temprature Reading Function unsigned int temp(){ ADCSRA |=(1<<ADSC); while ((ADCSRA & (1<<ADIF))==0); ADCSRA |=(1<<ADIF); return ADCW; } // 7Seg Display Function void seg_display(unsigned int temp){ // Common Cathod 4-Digit 7Seg Display Code unsigned char seg[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x1C,0x46}; unsigned char data[4]; DDRB=0xFF; DDRD=0x0F; // Number Separating data[0]=seg[temp/10]; data[1]=seg[temp%10]; data[2]=seg[10]; data[3]=seg[11]; // Displaying Loop for (i = 0; i < 4; i++) { PORTB=data[i]; PORTD=0x00; PORTD=1<<i; delay_us(500); } } // Main Function int main(void) { while(1) { adc_configuration(); // Temprature Calculating T = temp(); T=(T*256/1023); seg_display(T); } }
توجه : اگه میخواین این پروژه رو عملی ببندید و ازش استفاده کنید قبلش مشکل جریان سون سگمنتها رو حل کنید !
چون هدف ما اینجا ساخت پروژه نبود،بنده از توضیح اینکه چجوری مشکل جریان رو رفع کنیم،خودداری کردم.
اما اگه از دوستان کسی نیاز به رفع این مشکل داره در انجمن مطرح کنه تا سر فرصت براش اونجا توضیحاتی بدم.
اینم از قسمت دوم کارگاه عملی ...
نظر یادتون نره.
سوالی بود تو انجمن بپرسید.
فعلا...
ممنون که ادامه دادید!
مثل همیشه عالی بود
خداوند به شما قوت بده که انشاالله همینطور قوی ادامه بدید
موفق باشی