Go Down

Topic: Absolute rotary Encoder SSI SPI how ? (Read 22089 times) previous topic - next topic

colorsound

Hello guys

I,m trying to get data from an Absolute rotary Encoder 13 bit and 25 bit multiturn:

http://www.posital.com/us/products/POSITAL/AbsoluteEncoders/AbsoluteEncoders_base.html
POSITAL OCD-S101B-0012-C100-CRW

http://www.posital.eu/en/products/POSITAL/AbsoluteEncoders_Context/AbsoluteEncoders_Context_Technology_SSI_AppNote.pdf
http://www.posital.com/us/products/POSITAL/AbsoluteEncoders/AbsoluteEncoders_OCD_SSI_Datasheet_DataContent.pdf

I,m using a SN75179B DIFFERENTIAL DRIVER AND RECEIVER PAIR
http://www.farnell.com/datasheets/1534200.pdf and i have connected as the Figure 2.1: Simple SSI Master in the
AbsoluteEncoders_Context_Technology_SSI_AppNote.pdf

A and  B to D+ and  D-
R to receive in arduino input
Y and  Z to clock+ and clock-
D as arduino output to generate clock



I,m also not sure if i need to use the spi way and if so how ?

I look in many forum post about similar staff i could run some most of then did not do anything this one
http://www.reprap.org/wiki/Magnetic_Rotary_Encoder_1_0#PWM_Output for example it does not look like the perfect one but at least i get some response when moving the encoder which at least sounds to me that the SN75179B is working well.

inside the AbsoluteEncoders_Context_Technology_SSI_AppNote.pdf  there are some apparently interesting codes to get it working but i,m not sure how to convert to arduino soft?
i tried to paste here but i got :exceeds the maximum allowed length (9500 characters).

btw I,m using arduino Uno but i could use other type if neccesary.

could you guide me to get the examples from the encoder,s pdf or other to work with arduino in order to get the rotation data from the encoder ?.

cheers and thanks

johnwasser

From the documentation it looks like this might get you started:

Code: [Select]

const int CLOCK_PIN = 5;
const int DATA_PIN = 6;
const int BIT_COUNT = 25;

void setup() {
  //setup our pins
  pinMode(DATA_PIN, INPUT);
  pinMode(CLOCK_PIN, OUTPUT);

  //give some default values
  digitalWrite(CLOCK_PIN, HIGH);

  Serial.begin(19200);
}


void loop() {
  unsigned long reading = readPosition();

  Serial.print("Reading: ");
  Serial.print(reading, DEC);

  delay(1000);
}

//read the current angular position
int readPosition() {
  // Read the same position data twice to check for errors
  unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  unsigned long sample2 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);

  delayMicroseconds(25);  // Clock mus be high for 20 microseconds before a new sample can be taken

  if (sample1 != sample2) {
    Serial.print("Samples dont match: sample1=");
    Serial.print(sample1);
    Serial.print(", sample2=");
    Serial.println(sample2);
  }

  return sample1;
}

//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
  unsigned long data = 0;

  for (int i=0; i<bit_count; i++) {
    data <<= 1;
    digitalWrite(clock_pin, LOW);
    delayMicroseconds(1);
    digitalWrite(clock_pin, HIGH);
    delayMicroseconds(1);

    data |= digitalRead(data_pin);
  }

  return data;
}
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

colorsound

Hello johnwasser thanks a lot for your reply.

This is what i have so far , the first code works quite accurate apart from a repeting error every certain time.
It gives one or 2 values wrong and then keeps with the correct ones , i copy pieces of the  outputs  values so you see:

55.8984375000
53.7890625000 --wrong
13.7109375000 --wrong
55.8984375000
55.8984375000

55.8984375000
55.8984375000
46.4062500000 --wrong
13.7109375000 --wrong
55.8984375000
55.8984375000

also it seems in this code i,m not benefit from the 13,25 bits of the encoder



Code: [Select]
#define CLOCK_PIN 5
#define DATA_PIN 6

void setup()
{
  //setup our pins
  pinMode(DATA_PIN, INPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  //give some default values
  digitalWrite(CLOCK_PIN, HIGH);
  Serial.begin(115200);
}
//variables to keep track of position
int reading = 0;
float angle = 0;

void loop()
{
   reading = readPosition();
   
   if (reading >= 0)
   {   // Now it,s got a resolution of 1024
       angle = ((float)reading/1024) * 360.0;
       Serial.println(angle,DEC);
      //Serial.println(reading,DEC);
   }

   delay(200);
}

//read the current angular position
int readPosition()
{
  unsigned int position = 0;

  //shift in our data 

  delayMicroseconds(1);
  byte d1 = shiftIn(DATA_PIN, CLOCK_PIN);
  byte d2 = shiftIn(DATA_PIN, CLOCK_PIN);


  //get our position variable
  position = d1;
  position = position << 8;

  position |= d2;

  position = position >> 6; // by lowering this value i seem to be getting more resolution not sure if true or fake.

  return position;
}

//read in a byte of data from the digital input of the board.
byte shiftIn(byte data_pin, byte clock_pin)
{
  byte data = 0.0;

  for (int i=7; i>=0; i--)
  {
    digitalWrite(clock_pin, LOW);
    delayMicroseconds(1);
    digitalWrite(clock_pin, HIGH);
    delayMicroseconds(1);

    byte bit = digitalRead(data_pin);

    data |= (bit << i);

  }

  return data;
}



when using your code which looks more interesting for benefit from 13 and 25 bits i get this output which seem to be doing something but causing sort of random amount of values :

Samples dont match: sample1=1294415, sample2=5185852
Reading: 4294950991
Samples dont match: sample1=5874022, sample2=5873942
Reading: 4294943078
Reading: 388
Reading: 4294934950
Samples dont match: sample1=7643602, sample2=7661891
Reading: 4294943186
Reading: 16905
Samples dont match: sample1=9413181, sample2=9421375
Reading: 4294943293
Samples dont match: sample1=9038375, sample2=10396282
Reading: 4294961703
Samples dont match: sample1=11338420, sample2=11338326
Reading: 692
Samples dont match: sample1=12395252, sample2=12394874
Reading: 8948


i played a bit with your code and i seem to be getting sort of reasonable data apart from some error similar to the one of the other code i described above, some other error also a little flickering when no move .and also that it is not multiturn data single turn so far:
values go from 0-4096 for full revolution 360º.

Reading: 275
Reading: 264
Reading: 275
Reading: 260
Reading: 275
Reading: 260
Reading: 275
Reading: 260
Reading: 275
Reading: 260
Reading: 275

Here is the your modify code :

Code: [Select]
const int CLOCK_PIN = 5;
const int DATA_PIN = 6;
const int BIT_COUNT = 25;

void setup() {
  //setup our pins
  pinMode(DATA_PIN, INPUT);
  pinMode(CLOCK_PIN, OUTPUT);

  //give some default values
  digitalWrite(CLOCK_PIN, HIGH);

  Serial.begin(115200);
}


void loop() {
  unsigned long reading = readPosition();

  Serial.print("Reading: ");
  Serial.println(reading, DEC);

  delay(200);
}

//read the current angular position
int readPosition() {
  // Read the same position data twice to check for errors
  unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  unsigned long sample2 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
 
  unsigned long sample3;

  delayMicroseconds(25);  // Clock mus be high for 20 microseconds before a new sample can be taken

//  if (sample1 != sample2) {
//    Serial.print("Samples dont match: sample1=");
//    Serial.print(sample1);
//    Serial.print(", sample2=");
//    Serial.println(sample2);
//  }
 
  sample3 = sample1;
   
//sample3 = sample3 << 25;

  //sample3 = sample3 << 5;
  //sample3 |= sample2;
  //sample3 = (sample3 >> 12) & 0x0FFF;

  sample3 = sample3 >> 13; // this is giving and output from 0-4095 which is correct apart from the random erros
  //but  singleTurn only though not to sure how to split get the multiturn data i presume is the rest of the message ?
   
  return sample3 ;
}

//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
  unsigned long data = 0;

  for (int i=0; i<bit_count; i++) {
    data <<= 1;
    digitalWrite(clock_pin,LOW);
    delayMicroseconds(1);
    digitalWrite(clock_pin,HIGH);
    delayMicroseconds(1);

    data |= digitalRead(data_pin);
  }

  return data;
}


basicly what i am missing is a clean output without error and the multiturn data .

let me know if any ideas or solutions.

thanks again .

johnwasser

POSITAL OCD-S101B-0012-C100-CRW

the 'B-0012-' part means Binary, SINGLE TURN, 12 bit (4096 steps per revolution)

The position should be in the bottom 12 bits.  The multi-turn data in the upper 12 bits shouldn't be doing anything useful.

If an interrupt takes more then 20 microseconds you will get a misread.  They recommend you read the data twice and throw out any sample where the two don't match.

Try this version:
Code: [Select]


const int CLOCK_PIN = 5;
const int DATA_PIN = 6;
const int BIT_COUNT = 25;

void setup() {
  //setup our pins
  pinMode(DATA_PIN, INPUT);
  pinMode(CLOCK_PIN, OUTPUT);

  //give some default values
  digitalWrite(CLOCK_PIN, HIGH);

  Serial.begin(115200);
}


void loop() {
  float reading = readPosition();

  if (reading >= -0.5) {
      Serial.print("Reading: ");
       Serial.println(reading,2);
  }

  delay(500);
}

//read the current angular position
float readPosition() {
  // Read the same position data twice to check for errors
  unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  unsigned long sample2 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  delayMicroseconds(25);  // Clock mus be high for 20 microseconds before a new sample can be taken

  if (sample1 != sample2)
    return -1.0;

  return ((sample1 & 0x0FFF) * 360UL) / 4096.0;
}

//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
  unsigned long data = 0;

  for (int i=0; i<bit_count; i++) {
    data <<= 1;
    digitalWrite(clock_pin,LOW);
    delayMicroseconds(1);
    digitalWrite(clock_pin,HIGH);
    delayMicroseconds(1);

    data |= digitalRead(data_pin);
  }

  return data;
}
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

colorsound

Hi again ,

i just change now the const int BIT_COUNT = 13;
It works so smooth and nice no erros at all so cool :)

thanks so much , i appreciated your help ;D

Ma77h3w

I'm doing something similar with a 17-bit Hengstler angle encoder. It displays angle, minutes, seconds on an LCD.
It communicates ok with this code, but about 40-45% of the samples fail the match check. I have this being displayed on a 2x16 LCD.
I found that the original method above for clocking out 2 readings and comparing them produces 80-90% miss-match when the angle encoder rotates.
I added a extra clock cycle in between the two 17-bit readings (see wikipedia for SSI) and this keeps the miss-match at 40-45% even when rotating.
I also found a marginal improvement by removing the 2nd delayMicroseconds(1); I thought that the digitalRead must take a few microseconds so this delays it anyway.
Any ideas of the remaining 40-45% sample fail rate?

Here's my code:

Code: [Select]

#include <LiquidCrystal.h>

const int CLOCK_PIN = 9;
const int DATA_PIN = 10;
const int BIT_COUNT = 17; //for 17 bit encoder

unsigned long count;
unsigned long errcount;
unsigned long clock, clock2;
float freq;

byte degsign[8] = {
  B01100,
  B10010,
  B10010,
  B01100,
  B00000,
  B00000,
  B00000,
};

byte minsign[8] = {
  B01100,
  B01100,
  B00100,
  B01000,
  B00000,
  B00000,
  B00000,
};

byte secsign[8] = {
  B11011,
  B11011,
  B01001,
  B10010,
  B00000,
  B00000,
  B00000,
};

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);//set up LCD pins

void setup() {
  lcd.createChar(0, degsign);
  lcd.createChar(1, minsign);
  lcd.createChar(2, secsign);

  pinMode(DATA_PIN, INPUT);
  pinMode(CLOCK_PIN, OUTPUT);

  digitalWrite(CLOCK_PIN, HIGH);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.setCursor(0, 1);
  lcd.print("Starting..");
  clock = 0;
  clock2 = 0;
  count = 0;
  errcount = 0;
}

void loop() {

  int degree = 0;
  int arcmin = 0;
  int arcsec = 0;
 
  unsigned long reading = readPosition();
  //reading = 130999; //test
  degree = reading * 360.0 / 131072.0;
  arcmin = reading * 21600.0 / 131072.0 - degree*60;
  arcsec = (reading*10125UL/1024UL)-(degree*60*60)-(arcmin*60);
 
  if (reading > 0.0) { //checks if reading was valid
    count++;
   
    if (clock2+100 < millis()) {//LCD update rate 100ms
      clock2 = millis(); //reset LCD update timer
      if (clock+10000 < millis()) {//every 10 seconds run this
        if (freq == 0) freq = count/10.0; //calculate successful readings frequency
        lcd.setCursor(0, 0);
        lcd.print("Rate:         Hz");
        lcd.setCursor(6, 0);
        lcd.print(freq,1);
        if (clock+11000 < millis()){
          lcd.setCursor(0, 0);
          lcd.print("Comms Err:   %  ");
          lcd.setCursor(11, 0);
          lcd.print(100.0*errcount/(count+errcount),0); //calculate and display the % of readings which failed
          if (clock+12000 < millis()){ //resets timer
            freq = 0;
            count = 0;
            errcount = 0;
            clock = millis();
          }
        }
 
      } else {
        lcd.setCursor(0, 0);
        lcd.print("Raw:            ");
        lcd.setCursor(5, 0);
        lcd.print(reading);
      }
     
      lcd.setCursor(0, 1);
      lcd.print("Deg:            ");
      lcd.setCursor(5, 1);
      lcd.print(degree);
      lcd.setCursor(8, 1);
      lcd.write(byte(0));
      lcd.setCursor(9, 1);
      lcd.print(arcmin);
      lcd.setCursor(11, 1);
      lcd.write(byte(1));
      lcd.setCursor(12, 1);
      lcd.print(arcsec);
      lcd.setCursor(14, 1);
      lcd.write(byte(2));

    }
  } else {
    errcount++; //counts errornous results
  }

}

//read the current angular position
unsigned long readPosition() {
  // Read the same position data twice to check for errors - Now reads twice in shiftIn function
  unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  //unsigned long sample2 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  delayMicroseconds(25);  // Clock must be high for 20 microseconds before a new sample can be taken
  //if (sample1 != sample2) return 0;
  return sample1;
}

//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
  unsigned long data = 0;
  unsigned long data2 = 0;

  for (int i=0; i<bit_count; i++) { //reads first bits
    data <<= 1;
    digitalWrite(clock_pin,LOW);
    delayMicroseconds(1);
    digitalWrite(clock_pin,HIGH);
    //delayMicroseconds(1);
    data |= digitalRead(data_pin);
  }
  digitalWrite(clock_pin,LOW); //clocks space bit
  delayMicroseconds(1);
  digitalWrite(clock_pin,HIGH);
  delayMicroseconds(1);
   
  for (int i=0; i<bit_count; i++) { //reads second set of bits
    data2 <<= 1;
    digitalWrite(clock_pin,LOW);
    delayMicroseconds(1);
    digitalWrite(clock_pin,HIGH);
    //delayMicroseconds(1);
    data2 |= digitalRead(data_pin);
  }

  if (data != data2) return 0;
  return data;
}

HTIEN

HI guys,
I have an absolute encoder Ref. SCH24AB with a 12 bits resolution and an arduino Mega 2560. My aim is to read the angular position in the serial monitor if I turn my encoder. I want to use the example gived by Johnwasser but  in my serial monitor, I obtain: reading=0. My question is what is the mean to connect correctly  my absolute encoder with the pins arduino . You find a datasheet in: http://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCAQFjAA&url=http%3A%2F%2Fwww.sensorsystem.it%2FEncoder_pdf%2Fassoluti%2FSCH24AB.pdf
See you!

HTIEN


HI guys,
I have an absolute encoder Ref. SCH24AB with a 12 bits resolution and an arduino Mega 2560. My aim is to read the angular position in the serial monitor if I turn my encoder. I want to use the example gived by Johnwasser but  in my serial monitor, I obtain: reading=0. My question is what is the mean to connect correctly  my absolute encoder with the pins arduino . You find a datasheet in: http://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCAQFjAA&url=http%3A%2F%2Fwww.sensorsystem.it%2FEncoder_pdf%2Fassoluti%2FSCH24AB.pdf
See you!

Gfast

Thank you Colorsound!
Inspired by your thread, I sucessfully read my own 13 bit absolute rotary encoder from LEINE & LINDE (from sweden). It uses SSI (Synchronize Serial Interface).

I'm using two SN75176BP (RS485 chip).
clock+ und clock- connect to A and B to the SN75176, which sending data. Data+ and Data- connect to A and to the SN75176, which receiving the echo from the encoder.

The last code update from Colorsound worked just fine. But my encoder really need higher communication speed. Original code give me some time just wrong position. But if I change "digitalWrite(A, 1) to typical AVR C command. the cycle of the infomation transmittion is dramatically faster then ever before. from about 20uS per cycle to less then 10uS (unbelievable). The read value is now totally perfect now. I don't have any kinda of error reading value.

hier ist the code I used at last:
Code: [Select]

/* Test Snippet for Encoder RHA 507 from LEINE LINDE
 * This code read a 13bit absolute rotary encoder, which use SSI (Syncronize Serial Interface).
 * This encoder can echo binary or gray code. This code communicate with binary code.
 * 13bit == 8192 positions per revolution
 * Datasheet: http://www.whp.cz/files/ds_rha507ssi_eng.pdf
 *
 * Link: http://forum.arduino.cc/index.php?topic=156812.0
 *
 * Written by : Su Gao
 * Last Edite : 14.06.2015
 */

const int CLOCK_PIN = 5;
const int DATA_PIN = 6;
const int BIT_COUNT = 13; // this's the percision of rotary encoder.

void setup() {
  pinMode(DATA_PIN, INPUT);
  pinMode(CLOCK_PIN, OUTPUT);
 
  digitalWrite(CLOCK_PIN, HIGH);

  Serial.begin(115200);
}

void loop() {
  float reading = readPosition();
  Serial.println(reading,2);
  delay(2);
}

//read the current angular position
float readPosition() {
  unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  delayMicroseconds(25);  // Clock must be high for 20 microseconds before a new sample can be taken

  return ((sample1 & 0x0FFF) * 360UL) / 4096.0; // ouptut value from 0 to 360 with two point percision
}

//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
  unsigned long data = 0;

  for (int i=0; i<bit_count; i++) {
    data <<= 1; // shift all read data left one bit.
   
    /*
    // speed up I/O In order to meet the communication speed of this encoder.
    The correct form is:
    PORTD &= ~(1 << n); // Pin n goes low
    PORTD |= (1 << n); // Pin n goes high
    So:
    PORTD &= ~(1 << PD0); // PD0 goes low
    PORTD |= (1 << PD0); // PD0 goes high

    PORTD &= ~(1 << PD1); // PD1 goes low
    PORTD |= (1 << PD1); // PD1 goes high
     */
     
    //digitalWrite(clock_pin,LOW);
    PORTD &= ~(1 << 5); // clock pin goes low
    delayMicroseconds(1);
    //digitalWrite(clock_pin,HIGH);
    PORTD |= (1 << 5); // lock pin goes high
    delayMicroseconds(1);

    data |= digitalRead(data_pin); // cat the new read bit to the whole read data.
  }
  return data;
}


Scope snapshoot can't be added to this forum. I just don't know how. But I've prepared...

willoubu

Hello

I bring out from ground this topic beceause i'm trying to use a 15 bits Absolute encoder in grey code

http://www.portalnaukowy.edu.pl/allegro/karty_katalogowe/ag615.pdf

apart from the fact that the code you offert is for a binary encoder, I should have at least a reaction on the serial monitor but nothing happen...

I have connected directly the SN75179B to the arduino as done by Colorsound.
The Maximum Frequency of my Encoder is 100khz so a delay of 10µs.

I don't have an Oscilloscope to check the signal.

Should i have to change something to let it work ?

Why did you used two RS485 chip ? One should be enought isnt'it ?

Thank you

William

willoubu

Hello,

I have found the solution, in fact a pull-down resistor was necessary on the Data pin.

As my encoder runs with Gray cod, I have to found how to convert in the ShiftIn Function.

William

simonchin76

Hi William,

Can share with me how you convert the binary to gray code.
I'm also working with rotary encoder , 14bits, my clock is 200Khz max.
Is it necessary to use the SN75179B before connect to arduino?

-Simon

andre777

#12
Dec 14, 2016, 11:41 am Last Edit: Dec 14, 2016, 11:47 am by andre777
Hi William

Hello,

I have found the solution, in fact a pull-down resistor was necessary on the Data pin.

As my encoder runs with Gray cod, I have to found how to convert in the ShiftIn Function.

William
Could you help me with my absolute encoder. I'm not sure what i have to change in the code.
Code: [Select]

/* Test Snippet for Encoder RHA 507 from LEINE LINDE
 * This code read a 13bit absolute rotary encoder, which use SSI (Syncronize Serial Interface).
 * This encoder can echo binary or gray code. This code communicate with binary code.
 * 13bit == 8192 positions per revolution
 * Datasheet: http://www.whp.cz/files/ds_rha507ssi_eng.pdf
 *
 * Link: http://forum.arduino.cc/index.php?topic=156812.0
 *
 * Written by : Su Gao
 * Last Edite : 14.06.2015
 */

const int CLOCK_PIN = 13;
const int DATA_PIN = 11;
const int BIT_COUNT = 12; // this's the percision of rotary encoder.
int udd=7;

void setup() {
  pinMode(DATA_PIN, INPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(udd, OUTPUT);

  digitalWrite(udd, HIGH); 
  digitalWrite(CLOCK_PIN, HIGH);

  Serial.begin(9600);
}

//read the current angular position
float readPosition() {
  unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
  delayMicroseconds(25);  // Clock must be high for 20 microseconds before a new sample can be taken

  return ((sample1 & 0x0FFF) * 360UL) / 4096.0; // ouptut value from 0 to 360 with two point percision
}

//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
  unsigned long data = 0;

  for (int i=0; i<bit_count; i++) {
    data <<= 1; // shift all read data left one bit.
   
    /*
    // speed up I/O In order to meet the communication speed of this encoder.
    The correct form is:
    PORTD &= ~(1 << n); // Pin n goes low
    PORTD |= (1 << n); // Pin n goes high
    So:
    PORTD &= ~(1 << PD0); // PD0 goes low
    PORTD |= (1 << PD0); // PD0 goes high

    PORTD &= ~(1 << PD1); // PD1 goes low
    PORTD |= (1 << PD1); // PD1 goes high
     */
     
    //digitalWrite(clock_pin,LOW);
    PORTD &= ~(1 << 5); // clock pin goes low
    delayMicroseconds(1);
    //digitalWrite(clock_pin,HIGH);
    PORTD |= (1 << 5); // lock pin goes high
    delayMicroseconds(1);

    data |= digitalRead(data_pin); // cat the new read bit to the whole read data.
  }
  return data;
}



void loop() {
  float reading = readPosition();
  Serial.println(reading,2);
  delay(2);
}



Datasheet:
https://fmcc.faulhaber.com/resources/img/EN_AESM-4096_DFF.PDF

G0MJW

I was having problems with reading two encoders. I suspect largely due to variable timing of the delays and the impact of interrupts. Here is what I modified the above to. I am using the built in AVR cycle delays to wait 16 cycles, 1 uS at 16 MHz on a nano. Not portable but who cares, at least it will always be nearly the same.

The result is absolutely stable reading.

You could use the timers but why complicate things. I disable interrupts at the start of the read and re-enable them afterwards.

I could replace the digitalRead function with a direct reading of the port. It is slow but this isn't a problem in this application as I am only reading the encoders 10 times a second. There is a lot more time spent updating displays etc.

It would be more efficient to read both encoders at once, however this would complicate this example. It simply needs two data variables and in this case, direct port reading would be useful, assuming both encoders are on the same port.



#define DELAY_CYCLES(n) __builtin_avr_delay_cycles(n)






//read in a word of data
unsigned long shiftIn(const int data_pin, const int bit_count) {
  unsigned long data = 0;
  // prevent interrupts causing timing problems
  noInterrupts();
  for (int i = 0; i < bit_count; i++) {
    data <<= 1;

 /*
    // speed up I/O In order to meet the communication speed of this encoder.
    The correct form is:
    PORTD &= ~(1 << n); // Pin n goes low
    PORTD |= (1 << n); // Pin n goes high
    So:
    PORTD &= ~(1 << PD0); // PD0 goes low
    PORTD |= (1 << PD0); // PD0 goes high

    PORTD &= ~(1 << PD1); // PD1 goes low
    PORTD |= (1 << PD1); // PD1 goes high
     */     

    PORTD &= ~(1 << 5); // clock pin goes low
    DELAY_CYCLES(16); // Wait for 16 CPU clock cycles @16MHz this is 1 uS
    PORTD |= (1 << 5); // clock pin goes high
    DELAY_CYCLES(16); // Wait for 16 CPU clock cycles   
    data |= digitalRead(data_pin); 
 
  }
  // Re-enable interrupts
  interrupts();
  return data;
}

schnibli

Hello,

I like to read Data from "OCD-S101G-1212-C100-PRL".

My connection are:
A and  B to D+ and  D-
R to receive in arduino input
Y and  Z to clock+ and clock-
D as arduino output to generate clock

And my Chip is a:
SN75179BD RS422, RS485

Can Somebody help me with code?

Thank you
Schnibli

Go Up