اطلاعیه

Collapse
No announcement yet.

چگونه با ولوم Rotary Encoders کار کنیم؟ [آموزشی]

Collapse
X
 
  • فیلتر
  • زمان
  • Show
Clear All
new posts

    چگونه با ولوم Rotary Encoders کار کنیم؟ [آموزشی]

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

    بخش 1 :
    ساختمان روتاری انکودر :
    روتاری انکودرها از لحاظ سخت افزاری از یک صفحه ثابت که روی آن از دو ردیف مربع مربع شکل که به عنوان اتصالات از هم فاصله دارند و از یک اهرم مکانیکی متحرک(کانکتور متحرک) که روی آن صفحه ثابت حرکت میکند ، تشکیل شده است . مانند شکل زیر


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

    شکل موج خروجی روتاری انکودر :
    همانطور که گفته شد روتاری انکودر از دو کلید متحرک تشکیل شده است که با هم اختلاف زمانی دارند . مانند شکل زیر
    اگر دو مقاومت Pullup بگذاریم شکل موج به این صورت تبدیل میشود .


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

    در بعضی جاها اختشاش کلیدزنی مهم نیست و لزومی ندارد که آن را حذف کنیم . ولی معمولا در سیستمهای دیجیتالی که میخواهند با دنیای بیرون ارتباط برقرار کنند نیاز داریم تا این گونه اختشاش را حذف کنیم .
    این ولوم ها هم مانند همین شکل Bounce تولید میکنند که باید آن را حذف کنیم .
    حذف Bounce یا همون Debounce به دو صورت انجام میگیرد:
    1. نرم افزاری
    2. سخت افزاری

    حذف کردن Bounce به صورت نرم افزاری :
    در این روش با دیدن اولین لبه کلید زنی زمانی را به عنوان تاخیر در نظر میگیریم و پس از آن سیگنال ها را استفاده میکنیم .
    خوبی این روش این است که سخت افزار اضافی ندارد و بدی این روش هم این است که به اندازه یک مدت کوتاهی پردازنده دیجیتالی را مشغول نگه می دارد .

    حذف کردن Bounce به صورت سخت افزاری :
    در این روش با گذاشتن دو مقاومت و یک خازن ، Bounce را حذف می کنیم . مانند شکل زیر
    خوبی این روش این است که پردازنده را مشغول نگه نمیدارد چون دستور تاخیری ندارد و نسبت به روش نرم افزاری هم دقیق تر است.

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

    خوب عزیزان این بخش به پایان رسید
    امیدوارم که خوب توضیح داده باشم
    موفق و پیروز باشید
    [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
    معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
    معرفی نرم افزار Codewizard PWM
    با من بیشتر آشنا شوید

    #2
    پاسخ : چگونه با ولوم های هرزگرد (Rotary Encoders) کار کنیم ؟

    با تشکر

    و در تکمیل اموزش مفیدتان اگر میشود یک نمونه برنامه (ساده ) لحاظ کنید

    دیدگاه


      #3
      چگونه با Rotary Encoders کار کنیم؟؟ (بخش2)

      بخش دوم :
      در بخش 1 درباره ساختمان ولوم و چگونگی کار کردن ولوم و همچنین مدار حذف Bounce بحث شد .
      در این بخش می پردازیم به یافتن راهی برای تشخیص چپگرد ، راستگرد بودن آن و همچنین یک کد بسیار ساده که کار را راحت میکند ارائه خواهم داد .

      روش های کدنویسی برای روتاری انکودر :
      1. در این روش هیچ گونه وقفه ای به کار نرفته است و پردازنده به طور مداوم در حال خواندن پورت ورودی می باشد
      2. استفاده از وقفه که خود به دو دسته تقسیم میشود :
      1-2. استفاده از دو وقفه خارجی که هر دو وقفه توی مد Any change (وقفه تغییر لبه)
      2-2. استفاده از وقفه Pin Change
      در این آموزش قصد داریم با روش دوم (وقفه ای) کار کنیم .

      راهی برای تشخیص چپگرد ، راستگرد بودن روتاری انکودر :
      برای یافتن چپگرد یا راستگرد ابتدا باید یک تحلیل را انجام دهیم و سپس کد را بنویسیم .
      راهی که من پیشنهاد میکنم روش ابتکاری خودم است و خیلی خوب هم جواب داده ...
      خوب برای اینکه یک کد به خوبی کار کند ابتدا باید خطاهای احتمالی را مورد بررسی قرار دهیم...
      ما در اینجا فرض بر این گرفتیم که مدار Debounce متصل به ولوم است و پالسها به طور دقیق به میکرو انتقال پیدا می کند . همانطور که میدانیم برای یک تشخیص ابتدا باید از این پالسها عبور کنیم (1و2و3و4) و P هم مخفف past حالت گذشته است .
      راستگرد
      11 و 10 و 00 و 01 و 11
      (4) و (3) و (2) و (1) و (P)
      چپگرد
      11 و 01 و 00 و 10 و 11
      (4) و (3) و (2) و (1) و (P)
      خوب
      یک روش ساده در نظر گرفتم که اگر خطا پیش آید ، عمل تشخیص انجام نگیرد. به عنوان مثال بیت سمت راست را در نظر بگیرید و حالا با هر تغییر مرحله فقط صفرها را شمارش کنید .
      در راستگرد :
      مرحله || شمارش صفر
      ------------------------------
      مرحله 1 0
      مرحله 2 1
      مرحله 3 2
      مرحله 4 2

      حالا اگر به هر نحوی روتاری انکودر را تا وسط کار بچرخانیم و سپس به P برگردیم(چهار مرحله ناقص صورت گیرد) شمارنده صفر بیت سمت راست یا بیشتر از 2 یا کمتر از 2 می شود .
      راستگرد :
      مرحله || شمارش صفر
      ------------------------------
      مرحله 1 0

      راستگرد :
      مرحله || شمارش صفر
      ------------------------------
      مرحله 1 0
      مرحله 2 1
      مرحله 1 1

      راستگرد :
      مرحله || شمارش صفر
      ------------------------------
      مرحله 1 0
      مرحله 2 1
      مرحله 3 2
      مرحله 2 3
      مرحله 1 3

      مشاهده می شود که اگر شمارش صفر برابر با دو شود تشخیص صحیح و اگر مخالف دو باشد تشخیص غیر صحیح می باشد .
      این روند برای چپگرد هم انجام بدهیم باز همین می شود . البته شمارش صفر متفاوت است .
      تا اینجا فقط تشخیص دادیم که عملیات به طور صحیح انجام شده یا خیر .برای اینکه چپگرد ، راستگرد بودن آن را تشخیص دهیم باید حالت قبلی را نگاه کنیم .
      مثلا در راستگرد مرحله قبلی 10 هست که باید شرط بگذاریم که اگر 10 شد راستگرد هست .
      مرحله || شمارش صفر || مرحله قبل
      ---------------------------------------------
      مرحله 1 0 11
      مرحله 2 1 01
      مرحله 3 2 00
      مرحله 4 2 10
      برای بررسی چپگرد ، راستگرد بودن باید در زمان تایید تشخیص صحیح شرط بگذاریم .
      پس در این روش 2 متغیر استفاده میشود یکی برای شمارش صفر بیت سمت راست و یکی دیگر برای حالت قبلی

      نمونه کد برای روتاری انکودر :
      نمونه کدی که در اختیارتان قرار میدهم دقیقا همین مراحلی که گفته شد را انجام میدهد
      کد:
      void Rotary_Encoder(uint8_t Input_PhaseA_PhaseB,uint8_t PIN,uint8_t *Var,uint8_t *Status,uint8_t *Counter)
      //For Example : Rotary_Encoder(0x03,PIND,&R1,&Status1,&Counter1); 
      {	
      	uint8_t bit_Right=0 , x ;
      	x = PIN & Input_PhaseA_PhaseB;
        for(uint8_t q = 1;q<200;q <<= 1)
      	if(Input_PhaseA_PhaseB & q)
      	{
      		bit_Right = q;
      		break;
      	}
      	if(x < Input_PhaseA_PhaseB)
      // اگر یکی از حالتهای میانی (10و00و01) قرار گرفت
       	{
      		if(!(x & bit_Right))*Counter += 1;
      // تعداد صفر سمت راست را می شمارد
       		*Status = x;
      //  ذخیره می شود (Status) آخرین حالت در متغیر
       	}
       	else if((x == Input_PhaseA_PhaseB) && (*Counter == 2))
      // اگر در حالت (11) قرار گرفت شمارنده صفر را بررسی میکند اگر مساوی 2 بود
       	{ 
      // بر اساس مقدار قبلی چپگرد یا راستگرد بودن آن مشخص می شود 
       		if	(*Status == bit_Right)	*Var += 1; // راستگرد
       		else						*Var -= 1; // چپگرد
      // پس از معلوم شدن چپگرد یا راستگرد بودن روتاری انکودر،دو متغیر (وضعیت و شمارنده) صفر می شود
       		*Status = 0;
       		*Counter= 0;
       	}
       	else
      	 //اگر با خطایی روبرو شد دو متغیر (شمارنده و وضعیت)صفر خواهد شد
       	{
       		*Status = 0;
       		*Counter = 0;
       	}
       }
      یه توضیح مختصری درباره زیر برنامه Rotary_Encoder بدم
      کد:
      void Rotary_Encoder(uint8_t Input_PhaseA_PhaseB,
      			uint8_t PIN,
      			uint8_t *Var,
      			uint8_t *Status,
      			uint8_t *Counter)
      ورودی Input_PhaseA_PhaseB :
      در این قسمت باید ورودی فاز B,A روی پورت را تعیین کنیم . مثلا اگر فاز A روی بیت 0 و فاز B روی بیت 1 بود باید این رو به صورت باینری دربیاریم که در اینجا میشه 0x03
      ورودی PIN :
      در این قسمت باید معلوم کنیم که روتاری انکودر روی چه پورتی قرار گرفته است . مثلا اگر روی پورت B بود باید وارد کنیم PINB
      ورودی Var :
      در این قسمت هم باید اشاره کنیم به آدرس اون متغیری که قراره کم یا زیاد بشه . مثلا متغیر ما RE1 هست که به صورت سراسری تعریف شده و باید در این قسمت وارد کنیم RE1& که اشاره به این متغیر کنه و اون رو کم و زیاد کنه ...
      ورودی Status :
      در این قسمت هم باید به متغیری اشاره کنیم که قرار است مقدار قبلی را در خود ذخیره کند . این متغیر باید به صورت سراسری تعریف بشود .
      ورودی Counter :
      در این قسمت هم باید به یک متغیری اشاره کنیم که قرار است مقدار صفر بیت سمت راست را شمارش کند . این متغیر باید به صورت سراسری تعریف بشود .
      با این توضیحات برنامه به صورت زیر میباشد .
      کد:
      Rotary_Encoder(0x03,PINB,&RE1,&Status1,&Counter1);
      شاید بپرسید که این تایع را کجا بگذاریم ؟؟؟
      این تابع را باید در زیر برنامه وقفه که توی مد Any change قرار دارد ، بگذاریم ...
      به عنوان مثال میخواهیم در وقفه خارجی 0 و 1 در مگا 16 این کار را انجام دهیم
      نمونه کد در اتمل استودیو :
      کد:
      ISR(INT0_vect)
      {
      	Rotary_Encoder(0x0C,PIND,&RE1,&Status1,&Counter1);
      }
      ISR(INT1_vect)
      {
      	Rotary_Encoder(0x0C,PIND,&RE1,&Status1,&Counter1);
      }
      نمونه کد در کدویژن :
      کد:
      interrupt [EXT_INT0] void ext_int0_isr(void)
      {
      	Rotary_Encoder(0x0C,PIND,&RE1,&Status1,&Counter1);
      }
      interrupt [EXT_INT1] void ext_int1_isr(void)
      {
      	Rotary_Encoder(0x0C,PIND,&RE1,&Status1,&Counter1);
      }
      میکروهایی که از امکانات Pin Any Change برخوردار هستند ، باید اینگونه نوشت .
      برای مثال میکروی مگا48 PCINT0 , PCINT1 از پورت B :
      نمونه کد برای اتمل استودیو :
      کد:
      ISR(PCINT0_vect)
      {
      	Rotary_Encoder(0x03,PINB,&RE1,&Status1,&Counter1);
      }
      نمونه کد برای کدویژن :
      کد:
      interrupt [PC_INT0] void pin_change_isr0(void)
      {
        Rotary_Encoder(0x03,PINB,&RE1,&Status1,&Counter1);
      }
      خوب عزیزان بخش دوم به پایان رسید
      امیدوارم خوب توضیح داده باشم ...
      موفق باشید
      ----------------------------------------------
      نوشته اصلی توسط دیجت
      بنظر من این فقط ساختار یک نوع روتاری است که شبیه انکودر مادون قرمز عمل میکند
      بله ساختارش مثل شافت اینکودر هست ولی در اینجا میخواهیم با ولوم کار کنیم
      نوشته اصلی توسط دیجت
      در ساختار های دیگه روتاری به ما یک کد ( گویا (گری) ) ارایه میدهد
      که باید ان را دیکد کرد تا به موقیعت مورد نظر دست یافت
      کد گری ؟؟
      کد گری اینجوریه
      00
      01
      11
      10
      بله اگر پشت سر هم قرار گیرند و فقط به یک سمت بچرخد حرف شما درسته
      اگر از این دید نگاه کنیم که بیت قبل با بعدی تنها یک بیت تفاوت داره بله اینجوری هست ولی کد گری نیست .
      نوشته اصلی توسط دیجت
      در تکمیل آموزش مفیدتان اگر میشود یک نمونه برنامه (ساده ) لحاظ کنید
      لحاظ کردم
      نوشته اصلی توسط دیجت
      بخش های بعدی شامل چه مباحثی است ؟
      بخش 2 که تمام شد ...
      بخش 3 میپردازیم به شبیه سازی مدار
      موفق باشید
      [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
      معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
      معرفی نرم افزار Codewizard PWM
      با من بیشتر آشنا شوید

      دیدگاه


        #4
        چگونه با Rotary Encoders کار کنیم؟؟ (بخش سوم)

        بخش سوم :
        یک مدل شبیه سازی در نرم افزار بسیار محبوب پروتئوس که به نظر من میتونه خیلی بهتون کمک کنه در تست صحیح برنامه ای که نوشتید . بنابراین در این بخش قصد داریم این روتاری انکودر را در پروتئوس شبیه سازی کنیم ...

        شبیه سازی روتاری انکودر در پروتئوس :
        همانطور که میدانیم شکل موج خروجی روتاری انکودر ، از دو موج مربعی که با هم 90 درجه اختلاف فاز دارد، تشکیل شده است . از آنجا که روتاری انکودر مثل یک کلید عمل می کند ، بنابراین باید یک حالتی را برای شبیه سازی تعریف کنیم که بتواند به عنوان یک کلید آن را با اختلاف فاز 90 درجه درست کند . همانطور که میدانید میکرو های AVR این قابلیت را دارد ، زمانی که ورودی تعریف بشود و pullup غیرفعال باشه مقاومت ورودی آن خیلی زیاد است و زمانی که آن را در حالت خروجی تعریف کنیم مقاومت خروجی آن کم میشود . ما از این ترفند استفاده میکنیم که به صورت یک کلید عمل کند ... بنابراین رجیستر PORT را برابر صفر رجیستر DDR را 0 و 1 میکنیم که در این صورت مثل یک کلید عمل می کند .
        توی محاسبات مهندسی اگر خطا زیر 10% ، 5% باشد (بسته به حساسیت کار) ، مورد قبول است . از آنجایی که اگر پورت را خروجی تعریف کنیم مقاومت آن حدودا" بین 50 تا 75 اهم است ، نسبت این مقاومت (بین 50 تا 75) و مقاومت pullup که حداقل 5کیلو تا 10 کیلو است ، 1 به 100 است . که برای شبیه سازی مناسب است .
        در عمل مقاومت خروجی AVR بین 50 تا 75 اهم است ولی در پروتئوس این عدد 20 اهم است . پس کارمان برای شبیه سازی بهتر شد چون مقاومت خروجی کمتر است ...
        بریم سر اصل مطلب
        برای شبیه سازی ابتدا پروتئوس را باز کرده و میکروی ATmega8 و BUTTON و RES را به لیست اضافه کنید و روی پورت B هشت کلید (BUTTON) متصل کنید و اون پایه دیگه کلید ها را به هم متصل کنید و بعد به زمین متصل کنید .
        پورت C0 و C1 را خروجی در نظر می گیریم که همان ولوم هرزگرد محسوب می شود . پورت C0 را فاز A و پورت C1 را فاز B نام گذاری می کنیم .
        دو پایه فاز A و B را با دو مقاومت 10 کیلو Pullup کنید . این دو پایه را به کانالهای A و B اسیلوسکوپ وصل کنید .
        مانند شکل زیر

        خوب
        حالا میریم سراغ برنامه
        برنامه برای Atmel Studio 6.1 :
        کد:
        #include <avr/io.h>
        #include <avr/iom8.h>
        #include <util/delay.h>
        
        #define F_CPU		8000000
        #define Set_A		DDRC |= 1
        #define Reset_A		DDRC &= 254
        #define Set_B		DDRC |= 2
        #define Reset_B		DDRC &= 253
        #define Delay		_delay_ms(10);
        #define Delay_Step	_delay_ms(100);
        
        int main(void)
        {
        	PORTB = 0xFF;
        	while(1)
          {
        		if (!(PINB & 1))
        		{
        			Set_A;
        			Delay;
        			Set_B;
        			Delay;
        			Reset_A;
        			Delay;
        			Reset_B;
        			Delay_Step;
        		}
        		if (!(PINB & 2))
        		{
        			Set_B;
        			Delay;
        			Set_A;
        			Delay;
        			Reset_B;
        			Delay;
        			Reset_A;
        			Delay_Step;	
        		}
          }
        }
        برنامه برای CodeVision :
        کد:
        #include <mega8.h>
        #include <delay.h>
        #define Set_A    DDRC |= 1
        #define Reset_A   DDRC &= 254
        #define Set_B    DDRC |= 2
        #define Reset_B   DDRC &= 253
        #define Delay    delay_ms(10);
        #define Delay_Step delay_ms(100);
        
        void main(void)
        {
          PORTB = 0xFF;
          while(1)
          {
        		if (!(PINB & 1))
        		{
        			Set_A;
        			Delay;
        			Set_B;
        			Delay;
        			Reset_A;
        			Delay;
        			Reset_B;
        			Delay_Step;
        		}
        		if (!(PINB & 2))
        		{
        			Set_B;
        			Delay;
        			Set_A;
        			Delay;
        			Reset_B;
        			Delay;
        			Reset_A;
        			Delay_Step;
        		}
          }
        }
        با هر کدام از نرم افزارها که کار می کنید یک New Project باز کنید و برنامه رو بریزید همونجا و کامپایل کنید . در برنامه پروتئوس مسیر فایل hex رو به میکرو معرفی کنید و فرکانس رو بگذارید روی 8 مگا هرتز .
        خوب حالا Play کنید و کلید راستگرد یا چپگرد را نگه دارید ، شکل موج را به صورت زیر مشاهده می کنید .


        می بینیم که هر دو شکل موج با 90 درجه اختلاف فاز درست شده است .
        همانطور که قبلا گفته شد روتاری انکودر هیچگاه شکل واقعی آن به این شکل نیست و Bounce دارد .
        بنابراین باید در برنامه Bounce تعریف شود . زمانهای بین قطع و وصل Bounce هیچگاه یکی نیست ... یا به عبارت بهتر زمانی که Bounce ایجاد می شود فرکانس خاصی نداره ... بنابراین زمانی که برنامه Bounce را مینویسیم ، باید این نکته را مد نظر داشته باشیم که با یک زمان خاص قطع و وصل نکنیم ...
        برنامه شبیه ساز روتاری انکودر با نرم افزار ATmel Studio
        کد:
        #include <avr/io.h>
        #include <avr/iom8.h>
        #include <util/delay.h>
        
        #define F_CPU		8000000
        #define Set_A		DDRC |= 1
        #define Reset_A		DDRC &= 254
        #define Set_B		DDRC |= 2
        #define Reset_B		DDRC &= 253
        #define Delay		_delay_ms(10);
        #define Delay_Step	_delay_ms(100);
        #define Bounce_Set_A \
        {\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(2);\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(3);\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(5);\
        	Reset_A;\
        	_delay_us(3);\
        	Set_A;\
        	_delay_us(3);\
        	Reset_A;\
        	_delay_us(2);\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(6);\
        	Set_A;\
        	_delay_us(3);\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(2);\
        	Set_A;\
        	_delay_us(2);\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(1);\
        }
        #define Bounce_Set_B \
        {\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(2);\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(3);\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(5);\
        	Reset_B;\
        	_delay_us(3);\
        	Set_B;\
        	_delay_us(3);\
        	Reset_B;\
        	_delay_us(2);\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(6);\
        	Set_B;\
        	_delay_us(3);\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(2);\
        	Set_B;\
        	_delay_us(2);\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(1);\
        }
        #define Bounce_Reset_A \
        {\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(2);\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(3);\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(5);\
        	Set_A;\
        	_delay_us(3);\
        	Reset_A;\
        	_delay_us(3);\
        	Set_A;\
        	_delay_us(2);\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(6);\
        	Reset_A;\
        	_delay_us(3);\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(1);\
        	Set_A;\
        	_delay_us(2);\
        	Reset_A;\
        	_delay_us(2);\
        	Set_A;\
        	_delay_us(1);\
        	Reset_A;\
        	_delay_us(1);\
        }
        #define Bounce_Reset_B \
        {\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(2);\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(3);\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(5);\
        	Set_B;\
        	_delay_us(3);\
        	Reset_B;\
        	_delay_us(3);\
        	Set_B;\
        	_delay_us(2);\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(6);\
        	Reset_B;\
        	_delay_us(3);\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(1);\
        	Set_B;\
        	_delay_us(2);\
        	Reset_B;\
        	_delay_us(2);\
        	Set_B;\
        	_delay_us(1);\
        	Reset_B;\
        	_delay_us(1);\
        }
        
        int main(void)
        {
        	PORTB = 0xFF;
        	while(1)
          {
        		////////////////////////////////////// Bounce بدون 
        		if (!(PINB & 1))
        		{
        			Set_A;
        			Delay;
        			Set_B;
        			Delay;
        			Reset_A;
        			Delay;
        			Reset_B;
        			Delay_Step;
        		}
        		if (!(PINB & 2))
        		{
        			Set_B;
        			Delay;
        			Set_A;
        			Delay;
        			Reset_B;
        			Delay;
        			Reset_A;
        			Delay_Step;	
        		}
        		//////////////////////////////////////
        		////////////////////////////////////////////////////////////////////////////
        		////////////////////////////////////// Bounce با
        		if (!(PINB & 4))
        		{
        			Bounce_Set_A;
        			Delay;
        			Bounce_Set_B;
        			Delay;
        			Bounce_Reset_A;
        			Delay;
        			Bounce_Reset_B;
        			Delay_Step;
        		}
        		if (!(PINB & 8))
        		{
        			Bounce_Set_B;
        			Delay;
        			Bounce_Set_A;
        			Delay;
        			Bounce_Reset_B;
        			Delay;
        			Bounce_Reset_A;
        			Delay_Step;
        		}
        		//////////////////////////////////////
          }
        }
        برنامه شبیه ساز روتاری انکودر با نرم افزار CodeVision
        کد:
        #include <mega8.h>
        #include <delay.h>
        #define Set_A    DDRC |= 1
        #define Reset_A   DDRC &= 254
        #define Set_B    DDRC |= 2
        #define Reset_B   DDRC &= 253
        #define Delay    delay_ms(10);
        #define Delay_Step delay_ms(100);
        #define Bounce_Set_A \
        {\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(2);\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(3);\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(5);\
          Reset_A;\
          delay_us(3);\
          Set_A;\
          delay_us(3);\
          Reset_A;\
          delay_us(2);\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(6);\
          Set_A;\
          delay_us(3);\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(2);\
          Set_A;\
          delay_us(2);\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(1);\
        }
        #define Bounce_Set_B \
        {\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(2);\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(3);\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(5);\
          Reset_B;\
          delay_us(3);\
          Set_B;\
          delay_us(3);\
          Reset_B;\
          delay_us(2);\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(6);\
          Set_B;\
          delay_us(3);\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(2);\
          Set_B;\
          delay_us(2);\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(1);\
        }
        #define Bounce_Reset_A \
        {\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(2);\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(3);\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(5);\
          Set_A;\
          delay_us(3);\
          Reset_A;\
          delay_us(3);\
          Set_A;\
          delay_us(2);\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(6);\
          Reset_A;\
          delay_us(3);\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(1);\
          Set_A;\
          delay_us(2);\
          Reset_A;\
          delay_us(2);\
          Set_A;\
          delay_us(1);\
          Reset_A;\
          delay_us(1);\
        }
        #define Bounce_Reset_B \
        {\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(2);\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(3);\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(5);\
          Set_B;\
          delay_us(3);\
          Reset_B;\
          delay_us(3);\
          Set_B;\
          delay_us(2);\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(6);\
          Reset_B;\
          delay_us(3);\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(1);\
          Set_B;\
          delay_us(2);\
          Reset_B;\
          delay_us(2);\
          Set_B;\
          delay_us(1);\
          Reset_B;\
          delay_us(1);\
        }
        
        void main(void)
        {
          PORTB = 0xFF;
          while(1)
          {
            ////////////////////////////////////// Bounce بدون
        		if (!(PINB & 1))
        		{
        			Set_A;
        			Delay;
        			Set_B;
        			Delay;
        			Reset_A;
        			Delay;
        			Reset_B;
        			Delay_Step;
        		}
        		if (!(PINB & 2))
        		{
        			Set_B;
        			Delay;
        			Set_A;
        			Delay;
        			Reset_B;
        			Delay;
        			Reset_A;
        			Delay_Step;
        		}
        		//////////////////////////////////////
        		////////////////////////////////////////////////////////////////////////////
        		////////////////////////////////////// Bounce با
        		if (!(PINB & 4))
        		{
        			Bounce_Set_A;
        			Delay;
        			Bounce_Set_B;
        			Delay;
        			Bounce_Reset_A;
        			Delay;
        			Bounce_Reset_B;
        			Delay_Step;
        		}
        		if (!(PINB & 8))
        		{
        			Bounce_Set_B;
        			Delay;
        			Bounce_Set_A;
        			Delay;
        			Bounce_Reset_B;
        			Delay;
        			Bounce_Reset_A;
        			Delay_Step;
        		}
            //////////////////////////////////////
          }
        }
        خوب حالا دوباره برنامه را Play کنید و دکمه سوم یا چهارم را نگه دارید . میبینید که ظاهر شکل موج کلیدهای اول و دوم با سوم و چهارم فرقی نمی کند . ولی در حقیقت اگر شکل موج را نزدیک ببریم می بینیم که کلید های 3 و 4 زمانی که میخواهند خروجی را قطع و وصل کنند حدود 20 باری قطع و وصل سریع شده است و بعد ثابت شده است ... برای اینکه این شکل موج های کلید 3و4 را خوب ببینیم ابتدا باید تقسیم زمانی (Time Dev)را روی 0.5 میکرو ثانیه بگذاریم و سپس Play کنیم . کلید 3 یا 4 را به مدت 2 ثانیه نگه دارید و به طور سریع تا کلیک موس را رها کردید کلید Esc را بزنید تا برنامه Pause شود . حالا روی اسکوپ کلیک کنید و با قرقره موس دور و نزدیک کنید و شکل واقعی را مشاهده کنید ...
        مانند شکل زیر


        خوب دوستان این بخش هم به پایان رسید ...
        امیدوارم که خوب توضیح داده باشم
        موفق و سرافراز باشید
        [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
        معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
        معرفی نرم افزار Codewizard PWM
        با من بیشتر آشنا شوید

        دیدگاه


          #5
          چگونه با Rotary Encoders کار کنیم؟؟ (بخش چهارم)

          بخش چهارم :
          در این بخش می پردازیم به آزمایش کردن اتصال روتاری انکودر شبیه سازی شده و میکروی برنامه ریزی شده (برنامه بخش 2).

          آزمایش روتاری انکودر در پروتئوس :

          در این برنامه یک میکرویی را انتخاب میکنیم که از امکانات وقفه خارجی و وقفه PIN Change برخوردار باشد . البته منظور این نیست که حتما از این امکانات برخوردار باشه ، بلکه قصد ما از این کار این است که بدانیم از چه راه هایی میتوان این روتاری انکودرها را راه اندازی کرد . میکرویی که ما انتخاب کردیم ATmega48 می باشد . همانطور که قبلا گفته شد ، از دو راه میتوان ولوم هرزگرد را راه اندازی کرد که ما در اینجا از روش وقفه ای استفاده می کنیم ، که این هم خود به دو دسته تقسیم می شود :
          1: وقفه های خارجی
          2: وقفه PIN Change


          برای دوستانی که نمیدونند وقفه PIN Change چی هست یک توضیح مختصر بدم ...
          PIN Change یکی از بهترین امکانات میکروهای AVR محسوب میشه . PIN Change در حقیقت یک وقفه پورت است و در آن هر تغییری احساس شد ، برنامه وارد روتین وقفه PIN Change میگردد . حال با توجه به تنظیمات در رجیستر شما میتوانید هر کدام از وقفه یک پورت را فعال کنید و از آن استفاده کنید ... مثلا من میخواهم از پینهای 4 تا 7 پورت D استفاده کنم و در این پینها هر گونه تغییری احساس شد وارد یک زیربرنامه بشوم . برای این کار باید وقفهای مورد نظرم(PIN Change) را در پورت D فعال کنم و برنامه مورد نظرم را در آن روتین بریزم ....


          ابتدا همان فایل پروتئوس (نقشه قبلی در بخش 3)را باز کنید و یک save as بسازید و سپس در لیست قطعات، میکروی ATmega48 و Res و Cap را به لیست اضافه کنید.
          یک Virtual Terminal بیاورید و آن را به میکرو mega48 متصل کنید .
          دو برچسب BIDIR که قبلا آنها را به نام PhaseA و PhaseB نامگذاری کردید را جدا کنید و مدار Debounce را به میکروی 8 اضاف کنید و دو برچسب را به خروجی مدار Debounce وصل کنید و حالا از دو برچسب کپی بگیرید و به INT0 و INT1 وصل کنید . 8 کلید را مطابق شکل نامگذاری کنید .

          سپس برنامه ها را وارد کنید و کامپایل کنید ...
          استفاده از وقفه های خارجی :
          برنامه برای Atmel Studio 6.1 :
          کد:
          #include <avr/io.h>
          #include <avr/iom48.h>
          #include <util/delay.h>
          #include <avr/interrupt.h>
          
          uint8_t RE=0 , Status , Counter;
          
          void USART_Transmit( uint8_t data )
          {
          	while ( !( UCSR0A & (1<<UDRE0)) );
          	UDR0 = data;
          }
          void USART_puts(char *str)
          {
          	uint8_t i=0;
          	while(str[i])
          	{
          		USART_Transmit(str[i]);
          		i++;
          	}
          }
          void USART_put_uint8(uint8_t data)
          {
            uint8_t a,b=0,c;
            c=data;
            for(a=0;a<100;a++)
            {
          	  if(c==0)break;
          	  c/=10;
          	  if(b==0)b++;
          	  else b*=10;
            }
            if(b==0)USART_Transmit('0');
            for(a=b;a>0;a/=10)
            {
          	  c = data/a;
          	  data = data - (c*a);
          	  USART_Transmit(c+48);
            }
          }
          #define Enter	\
          {\
          	USART_Transmit(0x0D);\
          	USART_Transmit(0x0A);\
          }
          void Rotary_Encoder(uint8_t Input_PhaseA_PhaseB,uint8_t PIN,uint8_t *Var,uint8_t *Status,uint8_t *Counter)
          {
          	uint8_t bit_Right=0 , x ;
          	x = PIN & Input_PhaseA_PhaseB;
          	for(uint8_t q = 1;q<200;q <<= 1)
          	if(Input_PhaseA_PhaseB & q)
          	{
          		bit_Right = q;
          		break;
          	}
          	if(x < Input_PhaseA_PhaseB)
          	{
          		if(!(x & bit_Right))*Counter += 1;
          		*Status = x;
          	}
          	else if((x == Input_PhaseA_PhaseB) && (*Counter == 2))
          	{
          		if	(*Status == bit_Right)	*Var += 1; // راستگرد
          		else						*Var -= 1; // چپگرد
          		*Status = 0;
          		*Counter= 0;
          	}
          	else
          	{
          		*Status = 0;
          		*Counter = 0;
          	}
          }
          
          ISR(INT0_vect)
          {
          	Rotary_Encoder(0x0C,PIND,&RE,&Status,&Counter);
          } 
          ISR(INT1_vect)
          {
          	Rotary_Encoder(0x0C,PIND,&RE,&Status,&Counter);
          }
          
          int main(void)
          {
            // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity
            // USART Receiver: Off
            // USART Transmitter: On
            // USART0 Mode: Asynchronous
            // USART Baud Rate: 9600
            UCSR0A=0x00;
            UCSR0B=0x08;
            UCSR0C=0x06;
            UBRR0H=0x00;
            UBRR0L=0x33;
          	// External Interrupt(s) initialization
          	// INT0: On Mode: Any change
          	// INT1: On Mode: Any change
          	EICRA=0x05;
          	EIMSK=0x03;
          	EIFR=0x03;
          	PCICR=0x00;
          	sei();
          	uint8_t x=10;	
          	while(1)
            {
          		if(RE!=x)
          		{	
          			USART_puts("RE=");
          			USART_put_uint8(RE);
          			Enter;
          			x=RE;
          		}		
          		_delay_ms(50);
            }
          }
          برنامه برای CodeVision :
          کد:
          /*****************************************************
          Project : Rotary Encoder
          Version : 1.0
          Date  : 4/19/2014
          Author : Saman.Asadi
          
          Chip type        : ATmega48
          AVR Core Clock frequency: 8.000000 MHz
          Memory model      : Small
          External RAM size    : 0
          Data Stack size     : 128
          *****************************************************/
          
          #include <mega48.h>
          #include <stdio.h>
          #include <delay.h>
          
          unsigned char RE=0 , Status , Counter;
          #define Enter \
          {\
            putchar(0x0D);\
            putchar(0x0A);\
          }
          void Rotary_Encoder(unsigned char Input_PhaseA_PhaseB,
                    unsigned char PIN,
                    unsigned char *Var,
                    unsigned char *Status,
                    unsigned char *Counter)
          {
            unsigned char bit_Right=0 ,x ,q ;
            x = PIN & Input_PhaseA_PhaseB;
            for(q = 1;q<200;q <<= 1)
            if(Input_PhaseA_PhaseB & q)
            {
              bit_Right = q;
              break;
            }
            if(x < Input_PhaseA_PhaseB)
            {
              if(!(x & bit_Right))*Counter += 1;
              *Status = x;
            }
            else if((x == Input_PhaseA_PhaseB) && (*Counter == 2))
            {
              if  (*Status == bit_Right)*Var += 1; // راستگرد
              else            *Var -= 1; // چپگرد
              *Status = 0;
              *Counter= 0;
            }
            else
            {
              *Status = 0;
              *Counter = 0;
            }
          }
          interrupt [EXT_INT0] void ext_int0_isr(void)
          {
            Rotary_Encoder(0x0C,PIND,&RE,&Status,&Counter);
          }
          interrupt [EXT_INT1] void ext_int1_isr(void)
          {
            Rotary_Encoder(0x0C,PIND,&RE,&Status,&Counter);
          }
          
          void main(void)
          {
            unsigned char x=10;
            CLKPR=0x80;
            CLKPR=0x00;
            // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity
            // USART Receiver: Off
            // USART Transmitter: On
            // USART0 Mode: Asynchronous
            // USART Baud Rate: 9600
            UCSR0A=0x00;
            UCSR0B=0x08;
            UCSR0C=0x06;
            UBRR0H=0x00;
            UBRR0L=0x33;
          	// External Interrupt(s) initialization
          	// INT0: On Mode: Any change
          	// INT1: On Mode: Any change
          	EICRA=0x05;
          	EIMSK=0x03;
          	EIFR=0x03;
          	PCICR=0x00;
            #asm("sei")
          	while(1)
            {
          		if(RE!=x)
          		{
          			printf("RE=%u",RE);
          			Enter;
          			x=RE;
          		}
          		delay_ms(50);
            }
          }
          برنامه شبیه ساز روتاری انکودر را تغییراتی دادم
          حتما" آن را هم وارد کنید و کامپایل کنید .
          برنامه شبیه سازی روتاری انکودر برای Atmel Studio :
          کد:
          #include <avr/io.h>
          #include <avr/iom8.h>
          #include <util/delay.h>
          
          #define F_CPU		8000000
          #define Set_A		DDRC |= 1
          #define Reset_A		DDRC &= 254
          #define Set_B		DDRC |= 2
          #define Reset_B		DDRC &= 253
          #define Delay		_delay_ms(2);
          #define Delay_Step	_delay_ms(1000);
          #define Bounce_Set_A \
          {\
          	Set_A;\
          	_delay_us(10);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(20);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(30);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(50);\
          	Reset_A;\
          	_delay_us(30);\
          	Set_A;\
          	_delay_us(30);\
          	Reset_A;\
          	_delay_us(20);\
          	Set_A;\
          	_delay_us(10);\
          	Reset_A;\
          	_delay_us(60);\
          	Set_A;\
          	_delay_us(30);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(10);\
          	Reset_A;\
          	_delay_us(20);\
          	Set_A;\
          	_delay_us(20);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(10);\
          }
          #define Bounce_Set_B \
          {\
          	Set_B;\
          	_delay_us(10);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(20);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(30);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(50);\
          	Reset_B;\
          	_delay_us(30);\
          	Set_B;\
          	_delay_us(30);\
          	Reset_B;\
          	_delay_us(20);\
          	Set_B;\
          	_delay_us(10);\
          	Reset_B;\
          	_delay_us(60);\
          	Set_B;\
          	_delay_us(30);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(10);\
          	Reset_B;\
          	_delay_us(20);\
          	Set_B;\
          	_delay_us(20);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(10);\
          }
          #define Bounce_Reset_A \
          {\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(20);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(30);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(50);\
          	Reset_A;\
          	_delay_us(30);\
          	Set_A;\
          	_delay_us(30);\
          	Reset_A;\
          	_delay_us(20);\
          	Set_A;\
          	_delay_us(10);\
          	Reset_A;\
          	_delay_us(60);\
          	Set_A;\
          	_delay_us(30);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(10);\
          	Reset_A;\
          	_delay_us(20);\
          	Set_A;\
          	_delay_us(20);\
          	Reset_A;\
          	_delay_us(10);\
          	Set_A;\
          	_delay_us(10);\
          	Reset_A;\
          	_delay_us(10);\
          }
          #define Bounce_Reset_B \
          {\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(20);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(30);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(50);\
          	Reset_B;\
          	_delay_us(30);\
          	Set_B;\
          	_delay_us(30);\
          	Reset_B;\
          	_delay_us(20);\
          	Set_B;\
          	_delay_us(10);\
          	Reset_B;\
          	_delay_us(60);\
          	Set_B;\
          	_delay_us(30);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(10);\
          	Reset_B;\
          	_delay_us(20);\
          	Set_B;\
          	_delay_us(20);\
          	Reset_B;\
          	_delay_us(10);\
          	Set_B;\
          	_delay_us(10);\
          	Reset_B;\
          	_delay_us(10);\
          }
          
          int main(void)
          {
          	PORTB = 0xFF;
          	while(1)
            {
          		////////////////////////////////////// Bounce is not 
          		if (!(PINB & 1))
          		{
          			Set_A;
          			Delay;
          			Set_B;
          			Delay;
          			Reset_A;
          			Delay;
          			Reset_B;
          			while(!(PINB & 1));
          		}
          		if (!(PINB & 2))
          		{
          			Set_B;
          			Delay;
          			Set_A;
          			Delay;
          			Reset_B;
          			Delay;
          			Reset_A;
          			while(!(PINB & 2));
          		}
          		if (!(PINB & 4))
          		{
          			Set_A;
          			Delay;
          			Set_B;
          			Delay;
          			Reset_A;
          			Delay;
          			Set_B;
          			Delay;
          			Set_A;
          			Delay;
          			Reset_B;
          			Delay;
          			Reset_A;
          			while(!(PINB & 4));
          		}
          		if (!(PINB & 8))
          		{
          			Set_B;
          			Delay;
          			Set_A;
          			Delay;
          			Reset_B;
          			Delay;
          			Set_A;
          			Delay;
          			Set_B;
          			Delay;
          			Reset_A;
          			Delay;
          			Reset_B;
          			while(!(PINB & 8));
          		}
          		////////////////////////////////////// by Bounce
          		if (!(PINB & 16))
          		{
          			Bounce_Set_A;
          			Delay;
          			Bounce_Set_B;
          			Delay;
          			Bounce_Reset_A;
          			Delay;
          			Bounce_Reset_B;
          			while(!(PINB & 16));
          		}
          		if (!(PINB & 32))
          		{
          			Bounce_Set_B;
          			Delay;
          			Bounce_Set_A;
          			Delay;
          			Bounce_Reset_B;
          			Delay;
          			Bounce_Reset_A;
          			while(!(PINB & 32));
          		}
          		if (!(PINB & 64))
          		{
          			Bounce_Set_A;
          			Delay;
          			Bounce_Set_B;
          			Delay;
          			Bounce_Reset_A;
          			Delay;
          			Delay;
          			Bounce_Set_A;
          			Delay;
          			Bounce_Reset_B;
          			Delay;
          			Bounce_Reset_A;
          			while(!(PINB & 64));
          		}
          		if (!(PINB & 128))
          		{
          			Bounce_Set_B;
          			Delay;
          			Bounce_Set_A;
          			Delay;
          			Bounce_Reset_B;
          			Delay;
          			Delay;
          			Bounce_Set_B;
          			Delay;
          			Bounce_Reset_A;
          			Delay;
          			Bounce_Reset_B;
          			while(!(PINB & 128));
          		}
            }
          }
          برنامه شبیه سازی روتاری انکودر برای CodeVision :
          کد:
          #include <mega8.h>
          #include <delay.h>
          
          #define Set_A    DDRC |= 1
          #define Reset_A   DDRC &= 254
          #define Set_B    DDRC |= 2
          #define Reset_B   DDRC &= 253
          #define Delay    delay_ms(2);
          #define Delay_Step delay_ms(1000);
          #define Bounce_Set_A \
          {\
            Set_A;\
            delay_us(10);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(20);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(30);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(50);\
            Reset_A;\
            delay_us(30);\
            Set_A;\
            delay_us(30);\
            Reset_A;\
            delay_us(20);\
            Set_A;\
            delay_us(10);\
            Reset_A;\
            delay_us(60);\
            Set_A;\
            delay_us(30);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(10);\
            Reset_A;\
            delay_us(20);\
            Set_A;\
            delay_us(20);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(10);\
          }
          #define Bounce_Set_B \
          {\
            Set_B;\
            delay_us(10);\
            Reset_B;\
            delay_us(10);\
            Set_B;\
            delay_us(20);\
            Reset_B;\
            delay_us(10);\
            Set_B;\
            delay_us(30);\
            Reset_B;\
            delay_us(10);\
            Set_B;\
            delay_us(50);\
            Reset_B;\
            delay_us(30);\
            Set_B;\
            delay_us(30);\
            Reset_B;\
            delay_us(20);\
            Set_B;\
            delay_us(10);\
            Reset_B;\
            delay_us(60);\
            Set_B;\
            delay_us(30);\
            Reset_B;\
            delay_us(10);\
            Set_B;\
            delay_us(10);\
            Reset_B;\
            delay_us(20);\
            Set_B;\
            delay_us(20);\
            Reset_B;\
            delay_us(10);\
            Set_B;\
            delay_us(10);\
          }
          #define Bounce_Reset_A \
          {\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(20);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(30);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(50);\
            Reset_A;\
            delay_us(30);\
            Set_A;\
            delay_us(30);\
            Reset_A;\
            delay_us(20);\
            Set_A;\
            delay_us(10);\
            Reset_A;\
            delay_us(60);\
            Set_A;\
            delay_us(30);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(10);\
            Reset_A;\
            delay_us(20);\
            Set_A;\
            delay_us(20);\
            Reset_A;\
            delay_us(10);\
            Set_A;\
            delay_us(10);\
            Reset_A;\
          	delay_us(10);\
          }
          #define Bounce_Reset_B \
          {\
          	Reset_B;\
          	delay_us(10);\
          	Set_B;\
          	delay_us(20);\
          	Reset_B;\
          	delay_us(10);\
          	Set_B;\
          	delay_us(30);\
          	Reset_B;\
          	delay_us(10);\
          	Set_B;\
          	delay_us(50);\
          	Reset_B;\
          	delay_us(30);\
          	Set_B;\
          	delay_us(30);\
          	Reset_B;\
          	delay_us(20);\
          	Set_B;\
          	delay_us(10);\
          	Reset_B;\
          	delay_us(60);\
          	Set_B;\
          	delay_us(30);\
          	Reset_B;\
          	delay_us(10);\
          	Set_B;\
          	delay_us(10);\
          	Reset_B;\
          	delay_us(20);\
          	Set_B;\
          	delay_us(20);\
          	Reset_B;\
          	delay_us(10);\
          	Set_B;\
          	delay_us(10);\
          	Reset_B;\
          	delay_us(10);\
          }
          
          void main(void)
          {
          	PORTB = 0xFF;
          	while(1)
            {
          		////////////////////////////////////// Bounce is not 
          		if (!(PINB & 1))
          		{
          			Set_A;
          			Delay;
          			Set_B;
          			Delay;
          			Reset_A;
          			Delay;
          			Reset_B;
          			while(!(PINB & 1));
          		}
          		if (!(PINB & 2))
          		{
          			Set_B;
          			Delay;
          			Set_A;
          			Delay;
          			Reset_B;
          			Delay;
          			Reset_A;
          			while(!(PINB & 2));
          		}
          		if (!(PINB & 4))
          		{
          			Set_A;
          			Delay;
          			Set_B;
          			Delay;
          			Reset_A;
          			Delay;
          			Set_B;
          			Delay;
          			Set_A;
          			Delay;
          			Reset_B;
          			Delay;
          			Reset_A;
          			while(!(PINB & 4));
          		}
          		if (!(PINB & 8))
          		{
          			Set_B;
          			Delay;
          			Set_A;
          			Delay;
          			Reset_B;
          			Delay;
          			Set_A;
          			Delay;
          			Set_B;
          			Delay;
          			Reset_A;
          			Delay;
          			Reset_B;
          			while(!(PINB & 8));
          		}
          		////////////////////////////////////// by Bounce
          		if (!(PINB & 16))
          		{
          			Bounce_Set_A;
          			Delay;
          			Bounce_Set_B;
          			Delay;
          			Bounce_Reset_A;
          			Delay;
          			Bounce_Reset_B;
          			while(!(PINB & 16));
          		}
          		if (!(PINB & 32))
          		{
          			Bounce_Set_B;
          			Delay;
          			Bounce_Set_A;
          			Delay;
          			Bounce_Reset_B;
          			Delay;
          			Bounce_Reset_A;
          			while(!(PINB & 32));
          		}
          		if (!(PINB & 64))
          		{
          			Bounce_Set_A;
          			Delay;
          			Bounce_Set_B;
          			Delay;
          			Bounce_Reset_A;
          			Delay;
          			Delay;
          			Bounce_Set_A;
          			Delay;
          			Bounce_Reset_B;
          			Delay;
          			Bounce_Reset_A;
          			while(!(PINB & 64));
          		}
          		if (!(PINB & 128))
          		{
          			Bounce_Set_B;
          			Delay;
          			Bounce_Set_A;
          			Delay;
          			Bounce_Reset_B;
          			Delay;
          			Delay;
          			Bounce_Set_B;
          			Delay;
          			Bounce_Reset_A;
          			Delay;
          			Bounce_Reset_B;
          			while(!(PINB & 128));
          		}
            }
          }
          خوب
          حالا به میکرو ها آدرس بدید و فرکانس اسیلاتور را روی 8 مگا تنظیم کنید .
          چهار کلید بالا مربوط به حالتهای بدون بانس و چهار کلید پایین هم حالتهای مختلف بانس دار می باشد .
          برنامه را Play کنید .
          و کلید های مورد نظرتان را بزنید .
          همانطور که مشاهده می کنید برنامه در مقابل عملکردهای ناقص هیچ گونه عکس العملی نشان نمیدهد ولی در مقابل عملکردهای صحیح عالی کار میکند .


          خداییش نگاه کردن این شکل موجها چه حالی میده ... :wow:
          [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
          معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
          معرفی نرم افزار Codewizard PWM
          با من بیشتر آشنا شوید

          دیدگاه


            #6
            چگونه با Rotary Encoders کار کنیم؟؟ (ادامه بخش چهارم)

            ادامه بخش چهارم :
            استفاده از وقفه های PIN Change:
            همونطور که تو شبیه سازی ملاحظه می کنید پایه های 4 و 5 میکروی ATmega48 پایه های وقفه PIN Change است که با نامهای PCINT18 و PCINT19 مشخص شده است . بنابراین ما باید وقفه های PCINT18 و PCINT19 را فعال کنیم . برای اینکار باید رجیستر های مربوطه را تغییر دهیم .
            برنامه برای Atmel Studio 6.1 :
            کد:
            #include <avr/io.h>
            #include <avr/iom48.h>
            #include <util/delay.h>
            #include <avr/interrupt.h>
            
            uint8_t RE=0 , Status , Counter;
            
            void USART_Transmit( uint8_t data )
            {
            	while ( !( UCSR0A & (1<<UDRE0)) );
            	UDR0 = data;
            }
            void USART_puts(char *str)
            {
            	uint8_t i=0;
            	while(str[i])
            	{
            		USART_Transmit(str[i]);
            		i++;
            	}
            }
            void USART_put_uint8(uint8_t data)
            {
            	uint8_t a,b=0,c;
            	c=data;
            	for(a=0;a<100;a++)
            	{
            		if(c==0)break;
            		c/=10;
            		if(b==0)b++;
            		else b*=10;
            	}
            	if(b==0)USART_Transmit('0');
            	for(a=b;a>0;a/=10)
            	{
            		c = data/a;
            		data = data - (c*a);
            		USART_Transmit(c+48);
            	}
            }
            #define Enter	\
            {\
            	USART_Transmit(0x0D);\
            	USART_Transmit(0x0A);\
            }
            void Rotary_Encoder(uint8_t Input_PhaseA_PhaseB,uint8_t PIN,uint8_t *Var,uint8_t *Status,uint8_t *Counter)
            {
            	uint8_t bit_Right=0 , x ;
            	x = PIN & Input_PhaseA_PhaseB;
            	for(uint8_t q = 1;q<200;q <<= 1)
            	if(Input_PhaseA_PhaseB & q)
            	{
            		bit_Right = q;
            		break;
            	}
            	if(x < Input_PhaseA_PhaseB)
            	{
            		if(!(x & bit_Right))*Counter += 1;
            		*Status = x;
            	}
            	else if((x == Input_PhaseA_PhaseB) && (*Counter == 2))
            	{
            		if	(*Status == bit_Right)	*Var += 1; // راستگرد
            		else						*Var -= 1; // چپگرد
            		*Status = 0;
            		*Counter= 0;
            	}
            	else
            	{
            		*Status = 0;
            		*Counter = 0;
            	}
            }
            
            ISR(PCINT2_vect)
            {
            	Rotary_Encoder(0x0C,PIND,&RE,&Status,&Counter);
            }
            
            int main(void)
            {
            	// USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity
            	// USART Receiver: Off
            	// USART Transmitter: On
            	// USART0 Mode: Asynchronous
            	// USART Baud Rate: 9600
            	UCSR0A=0x00;
            	UCSR0B=0x08;
            	UCSR0C=0x06;
            	UBRR0H=0x00;
            	UBRR0L=0x33;
            	// External Interrupt(s) initialization
            	// PCINT18 : on
            	// PCINT19 : on
            	EICRA=0x00;
            	EIMSK=0x00;
            	PCICR=0x04;
            	PCMSK2=0x0C;
            	PCIFR=0x04;
            	sei();
            	uint8_t x=10;
            	while(1)
            	{
            		if(RE!=x)
            		{
            			USART_puts("RE=");
            			USART_put_uint8(RE);
            			Enter;
            			x=RE;
            		}
            		_delay_ms(50);
            	}
            }
            برنامه برایCodeVision :
            کد:
            /*****************************************************
            Project : Rotary Encoder
            Version : 1.0
            Date  : 4/19/2014
            Author : Saman.Asadi
            
            Chip type        : ATmega48
            AVR Core Clock frequency: 8.000000 MHz
            Memory model      : Small
            External RAM size    : 0
            Data Stack size     : 128
            *****************************************************/
            
            #include <mega48.h>
            #include <stdio.h>
            #include <delay.h>
            
            unsigned char RE=0 , Status , Counter;
            #define Enter \
            {\
              putchar(0x0D);\
              putchar(0x0A);\
            }
            void Rotary_Encoder(unsigned char Input_PhaseA_PhaseB,
                      unsigned char PIN,
                      unsigned char *Var,
                      unsigned char *Status,
                      unsigned char *Counter)
            {
              unsigned char bit_Right=0 ,x ,q ;
              x = PIN & Input_PhaseA_PhaseB;
              for(q = 1;q<200;q <<= 1)
              if(Input_PhaseA_PhaseB & q)
              {
                bit_Right = q;
                break;
              }
              if(x < Input_PhaseA_PhaseB)
              {
                if(!(x & bit_Right))*Counter += 1;
                *Status = x;
              }
              else if((x == Input_PhaseA_PhaseB) && (*Counter == 2))
              {
                if  (*Status == bit_Right)*Var += 1; // راستگرد
                else            *Var -= 1; // چپگرد
                *Status = 0;
                *Counter= 0;
              }
              else
              {
                *Status = 0;
                *Counter = 0;
              }
            }
            interrupt [PC_INT2] void pin_change_isr2(void)
            {
              Rotary_Encoder(0x0C,PIND,&RE,&Status,&Counter);  
            }
            void main(void)
            {
              unsigned char x=10;
              CLKPR=0x80;
              CLKPR=0x00;
              // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity
              // USART Receiver: Off
              // USART Transmitter: On
              // USART0 Mode: Asynchronous
              // USART Baud Rate: 9600
              UCSR0A=0x00;
              UCSR0B=0x08;
              UCSR0C=0x06;
              UBRR0H=0x00;
              UBRR0L=0x33;
              // External Interrupt(s) initialization
              //PCINT18 : on
              //PCINT19 : on
              EICRA=0x00;
              EIMSK=0x00;
              PCICR=0x04;
              PCMSK2=0x0C;
              PCIFR=0x04;
              #asm("sei")
            	while(1)
              {
            		if(RE!=x)
            		{
            			printf("RE=%u",RE);
            			Enter;
            			x=RE;
            		}
            		delay_ms(50);
              }
            }
            این هم مثل برنامه قبل امتحانش کنید و با آن کار کنید ...
            --------------------------------------------------------------------
            خوب عزیزان این بخش هم به پایان رسید :wow:
            امیدوارم که خوب توضیح داده باشم ... :redface:
            موفق و کامیاب باشید
            [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
            معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
            معرفی نرم افزار Codewizard PWM
            با من بیشتر آشنا شوید

            دیدگاه


              #7
              پاسخ : چگونه با ولومهای هرزگرد(Rotary Encoders)کار کنیم؟ [آموزشی] "کافیه یکبار بخوانید"

              با تشکر از دوست گرامی

              یک اموزش مفید و کامل بود
              امیدوارم باز هم شاهد اموزش های شما دوست گرامی باشیم

              دیدگاه


                #8
                پاسخ : چگونه با ولومهای هرزگرد(Rotary Encoders)کار کنیم؟ [آموزشی] "کافیه یکبار بخوانید"

                ---
                اگر روزی بفهمی همه چیزایی که از بچگی تا حالا بهت گفتن بی اساس یا دروغه چه حالی میشی؟
                کارمندان نابکار، از دزدان و آشوبگران بیشتر به کشور آسیب ميآ‌رسانند

                دیدگاه


                  #9
                  پاسخ : چگونه با ولومهای هرزگرد(Rotary Encoders)کار کنیم؟ [آموزشی] "کافیه یکبار بخوانید"

                  نوشته اصلی توسط ناصر منتظری
                  oo: oo: oo:
                  عنوان تاپیک رو ببین لطفا و یه بار بخون لطفا و پست بی مورد نده لطفا :angry: !!

                  با تشکر فراوان از سامان اسدی عزیز به خاطر مطالب فوق العادش :applause: :applause: :applause:
                  با تشکر از دوست گرامی و مطلب اموزشیشون در سایت
                  من چندین بار تو انجمن دیدم به روتاری انکودر ها به اشتباه میگن ولوم هرزگرد! اقای رهایی هم درست ایراد گرفتند-ولوم هرزگرد جریانش کاملا با روتاری انکودر متفاوت هست و قیمت ولوم هرزگرد هم خیلی خیلی بالاتره! از 100 تومن شروع میشه تا چند میلیون!!! بهتر هست عنوان تاپیک اصلاح و روتاری انکودر باقی بمونه!

                  دیدگاه


                    #10
                    پاسخ : چگونه با ولومهای هرزگرد(Rotary Encoders)کار کنیم؟ [آموزشی] "کافیه یکبار بخوانید"

                    ممنون دوستان
                    نمیدونم چرا هر آموزشی که میخوام بدم همیشه خوب که میگردم اون مطالبی هم که تو انجمن هست تو تورم نمیخوره ؟؟؟
                    مثلا همین تاپیک که میخواستم باز کنم خیلی تو انجمن گشتم ولی چیز خوبی پیدا نکردم ...
                    یه بنده خدایی همون اوایل یه پیام خصوصی داد ولی من زیاد توجه نکردم ... البته اینو بگم که اون لینک مربوط میشد به یک تاپیکی که توی اون زیاد محتوایی نداشت ولی توی اون تاپیک یک لینک رو گذاشته بودن که آقای شهرام نوربخش راد درباره همین مطالب یه توضیح داده بودند و حتی یک کتابخونه هم نوشته بودند!! ، ولی من قبلش ندیده بودم ...
                    http://www.eca.ir/forum2/index.php?topic=64260.msg367962#msg367962
                    http://www.eca.ir/forum2/index.php?topic=64260.msg368165#msg368165
                    http://www.eca.ir/forum2/index.php?topic=64260.msg371452#msg371452
                    جا داره همینجا از استاد بزرگ آقای شهرام نوربخش راد تشکر کنم ... :applause:

                    نوشته اصلی توسط داود رهایی
                    خب دلیلی که چیزی پیدا نکردید شاید این باشه که اسمش رو اشتباه دارید میگید
                    بله ... دقیقا همه رو سرچ کردم ...
                    این رو هم بگم که بیشتر موقع ها سایت یا بالا نمیاد یا نمیشه جستجو کنیم یا پستی میخوایم جواب بدیم اصلا بالا نمیاد و ...
                    خلاصه اینکه اعصابم میشه
                    نوشته اصلی توسط داود رهایی
                    اسم اینها ولوم نیست بلکه روتاری انکودر هست
                    اسمهای مختلفی هست
                    Rotary encoder switch
                    Volume Rotary Encoder
                    Rotary Encoder
                    خیلی خوشحال میشم که برای این قطعه یک واژه فارسی پیدا کنیم ... :applause:
                    ---------------------------------------------------------------------------------------------------------------
                    نوشته اصلی توسط voyager2020
                    من چندین بار تو انجمن دیدم به روتاری انکودر ها به اشتباه میگن ولوم هرزگرد! اقای رهایی هم درست ایراد گرفتند-ولوم هرزگرد جریانش کاملا با روتاری انکودر متفاوت هست و قیمت ولوم هرزگرد هم خیلی خیلی بالاتره! از 100 تومن شروع میشه تا چند میلیون!!! بهتر هست عنوان تاپیک اصلاح و روتاری انکودر باقی بمونه!
                    به روی چشم ... اصلاح کردم
                    [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
                    معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
                    معرفی نرم افزار Codewizard PWM
                    با من بیشتر آشنا شوید

                    دیدگاه


                      #11
                      پاسخ : چگونه با Rotary Encoders کار کنیم؟ [آموزشی]

                      سلام.
                      یه خرده دیره واسه جواب دادن، ولی خواستم بگم نسخه ی راه اندازی روتاری سوئیچ با میکرو PIC هم داریم واسه متقاضیان! :nerd:

                      راه اندازی روتاری سوئیچ(ولوم هرزگرد) با PIC16F628A

                      منم اسم تاپیک رو عوض کنم یا همین خوبه؟

                      دیدگاه


                        #12
                        پاسخ : چگونه با Rotary Encoders کار کنیم؟ [آموزشی]

                        نوشته اصلی توسط شاهرخ مستقیمی
                        سلام.
                        یه خرده دیره واسه جواب دادن، ولی خواستم بگم نسخه ی راه اندازی روتاری سوئیچ با میکرو PIC هم داریم واسه متقاضیان! :nerd:

                        راه اندازی روتاری سوئیچ(ولوم هرزگرد) با PIC16F628A

                        منم اسم تاپیک رو عوض کنم یا همین خوبه؟
                        سلام
                        ممنون که لینک دادید
                        والا همونطور که مشاهده کردید عنوان تاپیک تقریبا مثل شما بود ولی به دلیل پیشنهاد دوستان اون رو عوض کردم ...
                        فکر کنم این اسم مناسبتر باشه
                        Volume Rotary Encoder
                        نظر شما چیه؟
                        [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
                        معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
                        معرفی نرم افزار Codewizard PWM
                        با من بیشتر آشنا شوید

                        دیدگاه


                          #13
                          پاسخ : چگونه با Rotary Encoders کار کنیم؟ [آموزشی]

                          فکر کنم روتاری انکدر یا روتاری سوئیچ (ولوم هرزگرد قدیم!! :mrgreen: ) خوب باشه!

                          دیدگاه


                            #14
                            پاسخ : چگونه با Rotary Encoders کار کنیم؟ [آموزشی]

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

                            میخواستم با اجازتون کد خودمو بذارم واسه اونایی که قصد دارن تو عمل استفادش کنن ولی درست جواب نگرفتن!
                            فقط کافیه این یه تیکه رو با یه سری معرفی ها (در حد 3-4 خط) تو برنامه اضافه کنن.همین!
                            توضیح برنامه :
                            من با یه مگا128 کار میکنم که واسه انکودر وقفه خارجیش رو تو حالت anychange فعال کردم و یکی از خروجی های انکودر رو به این وقفه وصل کردم و خروجی دیگش رو به یه پایه دلخواه( اینجا من وقفه رو روی PE.4 و پایه دلخواهمو PE.7 در نظر گرفتم)
                            هر تیک چرخش و تغییر سطح در خروجی انکودر(که به وقفه خارجی وصله) وقفه رو فعال میکنه.
                            به خاطر اختلاف زمانی که دو خروجی با هم دارن، بسته به اینکه روتاری از کدوم طرف چرخیده باشه اون دوتا پایه مقادیر مختلفی نسبت به هم میتونن داشته باشن
                            تو لحظه ای که وقفه اتفاق می افته PORTE رو روی یه متغیر save میکنم که اون حالت اولیه رو از دست ندم
                            بعد اون دوتا بیت که مربوط به پایه های خروجی انکودر هست رو جدا میکنم
                            بعد چک میکنم که از کدوم طرف چرخیده و بنا به نتیجش متغیر rotary رو کم یا زیاد میکنم
                            کد:
                            interrupt [EXT_INT4] void ext_int4_isr(void){
                                pe_save=PINE;
                                pe_save&=0x90;
                                if(pe_save==0x80 || pe_save==0x10) {
                                  ++rotary;
                                  return;
                                  }
                                if(pe_save==0x90 || pe_save==0x00){
                                  --rotary;
                                  return;
                                  }
                                }
                            تنها تغییری که شما باید تو برنامه بدین اینه :
                            1- دوتا متغیر pe_save و rotary رو تعریف کنین
                            2- تنظیمات رجیسترهای مربوط به وقفه خارجی رو روی حالت anychange انجام بدین (فقط یک وقفه کافیه)
                            3- اگه از میکروی دیگه ای استفاده میکنین اسم پورت و شماره پایه وقفه عوض میشه

                            اگه متوجه توضیحاتم نشدین بگین تا بیشتر توضیح بدم :biggrin:

                            دیدگاه


                              #15
                              پاسخ : چگونه با Rotary Encoders کار کنیم؟ [آموزشی]

                              خیلی ممنون از اینکه نظرتون رو اعلام میکنید ...
                              نوشته اصلی توسط ameen.kh
                              فقط یه مساله ای هست ، اینکه روتاری هایی که توی بازار هستندطرز کارشون به این صورت نیست
                              نمیدونم حالا اینایی که ما داریم اینطوریه یا همش :biggrin:
                              ولی من چند مدل امتحان کردم و همش مثل هم بود
                              :redface: پناه بر خدا ... مگه روتاری اینکدر شما چطوریه؟
                              فقط قبل از اینکه بحثی صورت بگیره این رو لازم میدونم بگم ...
                              سه نوع ولوم روتاری انکودر وجود داره که من خودم شخصا دو نمونه اول رو دیدم
                              نوع اول که در این تاپیک کاملا بحث شده و بیشتر عمومی هست ...
                              نوع دوم که همین دو هفته پیش رفتم تهران خریدم (برنامه آن ساده تره)
                              و نوع سوم که ندیدم تا حالا ....
                              دلیل این که میگید همه مثل هم بوده به خاطر اینه که با اهم متر فقط تستش کردید ...
                              دوستان برای اینکه بهتر متوجه بشوید که شکل موج به چه صورتی هست و بهتر آن را درک کنید مدار زیر را ببندید و مشاهده کنید .
                              مدار خیلی ساده ...
                              خوب حالا خیلی آروم آروم ولوم رو بچرخونید و هر دفعه روی هر دندانه صبر کنید ...
                              میبینید و مشاهده میکنید که شکل موج به چه صورتی است ... و از همه مهمتر بهتر درک میکنید ...
                              حالا من خودم از نوع اول و دوم استفاده کردم و دیدم که با هم تفاوت دارند ...
                              بگذریم ...
                              نوشته اصلی توسط ameen.kh
                              نمیدونم شما هم به صورت عملی تست کردی یا نه!
                              بله ... جواب هم گرفتم ...
                              نوشته اصلی توسط ameen.kh
                              تو عمل ،روتاری پالسی نمیده! بلکه با هر تیک چرخش، هر دو خروجیش تغییر لول پیدا میکنن و این تغییر لول با یه اختلاف زمانی کوچکی انجام میشه.
                              تاپیکم رو کامل بخونید متوجه می شوید که من در هیچ جای این تاپیک نگفته ام که این قطعات پالس درست میکنه ...
                              اون مداری هم که میبینید به خاطر این هست که چون در پروتئوس این قطعه نداشتیم ، خواستم به صورت عملی تر شبیه سازی کنم ...
                              نوشته اصلی توسط ameen.kh
                              ولی تا یه تیک دیگه نچرخه، سطح ولتاژ خروجی به حالت قبلی بر نمیگرده!
                              اون ولومی هم که شما خریدید از نوع دوم هست ...
                              نوشته اصلی توسط ameen.kh
                              برنامش هم اصلا پیچیده نیست، نه نیازی به هدر فایل داره نه به این همه روش های مختلف واسه دیبانس!
                              من فقط روش سخت افزاری رو پیشنهاد دادم ... که دلیل اون هم همونطور که میدونید اگر مدار دیبانس گذاشته نشه برنامه چندبار به روتین وقفه رفته واین باعث میشود که پردازش بیشتر صورت گیرد ... ولی اگر مدار دیبانس بگذاریم فقط یکبار به روتین مربوطه می رود ...
                              نوشته اصلی توسط ameen.kh
                              البته من چون خودم تو عمل ازش به خوبی جواب گرفتم اینو میگم وگرنه اصلا قصد جسارت ندارم :biggrin: :biggrin: :biggrin:
                              نه بابا ... این چه حرفیه ... اتفاقا" حال میکنم با این موج های منفی ... چون بادبادک وقتی بالا میره که با باد مخالف روبرو بشه !!!
                              نوشته اصلی توسط ameen.kh
                              میخواستم با اجازتون کد خودمو بذارم واسه اونایی که قصد دارن تو عمل استفادش کنن ولی درست جواب نگرفتن!
                              فقط کافیه این یه تیکه رو با یه سری معرفی ها (در حد 3-4 خط) تو برنامه اضافه کنن.همین!
                              خواهش میکنم ... صاحب اجازه هستید عزیز ...
                              نوشته اصلی توسط ameen.kh
                              توضیح برنامه :
                              من با یه مگا128 کار میکنم که واسه انکودر وقفه خارجیش رو تو حالت anychange فعال کردم و یکی از خروجی های انکودر رو به این وقفه وصل کردم و خروجی دیگش رو به یه پایه دلخواه( اینجا من وقفه رو روی PE.4 و پایه دلخواهمو PE.7 در نظر گرفتم)
                              هر تیک چرخش و تغییر سطح در خروجی انکودر(که به وقفه خارجی وصله) وقفه رو فعال میکنه.
                              به خاطر اختلاف زمانی که دو خروجی با هم دارن، بسته به اینکه روتاری از کدوم طرف چرخیده باشه اون دوتا پایه مقادیر مختلفی نسبت به هم میتونن داشته باشن
                              تو لحظه ای که وقفه اتفاق می افته PORTE رو روی یه متغیر save میکنم که اون حالت اولیه رو از دست ندم
                              بعد اون دوتا بیت که مربوط به پایه های خروجی انکودر هست رو جدا میکنم
                              بعد چک میکنم که از کدوم طرف چرخیده و بنا به نتیجش متغیر rotary رو کم یا زیاد میکنم
                              کد:
                              interrupt [EXT_INT4] void ext_int4_isr(void){
                                  pe_save=PINE;
                                  pe_save&=0x90;
                                  if(pe_save==0x80 || pe_save==0x10) {
                                    ++rotary;
                                    return;
                                    }
                                  if(pe_save==0x90 || pe_save==0x00){
                                    --rotary;
                                    return;
                                    }
                                  }
                              تنها تغییری که شما باید تو برنامه بدین اینه :
                              1- دوتا متغیر pe_save و rotary رو تعریف کنین
                              2- تنظیمات رجیسترهای مربوط به وقفه خارجی رو روی حالت anychange انجام بدین (فقط یک وقفه کافیه)
                              3- اگه از میکروی دیگه ای استفاده میکنین اسم پورت و شماره پایه وقفه عوض میشه

                              اگه متوجه توضیحاتم نشدین بگین تا بیشتر توضیح بدم :biggrin:
                              البته من هنوز این تاپیک رو کامل نکرده بودم ... ولوم نوع دوم رو از بازار خریدم و میخواستم برنامه اون رو بگذارم که شما دیگه پیش دستی کردید ...
                              انشالله وقت کردم کاملترش هم میکنم ...
                              ممنون

                              موفق و پاینده باشید
                              [b]چگونه همه پایه های میکروکنترلر AVR را PWM کنیم؟
                              معرفی نرم افزارEasy 7segment (برای راه اندازی آسانتر 7segment )
                              معرفی نرم افزار Codewizard PWM
                              با من بیشتر آشنا شوید

                              دیدگاه

                              لطفا صبر کنید...
                              X