CSE: Pitch Rot

This sketch plays an intermittent tone in loop(), moving the pitch up a step each time. If either the top button or the encoder's built-in button is pressed, the pitch cycle resets. Turning the encoder shaft to the right increases the playing speed (and vice versa).

// pitch_rot - vary delay and pitch, using a rotary encoder

int oj_rc     =   9;  // D9 drives the right channel.
int pb_top    =  11;  // D11 is the top button.

int re_ca     =   4;  // D2 is contact A (eg, CLK).
int re_cb     =   5;  // D3 is contact B (eg, DT).
int re_pb     =   2;  // A2 hears the left channel.

int delay_ms  = 500;  // delay (ms)

// define an (approximately :-) tempered scale
int scale[] = {
     392, 415, 440, 466, 494, 523,
  //   G   Ab    A   Bb    B    C
     554, 587, 622, 659, 698, 740  };
  //  Db    D   Eb    E    F   Gb
int scale_ndx =   0;  // Start at the beginning.

volatile boolean pb_pressed = false;
volatile boolean re_pressed = false;
volatile int     re_calls   = 0;
volatile int     re_steps   = 0;

// pin D11 (top push button)
ISR (PCINT0_vect) { pb_pressed = true; }

// pin D2 (encoder push button )
void do_epb() {
  if (re_sw == LOW) { re_pressed = true; }
}

// pin D3 (encoder contact A)
void do_eca() {
  boolean re_ca_s = digitalRead(re_ca);
  boolean re_cb_s = digitalRead(re_cb);

  if (re_ca_s == re_cb_s) { re_steps++; }
  else                    { re_steps--; }
  re_calls++; 
}

void setup_in(int pin) {
  pinMode(pin, INPUT);
  digitalWrite(pin, HIGH);
}

void setup() {
  Serial.begin(9600);
  pinMode(oj_rc, OUTPUT);
  setup_in(pb_top); setup_in(re_ca);
  setup_in(re_cb);  setup_in(re_pb);

  PCMSK0 |= bit(PCINT3);  // pin D11
  PCIFR  |= bit(PCIF0);   // clear  interrupt
  PCICR  |= bit(PCIE0);   // enable interrupt

  // Interrupts 0 and 1 are on pins D2 and D3.
  attachInterrupt (0, do_epb, FALLING);
  attachInterrupt (1, do_eca, FALLING);
}

void loop() {
  scale_ndx = (scale_ndx + 1) % 12;  // cycle

  noInterrupts();
  // At least one button was pressed.
  if (pb_pressed || re_pressed) { 
    scale_ndx  = 0;  // clear
    pb_pressed = re_pressed = false;
    Serial.println("button pressed"); //T
  }

  // The encoder shaft was rotated.
  if (re_steps != 0) {
    delay_ms  += re_steps * 10;
    delay_ms   = constrain(delay_ms, 100, 1000);

    if (true) {
      Serial.println("delay_ms: " + String(delay_ms)  +
                  ";  re_steps: " + String(re_steps)  +
                  ";  re_calls: " + String(re_calls));
    }
    re_steps = 0;
  }
  interrupts();

  tone(oj_rc, scale[scale_ndx], delay_ms);
  delay(delay_ms * 2);
}

//SYSIN DD DUMMY

Discussion

The top button uses a Pin Change Interrupt; the rotary encoder's built-in button uses an External Interrupt. AFAIK, they need to be programmed rather differently. At least, things work when I do so (:-).

Encoder Theory

The Control Shield uses an incremental rotary encoder. This is an electromechanical device, based on a toothed disk and a pair of switch contacts. The contacts (A / CLK, B / DT) are in quadrature (90 degrees out of phase) with each other: if one is on the edge of a tooth (i.e., changing), the other must be in the middle of a tooth (i.e., stable). Rotating the shaft (in either direction) produces a pair of square waves:

A Hi      ?_____?     ?_____?     ?___
A Lo   ___?  .  ?_____?  .  ?_____?
       .  .  .  .  .  .  .  .  .  .  .
B Hi   ?_____?  .  ?_____?  .  ?_____?
B Lo   ?     ?_____?     ?_____?     ?

Interpretation

Let's say we just got an interrupt on contact A. By comparing the new value of A with the stable value of B, we can determine the direction of rotation. If the values agree, the rotation must be clockwise; if not, it must be counter-clockwise. Here is a truth table:

         B Lo   B Hi

A Lo     CW     CCW
A Hi     CCW    CW

The rotary encoder on the Control Shield emits two transitions each time it moves to an adjacent detent position. To keep from counting both of these, we only pay attention to the FALLING edge.


This wiki page is maintained by Rich Morin, an independent consultant specializing in software design, development, and documentation. Please feel free to email comments, inquiries, suggestions, etc!

Topic revision: r17 - 16 Mar 2016, RichMorin
This site is powered by Foswiki Copyright © by the contributing authors. All material on this wiki is the property of the contributing authors.
Foswiki version v2.1.6, Release Foswiki-2.1.6, Plugin API version 2.4
Ideas, requests, problems regarding CFCL Wiki? Send us email