Author Topic: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...  (Read 6488 times)

0 Members and 1 Guest are viewing this topic.

Offline elcrniTopic starter

  • Regular Contributor
  • *
  • Posts: 98
  • Country: at
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #25 on: March 18, 2021, 11:41:31 pm »
Something like this, seems to work... again, uses 2 pins, not sure how i do it with one pin though.

Code: [Select]
#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() {
 
}


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

Many thanks,
Alek
« Last Edit: March 18, 2021, 11:44:24 pm by elcrni »
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2762
  • Country: us
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #26 on: March 19, 2021, 12:42:27 am »
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: [Select]

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

}



 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2762
  • Country: us
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #27 on: March 19, 2021, 12:55:31 am »
In order to read Port B, I believe the command should be
  pins = PINB;

and not
  pins = PORTB;
 

Offline elcrniTopic starter

  • Regular Contributor
  • *
  • Posts: 98
  • Country: at
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #28 on: March 19, 2021, 01:15:29 am »
Many thanks MarkF.
In a meantime i got the code changed:

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

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
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2762
  • Country: us
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #29 on: March 19, 2021, 04:26:58 am »
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
 

Offline elcrniTopic starter

  • Regular Contributor
  • *
  • Posts: 98
  • Country: at
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #30 on: March 19, 2021, 12:16:22 pm »
Alright, changed the prescaler to 256 and now reading ~496Hz on the scope port.
I am very happy with this now!


Code: [Select]
#define encoderA 2
#define encoderB 3

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

const int scope_pin =PB0;

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 --;
    }
    PORTB ^= (1<< scope_pin);
}


void setup() {
  pinMode(encoderA, INPUT);
  pinMode(encoderB, INPUT);

  DDRB |= (1 << scope_pin);

  TIMSK1 |= (1<<OCIE1A);

  TCCR1A = 0;
  TCCR1B = (1<<WGM12) | (1<<CS12);
  OCR1A = 125;
 
  sei();
 
}

void loop() {
 
}


Many thanks for all your help MarkF!

Alek
 

Offline elcrniTopic starter

  • Regular Contributor
  • *
  • Posts: 98
  • Country: at
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #31 on: March 19, 2021, 04:24:24 pm »
very strange thing happens, i have just measured frequency on the scope pin again, whatever i do i get 248Hz, half of the 500Hz target... once i remove the ground connection and measure with positive scope probe i get 496Hz...
either i am doing something very wrong or my math in the code is no good...

Thanks,
Alek
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2762
  • Country: us
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #32 on: March 19, 2021, 04:49:27 pm »
very strange thing happens, i have just measured frequency on the scope pin again, whatever i do i get 248Hz, half of the 500Hz target... once i remove the ground connection and measure with positive scope probe i get 496Hz...
either i am doing something very wrong or my math in the code is no good...

Thanks,
Alek

Think about what your code is doing...

Hint:  Every time you enter the ISR() routine you toggle the scope_pin.

If you set the scope_pin when you enter the ISR() and then clear the scope_pin when you exit the ISR(), you will be able to measure the time spent inside the ISR().

Question:  Why are you doing Port writes for the scope_pin and bit reads for the encoder lines?
  1)  Doing the Port write for the scope_pin effects ALL bits in that port.
  2)  I would expect the opposite.  Bit write for scope_pin and port read for encoder bits.
Ideally, doing a port read for the encoder will avoid time skew of encoder_A and encoder_B lines.  All be it, the time delay should be very small.  You never really know how much overhead is inside the digitalRead() function.
 

Offline elcrniTopic starter

  • Regular Contributor
  • *
  • Posts: 98
  • Country: at
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #33 on: March 19, 2021, 05:11:13 pm »
if i do it like you suggested:

Code: [Select]
uint8_t pins, pinA, pinB, pinS;

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


I get no readout at all on pin0 (digital pin 53 on mega2560)

As for the port/pin part of it, i am still trying to get a hang of it, still a bit confusing so i am basically shooting in the dark here :-)

Many thanks,
Alek
 

Offline elcrniTopic starter

  • Regular Contributor
  • *
  • Posts: 98
  • Country: at
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #34 on: March 19, 2021, 05:22:01 pm »
ok, just changed your pin0 to pin53 and i have a reading of ~500Hz now. this should be it.


json object validator

Off to the next thing, pin/port confusion and trying to figure out your encoder code.

Thanks,
Alek
 

Offline MarkF

  • Super Contributor
  • ***
  • Posts: 2762
  • Country: us
Re: Schmitt Buffer/Trigger with Encoder and buttons - Inverting...
« Reply #35 on: March 19, 2021, 06:12:51 pm »
The short story:

1)  digitalRead(), digitalWrite(), pinMode() functions operate on an individual pin

2)  PINx, PORTx, DDRx operate on multiple pins at once. 
The number of pins effected depends on the width of the port (up to and including 8 pins).
 
The following users thanked this post: elcrni


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf