Incremental rotary encoders (Part 2)

Part 1234567, 8, 9, 10

Fed up rotating the encoder’s knob? It is time to improve a little bit our counting technique. The encoder reading routine analyses the interval between two counts. If this interval is more than a certain time (in our case 100 ms), the counter is incremented or decremented by unitary steps. If the interval is less than 100 ms, the counter is incremented or decremented inversely proportionally to the interval: in other words, the faster the knob rotation, the faster the counting process.

int enc_read(void) {
// returns change in encoder state (-1: ccw, 0: no change, 1: cw) 
  int result = 0;
	static long lastTime = 0;
	static byte prevState = 0;
	static int bufferedCounts = 0;
	byte startState = State(); // Get current state
  delayMicroseconds(samplingTime); // Wait safety bounce time
	byte stopState = State(); // Get current state
	if ((startState == stopState) && (stopState != prevState)) { // check if the previous state was stable
		if (stopState == nextEncoderState[prevState]) {
			bufferedCounts++; 
		}
		else if (stopState == prevEncoderState[prevState]) {
			bufferedCounts--; 
		}
		prevState = stopState; // Record state for next pulse interpretation
		if (abs(bufferedCounts) == pulsesPerStep) {
			result = int(bufferedCounts / pulsesPerStep);
			long interval = (millis() - lastTime);
			if (interval < 100) {
				result *= (500/interval);
			}
			bufferedCounts = 0;
			lastTime = millis();
		}
	}
	return(result);
}

Next post on same subject

2 Comments

  1. aleandro says:

    Really cooooooooooooool! Finally I’ve see a really clever way to use my 2 buks cheap and crappy encoder that lays on my table from eons.
    The only problem I found is that I’m using a Arduino MEGA and connect encoder to digital pins 6 and 7.
    I spent some time to figure out what are the ports name and if I’m not wrong must be H3 and H4. At the end had to give up since port manipulation it’s a bit too advanced for what I’m acttualy know about arduino.
    Can you make a verion that doesn’t use PORTD, etc and just the old digitalWrite, etc.?

  2. Didier says:

    Aleandro,

    I do not plan to maintain multiple options for each library: it would be too much efforts for too few visitors. And I do not plan to get back to Digital Reads or Writes 🙁 : they are too slow for some of my applications, or even inadequate (e.g. DDS).
    I strongly encourage you to get familiar with the use of PORTx, PINs and DDRx registers. That should not be too hard.

    Anyway, if you really want to stick to high-level programming language:

    uint8_t currentState = ((((PIN(*_encPort) >> _swA) & 0x01) < < 1) | ((PIN(*_encPort) >> _swB) & 0x01));

    may be written:

    uint8_t currentState = 0;
    if (DigitalRead(_swA)) currentState += 2;
    if (DigitalRead(_swB)) currentState += 1;

    Assigning pins should not be a problem. Try it, and let us know!

Leave a Reply

You must be logged in to post a comment.