اطلاعیه

Collapse
No announcement yet.

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

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

  • SAMAN.ASADI
    replied
    چگونه با 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:

    یک دیدگاه بنویسید:


  • SAMAN.ASADI
    replied
    چگونه با 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 شود . حالا روی اسکوپ کلیک کنید و با قرقره موس دور و نزدیک کنید و شکل واقعی را مشاهده کنید ...
    مانند شکل زیر


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

    یک دیدگاه بنویسید:


  • SAMAN.ASADI
    replied
    چگونه با 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 میپردازیم به شبیه سازی مدار
    موفق باشید

    یک دیدگاه بنویسید:


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

    با تشکر

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

    یک دیدگاه بنویسید:


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

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

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


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

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


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

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

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

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

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

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