CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Encoder to PIC interfacing

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
scaven92



Joined: 06 Oct 2006
Posts: 44

View user's profile Send private message

Encoder to PIC interfacing
PostPosted: Fri Oct 06, 2006 8:18 pm     Reply with quote

I was hoping someone could shed some insight on the software needed to interface a US Digital LS7266 (Encoder to Microprocessor Interface) chip. You can see the product here: http://www.usdigital.com/products/ls7266/ .

I am new to embedded design and was hoping someone has some software they have used for this chip that I can learn from. I am using a PIC18F452 with a transmisive optical encoder.

Thanks in advance for your help and suggestions.
bsodmike



Joined: 05 Aug 2006
Posts: 52

View user's profile Send private message Visit poster's website AIM Address MSN Messenger

PostPosted: Sat Oct 07, 2006 1:25 am     Reply with quote

Looks like a fun project. Most of it seems more or less straight forward. The key is to reading over the datasheet and communicating with it as described.

What you should do is come up with some code and if you have issues, post back - this would be the best way to learn rather than having someone else do it all for you Smile
Ttelmah
Guest







PostPosted: Sat Oct 07, 2006 3:05 am     Reply with quote

I have used the 7166 (the single channel version), some time ago, and it really is fairly simple. You read it just like a memory (select 'read', select 'data', lower the CS, and read a byte). If you write '3' to the master control register, it resets the read counter, and copies the current 'count', into the output register. The counter for the output, automatically increments, so three reads, give the full 24bit value. If you are handling potentially 'large' counts, you need to have a interrupt driven off the carry/borrow pins, and increment/decrement your own carry register.
It is a very easy way of handling fast/large encoder counts. :-)
As bsodmike says, have a little 'try', work out which pins are connected to what on your processor, and try a simple program to just read the value every few seconds. This can be done in only a few dozen lines of code, and if you get problems, post back, and I'll try to remember how I did it, and help. :-)

Best Wishes
jbmiller



Joined: 07 Oct 2006
Posts: 73
Location: Greensville,Ontario

View user's profile Send private message

LS7266
PostPosted: Sat Oct 07, 2006 5:58 am     Reply with quote

US Digital makes great shaft encoders and interface chips. I used a lot of them when I worked for Quanser( www.quanser.com). We developed a series of robotics learning products for universities.
The US digital encoders are far superior to the HP types. FAR easier o install and replace when damaged(see the 'pendulums' at quanser).
I still have code on this hard drive that may help.

Jay
scaven92



Joined: 06 Oct 2006
Posts: 44

View user's profile Send private message

PostPosted: Sat Oct 07, 2006 1:38 pm     Reply with quote

Alright, I think you guys are right. I will try to write some code and post it for some help. Thanks! I'll try to get it back to you guys to look at tonight!

I appreciate all of your comments
scaven92



Joined: 06 Oct 2006
Posts: 44

View user's profile Send private message

PostPosted: Sat Oct 07, 2006 3:30 pm     Reply with quote

Ok, here is what I have come up with so far. I do have some questions. First off, this encoder will be for wheel position. Will it count negative values, telling me that the position is behind the start position? Also, I do not need to use the XFLAG, YFLAG pins do I? How do I deal with FCLK? Also am I reseting the counter correctly? I am only using this encoder to tell me position as feedback for a controller. I believe all I will need to do it have the ability to resest both counters and read the two counters. Can anyone think of other features I should implement? Thanks so much for your help and time! Dont hold back on your comments or criticism, thats how I learn!

Code:

#include <18F452.h>
#include <stdio.h>
#include <math.h>

#FUSES NOWDT, XT, NOPROTECT, BROWNOUT
#use delay(clock=4000000)

//Data Pins
#define DATA          PORTB
#define DATA_SELECT   PIN_D2
#define WRITE         PIN_D3
#define CS            PIN_D4
#define READ          PIN_D5
#define X_OR_Y        PIN_D6
#define FCLK          PIN_D7

#define CHIP_ON       0
#define CHIP_OFF      1
#define X             0
#define Y             1
#define RESET         0b00000011          // Resets the Counter using RLD, selectable by X_OR_Y, from page 2 of datasheet

// Reads the 24 bit Count from either X or Y Channels
long Read_Position( int axis ) {          // read position of encoder
   long position;

   output_bit(READ, CHIP_ON);             // Select READ Mode
   output_bit(CS, CHIP_ON);               // Select Chip Select On
   output_bit(DATA_SELECT, CHIP_ON);      // Select Data Mode
   output_bit(X_OR_Y, axis);              // Selects X or Y Channel

   position  = (long)input_b();           // least significant byte
   position += (long)input_b() << 8;      // mid
   position += (long)input_b() <<16;      // most significant byte

   output_bit(CS, CHIP_OFF);               // Select Chip Select Off
   return position;
}

// Reset either X or Y Channel Counter
void Reset_Count( int axis )
{
   output_bit(WRITE, CHIP_ON);             // Select READ Mode
   output_bit(CS, CHIP_ON);                // Select Chip Select On
   output_bit(DATA_SELECT, CHIP_ON);       // Select Data Mode
   output_bit(X_OR_Y, axis);               // Selects X or Y Channel

   output_b(RESET);                        // Write a '3' to reset Counter selected by axis
   output_bit(CS, CHIP_OFF);               // Select Chip Select Off
}

void main( void )
{
   long count = 0;

   //Init_Chip();
   //Init_Encoder();
   count = Read_Position( X );            // Read count of X Channel
   Reset_Count( X );
}
Ttelmah
Guest







PostPosted: Sun Oct 08, 2006 3:11 pm     Reply with quote

You need to use an int32, not a 'long'. Long in CCS, is only 16 bits.
You need to reset the byte counter (which also latches the current position), _before_ reading the bytes. Doing this afterwards, would mean that the data you read next time, could be several counts 'out of data'.
No, the counter will not itself handle negative values. The readout will wrap, to return a maximum value, and a carry bit gets set. You have two choices (depending on how large the values are likely to get). The first is to set the counter to 0x800000, when you wake the encoder up, and then anything below this corresponds to a reverse movement. The second is to use a signed int32, and handle the overflow bit.
_You_ need to handle the control transactions for each byte (CS/RD etc.).
The sequence will be something like:
Code:

//Data Pins
#define DATA                PORTB
#define DATA_SELECT    PIN_D2
#define WRITE               PIN_D3
#define CS                    PIN_D4
#define READ                PIN_D5
#define X_OR_Y            PIN_D6
#define FCLK                PIN_D7

#define SETUP_REGISTERS(register)    DATA_SELECT=(register & 1);\
   X_OR_Y = (register & 2)

void output_data_byte(int8 val,int8 register) {
   SETUP_REGISTERS(register);
   DATA=val;
   WRITE=0;
   CS=0;
   delay_cycles(1);
   CS=1;
   WRITE=1;
}

int8 input_data_byte(int8 register) {
   temp rval;
   SETUP_REGISTERS(register);
   READ=0;
   rval=DATA; //ensure port is set to input _before_ selecting chip...
   (assuming 'standard_io' - otherwise you need to set the tris).
   CS=0;
   delay_cycles(1);
   rval=data;
   CS=1;
   READ=1;
}     

// Reads the 24 bit Count from either X or Y Channels
int32 Read_Position( int axis ) {          // read position of encoder
   int32 position;
   axis<<=1;      //using 'X/Y in second bit

   output_data_byte(0x81, axis+1);   //reset pointer;         
   
   position  = input_data_byte(axis);           // least significant byte
   position += (long)input_data_byte(axis) << 8;   // mid
   position += (long)input_data_byte(axis) <<16;  // most significant byte

   return position;
}

No guarantees, but is should be getting close.

Best Wishes
scaven92



Joined: 06 Oct 2006
Posts: 44

View user's profile Send private message

PostPosted: Sun Oct 08, 2006 4:47 pm     Reply with quote

Thanks for your help! Alright I have taken your code and tried to understand it a bit better and have come up with this. Since I don't need the full range of the counter I am going to center is at 0x800000 and then subtract that value from the int32 that I read from the chip. Then value will be a signed int32 so I can have posivitve and neg values.

Please let me know if I have created the Reset_Counter function correctly. I don't have an encoder nor counter yet, so I cannot implement and test yet. Thank again for your time and help!

I am having trouble posting the code, it is clipping it so I'll post it next...
scaven92



Joined: 06 Oct 2006
Posts: 44

View user's profile Send private message

PostPosted: Sun Oct 08, 2006 5:09 pm     Reply with quote

Here is the first half of the code... (it won't let me post it all at once, it overlaps when submitted)

Code:

#include <18F452.h>
#include <stdio.h>
#include <math.h>

#FUSES NOWDT, XT, NOPROTECT, BROWNOUT
#use delay(clock=4000000)

//Data Pins
#define DATA                  input_b()
#define DATA_SELECT(value)    output_bit(PIN_D2, value)
#define WRITE(value)          output_bit(PIN_D3, value)
#define CS(value)             output_bit(PIN_D4, value)
#define READ(value)           output_bit(PIN_D5, value)
#define X_OR_Y(value)         output_bit(PIN_D6, value)
#define FCLK(value)           output_bit(PIN_D7, value)

#define SETUP_REGISTERS(register1)    DATA_SELECT(register1 & 1);\
   X_OR_Y(register1 & 2)

#define CHIP_ON       0
#define CHIP_OFF      1
#define X             0b00000000
#define Y             0b00000010
#define RESET_BP      0b10000001

void output_data_byte(int8 val,int8 register1)
{
   SETUP_REGISTERS(register1);
   output_b(val);
   WRITE(0);
   CS(0);
   delay_cycles(1);
   CS(1);
   WRITE(1);
}

int8 input_data_byte(int8 register1)
{
   int8 rval;
   SETUP_REGISTERS(register1);
   READ(0);
   rval=DATA; //ensure port is set to input _before_ selecting chip...(assuming 'standard_io' - otherwise you need to set the tris).
   CS(0);
   delay_cycles(1);
   rval=DATA;
   CS(1);
   READ(1);
   return rval;
}

// Reads the 24 bit Count from either X or Y Channels
int32 Read_Position( int axis ) {          // read position of encoder
   int32 position;
   axis<<=1;      //using 'X/Y in second bit

   output_data_byte(RESET_BP, axis+1);   //reset byte pointer (x and y);

   position  = (int32)input_data_byte(axis);       // least significant byte
   position += (int32)input_data_byte(axis) << 8;  // mid
   position += (int32)input_data_byte(axis) << 16; // most significant byte

   return position;
}
scaven92



Joined: 06 Oct 2006
Posts: 44

View user's profile Send private message

PostPosted: Sun Oct 08, 2006 5:09 pm     Reply with quote

and here is the last part...

Code:
// Reset either X or Y Channel Counter
void Reset_Count( int axis )
{
   int32 preset = 0x800000;                        // Middle value.

   output_data_byte(RESET_BP, axis+1);

   output_data_byte(preset, axis);
   output_data_byte(preset >> 8, axis);
   output_data_byte(preset >> 16, axis);
}

void main( void )
{
   int32 count = 0;
   signed int32 true_count = 0;

   count = Read_Position( X );            // Read count of X Channel
   true_count = count - 0x800000;
   Reset_Count( X );
}
Ttelmah
Guest







PostPosted: Mon Oct 09, 2006 8:59 am     Reply with quote

You don't want to keep resetting the count. Remember that the chip is potentially counting all the time. If you read, then reset, if a count has occured between these moments, it'll be lost.
You reset at the start of the program only.
Then the question is just how large your counts may become?. This will depend on how far your shaft can turn, and the resolution of the coupler involved. If the likely count will fit in a signed int32, then breath a sigh of relief, use this, and 'sign extend' the 24bit value. You can do this, if it is declared as a signed int32, by simply subtracting 0x800000 after the value is retrieved.
If it won't fit into an int32, then you will need to have custom arithmetic routines to handle larger values.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group