Go Down

Topic: Arduino UNO and CUI encoder (SPI ) (Read 2328 times) previous topic - next topic

colorbomb

Apr 06, 2013, 02:47 pm Last Edit: Apr 06, 2013, 03:50 pm by colorbomb Reason: 1
Good Day ALL

  I am trying to interface an absolute encoder with the Arduino. I have never worked with SPI, I have read information and understand the concept. I am just unclear when it comes to setting the code up. I found an example that someone had posted for the encoders they were working with , so I took the code and tried modifying it to work with the CUI encoder but am a bit lost. Please lend me a hand if you can. Note the code may not make much sense as it has some pieces of the old code basically I added the pins for MOSI , MISO, and CS.  


Code: [Select]

const int PIN_CS = 4;
const int PIN_CLOCK = 13;
const int PIN_MOSI =11;
const int PIN_MISO = 12;

void setup() {
 Serial.begin(9600);
 pinMode(PIN_CS, OUTPUT);
 pinMode(PIN_CLOCK, OUTPUT);
 pinMode(PIN_MOSI, OUTPUT);
 pinMode(PIN_MISO, INPUT);

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


//byte stream[16];
void loop() {

 digitalWrite(PIN_CS, HIGH);
 digitalWrite(PIN_CS, LOW);
 int pos = 0;
 for (int i=0; i<10; i++) {
   digitalWrite(PIN_CLOCK, LOW);
   digitalWrite(PIN_CLOCK, HIGH);
   
   byte b = digitalRead(PIN_MOSI) == HIGH ? 1 : 0;
   pos += b * pow(2, 10-(i+1));
 }
 for (int i=0; i<6; i++) {
   digitalWrite(PIN_CLOCK, LOW);
   digitalWrite(PIN_CLOCK, HIGH);
 }
 digitalWrite(PIN_CLOCK, LOW);
 digitalWrite(PIN_CLOCK, HIGH);
 Serial.println(pos);
}  


I appreciate any help/examples that you guys can offer.

 JH

encoder
Code: [Select]
http://www.cui.com/Product/Components/Encoders/Absolute_Encoders/Modular/AMT203-V

uaefame

I am working on  similar stuff (Connecting arduino to AMT203-V). arduino as the master and AMT203-V as slave. The goal is to display the encoder reading.

I still can't figure out how or where to read in the manual AMT203-V and get the necessary information for SPI connection.

The codes That i fill up so far
Code: [Select]
//Include the SPI library
#include <SPI.h>

//Set the slave select pin
//Other SPI pins are set automatically
int SS=10; //Any pin can be used for SS(slave select) signal.
//we choose 10 here

void setup()
{
  Serial.begin(9600);
  //Set SS Pin Directions
  //Others are Handled Automatically
  pinMode(SS,OUTPUT);
  SPI.setBitOrder(MSBFIRST); //Most significent bit or use
  //LSBFIRST least significent bit
  //Initialize SPI
  SPI.begin();
 
}

void loop()
{
  int encoder_value=EncoderRead()
  Serial.println(encoder_value);
  delay(1000);
}

int EncoderRead() {
  // take the SS pin low to select the chip:
  digitalWrite(SS,LOW);
  //  send in the address and value via SPI:
  SPI.transfer(value);
  // take the SS pin high to de-select the chip:
  digitalWrite(SS,HIGH);
}

uaefame

Still no luck with the codes

I try ignoring the SPI library and use shiftin instead and still no luck

here is my updated codes
Code: [Select]

void setup()
{
  pinMode(4,OUTPUT);//CLock Pin
  pinMode(5,OUTPUT);//Data Pin
  pinMode(3,OUTPUT);//Slave Select
  Serial.begin(9600);
}

byte incoming;

void loop()
{
digitalWrite(3,LOW);
byte incoming =  shiftIn(5,4,LSBFIRST);
Serial.println(incoming);
digitalWrite(3,HIGH);
delay(1000);

}


I am getting all zero reading...

Docedison

Is it possible that you have to ask the decoder for something first? Perhaps absolute position? or that it might require some kind of calibration/initialization or reset first time it's used or powered up?

Doc
--> WA7EMS <--
"The solution of every problem is another problem." -Johann Wolfgang von Goethe
I do answer technical questions PM'd to me with whatever is in my clipboard

uaefame

My updated codes still no luck

Code: [Select]
#include <SPI.h>
void setup()
{
  SPI.begin();
  pinMode(3,OUTPUT);//Slave Select
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  Serial.begin(9600);
}



void loop()
{
digitalWrite(3,LOW);
byte response = SPI.transfer(0);
Serial.println(response);
digitalWrite(3,HIGH);
delay(1000);
}


From datasheet
Quote
The msb data out on MISO is valid soon after CSB goes low. The MOSI data is valid soon after the falling edge
of SCK. The Encoder drives data out on MISO as long as CSB is low.
Normally, CSB goes low, then after 8 clocks the command is interpreted. CSB high resets the
clock counter, and terminates any command sequence.


which can be found here http://www.cui.com/product/resource/amt203.pdf

Running this code i get 0, 255 no idea why...
it is weird i am expecting a byte and i am getting 0 or 255.

uaefame

#5
Jul 26, 2013, 09:57 pm Last Edit: Jul 26, 2013, 11:14 pm by uaefame Reason: 1

Is it possible that you have to ask the decoder for something first? Perhaps absolute position? or that it might require some kind of calibration/initialization or reset first time it's used or powered up?

Doc


I found this doc http://www.cui.com/product/resource/amt203-appnote.pdf
it tells you exactly what to send here is the updated code i am using
.
Code: [Select]
#include <SPI.h>
void setup()
{
  SPI.begin();
  pinMode(3,OUTPUT);//Slave Select
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  digitalWrite(3,LOW);
byte response = SPI.transfer(0x00);
digitalWrite(3,HIGH);
  Serial.begin(9600);
}



void loop()
{
digitalWrite(3,LOW);
byte response = SPI.transfer(0x10);
digitalWrite(3,HIGH);
     Serial.print("I received: ");
     Serial.print(response, BIN);
     Serial.print("  this has an ASCII value of ");
     Serial.println(response ,DEC); 
delay(2000);

}


I am still getting weird numbers...

I found out the datasheet page 4 of it with all information needed http://www.cui.com/product/resource/amt203-appnote.pdf

i still can't figure what why my code is not working

uaefame

I got the code working

here is the update code
Code: [Select]
#include <SPI.h>
void setup()
{
  SPI.begin();
  pinMode(3,OUTPUT);//Slave Select
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  digitalWrite(3,LOW);
byte response = SPI.transfer(0x00);
digitalWrite(3,HIGH);
  Serial.begin(9600);
}

void loop()
{
digitalWrite(3,LOW);
byte response = SPI.transfer(0x10);
digitalWrite(3,HIGH);
     Serial.print("I received: ");
     Serial.println(response ,DEC); 
     
delay(1000);
}


I am getting 3 reading and the buffer doesn't reset after each reading. 2 of the reading are junk or i am not sure what they are.

I looked at the encoder data sheet and it state this
Quote
Command 0x10: rd_pos
This command causes a read of the current position.
The sequence is as follows:
1) issue read command, receive idle character
2) issue NOP, receive idle character 0xA5 or 0x10
3) repeat step 2 if it is 0xA5
4) issue NOP and receive MSB position (4 bits valid data)
5) issue NOP and receive LSB position (8 bits valid data)
Note that it is possible to overlap commands, so instead of NOP is several steps above
the user could start another operation. The read and write FIFOs for the PCI streams are
16 bytes long and it is up to the user to avoid overflow


full datasheet can be found here
http://www.cui.com/product/resource/amt203.pdf

So the code gives what i expect it to receive. How to work with buffer? or how to select certain thing to be displayed instead of displaying everything. I think it display the position then MSB and LSB which i don't know how to remove them and just keep the display for the position. Also, I have 1 second delay, let say i rotate the encoder after couple of second i get the right position reading. as if the data was in a buffer and it send old data. so, is there a way to reset the buffer for each reading ? I don't want to get old data....

uaefame

#7
Jul 30, 2013, 11:42 pm Last Edit: Jul 31, 2013, 07:02 pm by uaefame Reason: 1
I figured out what the 3 bytes are

Here is the update code
Code: [Select]
//#define 3 3 //Slave select pin

#include <SPI.h>

float response[2];

void setup()
{

  pinMode(3,OUTPUT);//Slave Select
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  digitalWrite(3,HIGH);
  Serial.begin(9600);
  delay(5000);
// byte answer[2];
 
}

void loop()
{
  // Serial.flush();
  digitalWrite(3,HIGH);
   SPI.begin();
   //For LOOP START HERE
    for (int i=0; i <= 2; i++){
     digitalWrite(3,LOW);
     response[i] = SPI.transfer(0x10);
     Serial.print(response[i] ,DEC);
     Serial.print("  ");
     digitalWrite(3,HIGH);
     delay(50);
   }//END FOR
   
   //Calculation NICK WAY BITS TO DEGREE
   delay(200);
     float total;
     total=((response[0]*256)+response[1])*360/4096;
     Serial.print(total,DEC);   
     Serial.println("  ");
   //END OF CALCULATION
   digitalWrite(3,HIGH);
   SPI.end();

}


It work fine, The only problem i have is the bytes come everytime i start the program differently.
For example, byte1 byte2 byte3 comes in this expected order
lets say i run it again, i get byte3 byte1 byte2.

I was thinking about clearing the buffer like doing
Code: [Select]
Serial.flush();
i am not sure how to fix it

Unwanted Results
Code: [Select]

182.0000000000  16.0000000000  2.0000000000  4096.4062500000 
182.0000000000  16.0000000000  2.0000000000  4096.4062500000 
182.0000000000  16.0000000000  2.0000000000  4096.4062500000 
182.0000000000  16.0000000000  2.0000000000  4096.4062500000 
182.0000000000  16.0000000000  2.0000000000  4096.4062500000 
182.0000000000  16.0000000000  2.0000000000  4096.4062500000 
182.0000000000  16.0000000000  2.0000000000  4096.4062500000 

First 3 columns I get from the Encoder, I do simple calculation to get the angle between 0-360 as you can see in column 4 the angle value is not right. since, the order i received was mixed up.

Keep closing and opening the serial monitor till i have the right one. and here it is.
Desired results
Code: [Select]

2.0000000000  182.0000000000  16.0000000000  60.9960937500 
2.0000000000  182.0000000000  16.0000000000  60.9960937500 
2.0000000000  182.0000000000  16.0000000000  60.9960937500 
2.0000000000  182.0000000000  16.0000000000  60.9960937500

uaefame

Any expert (or ideas) in byte order will be greatly appreciated

uaefame

I figured it out,

So what i was receiving was 3 bytes, 4bits, 8bits, and a constant number 16.

I used the 16 as my reference point because after number 16 I get 4bits and 8bits always

So my codes work fine now.

If anyone stuck with cui inc encoder I can help.

uaefame

Here is the codes for cui inc encoder that I wrote.

I feel this code can undergo alot of improvements for example efficient wise. like faster running.

Any idea where to start. All idea are appreciated.

Code: [Select]
#define CS 3 //Chip or Slave select
#include <SPI.h>

float response[2];
float Wheel_Diameter=6.615; //mm

void setup()
{
  pinMode(CS,OUTPUT);//Slave Select
  digitalWrite(CS,HIGH);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  Serial.begin(9600);
  Serial.flush();
  delay(2000);
  SPI.end();
 

}

void loop()
{
   digitalWrite(CS,HIGH);
   SPI.begin();
   
     //For LOOP START HERE
    for (int i=0; i <= 2; i++){
     digitalWrite(CS,LOW);
     delay(5);
     response[i] = SPI.transfer(0x10);
    // Serial.print(response[i],DEC);
     //Serial.print("  ");
     digitalWrite(CS,HIGH); 
   }//END FOR
   if (response[0]==16.0)
   {
     if(response[1]==16.0)
     {
     }
     else if(response[2]==16.0)
     {
     }
     else
     {
     float total;
     total=((response[1]*256)+response[2])*360/4096;
     Serial.print(total,DEC);   
     Serial.println("  ");
     }
   }
   else if (response[1]==16.0)
   {
     if(response[0]==16.0)
     {
     }
     else if(response[2]==16.0)
     {
     }
     else
     {
     float total;
     total=((response[2]*256)+response[0])*360/4096;
     Serial.print(total,DEC);   
     Serial.println("  ");
     }
   }
  else if(response[2]==16.0)
   {
     
     if(response[0]==16.0)
     {
     }
     else if(response[1]==16.0)
     {
     }
     else
     {
     float total;
     total=((response[0]*256)+response[1])*360/4096;
     Serial.print(total,DEC);   
     Serial.println("  ");
     }
   }
   

   
   digitalWrite(CS,HIGH);
   SPI.end();

}//END LOOP



jamiec

Hay Ya, thanks for posting your code, it helped me get started.
not sure about the order mix up issue you have a, i don't seem to have it.

here is what i did anyway and don't seem to have any issues
cheers
Code: [Select]

#include <SPI.h>

#define CS 3 //Chip or Slave select

uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[1];

float deg = 0.00;

void setup()
{
  pinMode(CS,OUTPUT);//Slave Select
  digitalWrite(CS,HIGH);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  Serial.begin(115200);
  Serial.println("starting");
  Serial.flush();
  delay(2000);
  SPI.end();

}
uint8_t SPI_T (uint8_t msg)    //Repetive SPI transmit sequence
{
   uint8_t msg_temp = 0;  //vairable to hold recieved data
   digitalWrite(CS,LOW);     //select spi device
   msg_temp = SPI.transfer(msg);    //send and recieve
   digitalWrite(CS,HIGH);    //deselect spi device
   return(msg_temp);      //return recieved byte
}

void loop()
{
   uint8_t recieved = 0xA5;    //just a temp vairable
   ABSposition = 0;    //reset position vairable
   
   SPI.begin();    //start transmition
   digitalWrite(CS,LOW);
   
   SPI_T(0x10);   //issue read command
   
   recieved = SPI_T(0x00);    //issue NOP to check if encoder is ready to send
   
   while (recieved != 0x10)    //loop while encoder is not ready to send
   {
     recieved = SPI_T(0x00);    //cleck again if encoder is still working
     delay(2);    //wait a bit
   }
   
   temp[0] = SPI_T(0x00);    //Recieve MSB
   temp[1] = SPI_T(0x00);    // recieve LSB
   
   digitalWrite(CS,HIGH);  //just to make sure   
   SPI.end();    //end transmition
   
   temp[0] &=~ 0xF0;    //mask out the first 4 bits
   
   ABSposition = temp[0] << 8;    //shift MSB to correct ABSposition in ABSposition message
   ABSposition += temp[1];    // add LSB to ABSposition message to complete message
   
   if (ABSposition != ABSposition_last)    //if nothing has changed dont wast time sending position
   {
     ABSposition_last = ABSposition;    //set last position to current position
     deg = ABSposition;
     deg = deg * 0.08789;    // aprox 360/4096
     Serial.println(deg);     //send position in degrees
   }   

   delay(10);    //wait a bit till next check

}

JLuisMx

Wonderful! Thanks a lot to all the contributors.
Uaefame, I suppose you already fix the problem but for future readers the problem was, very probably, that the AMT encoder expects for a specific order of commands (as jamiec code's show).

Just a detail with the jamiec code, the temp variable must be an  array of two elements, I think:

Code: [Select]

.
.
.
uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[2];    //This one.

float deg = 0.00;
.
.
.


Thanks again.

IRE_student

Is it possible to have this code record continuous revolutions, rather than resetting after each full revolution?

Go Up