General > General Technical Chat
Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
<< < (6/8) > >>
elcrni:
Something like this, seems to work... again, uses 2 pins, not sure how i do it with one pin though.


--- Code: ---#define encoderA 2
#define encoderB 3


volatile int8_t altAB = 0;
volatile int encoderCount = 0;


int8_t steps[16] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};


ISR(TIMER1_COMPA_vect) {
  altAB <<= 2;
  altAB &= B00001100;
  altAB |= (digitalRead(encoderA) << 1) | digitalRead(encoderB);
  encoderCount += steps[altAB];
}



void setup() {
  pinMode(encoderA, INPUT);
  pinMode(encoderB, INPUT);
 
  noInterrupts();
  TIMSK1 |= (1<<OCIE1A); 

  TCCR1A = 0;

  TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10);

  // Frequency = 16000000 / 1024 / 31 = sampling rate;
 
  OCR1A = 31;
 
  interrupts();
}

void loop() {
 
}

--- End code ---


btw, i would love to test this frequency but not sure how to connect the oscilloscope, to what pins that is

Many thanks,
Alek
MarkF:
You will have to check my code.
I typically use Microchip PIC processors and rarely do any Arduino coding.   :D

Answer to #1:

   Two pins, one read.
   You have pins 2 and 3 for the encoder.
   I believe these are PortB bits 2 and 3.

   Let's assume the encoder switch is on pin 1 (PortB bit 1) with  pull-up resistor.

Answer to #2:

  To check the ISR() timing with a Mega pin, pick an unused pin and toggle it inside the ISR() routine.
  Let's pick pin 0 (PortB bit 0) for timing check.

Hence:

--- Code: ---
// global variables
int count=0;     // encoder turn count used in loop() function
uint8_t sw0=0;   // encoder switch flag used in loop() function
uint8_t last_sw0=0;

ISR(TIMER1_COMPA_vect) {
   uint8_t pins, pinA, pinB, pinS;

   digitalWrite(0, HIGH);  // set pin 0 high when entering ISR(),  check this pin with scope

   // Read encoder
   pins = PORTB;  // Read both encoder inputs at once to avoid any time delay between pin sampling
   pinS = (pins >> 1) & 0x01;   // encoder switch
   pinA = (pins >> 2) & 0x01;   // encoder A
   pinB = (pins >> 3) & 0x01;   // encoder B

   // Decode gray_code
   . . .

   // Encoder switch
   if (last_sw0 != 0 && pinS == 0) {
      sw0 = 1;   // set switch flag when depressed
   }
   last_sw0 = pinS;

   digitalWrite(0, LOW);  // set pin 0 low when leaving ISR()
}

void loop() {
   int local_count;

   if (count != 0)  {
      local_count = count;
      count = 0;  // reset encoder turn count
      // process encoder turns here using local_count variable
      . . .
   }

   if (sw0) {
      sw0 = 0;  // reset encoder switch flag
      // process encoder switch depressed
      . . .
   }

   // Do non-encoder tasks here
   . . .
}

void setup() {

  pinMode(0, OUTPUT);  // scope timing check
  pinMode(1, INPUT);   // encoder switch
  pinMode(2, INPUT);   // encoder A
  pinMode(3, INPUT);   // encoder B

}



--- End code ---

MarkF:
In order to read Port B, I believe the command should be
  pins = PINB;

and not
  pins = PORTB;
elcrni:
Many thanks MarkF.
In a meantime i got the code changed:


--- Code: ---#define encoderA 2
#define encoderB 3

volatile int encoderCount = 0;
boolean A_set = false;
boolean B_set = false;

ISR(TIMER1_COMPA_vect) {
 
  if ( digitalRead(encoderA) != A_set ) { // debounce once more
    A_set = !A_set;
    if ( A_set && !B_set )
        encoderCount ++;
  }
    if ( digitalRead(encoderB) != B_set ) {
     B_set = !B_set;
      if ( B_set && !A_set )
        encoderCount --;
    }
}


void setup() {
  pinMode(encoderA, INPUT);
  pinMode(encoderB, INPUT);
 
 
  TIMSK1 |= (1<<OCIE1A); 
  TCCR1A = 0;
  TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10);
  // Frequency = 16000000 / 1024 / 15 = sampling rate;
  OCR1A = 31;
 
   sei();
  Serial.begin(115200);
}

void loop() {
 while(true) {
    Serial.println(encoderCount);
    delay(100);
  }
}

--- End code ---

I added Serial just so i can check if it's working.
It does work, nicely, although on restart it starts at 1 rather than at 0, for some reason, but it works.

Now, will have to study your code, seems more elegant to my untrained eye :-)

thanks,
Alek
MarkF:
I would set the prescaler to 256 and the OCR1A to 125.  You do not want a fractional divisor.
In your case the timing is not critical.  Best case is to always try to have an integer divisor.

16000000 / 256 / 500 = 125

16000000 / 1024 / 500 = 31.25
Navigation
Message Index
Next page
Previous page
There was an error while thanking
Thanking...

Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod