Thursday, October 16, 2014

Minima - Encoder, Two Implementions

After several days of work, I think I now have a working set of Encoder Routines that are usable for the Minima. Testing has been done by several builders.

The first routine: Encoder01, uses a polling analog read (non interrupt) to detect the Encoder switch changes and is not listed below.

The second routine; Encoder02, is usable for the builders that have moved to an I2C LCD and therefore have two dedicated microprocessor pins to connect to the Encoder pins A and B.

The third routine; Encoder03, is usable for builders that continue to use the parallel LCD and therefore do NOT have dedicated pins to connect to the Encoder. The previous Analog Tuning Pin and the FN Pin are used as shown in the suggested multi-switch schematic.

Selecting which Encoder routines are used, is done via a Optional Configuration selection in the "A1Config.h" file, by un-commenting the selected Encoder.



//#define USE_POT_KNOB  1 // 2304b - Option to include POT support
//#define USE_ENCODER01 1 // 2220b - Option to include Simple Encoder01 support
//#define USE_ENCODER02 1 // 2610b - Option to include FULL Two Digital Pin ISR Encoder02 support
  #define USE_ENCODER03 1 // 2604b - Option to include ISR Encoder03 support On Tuning Pin


Now that the details are work out, the Encoder supporting routines are short and simple. Each containing the "tigger" debounce timers as suggested by the author of the PinChange Library. Yes, it is called "tigger", because everyone knows tiggers bounce, as in Winnie-the-Pooh.

Some unnecessary detail are left out of these listing, check the GitHub for the actual code.

For Encoder02, these routines are used:



#include "PinChangeInt.h"

volatile int knob;

// ###############################################################################
void encoderISR() {
    int pin = ENC_B_PIN;
    static unsigned long startTime = 0;
    unsigned long tigermillis;
    uint8_t oldSREG = SREG;

    cli();
    tigermillis = millis();
    SREG = oldSREG; 
    if (tigermillis-startTime <= ISR_DEBOUNCE_TIMEOUT) return;
    startTime=tigermillis;
    
    knob += digitalRead(ENC_B_PIN) ? -1 : +1;
}

// ###############################################################################
void initEncoder() {
    int pin = ENC_A_PIN;
     
    pinMode(ENC_A_PIN, INPUT_PULLUP);
    pinMode(ENC_B_PIN, INPUT_PULLUP);
    
    PCintPort::attachInterrupt(pin, &encoderISR, FALLING);
}

// ###############################################################################
int getEncoderDir() {
    char tmp = knob;
      
    if (tmp>0) {uint8_t oldSREG = SREG; cli(); knob--; SREG = oldSREG; return +1;}      
    if (tmp<0) {uint8_t oldSREG = SREG; cli(); knob++; SREG = oldSREG; return -1;}
    return 0;
}


For Encoder03, these routines are used:



#include "PinChangeInt.h"

volatile char knob;

// ###############################################################################
void encoderISR() {
    int pin = ENC_B_PIN;

    static unsigned long startTime = 0;
    unsigned long tigermillis;  
    uint8_t oldSREG = SREG;

    cli();
    tigermillis = millis();
    SREG = oldSREG;   
    if (tigermillis-startTime <= ISR_DEBOUNCE_TIMEOUT) return;
    startTime=tigermillis;
        
    knob += analogRead(pin) < 440 ? -1 : +1;
}

// ###############################################################################
void initEncoder() {
    int pin = ENC_A_PIN;
      
    pinMode(ENC_A_PIN, INPUT_PULLUP);

    PCintPort::attachInterrupt(pin, &encoderISR, FALLING);
}

// ###############################################################################
int getEncoderDir() {
    char tmp = knob;

    if (tmp>0) {uint8_t oldSREG = SREG; cli(); knob--; SREG = oldSREG; return +1;}
    if (tmp<0) {uint8_t oldSREG = SREG; cli(); knob++; SREG = oldSREG; return -1;}
    return 0;
}


Notice: Only a few lines are different between the two implementations.


-- Home Page: https://WA0UWH.blogspot.com

1 comment: