[Solved] Reading an Absolute Encoder (Bourns EMS22A)

Hey,
I’m having problems reading an Bourns EMS22A Absolute Encoder. It outputs a stream of bitwise data which is controlled by a clock line. you can find the Data Sheet here.
I connected the Pin 6 & 1(chip select & digital input) to ground since I only have 1 encoder and don’t need to daisy chain anything.
Here my test code to test the encoder, but somehow it only outputs zeros and I’m not sure why:

const int PIN_CLOCK = 6;
const int PIN_OUTPUT = 7;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_CLOCK, OUTPUT);
  pinMode(PIN_OUTPUT, INPUT);
  digitalWrite(PIN_CLOCK, HIGH);
}

int last_output = -1;

void loop() {
  delay(1000);
  for (int i=0; i<16; i++) {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);
    Serial.print(digitalRead(PIN_OUTPUT));
  }
  digitalWrite(PIN_CLOCK, LOW);
  digitalWrite(PIN_CLOCK, HIGH);
  Serial.println(""); 
}

Maybe some one can figure out what I’m doing wrong.

It SAYS you can connect CS to GND but all of the timing diagrams show the sample being taken when you drop CS. :(

On the second page of the datasheet the timing diagram shows that the CSn pin must be high for a minimum of 500ns between readings.

Your datasheet link didn't work, so I'm reading it from a random "datasheet archive" site.

I figured, that the cs pin would only if you daisy chain several encoders together. I tried it anywhy but it didn’t changened anything:

const int PIN_CS = 5;
const int PIN_CLOCK = 6;
const int PIN_OUTPUT = 7;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_CLOCK, OUTPUT);
  pinMode(PIN_OUTPUT, INPUT);
  
  digitalWrite(PIN_CLOCK, HIGH);
  digitalWrite(PIN_CS, LOW);
}

void loop() {
  delay(1000);
  digitalWrite(PIN_CS, HIGH);
  delayMicroseconds(1);
  digitalWrite(PIN_CS, LOW);
  delayMicroseconds(1);
  
  for (int i=0; i<16; i++) {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);
    Serial.print(digitalRead(PIN_OUTPUT));
  }
  digitalWrite(PIN_CLOCK, LOW);
  digitalWrite(PIN_CLOCK, HIGH);
  Serial.println(""); 
}

BTW: I updated the links in my post above.

Seems I just confused with the wiring, since it works now :stuck_out_tongue:
Thanks for the help anyway.

btw: The ChipSelect pin is realy necessary. Here is my example code in case somebody else wants to tinker with this type of encoders:

const int PIN_CS = 5;
const int PIN_CLOCK = 6;
const int PIN_DATA = 7;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_CLOCK, OUTPUT);
  pinMode(PIN_DATA, INPUT);

  digitalWrite(PIN_CLOCK, HIGH);
  digitalWrite(PIN_CS, LOW);
}


//byte stream[16];
void loop() {

  digitalWrite(PIN_CS, HIGH);
  digitalWrite(PIN_CS, LOW);
  int pos = 0;
  for (int i=0; i<10; i++) {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);
    
    byte b = digitalRead(PIN_DATA) == HIGH ? 1 : 0;
    pos += b * pow(2, 10-(i+1));
  }
  for (int i=0; i<6; i++) {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);
  }
  digitalWrite(PIN_CLOCK, LOW);
  digitalWrite(PIN_CLOCK, HIGH);
  Serial.println(pos);
}

Thanks brah - That works perfect!

sepal:
Seems I just confused with the wiring, since it works now :stuck_out_tongue:
Thanks for the help anyway.

btw: The ChipSelect pin is realy necessary. Here is my example code in case somebody else wants to tinker with this type of encoders:

const int PIN_CS = 5;

const int PIN_CLOCK = 6;
const int PIN_DATA = 7;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_CLOCK, OUTPUT);
  pinMode(PIN_DATA, INPUT);

digitalWrite(PIN_CLOCK, HIGH);
  digitalWrite(PIN_CS, LOW);
}

//byte stream[16];
void loop() {

digitalWrite(PIN_CS, HIGH);
  digitalWrite(PIN_CS, LOW);
  int pos = 0;
  for (int i=0; i<10; i++) {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);
   
    byte b = digitalRead(PIN_DATA) == HIGH ? 1 : 0;
    pos += b * pow(2, 10-(i+1));
  }
  for (int i=0; i<6; i++) {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);
  }
  digitalWrite(PIN_CLOCK, LOW);
  digitalWrite(PIN_CLOCK, HIGH);
  Serial.println(pos);
}

Hi,
reading the absolute data bits works fine with your code! thanks for this!

i am looking at the datasheet and it definitely says:
"
Data Content:
yadda yadda
S4: Increase in Magnitude
S5: Decrease in Magnitude
"

Magnitude means Full Rotation Count right??
When I look at the 16Bit Stream I don’t see a Change in those Bits when rotating!
Am I doing something wrong?

const int PIN_CS = 5;
const int PIN_CLOCK = 6;
const int PIN_DATA = 7;

void setup() {
  Serial.begin(115200);

  //SETUP BOURNS EMS22A
  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_CLOCK, OUTPUT);
  pinMode(PIN_DATA, INPUT);

  digitalWrite(PIN_CLOCK, HIGH);
  digitalWrite(PIN_CS, LOW);
}


//byte stream[16];
void loop() {

  //READ BOURNS
  digitalWrite(PIN_CS, HIGH);
  digitalWrite(PIN_CS, LOW);

   for (int i=0; i<16; i++) {
   digitalWrite(PIN_CLOCK, LOW);
   digitalWrite(PIN_CLOCK, HIGH);
   Serial.print(digitalRead(PIN_DATA));
   }

  digitalWrite(PIN_CLOCK, LOW);
  digitalWrite(PIN_CLOCK, HIGH);

  Serial.println(""); 

}

In fact there is No Output (0 all the time) on any Status Bit, but i wouldnt know what to do with S1-S3 anyway (Linearity Alarm?)

Nothing in the Datasheet tells me that the Absolute Version has no Magnitude Detection.

I need the Rotation Count, what would be the best/fastest way to get a reliable count?

you might consider a bit shift operation for the reading of the data, something like:

pos = 0;
for(…){
pos <<=1;
pos = digitalRead( PIN_DATA );

}

instead of

byte b = digitalRead(PIN_DATA) == HIGH ? 1 : 0;
pos += b * pow(2, 10-(i+1));