Rotary encoder troubles

Hi, I'm having a small issue with my rotary encoder. It seems to only ever count up (generally in multiples of two), I have a feeling it may be my logic, but I cant spot the issue. If someone can have a look, It would be much appreciated.

#include <Wire.h>

//Initialise Pins
//Encoder Pins
static int encoder0PinA = 4;
static int encoder0PinB = 5;

//Hold Button
static int holdButton = 2;

//Other Variables
//Initialise Encoder Variables
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;
int rotateFlag = 1; // Flag set if rotation has changed

//Initialise Touchscreen Variables
int x,y,ny,nx = 0; //X and Y variable holders for touch value
int halfwidth = 500; //Midpoint on Touchscreen X
int halfheight = 500; //Midpoint on Touchscreen Y
int touchFlag = 0; //Flag set if touch enabled has been sent 
int prevSend = 0; // holder for previous values of y abnd x


//Initialise Hold Button Variables
int holdFlag = 0; //Set if hold button toggled

//Initialise Blinkm Variables
int redVal = 0, greenVal = 0, blueVal = 0;
int scriptFlag = 0;  //Flag set if BlinkM script active
unsigned long seconds = millis(); // Used to time start of blinkm script after inactivity on touchscreen


void setup(){
  //Init Hold Button
  pinMode(holdButton,INPUT);
  digitalWrite(holdButton,HIGH); //Pullup enabled
  attachInterrupt(0,holdToggle,FALLING); //Hold Button interrupt pin 0 is pin 2

  //Initialise Encoder Pins
  pinMode (encoder0PinA,INPUT);
  digitalWrite(encoder0PinA,HIGH); //Pullup enabled
  pinMode (encoder0PinB,INPUT);
  digitalWrite(encoder0PinB,HIGH); //Pullup enabled

  //Init MIDI port
  Serial.begin(31250);

  //Init BlinkM
  Wire.begin();                // set up I2C on 4 and 5 analog
  Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
  Wire.send("p");              
  Wire.send(0x00);            
  Wire.send(0);             
  Wire.send(0);            
  Wire.endTransmission();      // leave I2C bus 
  Wire.begin();                // set up I2C on 4 and 5 analog
  Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
  Wire.send("f");              
  Wire.send(20);                
  Wire.endTransmission();      // leave I2C bus 
}

//Get X value from touchscreen
int readX() {
  int xr=0;
  pinMode(14, INPUT);   // A0
  pinMode(15, OUTPUT);    // A1
  pinMode(16, INPUT);   // A2
  pinMode(17, OUTPUT);   // A3
  digitalWrite(15, LOW); // set A1 to GND
  digitalWrite(17, HIGH);  // set A3 as 5V
  delay(5); // short delay is required to give the analog pins time to adjust to their new roles
  xr=analogRead(0) - 50; //  return xr;
}

//Get Y value from touchscreen
int readY(){ 
  int yr=0;
  pinMode(14, OUTPUT);   // A0
  pinMode(15, INPUT);    // A1
  pinMode(16, OUTPUT);   // A2
  pinMode(17, INPUT);   // A3
  digitalWrite(14, LOW); // set A0 to GND
  digitalWrite(16, HIGH);  // set A2 as 5V
  delay(5); // short delay is required to give the analog pins time to adjust to their new roles
  yr=analogRead(1) -50; //
  return yr;

}

//Toggles Hold on interrupt
void holdToggle(){
  //Set to !holdflag 
  if (holdFlag ==1){
    holdFlag = 0;
    midiCC(0xB0,92,0x00); //Touchpad up command
    touchFlag=0;
  }
  else
    holdFlag = 1; 
}

//Get Rotary Encoder Status
int getRot() { 
  n = digitalRead(encoder0PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {
      encoder0Pos--;
      rotateFlag = 1;
    } 
    else {
      encoder0Pos++;
      rotateFlag = 1;
    }
    //Normalise values to 7 bit midi
    if ( encoder0Pos < 0){
      encoder0Pos =  encoder0Pos + 127;
    }
    else if ( encoder0Pos > 127){
      encoder0Pos =  encoder0Pos -127;
    }
  }
  else{
    rotateFlag = 0;
  }
  encoder0PinALast = n;
  return rotateFlag; //1 of rotated, 0 if not
}

void loop()
{
  if(holdFlag == 0){
    prevSend = x+y; //quick easy fast calculation prep
    y = readY();
    x = readX();
    if(x <1000 && y < 1000){
      if(prevSend != x+y){ //check if the buffers changed
        ny = map(y,0,1016,0,127);  // maps the value range of the axis to midi 0->127
        nx = map(x,0,1016,0,127);  // maps the value range of the axis to midi 0->127
        if(touchFlag == 0){ //check if touchpad is enabled.
          midiCC(0xB0,92,127); //Touchpad down command
          touchFlag = 1; //set touch flag
        }
        midiCC(0xB0, 12, nx);  // sends midi control change for touch pad X axis
        midiCC(0xB0, 13, ny);  // sends midi control change for touch pad y axis

        //Colour code
        seconds = millis(); //Record current time
        int y1 =0, x1 = 0;
        if (x < halfwidth){
          if (y <= halfheight){
            //Purple CC 00 CC
            redVal = 0xCC;
            greenVal = 0x00;
            blueVal = 0xCC;
          }
          else {
            //Red  FF 00  00 
            redVal = 0xFF;
            greenVal = 0x00;
            blueVal = 0x00;

          }
        }
        else{
          if (x >= halfwidth){
            if (y <= halfheight){
              //Yell FF FF  00
              redVal = 0xFF;
              greenVal = 0xFF;
              blueVal = 0x00;
            }
            else { 
              //Blue 00 00 FF
              redVal = 0x00;
              greenVal = 0x00;
              blueVal = 0xFF;
            }
          }
        }
        if (scriptFlag == 0){
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('c');              // ‘c’ == fade to color
          Wire.send(redVal);            // value for red channel
          Wire.send(greenVal);             // value for blue channel
          Wire.send(blueVal);             // value for green channel
          Wire.endTransmission();      // leave I2C bus 
        } 
        else{
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('o');              // stop Script
          Wire.endTransmission();      // leave I2C bus 
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('c');              // ‘c’ == fade to color
          Wire.send(redVal);            // value for red channel
          Wire.send(greenVal);             // value for blue channel
          Wire.send(blueVal);             // value for green channel
          Wire.endTransmission();      // leave I2C bus 
          scriptFlag = 0;
        } 
      }
    }
    else{
      if(touchFlag){ //If touchpad still enabled
        midiCC(0xB0,92,0x00); //Touchpad up command
        touchFlag=0;
      }
    }
  }
  
  if((seconds + 1000)<millis() && scriptFlag == 0 && holdFlag == 0){
    Wire.begin();                // set up I2C on 4 and 5 analog
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.send("p");              
    Wire.send(0x00);            
    Wire.send(0);             
    Wire.send(0);            
    Wire.endTransmission();      // leave I2C bus 
    Wire.begin();                // set up I2C on 4 and 5 analog
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.send("f");              
    Wire.send(20);                
    Wire.endTransmission();      // leave I2C bus 
    seconds = millis();
    scriptFlag = 1;
  }      
  if (getRot()){ //If rotary enc changed
    midiCC(0xC0,0,encoder0Pos); //send command
  }
}

//Send MIDI command
void midiCC(char command, char value1, char value2){
  Serial.print(command, BYTE);
  Serial.print(value1, BYTE);
  Serial.print(value2, BYTE);
}

Please try to minimize the sketch with only the rotary encoder that still shows the problem.

I would love to, but my issue is affected by the sketch, Due to the amount of processing involved, it delays interrupts slightly i think. The code you are looking at is mainly the interrupt code called getLoc()

//Toggles Hold on interrupt
void holdToggle(){
  //Set to !holdflag 
  if (holdFlag ==1){
    holdFlag = 0;
    midiCC(0xB0,92,0x00); //Touchpad up command
    touchFlag=0;
  }
  else
    holdFlag = 1; 
}

and

//Send MIDI command
void midiCC(char command, char value1, char value2){
  Serial.print(command, BYTE);
  Serial.print(value1, BYTE);
  Serial.print(value2, BYTE);
}

Problem: you do slow serial communication during the IRQ. Sending 3 bytes @ 31250 takes in the order of 1 milliseconds, while IRQ's should be handled in the order of microseconds.

Solution: What you should do is change the IRQ routine. The IRQ puts the bytes that need to be send by midiCC in a queue. And that queue will be emptied in the main loop. You have to search for a queue class on the forum or create a sketch specific yourself.

IRQ code would become

void holdToggle(){
  //Set to !holdflag 
  if (holdFlag ==1){
    holdFlag = 0;
    Q.add(0xB0);
    Q.add(92);
    Q.add(0x00); 
    touchFlag=0;
  }
  else
    holdFlag = 1; 
}

and loop()

void loop()
{
  ...
  if (Queue.Size() > 3) midiCC(Q.get(), Q,get(), Q.get());
  ...
}

Finally declare all vars used in an IRQ as volatile (that is a far nephew from static) - http://www.arduino.cc/en/Reference/Volatile

succes,
Rob

I have implemented your proposed changes, http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265230949/4 using this queue class. I still had the same issue with the encoder not decreasing. I have tried switching to the interrupt based encoder reading but now I cant even see a response. For reference, i am using the http://www.sparkfun.com/products/9786 encoder. The common pin is grounded, the two signal pins are digital 3,4 respectively. (pin 3 being interrupt1)

#include <Wire.h>
#include "Stack.h"

//Initialise Pins
//Encoder Pins
static int encoder0PinA = 3;
static int encoder0PinB = 4;

//Hold Button
static int holdButton = 2;

//Other Variables
//Initialise Encoder Variables
volatile int encoder0Pos = 0;
volatile int encoder0PinALast = LOW;
volatile int n = LOW;
volatile int rotateFlag = 1; // Flag set if rotation has changed

//Initialise Touchscreen Variables
int x,y,ny,nx = 0; //X and Y variable holders for touch value
int halfwidth = 500; //Midpoint on Touchscreen X
int halfheight = 500; //Midpoint on Touchscreen Y
int touchFlag = 0; //Flag set if touch enabled has been sent 
int prevSend = 0; // holder for previous values of y abnd x

//Init Queue
typedef Stack<int,12> IntStack;
static IntStack Q;

//Initialise Hold Button Variables
int holdFlag = 0; //Set if hold button toggled

//Initialise Blinkm Variables
int redVal = 0, greenVal = 0, blueVal = 0;
int scriptFlag = 0;  //Flag set if BlinkM script active
unsigned long seconds = millis(); // Used to time start of blinkm script after inactivity on touchscreen


void setup(){
  //Init Hold Button
  pinMode(holdButton,INPUT);
  digitalWrite(holdButton,HIGH); //Pullup enabled
  attachInterrupt(0,holdToggle,FALLING); //Hold Button interrupt pin 0 is pin 2

  //Initialise Encoder Pins
  pinMode (encoder0PinA,INPUT);
  digitalWrite(encoder0PinA,HIGH); //Pullup enabled
  pinMode (encoder0PinB,INPUT);
  digitalWrite(encoder0PinB,HIGH); //Pullup enabled
  attachInterrupt(1,getRot,LOW); //Hold Button interrupt pin 1 is pin 3

  //Init MIDI port
  Serial.begin(31250);

  //Init BlinkM
  Wire.begin();                // set up I2C on 4 and 5 analog
  Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
  Wire.send("p");              
  Wire.send(0x00);            
  Wire.send(0);             
  Wire.send(0);            
  Wire.endTransmission();      // leave I2C bus 
  Wire.begin();                // set up I2C on 4 and 5 analog
  Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
  Wire.send("f");              
  Wire.send(20);                
  Wire.endTransmission();      // leave I2C bus 
}

//Get X value from touchscreen
int readX() {
  int xr=0;
  pinMode(14, INPUT);   // A0
  pinMode(15, OUTPUT);    // A1
  pinMode(16, INPUT);   // A2
  pinMode(17, OUTPUT);   // A3
  digitalWrite(15, LOW); // set A1 to GND
  digitalWrite(17, HIGH);  // set A3 as 5V
  delay(5); // short delay is required to give the analog pins time to adjust to their new roles
  xr=analogRead(0) - 50; //  return xr;
}

//Get Y value from touchscreen
int readY(){ 
  int yr=0;
  pinMode(14, OUTPUT);   // A0
  pinMode(15, INPUT);    // A1
  pinMode(16, OUTPUT);   // A2
  pinMode(17, INPUT);   // A3
  digitalWrite(14, LOW); // set A0 to GND
  digitalWrite(16, HIGH);  // set A2 as 5V
  delay(5); // short delay is required to give the analog pins time to adjust to their new roles
  yr=analogRead(1) -50; //
  return yr;

}

//Toggles Hold on interrupt
void holdToggle(){
  //Set to !holdflag 
  if (holdFlag ==1){
    holdFlag = 0;
    Q.push(0xB0);
    Q.push(92);
    Q.push(0x00); 
    touchFlag=0;
  }
  else
    holdFlag = 1; 
}

//Get Rotary Encoder Status
void getRot() { 
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
    /*n = digitalRead(encoder0PinA);
     if ((encoder0PinALast == LOW) && (n == HIGH)) {
     if (digitalRead(encoder0PinB) == LOW) {*/
    encoder0Pos--;
    rotateFlag = 1;
  } 
  else {
    encoder0Pos++;
    rotateFlag = 1;
  }
  //Normalise values to 7 bit midi
  if ( encoder0Pos < 0){
    encoder0Pos =  encoder0Pos + 127;
  }
  else if ( encoder0Pos > 127){
    encoder0Pos =  encoder0Pos -127;
  }
  //}
  else{
    rotateFlag = 0;
  }
  //encoder0PinALast = n;
  // return rotateFlag; //1 of rotated, 0 if not
}

void loop()
{
  if(holdFlag == 0){
    while(Q.size() > 2) midiCC(Q.pop(), Q.pop(), Q.pop());
    prevSend = x+y; //quick easy fast calculation prep
    y = readY();
    x = readX();
    if(x <1000 && y < 1000){
      if(prevSend != x+y){ //check if the buffers changed
        ny = map(y,0,1016,0,127);  // maps the value range of the axis to midi 0->127
        nx = map(x,0,1016,0,127);  // maps the value range of the axis to midi 0->127
        if(touchFlag == 0){ //check if touchpad is enabled.
          midiCC(0xB0,92,127); //Touchpad down command
          touchFlag = 1; //set touch flag
        }
        midiCC(0xB0, 12, nx);  // sends midi control change for touch pad X axis
        midiCC(0xB0, 13, ny);  // sends midi control change for touch pad y axis

        //Colour code
        seconds = millis(); //Record current time
        int y1 =0, x1 = 0;
        if (x < halfwidth){
          if (y <= halfheight){
            //Purple CC 00 CC
            redVal = 0xCC;
            greenVal = 0x00;
            blueVal = 0xCC;
          }
          else {
            //Red  FF 00  00 
            redVal = 0xFF;
            greenVal = 0x00;
            blueVal = 0x00;

          }
        }
        else{
          if (x >= halfwidth){
            if (y <= halfheight){
              //Yell FF FF  00
              redVal = 0xFF;
              greenVal = 0xFF;
              blueVal = 0x00;
            }
            else { 
              //Blue 00 00 FF
              redVal = 0x00;
              greenVal = 0x00;
              blueVal = 0xFF;
            }
          }
        }
        if (scriptFlag == 0){
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('c');              // ‘c’ == fade to color
          Wire.send(redVal);            // value for red channel
          Wire.send(greenVal);             // value for blue channel
          Wire.send(blueVal);             // value for green channel
          Wire.endTransmission();      // leave I2C bus 
        } 
        else{
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('o');              // stop Script
          Wire.endTransmission();      // leave I2C bus 
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('c');              // ‘c’ == fade to color
          Wire.send(redVal);            // value for red channel
          Wire.send(greenVal);             // value for blue channel
          Wire.send(blueVal);             // value for green channel
          Wire.endTransmission();      // leave I2C bus 
          scriptFlag = 0;
        } 
      }
    }
    else{
      if(touchFlag){ //If touchpad still enabled
        midiCC(0xB0,92,0x00); //Touchpad up command
        touchFlag=0;
      }
    }
  }

  if((seconds + 1000)<millis() && scriptFlag == 0 && holdFlag == 0){
    Wire.begin();                // set up I2C on 4 and 5 analog
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.send("p");              
    Wire.send(0x00);            
    Wire.send(0);             
    Wire.send(0);            
    Wire.endTransmission();      // leave I2C bus 
    Wire.begin();                // set up I2C on 4 and 5 analog
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.send("f");              
    Wire.send(20);                
    Wire.endTransmission();      // leave I2C bus 
    seconds = millis();
    scriptFlag = 1;
  }      
  if (rotateFlag){ //If rotary enc changed
    midiCC(0xC0,0,encoder0Pos); //send command
    rotateFlag=0;
  }
}

//Send MIDI command
void midiCC(char command, char value1, char value2){
  Serial.print(command, BYTE);
  Serial.print(value1, BYTE);
  Serial.print(value2, BYTE);
}

If I'm reading it right, you're using rotateflag to determine that the rotary dial has been moved. If that's the case, you shouldn't be setting rotateflag = 0 in your ISR. The only time rotateflag remains true after the ISR is executed is when it's wrapped past 0 or 127. So just remove the else { } block from your second if() statement.

First a stack is no queue, a stack has a LIFO order where a Queue has a FIFO order. But at least the IRQ is handled faster.

(diving into the code ...)

There are 2 things on pin3 => the IRQ and the static int encoder0PinA = 3; raises questions...

attachInterrupt(1,getRot, LOW); you generate an IRQ when pin 3 is low and in getrot() you test if it is HIGH? That might be the reason why one direction doesn't work...

Possibly not germane to your immediate problem, but I think there is a problem with the logic of your roll over code - you describe it as "Normalise values to 7 bit midi".

You will only ever get a value of 127 in encoder0Pos if you approach it from a lower positive value (i.e. counting up as in 123, 124, 125, 126, 127). In the decreasing direction, you test if encoder0Pos is less than zero and then add 127 to it. Well, -1 + 127 = 126 in my part of the world.

Similarly, you will only ever get a value of zero when counting down (6, 5, 4, 3, 2, 1, 0) as your other test does 128 -127 = 1.

In both these cases with your current code, the value changes by two instead of one (i.e. 125, 126, 127, 1, 2, 3 and 2, 1, 0, 126, 125).

Since the count only changes by one each pulse, why do an inequality check when you only need to act if encoder0Pos is (equal to) 128 or -1?

Thanks for the suggestions, As far as I know, this Stack is FIFO. The second usage of Encoder0PinA is to read a value from it in the interrupt code. I have Fixed the wrapping code too. I have now got it going down. At this stage, Turning the encoder one way will increase the value reliably 2 at a time. Turning it the other way will when averaged out, lower the value, but it will not only go down, it goes about 60/40 down to up values. Same 2 at a time value incrementing.

#include <Wire.h>
#include "Stack.h"

//Initialise Pins
//Encoder Pins
static int encoder0PinA = 3;
static int encoder0PinB = 4;

//Hold Button
static int holdButton = 2;

//Other Variables
//Initialise Encoder Variables
volatile int encoder0Pos = 0;
volatile int encoder0PinALast = LOW;
volatile int n = LOW;
volatile int rotateFlag = 1; // Flag set if rotation has changed

//Initialise Touchscreen Variables
int x,y,ny,nx = 0; //X and Y variable holders for touch value
int halfwidth = 500; //Midpoint on Touchscreen X
int halfheight = 500; //Midpoint on Touchscreen Y
int touchFlag = 0; //Flag set if touch enabled has been sent 
int prevSend = 0; // holder for previous values of y abnd x

//Init Queue
typedef Stack<int,3> IntStack;
static IntStack Q;

//Initialise Hold Button Variables
int holdFlag = 0; //Set if hold button toggled

//Initialise Blinkm Variables
int redVal = 0, greenVal = 0, blueVal = 0;
int scriptFlag = 0;  //Flag set if BlinkM script active
unsigned long seconds = millis(); // Used to time start of blinkm script after inactivity on touchscreen


void setup(){
  //Init Hold Button
  pinMode(holdButton,INPUT);
  digitalWrite(holdButton,HIGH); //Pullup enabled
  attachInterrupt(0,holdToggle,FALLING); //Hold Button interrupt pin 0 is pin 2

  //Initialise Encoder Pins
  pinMode (encoder0PinA,INPUT);
  digitalWrite(encoder0PinA,HIGH); //Pullup enabled
  pinMode (encoder0PinB,INPUT);
  digitalWrite(encoder0PinB,HIGH); //Pullup enabled
  attachInterrupt(1,getRot,CHANGE); //Hold Button interrupt pin 1 is pin 3

  //Init MIDI port
  Serial.begin(31250);

  //Init BlinkM
  Wire.begin();                // set up I2C on 4 and 5 analog
  Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
  Wire.send("p");              
  Wire.send(0x00);            
  Wire.send(0);             
  Wire.send(0);            
  Wire.endTransmission();      // leave I2C bus 
  Wire.begin();                // set up I2C on 4 and 5 analog
  Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
  Wire.send("f");              
  Wire.send(20);                
  Wire.endTransmission();      // leave I2C bus 
}

//Get X value from touchscreen
int readX() {
  int xr=0;
  pinMode(14, INPUT);   // A0
  pinMode(15, OUTPUT);    // A1
  pinMode(16, INPUT);   // A2
  pinMode(17, OUTPUT);   // A3
  digitalWrite(15, LOW); // set A1 to GND
  digitalWrite(17, HIGH);  // set A3 as 5V
  delay(5); // short delay is required to give the analog pins time to adjust to their new roles
  xr=analogRead(0) - 50; //  return xr;
}

//Get Y value from touchscreen
int readY(){ 
  int yr=0;
  pinMode(14, OUTPUT);   // A0
  pinMode(15, INPUT);    // A1
  pinMode(16, OUTPUT);   // A2
  pinMode(17, INPUT);   // A3
  digitalWrite(14, LOW); // set A0 to GND
  digitalWrite(16, HIGH);  // set A2 as 5V
  delay(5); // short delay is required to give the analog pins time to adjust to their new roles
  yr=analogRead(1) -50; //
  return yr;

}

//Toggles Hold on interrupt
void holdToggle(){
  //Set to !holdflag 
  if (holdFlag ==1){
    holdFlag = 0;
    Q.push(0xB0);
    Q.push(92);
    Q.push(0x00); 
    touchFlag=0;
  }
  else
    holdFlag = 1; 
}

//Get Rotary Encoder Status
void getRot() { 
  if (digitalRead(encoder0PinA) == HIGH) {   // found a low-to-high on channel A
    if (digitalRead(encoder0PinB) == LOW) {  // check channel B to see which way
      // encoder is turning
      encoder0Pos = encoder0Pos - 1;         // CCW
      rotateFlag = 1;
    } 
    else {
      encoder0Pos = encoder0Pos + 1;         // CW
      rotateFlag = 1;
    }
  }
  else                                        // found a high-to-low on channel A
  { 
    if (digitalRead(encoder0PinB) == LOW) {   // check channel B to see which way
      // encoder is turning  
      encoder0Pos = encoder0Pos + 1;          // CW
    } 
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }
  }

  //Normalise values to 7 bit midi
  if ( encoder0Pos == -1){
    encoder0Pos =  encoder0Pos + 127;
  }
  else if ( encoder0Pos == 128){
    encoder0Pos =  encoder0Pos -127;
  }
  //}
  //encoder0PinALast = n;
  // return rotateFlag; //1 of rotated, 0 if not
}

void loop()
{
  if(holdFlag == 0){
    while(Q.size() > 2) midiCC(Q.pop(), Q.pop(), Q.pop());
    prevSend = x+y; //quick easy fast calculation prep
    y = readY();
    x = readX();
    if(x <1000 && y < 1000){
      if(prevSend != x+y){ //check if the buffers changed
        ny = map(y,0,1016,0,127);  // maps the value range of the axis to midi 0->127
        nx = map(x,0,1016,0,127);  // maps the value range of the axis to midi 0->127
        if(touchFlag == 0){ //check if touchpad is enabled.
          midiCC(0xB0,92,127); //Touchpad down command
          touchFlag = 1; //set touch flag
        }
        midiCC(0xB0, 12, nx);  // sends midi control change for touch pad X axis
        midiCC(0xB0, 13, ny);  // sends midi control change for touch pad y axis

        //Colour code
        seconds = millis(); //Record current time
        int y1 =0, x1 = 0;
        if (x < halfwidth){
          if (y <= halfheight){
            //Purple CC 00 CC
            redVal = 0xCC;
            greenVal = 0x00;
            blueVal = 0xCC;
          }
          else {
            //Red  FF 00  00 
            redVal = 0xFF;
            greenVal = 0x00;
            blueVal = 0x00;

          }
        }
        else{
          if (x >= halfwidth){
            if (y <= halfheight){
              //Yell FF FF  00
              redVal = 0xFF;
              greenVal = 0xFF;
              blueVal = 0x00;
            }
            else { 
              //Blue 00 00 FF
              redVal = 0x00;
              greenVal = 0x00;
              blueVal = 0xFF;
            }
          }
        }
        if (scriptFlag == 0){
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('c');              // ‘c’ == fade to color
          Wire.send(redVal);            // value for red channel
          Wire.send(greenVal);             // value for blue channel
          Wire.send(blueVal);             // value for green channel
          Wire.endTransmission();      // leave I2C bus 
        } 
        else{
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('o');              // stop Script
          Wire.endTransmission();      // leave I2C bus 
          Wire.begin();                // set up I2C on 4 and 5 analog
          Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
          Wire.send('c');              // ‘c’ == fade to color
          Wire.send(redVal);            // value for red channel
          Wire.send(greenVal);             // value for blue channel
          Wire.send(blueVal);             // value for green channel
          Wire.endTransmission();      // leave I2C bus 
          scriptFlag = 0;
        } 
      }
    }
    else{
      if(touchFlag){ //If touchpad still enabled
        midiCC(0xB0,92,0x00); //Touchpad up command
        touchFlag=0;
      }
    }
  }

  if((seconds + 1000)<millis() && scriptFlag == 0 && holdFlag == 0){
    Wire.begin();                // set up I2C on 4 and 5 analog
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.send("p");              
    Wire.send(0x00);            
    Wire.send(0);             
    Wire.send(0);            
    Wire.endTransmission();      // leave I2C bus 
    Wire.begin();                // set up I2C on 4 and 5 analog
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.send("f");              
    Wire.send(20);                
    Wire.endTransmission();      // leave I2C bus 
    seconds = millis();
    scriptFlag = 1;
  }      
  if (rotateFlag){ //If rotary enc changed
    midiCC(0xC0,0,encoder0Pos); //send command
    rotateFlag=0;
  }
}

//Send MIDI command
void midiCC(char command, char value1, char value2){
  Serial.print(command, BYTE);
  Serial.print(value1, BYTE);
  Serial.print(value2, BYTE);
}

You're only setting your rotateflag when PinA is high.

Since getRot() ONLY gets called when an encoder transition occurs, there's no need for multiple assignments of rotateflag. just set it at the very beginning of the function.

I think i have an answer of sorts. I made a simple sketch in which the interrupt is triggered on CHANGE and set it to report the two pins status. This is the output turning it around one direction:

Ah, Success at last.

void setup(){ //Initialise Encoder Pins
  pinMode (encoder0PinA,INPUT); //set pin as input
  digitalWrite(encoder0PinA,HIGH); //Pullup enabled
  pinMode (encoder0PinB,INPUT); //set pin as input
  digitalWrite(encoder0PinB,HIGH); //Pullup enabled
  attachInterrupt(1,getRot,FALLING); //Rotary encoder interrupt pin 1 is pin 3, interrupt triggers on the pin falling to 0
  Serial.begin(9600);
}

void getRot() { 
  if (digitalRead(encoder0PinA) == LOW) {   // found a low-to-high on channel A
    if (digitalRead(encoder0PinB) == LOW) {  // check pin B to see which way turn is.
      encoder0Pos = encoder0Pos - 1;         // CCW
    } 
    else {
      encoder0Pos = encoder0Pos + 1;         // CW
    }
  }
  Serial.println(encoder0Pos); //Send value to PC
}

void loop(){
  //do nothing here because we are using interrupts
}

Basically, the encoder is not standard, giving me erratic results when certain test cases were tested. I also added some hardware debouncing to the circuit too to make life easy.