Jump to content
Sign in to follow this  
h20

Reluctance machine position

Recommended Posts

Hello,

 

I'm iniciating myself on MSP430 programming and my first work is trying to make a program to read and save the position of a reluctance machine.

The sheme of the reluctance machine is shown in the picture below.

 

semtulotzl.jpg

 

Under the reluctance machine are 2 square waves that represent the output of 2 encoders.

If the machine moves to the right, the encoder's outputs are as shown in the first 2 waves.

If the machine moves to the left, the encoder's outputs are as shown in the last 2 waves.

Every times the machine goes any side, it increments or decrements an variable 'i'; if 'i' is negative, machine moved to the left, if 'i' positive, the machine moved to the right.

 

I've already made a program, but i would like to know if it will work and if something is wrong.

I've used P1 and P2 interrupts because i think it's the easiest way to implement this..

If another solution is possible, please teach me how :)

 

Thank you so much.

 

Here's the program i wrote:

 

 

#include

 

char i;

 

void main(void)

{

 

WDTCTL = WDTPW + WDTHOLD; // stop watchdor timer

P1DIR = 0x01; // P1.0 as input - encoder A

P2DIR = 0x01; // P2.0 as input - endoder B

P1IE |= 0x01; // P1.0 interrupt enable

P2IE |= 0x01; // P2.0 interrupt enable

P1IES &= ~0x01; // P1.0 low/high edge

P2IES &= ~0x01; // P2.0 low/high edge

P1IFG &= ~0x01; // P1.0 IFG reset

P2IFG &= ~0x01; // P2.0 IFG reset

 

_BIS_SR(GIE);

 

while(1);

}

 

#pragma vector=PORT1_VECTOR

__interrupt void Port_1 (void)

{

if (P2IFG & 0x01) // if P2IFG is set and as P1IFG is already set (because this is inside P1 interrupt vector)

{

 

i--; //the machine moved left

P2IFG &= ~0x01;

 

}

else

i++; // else, if P1IFG is unset, machine moved right (first step of the machine when is at position 0)

}

 

#pragma vector=PORT2_VECTOR

__interrupt void Port_2 (void)

{

if (P1IFG & 0x01) // if P1IFG is set and as P2IFG is already set (because this is inside P2 interrupt vector)

{

 

i++; //the machine moved right

P1IFG &= ~0x01;

 

}

else

i--; // else, if P1IFG is unset, machine moved left (first step of the machine when is at position 0)

}

 

P.S: I just saw that i might have posted in the wrong section.. I'm very sorry about that.. Please remove this post if so. I'll post it in the correct section :) Thank you.

Share this post


Link to post
Share on other sites

The encode you described is sometimes refereed as "A quad B" encoder. But I do not understand what are V1, V2, and V3 in the picture your posted.

 

Using P1 and P2 interrupt is good. But your code has a few problems.

 

You misunderstood the bits in DIR register. 1 means output, 0 means input.

 

You also mishandled the IFG register. Inside the ISR, you need to clear its own IFG, otherwise it will generate another interrupt the moment the CPU returns from that ISR. You should not clear the other guys IFG. Doing that will prevent the other ISR from being entered.

 

Your logic to decide i++ or i-- is also wrong. At the edge of A, you need to examine the level of B, not IFG of B. At the edge of B, you need to examine the level of A, not IFG of A.

 

After you fix the above problems, your code may work. But you are not getting the best resolution out of A-quad-B because you did not watch the other edge of the signals.

 

It is a good start!

 

-- OCY

Share this post


Link to post
Share on other sites
The encode you described is sometimes refereed as "A quad B" encoder. But I do not understand what are V1, V2, and V3 in the picture your posted.

 

Using P1 and P2 interrupt is good. But your code has a few problems.

 

You misunderstood the bits in DIR register. 1 means output, 0 means input.

 

You also mishandled the IFG register. Inside the ISR, you need to clear its own IFG, otherwise it will generate another interrupt the moment the CPU returns from that ISR. You should not clear the other guys IFG. Doing that will prevent the other ISR from being entered.

 

Your logic to decide i++ or i-- is also wrong. At the edge of A, you need to examine the level of B, not IFG of B. At the edge of B, you need to examine the level of A, not IFG of A.

 

After you fix the above problems, your code may work. But you are not getting the best resolution out of A-quad-B because you did not watch the other edge of the signals.

 

It is a good start!

 

-- OCY

 

The V1, V2 and V3 was just to exemplify that there were three recluctance components, it's not important :)

 

About DIR register, i did understood it.. i just made an error when copying my program to here :P

 

I also understood what you meant by not cleaning P2IFG in P1 interrupt routine and vice-versa. Altough, i can't figure out how to read the level of B in P1 ISR and the level of A in P2 ISR withou using the IFG, and after that how to save the moviment of the machine in a variable.. How can i accomplish that?

 

Thank you so much for your tips :)

Share this post


Link to post
Share on other sites

Quadrature encoders are pretty common these days, though most of us don't even realize we are using one, car radios, receivers, musical equipment, just FYI :)

 

As OCY already suggested, you are not getting the full resolution here. If you have inputs to spare, I suggest connecting two pins together (for each port) and setting one to rising and one to falling edge.

 

Altough, i can't figure out how to read the level of B in P1 ISR and the level of A in P2 ISR withou using the IFG, and after that how to save the moviment of the machine in a variable.. How can i accomplish that?

 

P1IN & 0x01 will test bit 0 of port 1, P2IN & 0x01 will test bit0 of port2, so

//port 2 interrupt routine
if(P1IN & 0x01) { //input high
   //moving left
} else {
   //moving right
}
P2IFG &= ~0x01;

//port 1 interrupt routine
if(P2IN & 0x01) { //input high
   //moving right
} else {
   //moving left
}
P1IFG &= ~0x01;

 

If you decide to add falling edge, you will have to also test the port that has triggered interrupt.

 

//port 2 interrupt routine
direction = (P2IN & 0x01) ^ (P1IN & 0x01) // we only need to test one pin as both are connected together
if(direction) {
   //moving left
} else {
   //moving right
}
P2IFG &= ~(0x01 + 0x02) // but we need to clear flags for both, I am assuming we are using P2.0 and P2.1

//port 1 interrupt routine
direction = (P2IN & 0x01) ^ (P1IN & 0x01)
if(direction) { //input high
   //moving right
} else {
   //moving left
}
P1IFG &= ~(0x01 + 0x02) // assuming we are using P1.0 and P1.1

 

Also, I think your drawing is not correct, A and B should be fixed in relation to each other, just shifted. In the lower drawing, A and B are not in the same position as in the upper drawing.

 

If you want to implement it on a single port, all you need to do is add another conditional that will test flags and determine which pin triggered interrupt:

//port 1 interrupt routine
aOrB = P1IFG & 0x01 // port 1.0 is A, port 1.1 is B, so if P1IFG & 0x01 is true it must be A, otherwise we assume it's B that requested IF, unless we have more ports in use, then we will have to also test P1IFG & 0x02, and so on.

Share this post


Link to post
Share on other sites

I completely forgot about P1IN and P2IN for reading both inputs.. :D

 

As OCY already suggested, you are not getting the full resolution here. If you have inputs to spare, I suggest connecting two pins together (for each port) and setting one to rising and one to falling edge.

 

Are you saying i should connect both P1.0 and P1.1 to encoder A and P2.0 and P2.1 to encoder B?

If so, is my program correct like this? Does it covers all possibilities?

 

#include 

int direction;

void main(void)
{

WDTCTL = WDTPW + WDTHOLD;	// stop watchdor timer
P1DIR &= 0x03;			// P1.0 and P1.1 as input - encoder A
P2DIR &= 0x03;			// P2.0 and P2.1 as input - encoder B
P1IE |= 0x03;			// P1.0 and P1.1 interrupt enable
P2IE |= 0x03;			// P2.0 and P2.1 interrupt enable
P1IES &= ~0x01;			// P1.0 low/high edge
P1IES |= 0x02;			// P1.1 high/low edge
P2IES &= ~0x01;			// P2.0 low/high edge
P2IES |= 0x02;			// P2.1 high/low edge
P1IFG &= ~0x03;			// P1.0 and P1.1 IFG reset
P2IFG &= ~0x03;			// P2.0 and P2.1 IFG reset

_BIS_SR(GIE);

while(1);
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1 (void)
{
direction = (P2IN & 0x01) ^ (P1IN & 0x01); 

if(direction) 				
 		//moving right
else 
  		//moving left

P1IFG &= ~0x03; // clear P1.0 and P1.1 IFG's

}

#pragma vector=PORT2_VECTOR
__interrupt void Port_2 (void)
{
direction = (P2IN & 0x01) ^ (P1IN & 0x01); 

if(direction) 
 		//moving left
else 
  		//moving right

P2IFG &= ~0x03; // clear P2.0 and P2.1 IFG's

}

 

Also, how can i implement a way to save the position of the machine?

 

Thank you ;)

Share this post


Link to post
Share on other sites

Looks good to me.

To capture position, you can basically do what you have done before with i, maybe just use int or long instead.

Declare i, for example

 unsigned int i = 1000; // middle position

then replace // moving right with i++; and // moving left with i--;

Share this post


Link to post
Share on other sites

Here it is:

 

#include 

int direction;
char i=0;

void main(void)
{

WDTCTL = WDTPW + WDTHOLD;	// stop watchdor timer
P1DIR &= 0x03;			// P1.0 and P1.1 as input - encoder A
P2DIR &= 0x03;			// P2.0 and P2.1 as input - encoder B
P1IE |= 0x03;			// P1.0 and P1.1 interrupt enable
P2IE |= 0x03;			// P2.0 and P2.1 interrupt enable
P1IES &= ~0x01;			// P1.0 low/high edge
P1IES |= 0x02;			// P1.1 high/low edge
P2IES &= ~0x01;			// P2.0 low/high edge
P2IES |= 0x02;			// P2.1 high/low edge
P1IFG &= ~0x03;			// P1.0 and P1.1 IFG reset
P2IFG &= ~0x03;			// P2.0 and P2.1 IFG reset

_BIS_SR(GIE);

while(1);
}

#pragma vector=PORT1_VECTOR
__interrupt void Port_1 (void)
{
direction = (P2IN & 0x01) ^ (P1IN & 0x01); 

if(direction) 				
 		i++;	// moving right
else 
  		i--;	// moving left

P1IFG &= ~0x03; // clear P1.0 and P1.1 IFG's

}

#pragma vector=PORT2_VECTOR
__interrupt void Port_2 (void)
{
direction = (P2IN & 0x01) ^ (P1IN & 0x01); 

if(direction) 
 		i--;	// moving left
else 
  		i++;	// moving right

P2IFG &= ~0x03; // clear P2.0 and P2.1 IFG's

}

 

I've used only a char i, because the machine only goes for like 10 steps.. It's more than enough.

Also, i prefer to use i++ and i-- around zero, so when i read the variable i i don't need to remember that e.g. 1000 is the middle position.. if i=-2, it went 2 steps to the left, if i=3, it went 3 steps to the right ;)

 

THANK YOU SO MUCH for your help! :mrgreen:

Share this post


Link to post
Share on other sites

Can't you also test for direction on quad' AB signals by XOR'ing old A with new B, or new A with old B, etc? The resulting XOR value, 0 or 1, corresponds to direction.

 

Cheerful regards, Mike

 

  /*
   *  direction = "old B" exclusive-or "new A"
   */
   EncNew = P1IN & 3;              // sample AB inputs (P1.0-P1.1)
   if(EncNew ^ EncOld)             // if AB input "change"
   { direction = EncOld >> 1;      // shift B bit into bit 0
     direction ^= EncNew;          // bit 0 = direction (0 or 1)
     EncOld = EncNew;              //
   }

Share this post


Link to post
Share on other sites
Can't you also test for direction on quad' AB signals by XOR'ing old A with new B, or new A with old B, etc? The resulting XOR value, 0 or 1, corresponds to direction.

 

Cheerful regards, Mike

 

  /*
   *  direction = "old B" exclusive-or "new A"
   */
   EncNew = P1IN & 3;              // sample AB inputs (P1.0-P1.1)
   if(EncNew ^ EncOld)             // if AB input "change"
   { direction = EncOld >> 1;      // shift B bit into bit 0
     direction ^= EncNew;          // bit 0 = direction (0 or 1)
     EncOld = EncNew;              //
   }

 

That's a valid option too.. Although, it would just complicate the routine and i'm trying to keep it simple..

I still have much to learn... I'll just begin with the easy things :D

 

But thank you so much for your idea ;)

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...