I have a BLDC-Motor with a absolut encoder from Faulhaber.
BLDC-Motor
Encoder
Now I should write a program. I want to read the exact position of the motor and stop at this position.
I'm not sure how I should connect the poles of the enocoder and how to read the position.
The following won't work, because there are a number of bits in the return value that are not data, like the start bit and the 6 bit CRC. It is also extremely ungainly, inefficient and slow.
pos += b * pow(2, 10-(i+1));
By my count, the encoder returns 22 bits of information, with a 12 bit value buried in the middle. This is the BISS-C protocol, which is well documented.
Use bit shift to read the encoder instead, something like:
pos = pos | digitalRead(PIN_DATA); //initialize pos to 0 before the loop!
pos = pos<<1;
Then fish out the bits that correspond to the actual data. You will need to use a long integer to store the entire returned result.
Only 12 bits of the 22 bits (not counting the ACK) are actual data.
Please post a hand drawn wiring diagram of your setup, identifying the pin numbers of both the encoder and the Arduino, and also show the power and ground connections.
The data sheet gives no reason to connect Pin 12 on the Arduino to pin 7 (N.C.) on the encoder. N.C. means "not connected". What do you think it does and why?
You will have to rethink your code. Please study the "output signals" diagram in the encoder data sheet and the documentation for the BISS-C protocol.
You need to
(1) start sending clock signals, while reading the data line and
(2) wait for ACK (LOW) and then START (HIGH),
(3) read the CDS bit,
(4) read 12 bits of position data,
(5) read two RES bits (ignore),
(6) read the 6 bit CRC value.
Finally, what will you do with the data? Using digitalRead() and digitalWrite(), the data will be read out at a rate of somewhere between 5-10 microseconds/bit, or at best in the range of 4000-8000 position samples/second.
I study the output signals but nothing works when i try to evaluate the data. I only have one week to finish my project and I still have no idea how i can read the position of this encoder ...
I already tried the second one and then my result is always 18.72
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);
}
As jremmington has pointed out the basic approach to this interface is to write a clock pin LOW, write a clock pin HIGH and read the data back after the HIGH. digitalWrite() is fine for the timing of the clock pin, and you don't need to get into direct port manipulation syntax.
The BISS-C protocol has the slave start responding on the second rising edge after the clock pulses begin following an inactive period where the clock is HIGH following a low timeout.
Send 1 clock pulse (LOW/HIGH) and with no reading back. Then send 22 more clock pulses and read the data into a byte array with 22 elements. Array elements 3 through 14 will contain your 12 bits of position data. I'm not sure, but you may need to send a 23rd pulse with no read back to generate the stop
digitalWrite(PIN_CLOCK, LOW);
digitalWrite(PIN_CLOCK, HIGH);
for (int i = 0; i < 22; i++) {
digitalWrite(PIN_CLOCK, LOW);
digitalWrite(PIN_CLOCK, HIGH);
array[i] = digitalRead(PIN_DATA);
}
//digitalWrite(PIN_CLOCK, LOW);//possible 23rd pulse to trigger stop
//digitalWrite(PIN_CLOCK, HIGH);
digitalWrite(PIN_CLOCK, LOW);
delay(timeout);
digitalWrite(PIN_CLOCK, HIGH);