دوشنبه , ۳۰ اردیبهشت ۱۳۹۸
آخرین مطالب
LINK TABLES
خانه | میکروکنترلر | دوره آموزشی AVR | مبدل آنالوگ به دیجیتال در AVR (جلسه ۲۲)

مبدل آنالوگ به دیجیتال در AVR (جلسه ۲۲)

سلام به دوستای همیشه فعال و پر جنب و جوش خودم. لازمه از کسایی که نظر میدن و مطالب سایت رو خیلی ریز بررسی میکنن و حتی اشتباهاتی که توی نوشتن پست ها پیش میاد را به ما تذکر میدن تشکر ویژه ای بکنم. یه خواهشم کنم از اون دوستایی که مطالب ما رو میخونن ولی کم لطفی میکنن و نظری نمیدن. این نظر دادن شما خیلی به ما نیرو میده و باعث بهتر شدن مطالب تولیدی میشه پس حتما وقتی مطلبی رو خوندید با نظرات ارزشمندتون ما رو تشویق به بهتر شدن کنید. 

بعد از این مقدمه بپردازم به درس امروز. از عنوان مشخصه که میخوایم با مبدل آنالوگ به دیجیتال در AVR کار کنیم. این که چی هست و چی نیست و باش میشه چه کارا کرد را در این پست کاملا باهاش آشنا میشید. در آخر بحث هم فاز عملی کارمونو بیشتر می کنیم و یه دونه سنسور معروف اندازه گیری دما به نام LM35 براتون راه اندازی می کنیم. پس درس امروز رو شروع می کنیم 🙂

  • توضیحات
  • کدنویسی
  • شبیه سازی

مفهوم آنالوگ و دیجیتال چیست؟

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

درست حدس زدید. باید کمیت آنالوگ را به دیجیتال تبدیل کنیم و سپس دست به پردازش بزنیم. اینجا همان نقطه ای بود که مبدل های آنالوگ به دیجیتال وارد بازی شدند تا بتوانند بین دنیای آنالوگ و دنیای دیجیتال پلی بزنند. برای روشن شدن موضوع اجازه بدهید تا یک مثال بزنم. شما به بازار می روید و یک سنسور LM35 خریداری می کنید. با این سنسور شما می توانید دمای محیط را اندازه گیری کنید.( اما به چه شکل؟) خروجی این سنسور ولتاژ است و به ازای هر درجه تغییر دما ۱۰ میلی ولت تغییر می کند. میخواهید با یک میکروکنترلر AVR این تغییرات دما را اندازه گیری کرده و ثبت کنید. اما توجه کنید که برای AVR با فرض اینکه از منبع تغذیه ۵ ولتی برای آن استفاده کرده باشید، فقط دو ولتاژ ۰ و ۵ ولت در پین های خروجی آن معنا دارد. پس چگونه می توان ولتاژ خروجی LM35 را به AVR فهماند(؟!). برای پیدا کردن پاسخ این سوال نیاز به یک سری مقدمات درباره ی مبدل آنالوگ به دیجیتال و روش کار آن در AVR دارید. پس تا آخر این پست با ما همراه باشید تا روش کار را یاد بگیرید.

مفاهیم اولیه (ADC (analog to digital convertor

در هر مبدل آنالوگ به دیجیتال یک سری مفاهیم مشترک وجود دارد که ابتدا باید آن ها را بدانید تا بتوانید با آن ها کار کنید.

اندازه گام:

هر ADC یک دقت دارد، به عبارتی از یک مقدار کمتر را نمی تواند انداز گیری کند. اندازه گام کوچکترین تغییری هست که یک مبدل آنالوگ به دیجیتال می تواند اندازه بگیرد. مثلا اگر اندازه گام برای یک ADC برابر با ۲۰ میلی ولت باشد. معنایش این است که  تغییرات ۵ میلی ولتی را متوجه نمی شود و هرگاه ولتاژ نسبت به مقدار قبلی ۲۰ میلی ولت بیشتر یا کمتر شود می تواند تغییرات را تشخیص دهد.

زمان تبدیل:

برای اینکه ورودی آنالوگ به خروجی دیجیتال تبدیل شود نیاز به زمان معینی است. این زمان به منبع کلاک متصل به ADC (چون ADC یک مدار دیجیتال است نیاز به کلاک دارد.)، روشی که برای تبدیل استفاده می شود و تکنولوژی ساخت مبدل آنالوگ به دیجیتال بستگی دارد.

رزولوشن:

رزولوشن یا وضوح یا درجه تفکیک نام های مختلفی است که برای تعداد بیت استفاده شده در ADC به کار می رود. شاید شنیده باشید که ADC در AVR ده بیتی است. این بدین معناست که خروجی دیجیتال در قالب ۱۰ بیت ارائه خواهد شد. هرچه رزولوشن بیشتر باشد، اندازه گام کمتر خواهد بود.( برای درک جمله ی آخر کمی صبور باشید.)

ولتاژ مرجع:

یک ولتاژ ورودی است که به عنوان مرجع استفاده شده و به همراه رزولوشن اندازه گام را معلوم می کند. دقت کنید که ولتاژ ورودی ADC می تواند بین صفر تا ولتاژ مرجع تغییرات کند. فرض کنید که از ADC هشت بیتی استفاده می کنید. اندازه گام به صورت روبه رو محاسبه می شود: (۲ به توان ۸/ولتاژ مرجع)

خروجی داده دیجیتال:

وقتی مقدار آنالوگ به دیجیتال تبدیل شد، باید در قالب یک رشته از بیت ها ارائه شود. به این رشته بیت خروجی داده دیجیتال گفته می شود.برای مثال در یک ADC هشت بیتی، ۸ بیت خروجی دیجیتال از D0 تا D7 داریم که با استفاده از رابطه زیر بدست می آید:

(اندازه گام/ولتاژ ورودی)

مفاهیم اولیه گفته شد. توصیه میکنم یک بار دیگر مفاهیم را با خودتان مرور کنید تا بهتر در ذهنتان جا بگیرید. حال که مفاهیم را مرور کردید. با بیان یک مثال بحث را بیشتر باز خواهیم کرد.

مثال

فرض کنید در یک ADC با رزولوشن ۸ بیت، ولتاژ مرجع را ۵ ولت انتخاب کرده ایم. در این صورت تغییر ولتاژ ورودی بین صفر تا ولتاژ مرجع باعث تغییر دیتای خروجی ADC بین ۰ تا ۰xFF خواهد شد. به عبارتی تغییرات به ۲۵۶ گام یا پله تقسیم می شوند. اگر ولتاژ ورودی روی صفر ولت باش خروجی ۰x00 و اگر ولتاژ ورودی روی ۵ ولت باشد خروجی ۰xFF خواهد بود. اگر ولتاژ ورودی روی ۲ ولت باشد. می خواهیم خروجی دیجیتال را به دست آوریم.

برای این کار باید اندازه گام را به دست آوریم. به عبارت دیگر باید بدانیم هر تغییر قابل اندازه گیری در  ADC چند ولت است. پس ولتاژ مرجع را بر ۲۵۶ (۲ به توان تعداد بیت که اینجا ۸ است) تقسیم می کنیم که ۱۹ میلی ولت به دست می آید. حال باید محاسبه کنیم که ۲ ولت از چند پله (چند تا ۱۹ میلی ولت) تشکیل شده است. پس ۲ را بر ۱۹ میلی ولت تقسیم می کنیم که ۱۰۵/۲ می شود. خب این عدد در مبنای ده است باید به مبنای دو برده شود که به صورت ۰۱۱۰۱۰۰۱ می شود. این رشته باینری همان چیزی است که در خروجی ADC قرار می گیرد.
توصیه میکنم برای همین مثال خروجی دیجیتال را برای ولتاژ ۴/۵ ولت و ۱/۷ ولت به دست آورید.

خب حالا نوبت به آن رسیده تا درباره اتفاقاتی که داخل ADC رخ می دهد بیشتر حرف بزنیم و با روش های تبدیل بیشتر آشنا شویم. (داخل پرانتز بگم که بلد بودن این قسمت تا حد زیادی درکی از روش کار بهتون میده. پس خوبه که مطالعه کنید. اما اگه واقعا حس می کنید لزومی نداره روش تبدیل را بلد باشید بدون نگرانی ازش عبور کنید و به سراغ قسمت بعدی برید.)

معرفی انواع روش های تبدیل آنالوگ به دیجیتال

۶ روش برای تبدیل مقدار آنالوگ به دیجیتال وجود دارد که در زیر به صورت لیست بیان می شوند، اما فقط روش تقریب متوالی توضیح داده خواهد شد.

  • روش موازی یا همزمان
  • روش پله ای
  • روش تقریب متوالی (Successive Approximation)
  • روش تبدیل ولتاژ به زمان( تک شیب)
  • روش دو شیب
  • روش تبدیل ولتاژ به فرکانس

روش تقریب متوالی

این روش برای اجرا نیاز به چهار بخش اساسی دارد. همانطور که در شکل زیر هم مشخص شده این بخش ها عبارتند از:

  • رجیستر تقریب متوالی
  • مقایسه کننده
  • واحد کنترل
  • مبدل دیجیتال به آنالوگ

adc

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

برای روش شدن بهتر بحث صحبت هایمان را با یک مثال ادامه می دهیم:

مثال

فرض کنید یک ADC با اندازه گام ۱۰ میلی ولت در اختیار داریم. جهت تشخیص ولتاژ یک ولت در ورودی مراحل زیر انجام می شود:

با ۱۰۰۰۰۰۰ شروع می کنیم که برابر با ۱۲۸ است. اگر آن را در انداز گام ضرب کنیم ولتاژ ورودی را می دهد.(فرمولی که در بالا توضیح داده شد.) پس ۱۲۸*۱۰mv برابر با ۱/۲۸ ولت می شود. این مقدار بزرگتر از یک ولت است پس باید کم شود. در نتیجه بیت ۷ پاک می شود.

  • با ۰۱۰۰۰۰۰۰ ادامه می دهیم. در نتیجه به مقدار ۶۴ ولت می رسیم که کمتر از یک ولت است پس بیت ۶ باید حفظ شود.
  • ۰۱۱۰۰۰۰۰ مقدار جدید است. خواهیم داشت ۹۶ ولت که بازهم کمتر از یک ولت است و باید حفظ شود پس بیت ۵ را نگه می داریم.
  • با ۰۱۱۱۰۰۰۰ ادامه می دهیم. چون ۱/۱۲ ولت را تولید می کند پس بیت ۴ ام باید حذف شود.
  • خواهیم داشت ۰۱۱۰۱۰۰۰ پس مقدار ۱/۰۸ را می دهد در نتیجه بیت سوم هم باید حذف شود.
  • ۰۱۱۰۰۱۰۰ باعث تولید یک می شود که دقیقا برابر است. پس بیت دو نگه داشته می شود.

انجام دو مرحله دیگر برای بیت های ۱ و ۰ هم ضروری است اما چون باعث تولید مقدار بیشتر از یک می شوند آن دو بیت هم حذف خواهند شد. توجه کنید که روش تقریب متوالی تمام مراحل را کامل انجام می دهد حتی اگر در مراحل اولیه به جواب صحیح دست پیدا کند. در این حالت زمان تبدیل ثابت خواهد بود.

معرفی واحد ADC در Atmega32

از آن جایی که میکروکنترلر Atmega32 در بین سایر اعضای خانواده ی AVR تقریبا تمام امکانات را در خود جای داده است، برای هدف آموزش خیلی خیلی مناسب به نظر می رسد. شما با یادگیری یکی از امکانات AVR در این شماره می توانید آن را تعمیم داده و در سایر اعضای خانواده AVR هم مورد استفاده قرار دهید. از این رو آن چه که از این به بعد برای ADC گفته می شود برای Atmega32 است.

مهم ترین ویژگی های ADC در Atmega32

  • دقت ده بیت
  • زمان تبدیل بین ۶۵ تا ۲۶۰ میکروثانیه
  • هشت کانال ورودی تک خروجی مولتی پلکس شده
  • هفت کانال ورودی دیفرانسیلی
  • دو کانال ورودی دیفرانسیلی با بهره ی ۱۰ و ۲۰۰
  • محدوده ی ولتاژ ورودی به ADC از صفر تا VCC
  • قابل انتخاب بودن ولتاژ مرجع داخلی ۲/۵۶ ولت برای ADC
  • امکان اتوماتیک نمودن آغاز تبدیل
  • امکان درخواست وقفه در پایان تبدیل
  • امکان استفاده از مد sleep برای کاهش نویز

پین های ADC

برای اینکه با ADC آشنا شویم بهتر است ابتدا از سخت افزار قابل مشاهده ی آن شروع کنیم. یعنی پین ها. در Atmega32 پورت A عملکرد دیگری هم دارد که تبدیل آنالوگ به دیجیتال است. یعنی در صورت فعال کردن ADC تمام ۸ پین آن می توانند به عنوان کانال های ورودی آنالوگ استفاده شوند. البته غیر از این ۸ پین یک پین مربوط به تغذیه بخش آنالوگ یعنی AVCC و یک پین مربوط به ولتاژ مرجع یعنی AREF است که در شکل زیر می توان مشاهده کرد.

AVRADCPIN

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

دقت کنید که تمام ورودی ها به صورت multiplex هستند یعنی یک واحد مبدل آنالوگ به دیجیتال وجود دارد که باید تک تک کانال ها را بررسی کند. پس در ورودی هر پین یک مدار به نام sample & hold (نمونه برداری و نگه داشتن) وجود دارد. کاری که این مدار انجام می دهد نمونه برداری از ولتاژ لحظه ای ورودی و ثابت نگه داشتن آن تا نمونه برداری بعدی است. حال اگر قرار باشد تمام ۸ کانال ورودی به طور هم زمان خوانده شوند چنین مداری به کار می رود تا ولتاژ تمام کانال ها را تا زمان خوانده شدن ثابت نگه دارد.

عملکرد ADC

 بعد از معرفی پارامترهای کلی بهتر است وارد جزئیات شویم. ابتدا حالت های عملکرد به صورت فهرست وار بیان شده و سپس رجیسترها و جزئیات بررسی می شوند.در نهایت با ارائه چند مثال کاربردی زوایای پنهان بحث را برای شما باز خواهیم کرد.

 مدار مبدل آنالوگ به دیجیتال در Atmega32 می تواند در دو حالت کار کند.

single یا تنها: در این حالت بعد از هر تبدیل، ADC منتظر می ماند تا دوباره تحریک شود (برنامه تحریک توسط کاربر نوشته می شود)

free یا آزاد: در این حالت عمل نمونه برداری و تبدیل به طور پیوسته از ورودی انجام می شود.(بدون دخالت برنامه)

رجیسترهای ADC

برای فعال سازی و کارکردن با ADC با ۴ رجیستر اختصاصی  و یک رجیستر که بین چند واحد مشترک است سر و کار خواهیم داشت.

رجیستر ADMUX

admuxنام این رجیستر از ADC Multiplexer Selection گرفته شده است. به کمک این رجیستر می توان انتخاب کانال ورودی + انتخاب ولتاژ مرجع + نحوه قرار گرفتن داده دیجیتال در رجیسترهای خروجی را معین کرد.

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

بیت های REFS0 و REFS1 برای انتخاب ولتاژ مرجع در نظر گرفته شده اند. در جدول زیر ترتیب کار را مشاهده می فرمایید.

refrence1

این جدول نشان می دهد که ولتاژ مرجع را چگونه می توان انتخاب کرد برای مثال در ردیف یک می توان ولتاژ موجود روی پین AREF را به عنوان ولتاژ مرجع انتخاب کرد.

تذکر: تغییر این دو بیت فقط زمانی موثر است که ADC در حال انجام عملیات تبدیل نباشد. در غیر این صورت پس از اتمام تبدیل، تغییر بیت ها اعمال خواهد شد.

بیت ADLAR پس از توضیح رجیسترهای ADCH و ADCL  توضیح داده خواهد شد.

رجیستر ADCSRA

adcsra

نام این رجیستر از  ADC Control and Status Register A گرفته شده است. در زیر عملکرد بیت های آن بیان شده است.

بیت (ADEN(ADC Enable

با یک کردن این بیت واحد مبدل آنالوگ به دیجیتال فعال شده و با صفر کردن آن غیر فعال می شود. دقت کنید که اگر ADC در حال انجام تبدیل باشد و این بیت را صفر کنیم، عملیات نیمه کاره رها شده و ADC غیرفعال می گردد.

بیت (ADSC(ADC start conversion

در مد single یک کردن این بیت برای انجام هر تبدیل ضروری است. برای مد free فقط باید بار اول این بیت را برای شروع تبدیل یک کرد.

بیت (ADATE(ADC Auto Trigger Enable

یک کردن این بیت ADC را در مد تحریک خودکار قرار می دهد. هر بار که یک لبه ی مثبت (بالا رونده) از منبع تحریک تشخیص داده شود، ADC عملیات تبدیل را شروع خواهد کرد. منابع تحریک توسط رجیستر SFIOR تعیین می شوند که در ادامه توضیح داده خواهد شد.

بیت (ADIF(ADC Interrupt Flag

هربار که عملیات تبدیل به پایان می رسد این بیت یک خواهد شد. حال اگر بیت های ADIE و بیت فعال ساز وقفه عمومی فعال باشند با یک شدن این بیت وقفه کامل شدن تبدیل ADC اجرا شده و بیت ADIF به صورت سخت افزاری پاک می شود.

بیت (ADIE(ADC Interrupt Enable

با فعال کردن این بیت و بیت فعال ساز وقفه عمومی در رجیستر حالت(SREG)  اجازه وقوع وقفه کامل شدن تبدیل ADC داده می شود.

بیت های ADPS0 تا ADPS2

چون مدار ADC یک مدار دیجیتال است، نیاز به پالس ساعت دارد. به کمک این سه بیت می توان تقسیم فرکانسی انجام داده (فرکانس کریستال متصل به میکروکنترلر) و پالس ساعت وارد شده به مدار ADC را تعیین کرد. دقت شود که برای داشتن رزولوشن ۱۰ بیت باید فرکانس پالس ساعت ADC بین ۵۰KHz تا ۲۰۰KHz انتخاب شود. در صورتی که فرکانس بیشتر از ۲۰۰KHz شود، رزولوشن کمتر از ۱۰ بیت خواهد شد.

به جدل زیر دقت کنید.

prescaler1

رجیسترهای ADCL و ADCH

این رجیسترها حاوی اطلاعات خروجی ADC هستند. یعنی پس از این که تبدیل کامل شد، خروجی دیجیتال در این رجیسترها قرار داده می شود. اما چون در AVR از ADC با رزولوشن ۱۰ بیت استفاده می شود؛ طبیعی است که ۶ بیت بدون استفاده باقی خواهد ماند. اکنون لازم است کاربرد بیت ADLAR را توضیح دهیم. به کمک این بیت می توان نحوه قرار گرفتن داده خروجی در این دو رجیستر را تعیین کرد. اگر این بیت یک باشد خروجی به صورت شکل زیر است:

و اگر صفر باشد به صورت تصویر زیر خواهد بود.

adlar0

در مواردی که نیاز به دقت بالاتر از ۸ بیت نداریم می توانیم، می توانیم این بیت را یک کرده و فقط ADCH را بخوانیم.

رجیستر SFIOR

نام این رجیستر از  Special Function IO Register گرفته شده است.

به کمک بیت های ADTS0 تا ADTS2 می توان منبع تحریک را زمانی که بیت ADATE یک شده باشد تعیین کرد.

جدول زیر منابع تحریک را نشان می دهد.

trigger1

فعال کردن ADC در مد single

همان طور که قبلا هم توضیح داده شد در این حالت برای انجام هر تبدیل باید بیت ADSC یک شود چرا که با پایان تبدیل قبلی این بیت به صورت خودکار صفر می شود. حال به ترتیب زیر باید رجیسترها را مقدار دهی کنیم تا این مد فعال شود:

  1. ابتدا در رجیستر ADMUX کانال مورد استفاده مشخص می شود. سپس ولتاژ مرجع و نحوه قرار گرفتن اطلاعات دیجیتال در رجیستر های خروجی داده معلوم می شود.
  2. در رجیستر ADCSRA ابتدا ADC فعال شده و تقسیم کننده ی فرکانس مشخص می شود. هم چنین در صورت نیاز بیت فعال ساز وقفه یک می شود.
  3. حال برای شروع تبدیل کافی است بیت ADSC یک شود. دقت شود که این بیت بعد از انجام تبدیل به صورت اتوماتیک صفر شده و برای انجام تبدیل بعدی باید دوباره فعال شود.

فعال کردن ADC در مد free

مراحل این مد هم شبیه مرحله قبلی است با این تفاوت که:

  1. در رجیستر ADCSRA بیت تحریک خودکار یک می شود.
  2. رجیستر SFIOR برای منبع تحریک تنظیم شود. که باید حالت اول یعنی free انتخاب شود.
  3. حال برای شروع تبدیل فقط کافی است که برای بار اول بیت ADSC را فعال کنیم. برای تبدیل های بعدی نیاز به فعال سازی مجدد وجود ندارد و همیشه یک خواهد ماند.

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

نکات سخت افزاری

دو پین مهم به نام AREF و AVCC وجود دارند که تا حدودی در مورد آن ها صحبت کردیم اما در پروژه های کاربردی باید به موارد زیر دقت کنید:

  1. برای اینکه نوسان VCC به ADC منتقل نشود، برای بخش ADC تغذیه جداگانه به نام AVCC در نظر گرفته شده است که حتما باید وصل شود.
  2. تغذیه ی AVCC حساس است و نباید اختلاف آن با VCC بیشتر از + یا – ۰/۳V شود.
  3. برای جلوگیری از انتقال نویز VCC به AVCC بهتر است از مدار زیر استفاده کنید:

Low pass1

توجه کنید که در صورت انتخاب VREF در یکی از حالات ۲/۵۶ داخلی یا AVCC، این ولتاژ روی پایه ی AREF نیز ظاهر می شود. لذا برای حذف نویز بهتر است که روی این پین یک خازن ۱۰۰nF قرار داده شود. اگر در چنین حالتی روی پین AREF ولتاژی قرار گیرد، امکان سوختن ADC وجود دارد.

توجه شود که در مورد کانال های دیفرانسیلی به دلیل طولانی شدن بحث در این جلسه صحبتی نشد. در پروژه های AVR حتما این حالت راهم مورد بررسی قرار خواهیم داد.

بحث ADC در AVR تقریبا کامل شد. توصیه می شود حتما از data sheet میکروکنترلر مورد نظر خود برای اطلاعات بیشتر استفاده کنید. اکنون وقت آن رسیده که با انجام چند تمرین و برنامه نویسی بحث امروز را بهتر متوجه شویم. پس مثال های زیر را بررسی می کنیم.

مثال

مثال یک: درAtmega32 یک پتانسیومتر ۱کیلواهم به پین صفر از پورت A وصل کرده و از کریستال داخلی ۱MHz استفاده کنید. حال واحد ADC را با رزولوشن ۱۰ بیت، ضریب تقسیم ۴،مد single و بدون وقفه تنظیم کرده سپس ولتاژ مرجع را روی AVCC تنظیم کرده و نتیجه خروجی را روی پورت های D  و C نمایش دهید. پتانسیومتر را تغییر داده و خروجی را با محاسبات خودتان مقایسه کنید.

مثال دو: شرایط مثال یک را در نظر گرفته ولی این بار از وقفه استفاده کنید.

مثال سه: شرایط مثال یک را در نظر گرفته ولی این بار از مد free و وقفه تکمیل محاسبه ADC  استفاده کنید.

مثال چهار: با تنظیم دلخواه خودتان به جای پتانسیومتر یک سنسور LM35 استفاده کرده و دمای خروجی را روی LCD کاراکتری متصل به پورت B نمایش دهید. چون سنسور LM35 بسیار معروف است و در اینترنت به راحتی می توانید در مورد آن اطلاعات کسب کنید از توضیح آن صرف نظر شده است.

پاسخ این مثال ها در تب کدنویسی در بالای صفحه نوشته شده است.

شبیه سازی مثال آخر هم در تب شبیه سازی به صورت تصویر gif موجود می باشد.

در ضمن توضیحات کدنویسی در یک ویدئو در تب کدنویسی به صورت کامل ارائه شده است که توصیه میکنم برای درک بهتر مثال ها حتما این ویدئوی آموزشی را مشاهده کنید.

تمام مثال های این بحث با زبان C در نرم افزار کدویژن ۳/۱۲ کامپایل شده و درپروتئوس ۸/۴ شبیه سازی شده است.
مثال ۱

تذکر: در فیلم آموزشی توضیح کدها، برای قسمت (unsigned char) به اشتباه در مورد typedef توضیح داده شده است که بدین وسیله به type cast اصلاح می گردد.

مثال ۲
مثال ۳
مثال ۴

 

ویدئوی آموزشی توضیح کدهای زبان C

این مثال با زبان C در نرم افزار کدویژن ۳/۱۲ کامپایل شده و درپروتئوس ۸/۴ شبیه سازی شده است.

برای خودم که جلسه خیلی لذت بخشی بود. سعی هم کردم اون چیزی را که بلدم به زبون ساده براتون بگم. امیدوارم برای شما هم همینطور بوده باشه. اما اگه جایی از بحث مبهم بود و (به زبون ساده) پیچونده بودمش 😉 حتما توی بخش نظرات سوال بپرسید تا جواب داده بشه. برای اینکه بتونید از آموزش امروز در یک پروژه آموزشی استفاده کنید به پست کنترل دور موتور DC بر اساس دما هم سر بزنید. مرسی که همراه ما بودید. تا جلسات بعدی خدا نگهدارتون

درباره ی احسان عبداللهی

احسان عبداللهی هستم | کارشناسی الکترونیک خوندم و کارشناسی ارشد مخابرات |در سال 94 وب سایت میکرولرن را راه اندازی کردم | سعی کردم هر چیزی را به صورت کاربردی دنبال کنم، برای همین از کارشناسی کار با میکروکنترلرهای AVR و ARM، برنامه نویسی C و طراحی PCB را به صورت تخصصی کار کردم و از کارشناسی ارشد برنامه نویسی پایتون ، Computer vision و deep learning را به صورت تخصصی و کاربردی شروع کردم | الان هم سعی میکنم همیشه خودم را به روز نگه دارم و لذت کار کردن با دنیای برنامه نویسی و امبدد سیستم ها را به دیگران انتقال بدم

۹۲ دیدگاه

  1. سلام
    اول از هر چیزی تشکر میکنم از توضیحات خوبتون
    من میخواستم با استفاده از سنسورntc دما رو روی سگمنت نشون بدم لظفا راهنمایی کنید.

  2. با تشکر فراوان
    من سعی کردم lm35 تو حالت free راه اندازی کنم.رجیستر ADATE را یک می کنیم. با تغیییر دما مقدار خروجی هیچ تغییر نمی کند. راه اندازی FREE ب چ صورت است؟؟
    نکته ای است ک باید لحاظ شود؟

  3. با سلام
    با تشکر از زحماتتون ویدیو وقتی دقیقه اولو رد می کنه صداش قطع می شه کیفیت افتضاح اگه می شد تو یوتیوب up می کردین عالی بود. می شه توضیح نوشتاری کدو بزارین؟؟

    • با سلام. میتونید وارد سایت آپارت بشید و کیفیت ویدیو را روی حداکثر بذارید. کیفیت صدا پایینه. متاسفانه امکان صبط مجدد ویدیو وجود نداره. اگه از هدفون استفاده کنید مشکلتون حل میشه.

  4. سلام
    چرا تابع وروردی adcرو ننوشتید.میکرو چطور مقدار رو بدون نشتن تابع دریافت میکنه .مستقیما نوشتید adcw در صورتی که تابع تعریف نشده اصلا

    • سلام دوست عزیز
      اگه با دقت بیشتری کدها رو بخونید متوجه میشید که ما اصلا از تابع استفاده نکردیم. چون یک کد آموزشی هست ابتدا رجیسترها رو مقدار دهی کردیم و کانال adc مورد نظر را فعال کردیم و بعد به وسیله adcw مقدار را خوندیم. شما می تونید در موارد پیشرفته تر تابع بنویسید و اقدام به خوندن از adc کنید که کار بسیار درستی هم هست.

  5. PORTD = (unsigned char)ADCW
    (PORTC = (ADCW>>8

    یعنی چی؟؟؟

  6. سلام ممنون از اطلاعات خوبتون
    یک سوال داشتم
    چطور میتونم مقدار تبدیلی که adc انجام میده رو بخونم و نمایش دهم (به طور کلی منظورم نمایش عدد بدست امده از adc نیست، تبدیل لحظه به لحظه رو میخوام ببینم)؟

    • سلام
      تبدیل لحظه به لحظه را که هربار عدد میخونید قابل مشاهده هست

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

        • نمایش که به صورت یک عدد ۰ تا ۱۰۲۳هست که باید در گام ضرب کنید تا ولتاژ صحیح به دست بیاد. داخل پست هم مطالعه بفرمایید توضیح داده شده.

  7. سلام
    مطالبتون بسیار مفید و بیانتون خیلی جذاب و روان هست.
    بسیار متشکرم.

  8. با سلام.
    آقا من کد زیرو نوشتم، ورودی ۵۰۰mv و یا کمتر که بش میدم درست کار می کنه اما از ۵۰۰mv بیشتر همون مقداری که تو ۵۰۰mv رو نشون میداد، نشون می ده. سر در نمیارم مشکل از کجاست…

    #include
    #include
    char s,s1;
    interrupt [15]void myadc(void){
    #asm(“cli”);
    s=ADCL;
    s1=ADCH;
    PORTD=s1;
    PORTB=s;
    #asm(“sei”);
    }
    void main(){
    DDRB=0xff;
    DDRD=0xff;
    ADMUX=0xE0;
    ADCSRA=0xFE;
    #asm(“sei”);
    }

    ممنون.

  9. سلام خسته نباشید ممنون از آموزش های بسیار عالی و مفید شما.
    ببخشید دو تا سوال داشتم:
    ۱- امکانش هست که در atmega32 خروجی ADC به جای ۱۰ بیت در ۸ بیت باشه؟ یعنی میشه resolution رو کم کرد؟؟
    ۲- میشه ۲ تا سیگنال آنالوگ رو بدیم به میکرو و خروجی ها رو به ازای هر کدوم بگیریم؟ پروژه ی من این شکلی هست که دو تا سیگنال آنالوگ میگیره بعد باید تبدیلش کنه و ۲ تا ۸ بیت بفرسته برای FPGA. که من این قسمت تبدیل رو با میکرو انجام میدم.

  10. سلام adc دیفرانسیلی رو چطور استفاده کنیم ؟ و ایا کتابخانه لودسل توی پروتئوس هست؟

  11. با سلام
    : (و یا این که کانال ها به صورت تفاضلی یا دیفرانسیلی باشند. بدین شکل که تفاضل ولتاژ آنالوگ موجود روی دو پین به عنوان ولتاژ آنالوگی که باید به دیجیتال تبدیل شود در نظر گرفته شود.)
    میشه مد عملکردی دیفرانسیلی را بیشتر توضیح بدهید؟

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

    • سلام به شما.
      خوشحالیم که براتون مفید بوده 🙂
      هر موقع اشکالی داشتید حتما در بخش نظرات مطرح کنید.

  13. مهندس خیلی خیلی مخلصیم..مرسی…فقط کاش یه منبعی یا سایتی که من پروتیوس رو بیشتر یاد بگیرم معرفی کنین عالی میشه

    • خواهش میکنم لطف داری. توی نت که آموزش های فراوونی برای پروتئوس وجود داره. خصوصا اینکه خیلی هم شبیه ساز ساده و روانی هست. اگه آموزش مناسب پیدا نکردی به تلگرام من پیام بده تا برات یک سری فایل ها بفرستم. https://telegram.me/EhsanAo

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

    • سلام
      برای این کار ابتدا کلمه pot را داخل پروتئوس سرچ کن. دو نوع میاد. نوعی را انتخاب کن که کنارش علامت های + و – برای کم و زیاد کردن وجود داره. حالا توی عکس GIF من یه نمونه ساده از کار کردن باهاش را برات درست کردم. امیدوارم مفید باشه برات.
      شبیه سازی عملکرد پتانسیومتر درپروتئوس

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

    • سلام به شما.
      نکته اول اینکه با وجود این همه سنسور با کیفیت دما در بازار چه نیازی به این کار هست؟
      دوم اینکه: بدون دونستن کد شما و جزئیات کارتون نمی تونم نظری بدم.
      میتونید کد را به ایمیل بنده ارسال بفرمایید:
      eaca89@gmail.com

  16. سلام
    یک کابل دارم که ولتاژ از -۵تا ۲۵ ولت تولید میکنه برای اندازه گیری ولتاژش علاوه بر مقسم ولتاژ برای خواندن ولتاژ منفی چکار باید کرد؟در ضمن از مقاومت های یک وده کیلو استفاده شده واز سر یک کیلو به میکرو دادم .اخر بار روی مقدار adchچه عملیات حسابی باید انجامم بشه؟ممنون

    • سلام به شما
      برای خواندن ولتاژ منفی باید بااستفاده از شیفت dcولتاژ را به محدوده مثبت وارد کنید تا قابل اندازه گیری شود. درنهایت برای محاسبه ولتاژ معکوس عملیات راباید اعمال کنید تاولتاژ صحیح بدست آید.

  17. slm
    vaqean az zahamati k kshidid mamnonam
    man mot3vaje khat 15 az mesal aval nmisham
    motevajeh nmisham k in dastoor daqiqan choker mikonad
    agar mishe dar morede amal kardesh tozih bdin

    • سلام به شما
      ممنون از لطف شما دوست عزیز
      ابتدا توصیه می کنم هم این پست را یک بار دیگه دقیق تر مطالعه کنید و هم اینکه ویدیوی توضیحات را یک بار دیگه مشاهده کنید.
      خط ۱۵ مثال یک برای تنظیم ADC استفاده شده و هم با استفاده از بیت ADSC تبدیل را شروع کرده و هم با استفاده از ADIF پرچم وقفه را صفر کرده. صفر کردن پرچم وقفه برای اینه که می خوایم انجام عملیات تبدیل را با یک شدن این بیت متوجه بشیم.

  18. سلام خسته نباشید چندتا پیشنهاد دارم:
    اگه بشه همراه با ویدئو، توضیحات نوشتاری برای کدها بذارید خیلی خوب میشه. کیفیت این ویدئو کمی پایین بود و صدای شما و کدها کمی نامفهوم بودن! اگه بشه کیفیتش رو کمی بالاببرید خیلی خوب میشه.
    کارتون عالیه و قالب بندی و مطالب سایت شما، به جرعت میتونم بگم هیچ جای دیگه تو سایت های فارسی پیدا نمیشه! فقط اگه میشه ریزه کاری های کد ها (مثل PORTD = (unsigned char)ADCW) رو بیشتر توضیح بدید تا تازه کارهایی مثل خود من توشون هنگ نمونن 😉

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

  19. با سلام و خسته نباشید.میخواستم در مورد چن خط از برنامم سوال بپرسم ک کاراییش واسه چیه.اگه میشه در موردشون توضیح بدین ممنون میشم.در مورد سنسور lm35 با برنامه c
    DDRD=255
    TCNT1=57722
    TIMSK=1<<TOIE1
    TIFR=1<<TOV1
    TCCR1A=0
    TCCR1E=1<<CS12|1<<CS10

    • سلام به شما
      سوالتون کمی عجیبیه. چون اگه برنامه رو خودتون نوشتید باید بدونید چی نوشتید دیگه!
      این چند تا کدی که اینجا گذاشتید مربوط به فعال کردن تایمر کانتر شماره یک هست. و پورت D هم خروجی شده.

  20. با سلام
    میخواستم بپرسم که دریافتی از سنسور دما توسط adc روباید حتما به کد اسکی تبدیل کرد تا بروی lcd نمایش داده بشه؟
    من مزی رو روی هشت بیت تنظیم کردم چجور یباید ADCL وADCHرو به پورتا ی خروجیم بدم برای استفاده LCD
    یه سوال دیگ این که نمیشه چندتا سنسور با هم خوانده بشن از طریق adc یا باید حتما یکی باشه و اگر بخوایم یکی در میان هم فعالشون کنیم باید چکار کرد؟
    ممنون

    • با سلام
      اگه از lcd کاراکتری استفاده می کنید از اسمش هم معلومه. هر چی میخواید روی lcd نمایش بدید باید در قالب رشته ای از کاراکترها برای lcd بفرستید تا نمایش داده بشه.
      برای خوندن ADCL و ADCH داخل پست بالا توضیح داده شده که اگه مطالعه کنید متوجه می شید.
      میتونید ۸ تا سنسور آنالوگ را به هشت تا ورودی آنالوگ AVR وصل کنید و به ترتیب اونا رو بخونید.

  21. خیلی ممنون از پاسختون

  22. سلام.
    ممنون از مطالب مفیدتون.
    من می خواستم مرتب از یه ورودی آنالوگ دیتای پارالل دیجیتال بگیرم. برای دسترسی به تک تک بیت های خروجی ADC چه باید کرد؟
    به عنوان توضیح بیشتر اینکه مثلا اگه بخوام بیت سومADCL رو به یه پرت و بیت چهارمش رو به یه پرت دیگه بدم چه باید کرد؟
    پیشاپیش ممنون

    • درود و ممنون از لطف شما.
      شما به وسیله ی ADCW تمام ۱۰ بیت را در اختیار دارید. حالا اگه بخواید بیت خاصی را استفاده کنید کافی ADCW را با عددی ۱۰ بیتی که فقط شماره بیت مورد نظر در اون یک هست AND کنید. اگر صفر شد که یعنی این بیت صفر است و در غیر این صورت بیت یک است و می تونید ازش هر استفاده ای بکنید.

  23. بهتر بود مرجع مطالب و تصاویر رو هم ذکر می کردید.

    • سلام.
      حق با شماست ولی چون در متن ذکر شده که مطلب برای Atmega32 نوشته شده دیتا شیت مرجع اصلی هست. و بعضی از تصاویر هم که توسط خودمون ترجمه و طراحی شدن.

  24. اینکه گفتم بحالت sleep بره این هست که ممکنه برای مدتی داده برای میکرو نیاد یا اینکه داریم دمای محیط رو اندازه گیری میکنیم و همچنان دمای محیط برای چند ساعتی تغییر نمیکند در این حالت برای چی واحد ADC الکی مشغول باشد یعنی هرموقع داده جدید به ADC وارد شود شروع بکار کند

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

  25. احسنت به شما آقا احسان باز هم مثله همیشه با توضیحات عالی

  26. مهندس جان موقع تبدیل ولت به دما که گفتین تقسیم بر ۱۰ میکنیم دلیلش چیه؟
    ——————–
    interrupt [ADC_INT] void adc_isr(void)
    ببخشید موقع فراخوانی وقفه ، اینکه [ADC_INT] و adc_isr را قرار دادید دلیل داره اینجوری نوشتین ؟

    • البته داخل ویدیو کامل توضیح داده شده ولی وقتی مقدار دیجیتال یعنی temp را در گام ضرب کردی یه عدد بر حسب میلی ولت به دست میاری که همون ولتاژ ورودی هست. چون خروجی LM35 به ازای هر درجه تغییر دما ۱۰mv عوض می شه با این تقسیم می فهمیم که دما چند درجه هست.
      ابتدا پست منابع وقفه را بخون:
      http://microlearn.ir/1008/int.html
      ADC_INT نام بردار وقفه تکمیل عملیات ADC هست و adc_isr هم نام این تابع وقفه.

  27. ببخشید چرا از رجیستر های ADCL و ADCH بصورت مستقیم استفاده نمیکنید؟
    اینکه هشت بیت پایینی خروجی (ADCL) رو یکی از پورت های قرار بگیرد و هشت بیت بالایی (ADCH) به پورت های دیگه داره شود
    اگه همزمان از این رجیستر های استفاده شود مگه نباید بصورت ADC نوشته شود چرا اینجا بصورت ADCW نوشتین؟

    • قبلا هم یکی از دوستان همین سوال را در کامنت ها پرسیده بودند. اشکالی نداره که از رجیستر های L و H استفاده کنید اما چون ADCW در کدویژن تعریف شده و مقدار هر دوی این رجیسترها را به صورت ۱۶ بیتی بر می گردونه بهتره که ازش استفاده کنیم اما اگه بخوایم در حالت ۱۰ بیتی فقط از ۸ بیت پر ارزش استفاده کنیم می تونیم طوری تنظیم کنیم که ۸ بیت پر ارزش در ADCH قرار بگیرند و فقط این رجیستر را بخونیم.

  28. فعال کردن ADC در مد free

    سلام.در مد فری اینکه میگید فقط یک بار ADSC یک میکنیم و تا اخر یک میماند . اگر ISR مربوط به ADC نیز اجرا شود باز هم این بیت یک میماند ؟ یا اینکه نیازی برای فعال سازی وقفه ADC نیست در این مد ؟
    ———————————————————-
    ببخشید ببینید برداشتم درسته
    در مد سینگل تحریک توسط کاربر انجام میگیرد
    در مد فری تحریک توسط بیت پرچم یعنی بصورت اتوماتیک انجام میگیرد
    ——————————————————————
    فکر کنم در مد فری به حالت sleep نره درسته ؟

    • سلام به استاد سوال های چالشی 😉
      خیلی کار خوبی کردی که به این پست هم سر زدی و سوالای قشنگی مطرح کردی. قبل از خوندن جواب من برو در قسمت توضیحات مثال شماره ۳ را که در همین مورد هست بخون و در تب کدنویسی جواب رو ببین. جواب اینه که بله در این حالت ADSC یک می مونه تا زمانی که خودت صفرش کنی. پاسخ دهی یا عدم پاسخ دهی به وقفه هم در وضعیت این بیت اثری نداره. می تونی از وقفه برای انجام کاری خاص در پایان تبدیل استفاده کنی.
      برداشتت هم درسته.
      منظورت از sleep را بیشتر توضیح بده که اصلا چرا میکرو را میخوای sleep کنی تا بتونم جواب درست بدم.

  29. واقعا خیلی عالی بود راهنمایی هاتون. الان متوجه شدم. مدار داره درست کار میکنه.

  30. سلام
    من مثال اول رو شبیه سازی کردم
    همون طوری که در آموزش گفتین باید این جا اندازه گام ۵۰۰۰mv/1024 باشه که میشه۴٫۸۸mv
    اما در شبیه سازی با دادن ولتاژ۲٫۵mv هم بیت کم ارزش اول ۱ میشه
    به نظرتون مشکل میتونه کجا باشه؟
    اگه فکر میکنین لازم هست ایملتون رو لطف کنین تا فایل شبیه سازی رو واستون بفرستم
    خیلی متشکرم

    • قبل از هر چیزی من توصیه میکنم که بری و مثال تقریب متوالی را یکبار به صورت دستی دوباره انجام بدی. (دومین مثال این پست)
      خب این روش داره میگه که به صورت پی در پی تقریب می زنیم تا نزدیک ترین مقدار به ولتاژ ورودی به صورت دیجیتال به دست بیاد. من همین آزمایش را با چند عدد به عنوان ورودی تست کردم. چون اندازه گام ما ۴٫۸۸mv هست پس از نصف اون یعنی ۲٫۴۴mv شروع کردم. خروجی ۰ بود. برای مقادیر کمتر هم دوباره صفر به دست اومد. اما وقتی ۲٫۴۵mv را تست کردم خروجی ۱ شد. این یعنی چی؟
      یعنی اینکه اومده تقریب زده، اگه اندازه ورودی از نصف گام بیشتر باشه به سمت بالا تقریب زده میشه (گرد میشه) و اگه کمتر از نصف ورودی باشه به سمت پایین تقریب زده می شه. برای همینه که وقتی بهش ۲٫۵mv دادی خروجی یک را دیدی. مدارت هیچ اشکالی نداره و درسته.
      حالا برای تمرین بیشتر برو دو تا عدد ۷٫۳۳mv و ۷٫۳۲mv را به ورودی بده و خروجی را ببین.

  31. سلام
    ببخشید من ویدئوی توضیح کد ها را دیدم اما دو خط زیر رو از مثال اول باز درست متوجه نشدم.
    PORTD = (unsigned char)ADCW;
    PORTC = (ADCW>>8);
    مگه ما نباید از ADCL و H داده رو ورداریم؟
    ADCW این جا چی هست و چی کار میکنه؟ خودتون تعریف کردین؟
    ممنون میشم بیشتر توضیح بدین

    • سلام به شما
      ADCW یک رجیستر داخل AVR نیست اما برای کدویژن تعریف شده تا خروجی ADC را به صورت ۱۶ بیتی (البته AVR نهایتا خروجی ۱۰ بیتی داره) برگردونه. در واقع با نوشتن ADCW کامپایلر این خط را طوری ترجمه می کنه تا مقادیر ADCL و ADCH خونده بشه و ترکیب شده و در قالب ۱۶ بیتی برگرده. البته در این مثال می شد مقادیر ADCL و ADCH را به صورت جداگونه خوند و روی پورت ها قرار داد ولی برای آشنایی با ADCW این کار انجام شده.

  32. متاسفانه توی کار با adc میکروم مشکل دارم هرکاری میکنم درست نمیشه ! ماژول من شتاب سنج هست

    و در حالت افقی توی محور x ولتاژ ۱٫۶۲ میده ، حالا همینو میبرم توی adc مثلا مقدار دیجیتال رو میخونه ۴۸۷

    ولی در عمل یه لحظه ۴۸۷ بعد ۴۵۰ بعد ۵۵۰ !!!!!!!!!!! در حلیکه توی پروتیوس درسته و مقدار دیجیتال رو روی ال سی دی

    همون ۴۸۷ ثابت نشون میده و تغییرات نداره !!

    یعنی مشکل از کجا میتونه باشه ؟؟ ولتاژ رفرنس (AREF)هم ثابت و ۵ ولت هست

    • سلام امیرجان 🙂
      اول یه نکته بگم که هیچ موقع پروتئوس را با آزمایش واقعی مقایسه نکن چون در عمل عوامل ناخواسته و غیرایده آلی وجود داره که هیچ کدومشون در پروتئوس در نظر گرفته نشده.
      الان شتاب سنجی که داری باهاش کار میکنی و تست افقی می گیری روی یه سطح صاف میذاری یا با دستت افقی نگه میداری؟ چون شتاب سنج حساسه و با کوچکترین لرزشی خروجیش تغییر می کنه و ممکنه همین باعث تغییرات کوچک در خروجیش بشه.

      • ممنونم بابت جوابت دوست عزیز !!

        ماژول رو روی سطح صاف میزارم و در حالت افقی ولتاژ ثابت ۱٫۶۲ و در حالت قایم ۲٫۳۸ رو میده …. ولی مقدار دیجیتال هر لحظه نوسان داره !!

        احتمال داره میانگیر گیری مشکل رو حل کنه ؟؟

        • خواهش میکنم دوست عزیز. اگه بتونم کمکی کنم باعث افتخاره
          من توصیه میکنم اول با یه ولت متر دقیق یا اسکوپ خروجی شتاب سنج را تست کنی که حتی کوچکترین نوسانی نداشته باشه.
          اما چند سوال در مورد خود ADC دارم.فرکانس میکرو چنده و با تقسیم فرکانسی چه فرکانسی به ADC میرسه؟
          ADC را در حالت ۱۰ بیتی راه انداختی یا ۸ بیتی؟
          تغذیه میکرو را از کجا میگیری؟ خیلی مهمه که نویز از طریق تغذیه وارد مدارت نشه ها.
          من توصیه میکنم که خروجی ADC را با یک ورودی غیر از شتاب سنج تست کنی.
          اما نکته ای که خودت گفتی بعد از رعایت تمام نکات برای بالا رفتن دقت همون میانگین گیری هست که به ثبات کمک میکنه.
          حالا جواب این سوالا رو بده تا ببینم مشکل از اینا هست یا جای دیگه

  33. با عرض درود و تشکر بسیار گویا و روان و مطلوب تضیح میدید. بنده بسیار لذت برم از شیوه توضیح. مو شکافی در چنین امر مهمی بسیار ضروری و مورد نیاز ماست. یعنی تا ریزتر و به زبان ساده تر توضیح داده بشه برای ما قابل درک تر و ماندگار تر است. دوباره از زحمت جنابعالی تشکر میکنم.

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

  34. سلام من اولین بار که سایت شما رو مشاهده میکنم
    راستش من دنبال راهی میگردم که بتونم با استفاده از تقسیم مقاومتی و دیود از طریق adc میکرو بتونم ولتاژ ac3 فاز رو بخونم تا یه حدودی موق شدم اما من از تابع read_adc استفاده کردم در هر ثانیه چندین بار adc خوانده می شد ولی من حداکثر ولتاژ رو می خواستم که به مشکل بر میخورد چون شاید ولتاژ بالا و پایین بشه
    شما در مد single توضیحاتی دادید که فکر کنم بتونه جواب من باشه اما چطور از مد single استفاده کنم بلد نیستم اگه امکان داره یه مثال بزنید با کمی توضیح

    • سلام آقا محمد. اول میشه یه توضیحی به من بدید که در چه کاری نیاز به خواندن ولتاژ ac سه فاز دارید تا بهتر بتونم کمکتون کنم.
      اما مثالی رو که فرمودید داخل پست وجود داره. در قسمت مثال شماره یک روش راه اندازی مد single گفته شده و توضیحات راه اندازیش هم که داخل متن وجود داره. اگه نکته خاصیش براتون مبهمه بفرمایید تا براتون توضیح بدم

  35. باسلام
    میخواستم بدونم اگه مثلا از ADC0 استفاده میکنیم، میتونیم از بقیه پین های همون پورت (مثلا پرت A در mega32) بعنوان I/O استفاده کنیم؟؟ یا با فعال کردن ADC عملکرد همه ی پین های پورت مربوطه از حالت I/O به ADC تغییر وضعیت پیدا میکنن
    ممنون

    • سلام.
      وقتی که شما از پورت در حالت ADC استفاده کنید دیگه عملکرد تمام پین ها از حالت I/O خارج میشه.

      • یعنی وقتی مثلا فقط ADC0 مورد نیازه بقیه پین های پورت باید خالی و بلااستفاده بمونن؟!!؟

        • سلام
          من اول از همه باید یه عذرخواهی از شما انجام بدم . چون پاسخ غلط دادم و شما رو به اشتباه انداختم.
          در حالت استفاده از ADC0 شما می تونید از سایر پین های پورت A برای عملکرد عادی استفاده کنید. برای نمونه من این کد کوتاه را نوشتم. یک بار با کدوژن کد را کامپایل کنید و بعد داخل پروتئوس نتیجه را مشاهده کنید. می بینید که ضمن عملکرد صحیح ADC دارید از ۲ تا پین های دیگه از پورت A هم استفاده می کنید.

          void main(void)
          {
          DDRA = 0xf0;
          DDRC = 0xFF;
          DDRD = 0xFF;
          PORTC = 0;
          PORTD = 0;
          // ADC initialization
          ADMUX = (1 < < REFS0); ADCSRA=(1<>8);

          if(PINA.0 == 3){
          PORTA.7=1;
          delay_ms(10);
          PORTA.7=0;
          delay_ms(10);
          }
          }
          }

  36. بله گلم شما درست میگی من اون کتابخونه رو فقط برای تمرین نوشتم نه چیز دیگه. ولی الان میخوام یه چیز دیگه بگم آقا احسان. شما بیا تو قسمت کد وقفتون چند خط کد بنویس تا چند تا سیکل کاری بگذره مثلا همین خط
    Vin=(float)ADCH*(VREF/ADC_STEPS);
    اونوقته که ADSC صفر میشه. حالا چرا نمیدونم. من کد کامل وقفه هم برات میذارم که وقتت گرفته نشه:
    interrupt [ADC_INT] void adc_isr(void)
    {
    float Vin;

    Vin=(float)ADCH*(VREF/ADC_STEPS);
    PORTC=ADCH;
    }

    • درسته کدت رو که بررسی کردم همین اتفاق می افته.
      فعلا نتونستم دلیلش رو متوجه بشم. اما بهم فرصت بده یکی دوهفته آینده شاید نتونم. بعدش دقیقتر بررسی میکنم اگه تونستم دلیلشو بفهمم حتما خبرت میکنم.
      اما کلا داخل زیر روال وقفه کدهای خیلی خیلی کوتاه باید نوشته بشه. مثلا در حد همین خوندن رجیستر خروجی ADC. وسایر عملیات در جاهای دیگه از برنامه انجام بشه. این محاسبات اعشاری داخل وقفه کمی سنگین هست. بهتر فقط داخل وقفه ADCW را بخون مشکلت حل میشه.

  37. سلام آقا احسان یه مطلبی تو این مقالتون بود که من کلا باهاش مخالفم. در بخش فعال کردن ADC در مد آزاد گفتید:
    “۳٫ حال برای شروع تبدیل فقط کافی است که برای بار اول بیت ADSC را فعال کنیم. برای تبدیل های بعدی نیاز به فعال سازی مجدد وجود ندارد و همیشه یک خواهد ماند.
    در مد free از پرچم وقفه به عنوان منبع تحریک استفاده می شود، در نتیجه پس از اتمام تبدیل، تبدیل جدید شروع خواهد شد. این روال تا زمانی که بیت ADSC یک است ادامه خواهد داشت.”
    والا من یک روز تمام وقت گذاشتم و آخرش فهمیدم که این بیت ADSC بدبخت بعد از اولین مرتبه تبدیل ADC صفر میشه (البته این مطلب رو با Proteus هم چکش کردم). بعدش به این نتیجه رسیدم که خوب اگه قراره این بیت صفر بشه پس به چه درد میخوره. اصلا دیگه وقفه اینجا چیکاره هستش! بعد از کلی کلنجار رفتن، رفتم سراغ کدویزارد خود کدویژن تا ببینم اصلا منظورش از free runnig mode چیه. کدای تولید شدش رو که نگاه کردم دیدم که اصلا منظور از این مد اینه که تو بیای یه تابع بنویسی و بعد توش ADC رو فعال کنی و نتیجت رو برگردونی. به زبون دیگه هر موقع که عشقت کشید از ADC استفاده کن.
    در ادامه همین ماجرا، برنامه ای که برای مثال ۳ نوشتید به نظرم فقط یک بار داره اجرا میشه. منم خودم یه برنامه مثل همین نوشتم منتها با LCD و دیدم ای دل غافل که مقدار ولتاژ از پتانسومتر فقط همون بار اول خونده میشه.

    • شما اول کدی را که برای این حالت نوشتید برای من بفرستید تا من بررسی کنم. اما برنامه مثال ۳ را که فرمودید من یک بار دیگه هم تست کردم. اینطور نیست و برنامه داره کار میکنه و هربار که مقدار پتانسیومتر عوض میشه خروجی هم روی پورت های C و D تغییر میکنه. در مد single شما برای هربار تبدیل کردن نیازه که ADSC را یک کنید چون با پایان تبدیل صفر میشه اما در مد free فقط بار اول اون رو یک کنید و دیگه نیازی به یک کردن مجدد نداره. به تفاوت مثال های ۲ و ۳ دقت کنید.

      • ممنون که پاسخ دادی. برای اینکه خوندن برنامه زیاد وقتت رو نگیره اولش بگم که من از ADC پایه شماره سه دارم می خونم و برای LCD هم از کتابخونه ی موجود کدویژن استفاده نکردم (خودم براش یه درایور نوشتم) واسه همین توابع کار با LCD اگه آشنا نبود ازش رد. باز هم بگم که تو مد free بعد از یک بار تبدیل ADC بیت ADSC صفر میشه. اینم از کد:
        #include
        #include “alcd1.h”
        #include

        const float VREF=5, ADC_STEPS=256;

        #define FIRST_ADC_INPUT 3
        #define ADC_VREF_TYPE ((0<<REFS1)|(1<<REFS0)|(1<<ADLAR)) //Voltage Reference: AVCC pin

        interrupt [ADC_INT] void adc_isr(void) //ADC interrupt service routine
        {
        float Vin;
        unsigned char str[17];

        Vin=(float)ADCH*(VREF/ADC_STEPS);
        sprintf(str,"Volt=%f V",Vin);
        alcd_gotorc(1,1);
        alcd_put(str);
        }

        void main(void)
        {

        //ALCD config
        alcd_ddr=0xff;
        //ALCD init
        alcd_init(0,1,1);
        alcd_cursor_off();

        //ADC initialization
        //ADC Clock frequency: 125.000 kHz
        //ADC Voltage Reference: AVCC pin
        //ADC Auto Trigger Source: ADC Stopped
        ADMUX=FIRST_ADC_INPUT|ADC_VREF_TYPE;
        ADCSRA=(1<<ADEN)|(0<<ADSC)|(1<<ADATE)|(0<<ADIF)|(1<<ADIE)|(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
        SFIOR=(0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);
        ADCSRA|=(1<<ADSC); //to start ADC conversation

        #asm("sei")

        while (1)
        {
        }
        }

        • ساختار کلی کدت رو بررسی کردم. شبیه مثال ۳ کار کردی یعنی اومدی منبع تحریک خودکار استفاده کردی و منبعت هم در حالت عملکرد آزاد هست، از طرفی وقفه را هم استفاده کردی. پس در این حالت پس از پایان یک تبدیل، تبدیل بعدی آغاز میشه. این حالت تا زمانی رخ میده که بیت ADSC یک باشه. تمام منابع آموزشی AVR و دیتا شیتش هم این حرف را میزنن. مثال ۳ راهم یک بار دیگه میگم شبیه سازی کن . نتیجه رو ببین که فقط یک بار خروجی نمیده و با هر بار تغییر پتانسیومتر جواب میده. باید عمیق تر این بحث را مطالعه کنی. اولش ممکنه برات گیج کننده باشه ولی بعدش متوجه میشی.
          راستی یه نکته را یادم رفت بگم. داخل پروتئوس حتما به پین های AREF و AVCC مقدار ۵ ولت را وصل کن وگرنه اصلا تغییر خروجی را با تغییر پتانسیومتر نمیتونی ببینی.
          موفق باشی

          • بله عزیزم حق با شماست با یه پورت دیگه که تست کردم جواب میده. فکر کنم حالا فهمیدم مشکل چیه.
            LCD روی پورت A بودش و نوشتن روش روی ADC هم تاثیر میذاشت. این مساله رو هم با کتابخونه LCD خود کدویژن هم تست کردم و دیدم همینجوریه. حالا اینکه چه جوری تاثیر میذاره رو نمیدونم. شما میدونید؟ فکر میکنم من یه مساله خیلی ساده رو نمیدونم!!!

          • موسی جان وقتی شما میای و از ADC استفاده می کنی، پورتی که برای ADC در نظر گرفته شده دیگه حالت ورودی خروجی معمولی را نباید براش در نظر گرفت. برای همینه که داده های مبدل آنالوگ به دیجیتال و LCD با هم تداخل میکنن و نتایج غیرمنتظره پیش میاد. یه نکته ی دیگه هم اینکه برای قطعات خیلی پرکاربرد و دم دستی مثل LCD کاراکتری از کتابخانه های آماده ای که سالها امتحانشونو پس دادن استفاده کن و وقت را برای نوشتن کتابخونه جدید هدر نده. به قول انگلیسیا:”چرخ را دوباره اختراع نکن”

  38. من مقاله رو خوندم ابتدا تشکر می کنم از بابت زحمتی که براش کشیدید ولی چند تا نکته برام مبهم مونده که می خوام ازتون بپرسم.

    ۱- اونجوری که من فهمیدم تو بحث خروجی داده دیجیتال اگه فرض کنیم مثلا رزلوشن ADC ده بیتی باشه اونوقت خروجی یکی از مقادیر بین ۰ تا ۱۰۲۳ خواهد بود. ولی شما تو این بحث یه مثال زدید گفتید خروجی عدد ۱۰۵٫۲ که اصلا یه عدد اعشاری هست. به نظر من حتما باید این عدد صحیح باشه (گسسته)؟

    ۲- تو این مقاله بحت تبدیل اعداد اعشاری به باینری شده بود مثل همون عدد ۱۰۵٫۲٫ من کلا با روند تبدیل عدد اعشاری به باینری آشنایی ندارم تو این سایت هم مطلبی در موردش ندیدم. میتونید یا در مورد اون توضیح بدید؟

    ۳- من پروژه دماسنج رو شبیه سازی کردم و نتیجه هم گرفتم پس حتما کدها درست هستن ولی یه کد هنوز هست که خیلی من رو گیچ کرده و نمیدونم مشکلم کجاست. کد
    while((ADCSRA&(1<

    • درود. خیلی متشکرم که انقدر ریز مقاله رو بررسی کردید. من سعی میکنم مختصر و مفید جواب سوال هاتون را بدم.
      ۱-این یک مثال بوده و فقط نتیجه محاسبه رو نشون میده. درسته خروجی دیجیتال هست و قسمت اعشار نداره چون خروجی دیجیتال به اندازه گام ربط داره یعنی شما باید ببینید که ولتاژ ورودی چند برابر اندازه گام هست و اون رو به عنوان خروجی دیجیتال در نظر بگیرید. اما اگه یه مقدار باقی مانده هم داشتیم( یعنی ما در این مثال خاص ۱۰۵ تا گام کامل داریم و یک گام ناقص) دیگه قسمت اعشار در نظر گرفته نمیشه. خب adc هم که نمیتونه تغییرات کمتر از یک گام رو اندازه بگیره پس نزدیگ ترین مقدار رو تقریب میزنه. اگه یادتون باشه داخل متن هم گفتم داریم از روش تقریب متوالی استفاده می کنیم. پیشنهاد می کنم این مثال خاص رو با روش تقریب متوالی که توضیح داده شده حل کنید.
      ۲-روند تبدیل اعشاری به باینری به این صورت هست:مثلا ما میخوایم عدد ۱۲٫۲۵ رو در مبنای ۱۰ ، تبدیل کنیم به مبنای ۲ :روش کار به اینصورت خواهد بود که : ۱) ابتدا قسمت صحیح اعداد اعشاری را جداگانه در مبنای ۲ بدست می آوریم ، ۱۲ => ۱۱۰۰ سپس ۲) قسمت اعشار را بطور متوالی در مبنای دو ضرب میکنیم ، هر بار قسمت صحیح عدد رو برداشته و قسمت اعشاری عدد حاصل رو دوباره در مبنا ضرب می کنیم تا زمانیکه به یک برسیم که ممکن است بعضی اوقات نرسیم که در این حالات باید تا یک تعداد محدودی ارقام اعشار محاسبه کنیم :

      ۰٫۲۵ * ۲ = ۰٫۵ ==> ۰
      ۰٫۵ * ۲ = ۱ ==> ۱
      Result :
      ۱۲٫۲۵ = (۱۱۰۰٫۰۱)
      ۲

      ۳-دقیقا متوجه این سوالتون نشدم لطفا بیشتر توضیح بدید.
      ۴-دقت کنید که شما برای تبدیل دما دارید از اعداد اعشاری استفاده می کنید.(ضرب عدد ۴٫۸۸ میلی ولت در خروجی دیجیتال و بعد تقسیم بر ۱۰ میلی ولت) اما خروجی دیجیتال صحیح هست. قسمت اعشاری حاصل که در LCD می بینید ناشی از این محاسبات میشه. بحث گسسته سازی هم که گفتید درسته. چون گام الان ۴٫۸۸ میلی ولت هست و خروجی سنسور داره ۱۰میلی ولت برای هر درجه سانتیگراد تغییر می کنه. می بینید که باقی مانده داریم و همینه که باعث میشه اعشار داشته باشیم و این جزئی از خطا کار هست. برای کاهش این خطا باید از ADC با دقت بالاتری استفاده بشه.

  39. سلام . برای اینکه بتونیم سیگنال های آنالوگی رو که AC هستن و دامنه ی منفی دارن رو به دیجیتال تبدیل کنیم چی کار باید کرد ؟ میشه ابتدا اون رو با یه مقدار DC جمع کنیم تا دامنه ی منفی از بین بره و سپس تبدیلش کنیم ؟

    • سلام. ببینید واسه avr شما یکم محدودیت دارین چون نهایتا بین صفر تا ۵ ولت را میتونید دیجیتال کنید. دقیقا بگید مقدار منفیتون چقدره و توی چه کاری لازمش دارید تا به جای کلی گویی بتونم راهکار اصلی را بگم.

      • من میخام یه سیگنال AC سینوسی که توسط اسیلاتور ساختم رو به AVR بدم و دامنش پیک تا پیکش هم کمتر از ۵ ولته تا بتونم روی اون مدولاسیون PWM انجام بدم و در خروجی داشته باشم . فقط اینکه برای اینکه برای دادن این موج اید اونو با DC جمع کنم یا راه دیگه ای هست ؟

        • در کل ولتاژ منفی را که نمیشه با avr اندازه گیری کرد پس باید با روش هایی که وجود داره مثل شیف dc یا استفاده از op amp و … به مثبت تبدیل کنی.ولی بهترین و ساده ترین روشی که وجود داره همون شیفت dc هست که میتونی ازش استفاده کنی. که من یه مقاله مفید و کلی بهت معرفی میکنم . بخونش حتما خصوصا قسمت خوندن ولتاژ بین منفی و مثبت ۱۵ ولت را. بعد حتما بیا تا دربارش اینجا بحث می کنیم. http://www.cq.cx/interface.pl#6

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

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