Quantcast
Channel: MSP430 Technical Forums
Viewing all articles
Browse latest Browse all 2077

MSP430G2553 and Rotary encoder

$
0
0

Hello,

 

I am trying to use rotary library for my VFO ad9850.

Originally writen for Arduino I just changed PCINT for PORT2_VECTOR interrupt.

so far  can say it almost works but I get some issues I cannot understand

Here is my test code :

/*
encoder_test.ino
Energia 011
MSP430G2553 launchpad ver 1.5
Windows 7
Rotary encoder KY-040
*/

#include <msp430g2553.h>
#include "rotary.h"

Rotary r = Rotary(P2_1, P2_2);

void setup()
{
  Serial.begin(9600);
  P2DIR &= ~(BIT1 + BIT2);
  P2IES = BIT1 + BIT2 ; //high to  low transition
  P2OUT |= BIT1 + BIT2;
  P2REN = BIT1 + BIT2;
  P2IE = BIT1 + BIT2; 
  P2IFG &= ~BIT1 + BIT2; 
  _BIS_SR(GIE); 
}

void loop()
{    
}

#pragma vector=PORT2_VECTOR
__interrupt void port_2 (void) {
  unsigned char result = r.process();
  if (result) {
    Serial.println(result == DIR_CW ? "Right" : "Left");
  }
  P2IFG &= ~BIT1 + BIT2; // P2.1 P2.2 interrupt flag cleared  
}

rotary.h

/*
 * Rotary encoder library for Arduino.
 */

#ifndef rotary_h
#define rotary_h

#include "Energia.h"

// Enable this to emit codes twice per step.
#define HALF_STEP

// Values returned by 'process'
// No complete step yet.
#define DIR_NONE 0x0
// Clockwise step.
#define DIR_CW 0x10
// Anti-clockwise step.
#define DIR_CCW 0x20

class Rotary
{
public:
  Rotary(char, char);
  // Process pin(s)
  unsigned char process();
private:
  unsigned char state;
  unsigned char pin1;
  unsigned char pin2;
};

#endif

rotary.cpp

/* Rotary encoder handler for arduino. v1.1
 *
 * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
 * Contact: bb@cactii.net
 *
 * A typical mechanical rotary encoder emits a two bit gray code
 * on 3 output pins. Every step in the output (often accompanied
 * by a physical 'click') generates a specific sequence of output
 * codes on the pins.
 *
 * There are 3 pins used for the rotary encoding - one common and
 * two 'bit' pins.
 *
 * The following is the typical sequence of code on the output when
 * moving from one step to the next:
 *
 *   Position   Bit1   Bit2
 *   ----------------------
 *     Step1     0      0
 *      1/4      1      0
 *      1/2      1      1
 *      3/4      0      1
 *     Step2     0      0
 *
 * From this table, we can see that when moving from one 'click' to
 * the next, there are 4 changes in the output code.
 *
 * - From an initial 0 - 0, Bit1 goes high, Bit0 stays low.
 * - Then both bits are high, halfway through the step.
 * - Then Bit1 goes low, but Bit2 stays high.
 * - Finally at the end of the step, both bits return to 0.
 *
 * Detecting the direction is easy - the table simply goes in the other
 * direction (read up instead of down).
 *
 * To decode this, we use a simple state machine. Every time the output
 * code changes, it follows state, until finally a full steps worth of
 * code is received (in the correct order). At the final 0-0, it returns
 * a value indicating a step in one direction or the other.
 *
 * It's also possible to use 'half-step' mode. This just emits an event
 * at both the 0-0 and 1-1 positions. This might be useful for some
 * encoders where you want to detect all positions.
 *
 * If an invalid state happens (for example we go from '0-1' straight
 * to '1-0'), the state machine resets to the start until 0-0 and the
 * next valid codes occur.
 *
 * The biggest advantage of using a state machine over other algorithms
 * is that this has inherent debounce built in. Other algorithms emit spurious
 * output with switch bounce, but this one will simply flip between
 * sub-states until the bounce settles, then continue along the state
 * machine.
 * A side effect of debounce is that fast rotations can cause steps to
 * be skipped. By not requiring debounce, fast rotations can be accurately
 * measured.
 * Another advantage is the ability to properly handle bad state, such
 * as due to EMI, etc.
 * It is also a lot simpler than others - a static state table and less
 * than 10 lines of logic.
 */

#include "Energia.h"
#include "rotary.h"

/*
 * The below state table has, for each state (row), the new state
 * to set based on the next encoder output. From left to right in,
 * the table, the encoder outputs are 00, 01, 10, 11, and the value
 * in that position is the new state to set.
 */

#define R_START 0x0

#ifdef HALF_STEP
// Use the half-step state table (emits a code at 00 and 11)
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
  // R_START (00)
  {
    R_START_M,            R_CW_BEGIN,     R_CCW_BEGIN,  R_START  }
  ,
  // R_CCW_BEGIN
  {
    R_START_M | DIR_CCW, R_START,        R_CCW_BEGIN,  R_START  }
  ,
  // R_CW_BEGIN
  {
    R_START_M | DIR_CW,  R_CW_BEGIN,     R_START,      R_START  }
  ,
  // R_START_M (11)
  {
    R_START_M,            R_CCW_BEGIN_M,  R_CW_BEGIN_M, R_START  }
  ,
  // R_CW_BEGIN_M
  {
    R_START_M,            R_START_M,      R_CW_BEGIN_M, R_START | DIR_CW  }
  ,
  // R_CCW_BEGIN_M
  {
    R_START_M,            R_CCW_BEGIN_M,  R_START_M,    R_START | DIR_CCW  }
  ,
};
#else
// Use the full-step state table (emits a code at 00 only)
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {
    R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START  }
  ,
  // R_CW_FINAL
  {
    R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW  }
  ,
  // R_CW_BEGIN
  {
    R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START  }
  ,
  // R_CW_NEXT
  {
    R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START  }
  ,
  // R_CCW_BEGIN
  {
    R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START  }
  ,
  // R_CCW_FINAL
  {
    R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW  }
  ,
  // R_CCW_NEXT
  {
    R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START  }
  ,
};
#endif

/*
 * Constructor. Each arg is the pin number for each encoder contact.
 */
Rotary::Rotary(char _pin1, char _pin2) {
  // Assign variables.
  pin1 = _pin1;
  pin2 = _pin2;

  // initialisation in the main

  // Initialise state.
  state = R_START;
}

unsigned char Rotary::process() {
  // Grab state of input pins.
  unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1);
  // Determine new state from the pins and state table.
  state = ttable[state & 0xf][pinstate];
  // Return emit bits, ie the generated event.
  return state & 0x30;
}


Sometimes I get LEFT among RIGHT et vice versa .

 

Turning knob very fast freezes the program.

 

Any help would be appreciate.

 

Salutations

Bernard


Viewing all articles
Browse latest Browse all 2077

Trending Articles