I have a problem with my Arduino Uno and my AS5311 position sensor
I am trying to get incremental output as described in Section 7 but I don't really know how to do it. It says that there are three outputs: A, B, and index. A and B will change states 512 times per 2mm of magnetic band (256 pulses) and index will produce a pulse every 2mm. It says that A "leads" B when the magnet is moving from right to left and B "leads" A when the magnet is moving from left to right.
What is the right way to get this information? I suppose it's using interrupts on A, B, and index but I'm not sure how.
Here is what I have so far (absolute position works fine):
const int A_Pin = 2;
const int B_Pin = 3;
const int Index_Pin = 8;
const int CSn_Pin = 5;
const int CLK_Pin = 6;
const int DO_Pin = 7;
int Bit;
int Position;
int Pow2[12] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};
int OCF, COF, LIN, MagINC, MagDEC, EvenPAR;
volatile int ACount = 0;
volatile int BCount = 0;
volatile int IndexCount = 0;
void fA(){
ACount++;
//What should I do here?
}
void fB(){
BCount++;
//What should I do here?
}
ISR(PCINT0_vect){
if(digitalRead(Index_Pin) == 1) IndexCount++;
}
void setup(){
//For incremental output
pinMode(A_Pin, INPUT_PULLUP);
pinMode(B_Pin, INPUT_PULLUP);
pinMode(Index_Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(A_Pin), fA, RISING);
attachInterrupt(digitalPinToInterrupt(B_Pin), fB, RISING);
digitalWrite(Index_Pin, HIGH);
//For absolute position
pinMode(CSn_Pin, OUTPUT);
pinMode(CLK_Pin, OUTPUT);
pinMode(DO_Pin, INPUT);
digitalWrite(CSn_Pin, HIGH);
digitalWrite(CLK_Pin, HIGH);
Serial.begin(9600);
cli();
PCICR = 1;
PCMSK0 = Pow2[Index_Pin - 8];
sei();
}
void loop(){
//Absolute position
//delay(1);
digitalWrite(CSn_Pin, LOW);
//delay(1);
Position = 0;
for(int z0 = 0; z0 < 12; z0++){
digitalWrite(CLK_Pin, LOW);
//delay(1);
digitalWrite(CLK_Pin, HIGH);
//delay(1);
Bit = digitalRead(DO_Pin);
Position += Bit * Pow2[11 - z0];
}
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
OCF = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
COF = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
LIN = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
MagINC = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
MagDEC = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
EvenPAR = digitalRead(DO_Pin);
digitalWrite(CSn_Pin, HIGH);
Serial.print(Position);
Serial.print(", ");
Serial.print(OCF);
Serial.print(", ");
Serial.print(COF);
Serial.print(", ");
Serial.print(LIN);
Serial.print(", ");
Serial.print(MagINC);
Serial.print(", ");
Serial.print(MagDEC);
Serial.print(", ");
Serial.print(EvenPAR);
Serial.print(", ");
//Incremental output
Serial.print(ACount);
Serial.print(", ");
Serial.print(BCount);
Serial.print(", ");
Serial.println(IndexCount);
}
The first problem is that after a while ACount
and BCount
drift apart so sometimes interrupts appear to be overlooked. The second problem is that I don't know how to tell which output "leads" the other one. How can I get this information (direction of movement) consistently?
Update: I tried what was suggested in the comments and it works most of the time. The problem is that sometimes I seem to get a false reading. When A goes up I check the state of B to see if I have left or right movement. I save the movement into a boolean variable (Left) which I then use in the function that is called when index is up. If Left is true I decrease the index counter, otherwise I increase it. But after some time the index counter differs by two from its true value which means that I had a false direction of movement when index is up. Here is my new code:
const int A_Pin = 2;
const int B_Pin = 3;
const int Index_Pin = 8;
const int CSn_Pin = 5;
const int CLK_Pin = 6;
const int DO_Pin = 7;
int Bit;
int Position;
int Pow2[12] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};
int OCF, COF, LIN, MagINC, MagDEC, EvenPAR;
bool Error = false;
volatile int ACount = 0;
//volatile int BCount = 0;
volatile bool Left = true;
volatile int IndexCount = 0;
void fA(){
if(digitalRead(B_Pin) == HIGH){
Left = true;
ACount--;
}
else{
Left = false;
ACount++;
}
}
//void fB(){
// BCount++;
//}
ISR(PCINT0_vect){
if(digitalRead(Index_Pin) == 1){
if(Left) IndexCount--;
else IndexCount++;
}
}
void setup(){
pinMode(A_Pin, INPUT_PULLUP);
pinMode(B_Pin, INPUT_PULLUP);
pinMode(Index_Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(A_Pin), fA, RISING);
//attachInterrupt(digitalPinToInterrupt(B_Pin), fB, RISING);
digitalWrite(Index_Pin, HIGH);
pinMode(CSn_Pin, OUTPUT);
pinMode(CLK_Pin, OUTPUT);
pinMode(DO_Pin, INPUT);
digitalWrite(CSn_Pin, HIGH);
digitalWrite(CLK_Pin, HIGH);
Serial.begin(4800);
cli();
PCICR = 1;
PCMSK0 = Pow2[Index_Pin - 8];
sei();
}
void loop(){
//delay(1);
digitalWrite(CSn_Pin, LOW);
//delay(1);
Position = 0;
for(int z0 = 0; z0 < 12; z0++){
digitalWrite(CLK_Pin, LOW);
//delay(1);
digitalWrite(CLK_Pin, HIGH);
//delay(1);
Bit = digitalRead(DO_Pin);
Position += Bit * Pow2[11 - z0];
}
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
OCF = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
COF = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
LIN = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
MagINC = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
MagDEC = digitalRead(DO_Pin);
digitalWrite(CLK_Pin, LOW); //delay(1);
digitalWrite(CLK_Pin, HIGH); //delay(1);
EvenPAR = digitalRead(DO_Pin);
digitalWrite(CSn_Pin, HIGH);
if(LIN == HIGH || MagINC == HIGH || MagDEC == HIGH) Error = true;
Serial.print(Position);
Serial.print(", ");
Serial.print(OCF);
Serial.print(", ");
Serial.print(COF);
Serial.print(", ");
Serial.print(LIN);
Serial.print(", ");
Serial.print(MagINC);
Serial.print(", ");
Serial.print(MagDEC);
Serial.print(", ");
Serial.print(EvenPAR);
Serial.print(", ");
Serial.print(ACount);
Serial.print(", ");
Serial.print(Left);
Serial.print(", ");
//Serial.print(BCount);
//Serial.print(", ");
Serial.print(IndexCount);
Serial.print(", ");
Serial.println(Error);
}
Update 2: Maybe the problem comes from the hysteresis described in section 7.2? If the change of direction is directly at the index pulse, wouldn't I get a false direction of movement?