View previous topic :: View next topic |
Author |
Message |
scottc
Joined: 16 Aug 2010 Posts: 95
|
Quadrature Encoder Using the PIC18F2331/PIC18F2431 |
Posted: Wed Feb 16, 2011 9:31 pm |
|
|
Hi, I’m trying to use the inbuilt hardware QEI decoder in the PIC18F2.xxx
series of chips. Currently I am using 4.116 of the compiler. The encoder
I am using is a Bourns 24det mechanical type with 3 pins, it also has a built in push switch. The pins of the encoder are pulled up via 47k resistors
to vcc and connected to pins 5 & 6 on the chip.
Anyway what I want to accomplish is to simply increment a variable as the encoder is turned clockwise and decrement it as its turned anti-clockwise. Similar to how a tuning knob works on your car radio.
Looking through the ccs help file there is some info on how to setup_qei
with various options. The .h file for the part also includes the defines, but
there is no worked example so it’s difficult to figure out how to really use
the qei features of the part.
Looking at the PIC app note I think what I am after is a way to read the
position counter and use that to increment/decrement my variable.
Here is what I have tried so far. I would prefer to get the code working
not using a ISR to start with and then go from there.
Code: |
#include <MAIN.h>
#USE delay(clock=10Mhz, crystal)
#USE FAST_IO(A)
#USE FAST_IO(B)
#USE FAST_IO(C)
#BYTE port_a = 0xF80
#BYTE port_b = 0xF81
#BYTE port_c = 0xF82
int Count;
#include <LCD4bit.c>
void Write_Display (void)
{
Lcd_Config( LCD_LINE1 );
printf(Write_LCD, "%d",Count);
}
#int_IC3DR
void IC3DR_isr(void)
{
Count--;
}
#int_IC2QEI
void IC2QEI_isr(void)
{
Count++;
}
void main(void)
{
set_tris_b(0b00001101); //Port B I/O Config
set_tris_c(0b11000000); //Port C I/O Config
LCD_Start(); //Enable LCD to Start up
Count=100;
setup_qei(QEI_MODE_X2);
enable_interrupts(INT_IC3DR);
enable_interrupts(INT_IC2QEI);
enable_interrupts(GLOBAL);
while(true)
{
Write_Display();
}
}
|
The code is really bare bones at this point as I don’t have much to go on.
I noticed that the #int_IC3DR appears to be working but the count goes
down by a large number on each click of the encoder. I can turn the
encoder either left or right but the count still goes down LOL got to love
that eh.
The #int_IC2QEI ISR, does not appear to do anything at this point.
As I mentioned above I would prefer to get the thing working not using
a ISR to begin with so as to fine tune things and then take it from there.
Any guidance would be welcome.
Thanks Scott. |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Wed Feb 16, 2011 9:53 pm |
|
|
If I remember correctly, the encoder count registers maintain the count without you having to do anything but set them up. The QEI interrupts are for overflows and underflows of the count registers so you can do some extra bookkeeping with a larger integer.
You don't want to service an interrupt every time the encoder clicked. You wouldn't use a chip in this 18fxx31 series if that's how you wanted to handle things. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Thu Feb 17, 2011 9:11 am |
|
|
ok, I'm back... I looked last night as I was going to bed and decided rather than clicking a response and my keyboard waking up my girlfriend, I would reply today.
You are absolutely using this module incorrectly.
For your value, you just read the QEI position counter... It automatically goes up and down. You don't have to do it.
You're using the interrupts incorrectly. DR is only for a change in direction... not every pulse that's backwards. (backwards relative to what?)
IC2QEIF only interrupts on a period match, a rollover or and index pulse.
Your display should be showing the value of POSCNTH:POSCNTL.
Also, keep in mind, this is a 16bit counter... after it reaches 0 or 0xFFFF it will roll over unless there's an index pulse. Are you using an encoder with an index pulse? if not, you'll want to find another way to zero the position, no? You haven't told us what encoder you're displaying and why.
Cheers,
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Thu Feb 17, 2011 10:22 am |
|
|
Another question I meant to ask is:
Is your encoder an absolute position encoder or just a counter (like a knob on a stereo)??
You describe your task as being one to get absolute position.. and if that's the case, you need to know the number of pulses for a full turn.
That, and you should have an index pulse.. otherwise you'll see the position counter zero out as it should on index.
This still will be important for modes like powerup when the PIC doesn't have a count or index on the position yet and doesn't know about the position of what the encoder is linked to... (and from there, all sorts of other problems can come up).
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
scottc
Joined: 16 Aug 2010 Posts: 95
|
|
Posted: Thu Feb 17, 2011 11:33 am |
|
|
Ben the Encoder is a mechanical type like a Stereo Knob. Its got
24 clicks in total for one revolution. It does not have a index.
Bourns PEC 11 Incremental Encoder
http://www.bourns.com/data/global/pdfs/PEC11.pdf
I figured I was not using the module correctly as the code is based on
info from the ccs help file and the .h file, really bare bones at this point.
The end result of what I am trying to do is. If I have a INT with a value
of 100 and I turn the encoder clockwise the INT value increments by 1.
If I turn the encoder anti-clockwise that INT value decrements by 1
I can do this with regular code and 2 pic pins. I wanted to try use the
dedicated hardware of the pic to try the same thing as the qei module also includes pin filtering for noise etc.
Thanks Scott |
|
|
scottc
Joined: 16 Aug 2010 Posts: 95
|
|
Posted: Thu Feb 17, 2011 11:39 am |
|
|
Thanks sseidman, Details on using this are really Dire in the CCS help file.
Its kind of amazing really that they never included an example on this.
I will keep digging at it to see if I can get it to function as expected.
Scott |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Thu Feb 17, 2011 12:15 pm |
|
|
As Ben says then, you can just read the position registers. Declare a 'WORD' to address these, and just read it. _All_ the donkey work is done for you in the hardware. No need for interrupts, separate counter, or anything. the counter is there just like the timer counters. They just return the 'position' as the knob is turned, nothing more is needed.
Caveat though, most mechanical counters like this, need external pull up resistors.
Best Wishes |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Thu Feb 17, 2011 1:28 pm |
|
|
scottc wrote: | Thanks sseidman, Details on using this are really Dire in the CCS help file.
Its kind of amazing really that they never included an example on this.
I will keep digging at it to see if I can get it to function as expected.
|
It's all about feedback.
most of the veteran PIC users wouldn't really need an example...
So how often are the new users doing this? No feedback - no example.
Why not write up an example and submit it to CCS for inclusion in the next release?
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Thu Feb 17, 2011 4:25 pm |
|
|
scottc wrote: | Thanks sseidman, Details on using this are really Dire in the CCS help file.
Its kind of amazing really that they never included an example on this.
I will keep digging at it to see if I can get it to function as expected.
Scott |
I posted a real code snippet from long ago in the other thread you were involved in-- just take a peek at that and things should get a bit clearer
http://www.ccsinfo.com/forum/viewtopic.php?t=23455 |
|
|
scottc
Joined: 16 Aug 2010 Posts: 95
|
|
Posted: Thu Feb 17, 2011 9:28 pm |
|
|
Sseidman, I took a look at your code and kind of get the jist of whats
going on, Something is odd tho. In ver 4.114 I believe CCS added
the defines for the rotary encoder module to the .H file for the parts that
support it but I do not see any of this defined in the .h file.
#BYTE QEICON=0xFB6 // quadrature configure
#bit QEICONDIR=0xFB6.5
#BYTE DFLTCON=0xF60 // quadrature noise filter configure
#BYTE CAP2BUFL=0xF66 // position counter
#BYTE CAP2BUFH=0xF67
#BYTE CAP3BUFL=0xF64 //max count
#BYTE CAP3BUFH=0xF65
They got a bunch of defines under
QEI Functions: setup_qei(), qei_set_count(), qei_get_count(),
// qei_status()
I was under the impression I could configure the QEI via setup_qei
and pass what is needed etc, but this does not appear to be the case.
Its like the actual implementation is not complete.
I will bang on the code a bit more and omit the setup_qei part
thanks Scott |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Fri Feb 18, 2011 7:03 am |
|
|
Yeah, when I wrote that I don't think CCS had support built in for the QE. Use this code as a lesson plan, though-- Don't be afraid to go to the datasheet for the chip and learn about the special registers you're writing too, then see if the new h-file makes sense. |
|
|
ALPL
Joined: 29 Mar 2009 Posts: 30
|
|
Posted: Fri Feb 18, 2011 9:03 am |
|
|
Scottc, this code will not work - you have to declare RA3 and RA4 as digital inputs (TRIS and ADCON0) first. Then set QEICON to the desired values, if applicable assign a value to MAXCNTL and MAXCNTH as well as to POSCNTL and POSCNTH and activate all interrupts. If needed activate the filter (DFLTCON). Then if the ISRs are correctly set up the code will work. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Feb 18, 2011 9:50 am |
|
|
ALPL wrote: | Scottc, this code will not work - you have to declare RA3 and RA4 as digital inputs (TRIS and ADCON0) first. Then set QEICON to the desired values, if applicable assign a value to MAXCNTL and MAXCNTH as well as to POSCNTL and POSCNTH and activate all interrupts. If needed activate the filter (DFLTCON). Then if the ISRs are correctly set up the code will work. |
Unless I'm reading the datasheet incorrectly,
One of his ISR's will fire on a change of direction... once that direction is changed, no more interrupts of that type will trigger on each successive rotation click in the same direction. So having the ISR do all the position count subtractions is an error of implementation.
For the other interrupt, it only triggers on an indx pulse. He's not using an index input.
So he needs to watch for under/overflows... otherwise, the rest is up to him how to implement.
Maybe I'm nutz. _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
ALPL
Joined: 29 Mar 2009 Posts: 30
|
|
Posted: Fri Feb 18, 2011 10:26 am |
|
|
Correct - he has to poll the POSTCNTL/H-register-pair in the main code to find out the position. |
|
|
scottc
Joined: 16 Aug 2010 Posts: 95
|
|
Posted: Fri Feb 18, 2011 9:31 pm |
|
|
I was looking through a data sheet last night and the analog pins need
to be set as digital IO, thanx ALPL for pointing that out.
I am wondering is it even necessary to use a ISR for this. I am back hunting the datasheet. THere has got to be a register that is getting either
a 1 or a 0 based on each pulse and direction. I believe if I can access that
then I can get to where I need to be.
Thanks Scott |
|
|
|