Pages: [1]   Go Down
Author Topic: Rotary encoder troubles  (Read 1232 times)
0 Members and 1 Guest are viewing this topic.
Australia
Offline Offline
Full Member
***
Karma: 8
Posts: 161
You dont have to touch powerlines for them to kill you, even looking at them for too long will make them angry.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
#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);
}

Logged

"Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent di

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Australia
Offline Offline
Full Member
***
Karma: 8
Posts: 161
You dont have to touch powerlines for them to kill you, even looking at them for too long will make them angry.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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()
Logged

"Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent di

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Code:
//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

Code:
//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
Code:
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()
Code:
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



Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Australia
Offline Offline
Full Member
***
Karma: 8
Posts: 161
You dont have to touch powerlines for them to kill you, even looking at them for too long will make them angry.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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)
Code:
#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);
}

Logged

"Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent di

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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...






Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
Newbie
*
Karma: 1
Posts: 28
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Australia
Offline Offline
Full Member
***
Karma: 8
Posts: 161
You dont have to touch powerlines for them to kill you, even looking at them for too long will make them angry.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
#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);
}

Logged

"Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent di

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Australia
Offline Offline
Full Member
***
Karma: 8
Posts: 161
You dont have to touch powerlines for them to kill you, even looking at them for too long will make them angry.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Logged

"Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent di

Australia
Offline Offline
Full Member
***
Karma: 8
Posts: 161
You dont have to touch powerlines for them to kill you, even looking at them for too long will make them angry.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah, Success at last.

Code:
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.
Logged

"Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent di

Pages: [1]   Go Up
Jump to: