en EN   ru RU   uk UK

Main

A2 OS

DRAKON

Arduino

Encoder

Programs

Utilities

Links

For webmaster

Contact info

CV


A2 OS forum

 
  Printable copy

The algorithmfor reliable reading encoder encoder angle rotation forArduino


SAGE


Inthe process experiments with analogue board Arduino Uno itturnedout, that isnot enough reliable code for reading readings mechanical encoder angle rotation, extracted ofthe mouse. Presented only wagon and small trolley half-working examples, working extremely unstable. Ihadto eliminate this annoying nuisance and write this code. Problem interaction with mechanical encoder is in volume, what need tosolveeffectively##32 problem rattling contacts, whichisinherentin inherentin##32ofthis device, islike#32and islikethe and button. Forthe button,the##32buttonisenoughforthe#32tosetthe delay to forafew milliseconds. For encoder thesame needsto#&32analyze its state with high frequency, and delays here immediately willreduce 'seffectiveness. Inthe#&32examples isenough explicitly make understand that ismore effective algorithm should use interrupt. What I and used.

Reading status outputs encoder carriedout 2 interrupts by level change. Each event interrupt issuppliedwith aunique identifier bitcapacity in 1 bytes, ofwhich iscompletely isenough, if inthe main cycle ofArduino analyze received events without extra delays. For identification isused single-byte number with sign (short). Constant increment ofits value naturally gives anoverflow, but in this isnot nothing scary if know as with such numbers workcorrectly . In particular, not looking at overflow, we can enter for ofeach of two numbers oftheresulting sequence, if they arenot too removed friend from friend, such operation as distance between two such numbers (function EventsBetween).

Through each 1 ms iscarriedout analysis ofreceived events for this period. Parsed number events (use EventsBetween) and special amount, helping determine, which level input signal in data events prevailed. Any event lowering level includes in thesum as term, equalto equalto -1, a any event increase level as term, equal +1. Inthis way, if theamount turnedout isnegative ismorelikely intotal happened decrease level, if sum ispositive - rather total occurred levelincrease , if sum turnedouttobe equalto 0, such result not carries no specific useful information about level(is just noise) at given input and isdiscarded, and beyond level matching outOde encoder isaccepted previous value. i.e. for review events in quality reliable source information needed tobe fixed some events (counter ofthenumber events not isequalto 0) and thesumof by levels ofthese events too not was equalto 0. This technique effectively solvesthe problem bounce ofcontacts and doesn’t requireany##32 time delays. Analysis status through every 1 ms showed high efficiency. i.e. polling encoder goes really with maximum frequency with which microcontroller iscapableof toprocess interrupts, a analysis information, accumulated during processing interrupt occurs with frequency order 321 kHz, ofwhich ismorethan than isenough. During debugging algorithm algorithm wasvisible that for for period 1 ms can occur to 40-50 interruptions and providedby byme tricks handle such significant for microcontroller stream information isenough effective.

Connectiondiagram encoder, Ithink,##32doesn’tmakesense#&32 here show, onthe internet such information missing. Encoder outputs areconnected to second and third pin, that correspondsto zero and tothefirst interrupt Arduino Uno. encoder controlsthe brightness oftheLED, connected tothe ninth output, used in mode PWM.

// Encoder pins
#define encoder0PinA 2
#define encoder0PinB 3
// LED pin
#define LED_PIN 9

// Encoder inputs in high state
unsigned short A_high, B_high;
// Count of encoder events between two timer events
unsigned short A_between = 0, B_between = 0;
// Previous decission on encoder state
unsigned short A_statePrev = 0, B_statePrev = 0;

// Current event id for each encoder input
short A_event = 0, B_event = 0;
// Id of event that already accounted
short A_eventPrev = 0, B_eventPrev = 0;
// Timestamps for time measurements
unsigned long timeCur, timePrev;
// Value for estimation of dominant inputs state
short A_level = 0, B_level = 0;

int encoder0Pos = 127;
int fadeAmount = 10;

// Number of events between two event id's
int EventsBetween(short iCur, short iPrev) {
  if ((iCur < 0) && (iPrev < 0)) {
    return (int(iCur) + 256) - (int(iPrev) + 256);
  } else if (iCur < 0) {
    return (int(iCur) + 256) - iPrev;
  }
  return iCur - iPrev;
}

// Keep value in limits
int clamp(int value, int low, int high) {
  if (value < low) {
    return low;
  }
  if (value > high) {
    return high;
  }
  return value;
}

void setup() {
  pinMode(encoder0PinA, INPUT); 
  pinMode(encoder0PinB, INPUT);
  pinMode(LED_PIN, OUTPUT);
  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);
  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderB, CHANGE);
  //Serial.begin(9600);
  analogWrite(LED_PIN, encoder0Pos);
  timePrev = millis();
}

void loop(){ 
  timeCur = millis();
  if (timeCur > timePrev) {
    timePrev = timeCur;
    boolean A_change = A_between && A_level;
    boolean B_change = B_between && B_level;
    if (A_change || B_change) {
      boolean A_state, B_state;
      if (A_change) {
        A_state = A_level > 0;
      } else {
        A_state = A_statePrev;
      }
      if (B_change) {
        B_state = B_level > 0;
      } else {
        B_state = B_statePrev;
      }
      if ((A_change && ((!A_state && A_statePrev && B_state) || (A_state && !A_statePrev && !B_state))) ||
        (B_change && ((!B_state && B_statePrev && !A_state) || (B_state && !B_statePrev && A_state)))) {
        encoder0Pos += fadeAmount;
      }
      if ((A_change && ((!A_state && A_statePrev && !B_state) || (A_state && !A_statePrev && B_state))) ||
        (B_change && ((!B_state && B_statePrev && A_state) || (B_state && !B_statePrev && !A_state)))){
        encoder0Pos -= fadeAmount;
      }
      encoder0Pos = clamp(encoder0Pos, 0, 255);
      analogWrite(LED_PIN, encoder0Pos);
      A_statePrev = A_state;
      B_statePrev = B_state;
    }
    A_between = 0;
    B_between = 0;
    A_level = 0;
    B_level = 0;
  }
  else
  {
    if (EventsBetween(A_event, A_eventPrev) >= 1) {
      A_eventPrev = A_event;
      if (A_high) {
        A_level++;
      } else {
        A_level--;
      }
      A_between++;
    }
    if (EventsBetween(B_event, B_eventPrev) >= 1) {
      B_eventPrev = B_event;
      if (B_high) {
        B_level++;
      } else {
        B_level--;
      }
      B_between++;
    }
  }
}

// Interrupt on A changing state
void doEncoderA(){
  A_high = (digitalRead(encoder0PinA) == HIGH);
  A_event++;
}

// Interrupt on B changing state
void doEncoderB(){
  B_high = (digitalRead(encoder0PinB) == HIGH);
  B_event++;
}




Last update: 24-2-20 01:22:59


 

alt CodeTyphon

Copyright © 2005-2021 SAGE. All rights reserved.