analyse signal to detect left or right

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

heej guys,

the problem is that i need to write in c a way to detect if a motor goes to the left or to the right.

There is a magnet on the top to the motor with 2 hall sensors. with those signals i can detect if a motor rotates to the left or to the right.

to the right:
signal 1 = __|--|__|--|__
signal 2 = ___|--|__|--|__

to the left:
signal 1 = __|--|__|--|__
signal 2 = _|--|__|--|__

i put the signals on 2 EXT interrupts, INT0 and INT1.
i toggle 2 variables in the interrupts: Sig1 in INT0 and Sig2 in INT1. The Interrupt sense control is on 'any logic change'. this way i can detect 4 diffent states in 1 periode.

           |----|    |----|
signal1  __|    |____|    |__
             |----|    |----|
signal2  ____|    |____|    |__
            A  B C  D

a: sig1 = 1 and sig2 =0
b: sig1 = 1 and sig2 =1
c: sig1 = 0 and sig2 =1
d: sig1 = 0 and sig2 =0

what i do is: i wait for a certain state and give that number 1, the second states what comes had number 2, i this till i have all 4 states. the codes comes after this. if things aint clear plz ask ^^


#include 
static volatile unsigned int Sig1, Sig2, timer;

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// The Signal connected to INTO0 is Signal 1
Sig1 = !Sig1;
++timer;
}

// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
// The Signal connected to INT1 is Signal 2
Sig2 = !Sig2;
++timer;

}

// Declare your global variables here
int countA, countB, countC, countD, chk1, chk2;
void main(void)
{
  // Declare your local variables here

  // interrupt settings for INT0 & INT1
  GICR=0xF0;
  MCUCR=0x05;
  MCUCSR=0x00;

  // Port declaration
  DDRB = 0xFF;   //  We put port A pins in output mode  
  PORTB = 0xFF;   // put all leds in off state 
  DDRD = 0x00;    // We put port D pins in input mode  
  PORTD = 0xFF; //  we activate the internal pull-up  

  // Global enable interrupts
  #asm("sei") 
  
  timer = 0;
  Sig1 = 0;
  Sig2 = 0;
  chk1 = 0;
  chk2 =0;

while (1)
  {
      //response on the Sig1 and Sig2
      
        if(Sig1 ==1 & Sig2 ==0) // i do this to 
                                  see in what order
                                  the states come.
          {
          countA = timer;
          PORTB.7 = !PORTB.7;
          }
        if(Sig1 == 1 & Sig2 ==1)
          {
          countB = timer;
          PORTB.6 = !PORTB.6;
          }
        if(Sig1 ==0 & Sig2 == 1)
          {
          countC = timer;
          PORTB.5 = !PORTB.5;
          }
        if(Sig1 ==0 & Sig2 ==0)
          {
          countD = timer;
          PORTB.4 = !PORTB.4;
          }
      
      // check if rotation is right
     if(countA < countB)
       {
       chk1 = 1;
       }
     if(chk1==0)
       {
       timer = 0;
       countA =0;
       countB =0;
       countC =0;
       countD =0;
       }
     if(chk1== 1)
       {
       if(countB < countC)
         {
         chk2 =1;
         }
       }
     if(chk2 == 1)
       {
       if(countC < countD)
         {
         PORTB.0 = 0; 
         PORTB.3 = 0;
         chk1 = 0;
         chk2 = 0; 
         timer = 0; 
         countA =0;
         countB =0;
         countC =0;
         countD = 0;
         } 
       }        
     // check if rotation is left
     if(countC < countB)
       {
       chk1 = 1;
       }
     if(chk1==0)
       {
       timer = 0;
       countA =0;
       countB =0;
       countC =0;
       countD =0;
       }
     if(chk1== 1)
       {
       if(countB < countA)
         {
         chk2 =1;
         }
       }
     if(chk2 == 1)
       {
       if(countA < countD)
         { 
         PORTB.3 = 0;
         PORTB.0 = 1;
         chk1 = 0;
         chk2 = 0; 
         timer = 0;
         countA =0;
         countB =0;
         countC =0;
         countD = 0;
         }
       }

  
  
  }    
            
}

this code itn't working, but i don't know an onther way to detect if the rotation goes to the left or right.

hopely you guys can help me out with idea's :), thanks

Robbin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is called a 'quadrature encoder' -there's been deep discussion on this, so do a search and ye will find.

I Googled on 'quadrature encoder avr' and found this:

http://hubbard.engr.scu.edu/avr/...

code already written and documented - problem solved.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ah thanks ^^,

i looked at the page and its good and easy writen. when i have it working, then i will look if i can get it also working with if-statements.

Robbin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#include 
#include 


#define PHASE_A	(PINC & 1<<PINC0)	// PINC.0
#define PHASE_B (PINC & 1<<PINC1)	// PINC.1


volatile char	enc_delta;		// -128 ... 127


int main( void )
{
  TCCR0 = 1<<CS01;			//divide by 8 * 256
  TIMSK = 1<<TOIE0;			//enable timer interrupt

  DDRB = 0xFF;
  sei();
  for(;;)				// main loop
    PORTB = enc_delta;
}


SIGNAL (SIG_OVERFLOW0)
{
  static char enc_last = 0x01;
  char i = 0;

  if( PHASE_A )
    i = 1;

  if( PHASE_B )
    i ^= 3;				// convert gray to binary

  i -= enc_last;			// difference new - last

  if( i & 1 ){				// bit 0 = value (1)
    enc_last += i;			// store new as next last

    enc_delta += (i & 2) - 1;		// bit 1 = direction (+/-)
  }
}

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry danni, but i don't really understand your code, what it is doing.

and about the quadrature, it wasn't as easy as i thought, so i'm trying to write my own code.

i have a question about the interrupt settings, is it oke if i change it during the code. cause when the motor starts i don't know in which state it is, so if i set it first on 'rising egde' and after that on 'any logic change' to make the program better.

what do you guys think ?

Robbin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No problem changing the sense in the ISR, but do it as early as possible in the ISR. Also clear the interrupt flag right after that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Only for direction detect:

Set connect one line as an interrupt.
Only on one edge triggering.
in the ISR only read the state of the other line. The state shows you the direction.

In hardware one uses a simple D-Flipflop: One line is CLK the other is D. Q gives the direction.

Klaus
********************************
Look at: www.megausb.de (German)
********************************

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is possible to detect 4 positions or states per cycle in that waveform... this is called x4 mode... code is a little simpler if you just look for two states per cycle... x2 mode....If you look for a falling edge on A, then inc or dec position on state of B, the code is very compact.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

for every state i let burn a led, this way i can see which patern it has and if it is rotating to the right or left. but the programm has to do this.

i tried allot of things and everything it didn't work like:

i placed a timer in everystate, the timer in state A is lower then in state B, cause state A comes for state B, when the motor rotates the other way, B is bigger then A. i thought that this would work, i placed both in an if-statment seperated. but it didn't work :(.

is there something else what i can try, let me know.

thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Make sure the inputs are well debounced when using interrupts.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i have 2 clear signals which are on INT0 and on INT1, i displayed them on the oscilloscope and the signals are nice ^^, so that's not the problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
i have 2 clear signals which are on INT0 and on INT1, i displayed them on the oscilloscope and the signals are nice ^^, so that's not the problem.

What frequency do you see?
Your program above seems to poll the signals.
you must read the ports at least 4 times the max. frequency of (one of) your input signal.

Klaus
********************************
Look at: www.megausb.de (German)
********************************

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

freq is only 85hz, cause i give the motor only 5v so the rotation is pretty slow. the STK500 works on 3.68mhz.

the problem ain't getting good signals, cause i can see in what states it gets and every state is every time visible.

i'm gonna try 2morrow something else, hopefully it works.

Robbin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Provak wrote:
sorry danni, but i don't really understand your code, what it is doing.

The code is very easy and short:

If you see both signals as a two bit number, you get the following numbers:

left: 0 - 1 - 3 - 2 - 0
right: 0 - 2 - 3 - 1 - 0

This code was named Gray code because only one bit alter at a time.
Unfortunately this code can not be used for arithmetic.
Thus it was converted to binary to get the following order:

left: 0 - 1 - 2 - 3 - 0
right: 0 - 3 - 2 - 1 - 0

Then you can substract the new state - previous state.

left:
0 - 1 = -1
1 - 2 = -1
2 - 3 = -1
3 - 0 = -1 (3 = -1 as signed two bit number)

right:
1 - 0 = 1
2 - 1 = 1
3 - 2 = 1
0 - 3 = 1 (wrap around)

This difference was then added to the count value.

Thats all.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hmm didn't thought that it was that easy :), thanks Peter!!

Robbin