Go Down

Topic: Read rotary decoder output (Read 280 times) previous topic - next topic


May 23, 2019, 02:31 pm Last Edit: May 23, 2019, 03:34 pm by TidensBarn
I've got a rotary encoder with the model name "MAB36 12HS 5 SER" and I'm not sure how to read its output, or even interpret its datasheet. On page 2 there's a timing diagram. Is this something maybe SPI.h or some other library can handle out of the box, given the right settings, or is this some non-standard stuff I'd need to implement myself?


I've got a rotary encoder
but you want to
Read rotary decoder output
Color me confused.

It's not clear to me, though it should be to you, how many wires are coming from the device. If there are four, as I'd expect, one should be connected to ground, one should be connected to a suitable power supply (I closed the file, so I can't check the voltage it operates at), and the other two should be connected to external interrupt pins on the Arduino.

There are several libraries for reading encoder output, using interrupts or not. For a 6000 RPM encoder, interrupts are almost certainly going to be needed.
The art of getting good answers lies in asking good questions.


That was a typo, it's an encoder, not a decoder..

Yes there are wires for power + ground, obviously. Then there's D0, CLK and CSn. Their function is explained in the diagram I was talking about. It's some sort of synchronous serial interface. D0 is the data line, CLK is for timing and CSn for polling, I guess.


Ok, without really knowing what I'm doing, I took a shot at this.. I simply took three digital pins and started flipping CLK and CSn as shown in the timing diagram, while reading D0... and it actually yields somewhat sensible values that seem to (kind of) correspond to the physical rotation. I'm actually surprised at how easy this was. :smiley-razz:
Still, can someone tell me if this is the right way to do this? Can my code be optimised?

What's strange is that the rotation value only reaches about 240 and then starts decreasing again, when it actually should go up to 4096 for a full rotation.

Code: [Select]

int d0 = 50;
int CLK = 52;
int CSn = 53;

void setup() {

  pinMode(d0, INPUT);
  pinMode(CLK, OUTPUT);
  pinMode(CSn, OUTPUT);

  digitalWrite(CSn, LOW);
  digitalWrite(CLK, HIGH);

void loop() {                                             

    byte res = 12;

    byte bits[res];

    digitalWrite(CSn, HIGH);
    digitalWrite(CSn, LOW);


    for(int i = 0; i < 18; i++) { // 12-bit rotation value + 6 status bits = 18 bits to read

      digitalWrite(CLK, LOW);
      if(i < res) {
        bits[i] = digitalRead(d0);

      digitalWrite(CLK, HIGH);

    int v = binaryDecode(bits, len);

int binaryDecode(char* bits, int len) {
    int value = 0;
    for (int i=0; i< len; i++)  //
      value *= 2;
      if (bits[i] == 1) value++; 
    return value;


Yes, that's an SSI (software serial interface) absolute encoder. There is a good reference thread here https://forum.arduino.cc/index.php?topic=156812.0

I wrote this some time ago for a similar encoder, and it might give you some ideas
Code: [Select]

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

int magnitude = 0;

int pos;
int oldPos = 0;

byte stream[16] = {0};//replace testStream with stream for actual data
//byte testStream[] = {1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1}; //test data stream
//byte testStream[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}; //test data stream

void setup() {

  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_DATA, INPUT);

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

void loop() {
  digitalWrite(PIN_CS, HIGH);
  digitalWrite(PIN_CS, LOW);

  stream[16] = {0};
  for (int i = 0; i < 16; i++) {
    digitalWrite(PIN_CLOCK, LOW);
    digitalWrite(PIN_CLOCK, HIGH);

    stream[i] = digitalRead(PIN_DATA);
    //pos = pos<<1 + stream[i]; can construct sum here
    //packeddata = ((packeddata << 1) + inputstream); // left-shift summing variable, add pin value

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

  oldPos = pos;
  //extract 10 bit position from data stream use testStream
  pos = 0; //clear previous data
  for (int i = 0; i < 10; i++) {
    pos = pos << 1;
    //pos += testStream[i]; //replace testStream with stream
    pos += stream[i];
    //pos = pos<<1 + stream[i];
    //packeddata = ((packeddata << 1) + inputstream); // left-shift summing variable, add pin value

  if(oldPos > 1021 && pos < 3) magnitude++;
  if(oldPos < 3 && pos > 1021) magnitude--;

  //print position 0-1023
  Serial.print(pos, BIN);

  //extract 6 bits of status
  //for (int i = 10; i < 16; i++)
    //Serial.println(testStream[i]);//replace testStream with stream

Go Up