Hello everyone. I have been working sourcing the clock signal for and read a Posital BISS-C encoder. Just in case the link becomes deprecated, here is the part number: KCD-BC33B-1617-E75W-JAQ. The encoder sends 41 bits in each frame. 16 bit multi-turn, 17 bit single-turn, 1 bit error, 1 bit warning, 6 bit crc. I struggled with this encoder for a very long time and wanted to post my solution for anyone else in this situation.
The encoder takes a CLK + and CLK - at frequencies ranging from 80 kHz to 10 MHz. The encoder sends the position data back on DATA + and DATA - based on the clock signal provided. To produce the necessary clock frequency consistently, I utilized a RS422/ RS 485 to TTL converter and manipulated the ports directly. This project would not have been possible without an oscilloscope. Lucky for me, my employer has a DSOX1204G. This was critical to get accurate timing.
As a warning, the code I posted below is not guaranteed to work for your project. The microseconds delays had to be adjusted while looking at my signal on the Oscope. The delays in code were not the same as the delays shown on the Oscope. Furthermore, I choose to use for loops to parse out the data just to keep the timing consistent as possible. A unsigned long long could store the entire frame in one variable but presents other issues when trying to manipulate the value. This is still a work in progress and further posts will come as the project develops.
/*
Use & operator to place 0's setting things LOW
Use | operator to place 1's setting things HIGH
270⁰ 98304 11000000000000000 // Angle Decimal Binary
360⁰ 131071 11111111111111111
*/
#define d5h B00001000 // *** D5 is PORT E3 for the Arduino Mega ***
#define d5l B11110111 // Set D5 low
#define d5o B00001000 // Set D5 high
#define writeDelay 6
#define readDelay 3
#define comh B00001000 // Value use when reading pin register
#define a_iter 4 // # of bits for acknowledge
#define m_iter 16 // # of bits for multi-turn data
#define s_iter 17 // # of bits for single-turn data
#define e_iter 1 // # of bits for error data
#define w_iter 1 // # of bits for warning data
#define c_iter 6 // # of bits for crc data
#define iter 45 // # of bits for BISS-S frame
#define shift 3 // # of bits to shift in bit registers
unsigned long ac; // acknowledge data
unsigned long mt; // multi-turn data
unsigned long st; // single-turn data
unsigned long er; // error data
unsigned long wn; // warning data
unsigned long crc; // crc data
float raw = 0.0; // dummy variable for conversion
float ratio; // dummy variable for conversion
float ang; // calculated angle
float full = 131071.0; // max single turn value
float circ = 360.0;
int i = 0;
int m = 0;
int s = 0;
int e = 0;
int w = 0;
int c = 0;
void setup(){
Serial.begin(115200);
delay(1500);
DDRE |= d5o; // Set E3 (Digital Pin 5) to an Output
}
void loop(){
for(i; i < a_iter; i++){
PORTE &= d5l; // TX+ lo TX- high
delayMicroseconds(writeDelay); // use a delay to make sure the frequency is consistent
PORTE |= d5h; // TX+ high TX- low
ac |= (PINH >> shift & comh >> shift); // read the pin register. Only update if the pin is high
ac <<= 1; // shift the value left one bit for next reading
delayMicroseconds(readDelay);
}
for(m; m < m_iter; m++){
PORTE &= d5l; // TX+ lo TX- high
delayMicroseconds(writeDelay);
PORTE |= d5h; // TX+ high TX- low
mt |= (PINH >> shift & comh >> shift);
mt <<= 1;
delayMicroseconds(readDelay);
}
for(s; s < s_iter; s++){
PORTE &= d5l; // TX+ lo TX- high
delayMicroseconds(writeDelay);
PORTE |= d5h; // TX+ high TX- low
st |= (PINH >> shift & comh >> shift);
st <<= 1;
delayMicroseconds(readDelay);
}
for(e; e < e_iter; e++){
PORTE &= d5l; // TX+ lo TX- high
delayMicroseconds(writeDelay);
PORTE |= d5h; // TX+ high TX- low
er |= (PINH >> shift & comh >> shift);
er <<= 1;
delayMicroseconds(readDelay);
}
for(w; w < w_iter; w++){
PORTE &= d5l; // TX+ lo TX- high
delayMicroseconds(writeDelay);
PORTE |= d5h; // TX+ high TX- low
wn |= (PINH >> shift & comh >> shift);
wn <<= 1;
delayMicroseconds(readDelay);
}
for(c; c < c_iter; c++){
PORTE &= d5l; // TX+ lo TX- high
delayMicroseconds(writeDelay);
PORTE |= d5h; // TX+ high TX- low
crc |= (PINH >> shift & comh >> shift);
crc <<= 1;
delayMicroseconds(readDelay);
}
delay(8000); // Delay so that values can be read and adjustments can be made before next iteration
i = 0; // reset values for next iteration
m = 0;
s = 0;
e = 0;
w = 0;
c = 0;
ac >>= 1; // shift the value right to get rid of extra bit
mt >>= 1;
st >>= 1;
er >>= 1;
wn >>= 1;
crc >>= 1;
raw = st; // store the single turn value as a float for floating point math
ratio = raw / full; // ratio of single turn angle
ang = (circ * ratio); // angle
Serial.print("ac: ");
Serial.println(ac, BIN);
Serial.print("mt: ");
Serial.println(mt, BIN);
Serial.print("st: ");
Serial.println(st, BIN);
Serial.print("er: ");
Serial.println(er, BIN);
Serial.print("wn: ");
Serial.println(wn, BIN);
Serial.print("crc: ");
Serial.println(crc, BIN);
Serial.print("ratio: "); // print out conversions for validation
Serial.println(ratio);
Serial.print("ang: ");
Serial.println(ang);
ac = 0; // reset values for next iteration
mt = 0;
st = 0;
er = 0;
wn = 0;
crc = 0;
}