View previous topic :: View next topic |
Author |
Message |
psicko275
Joined: 21 Mar 2013 Posts: 12
|
QEI Velocity measurement with 18F4431 |
Posted: Tue Apr 02, 2013 10:49 am |
|
|
Hi I am new in the forum, thanks for read this post!
I'm working with PIC18F4431 to read the velocity of CD motors with a encoder of 1200 PPR (Pulses per Revolution), I have read the NOTE: AN899 Brushless DC Motor Control Using PIC18FXX31 MCUs, and I find the correct form to read the velocity from counts of timer5 but don't from register velocity in CCS:
Code: | count=qei_get_count(QEI_GET_VELOCITY_COUNT); |
If I measure the speed from the timer 5 this works well but when the rotor stops the velocity have a value different to zero.
so this my code:
Code: |
#include <main_slave.h>
#byte CAP1BUFH = 0xF69
#byte CAP1BUFL = 0xF68
#byte CAP1CON = 0xF63
#bit CAP1REN = CAP1CON.6
#byte PIR3 = 0xFA4
#bit IC1IF = PIR3.1
float cte_velocity_rps = 0, cte_velocity_rpm=0;
int16 ad=0, count=0;
int32 INSTRUCTION_CYCLE = 5000000;
int16 ENCODER_PPR = 1200;
float RPM_CONSTANT_QEI = 0;
#int_IC1
/*
Velocity capture interrupt
*/
void IC1_isr()
{
count=qei_get_count(QEI_GET_VELOCITY_COUNT);
ad=get_timer5();
//! RPM_CONSTANT_QEI =cte_velocity_rps/ad ; //In RPS revolutions per second, This works fine except when the rotor is stopped.
//! RPM_CONSTANT_QEI =cte_velocity_rpm/ad ; //In RPM revolutions per minute, This works fine except when the rotor is stopped.
RPM_CONSTANT_QEI = 1953.125/count; //this value obtain of the equation 5 in AN899 and I can't read correctly the velocity
// RPM=((Operating Frequency/4) / (PPR x Velocity Update Rate x Pulse Reduction Ratio x Timer5 Prescale x VELR<H:L>)) x 60
set_timer5(0);
qei_set_count(0);
}
void main()
{
/*setup QEI*/
setup_qei(QEI_MODE_X4_RESET_ON_MATCH | QEI_VELOCITY_MODE_ENABLED | QEI_VELOCITY_PULSE_DIV_4 ,QEI_FILTER_ENABLE_QEB | QEI_FILTER_ENABLE_QEA, 2400);
//! setup_qei(QEI_MODE_X4_RESET_ON_MATCH, QEI_FILTER_ENABLE_QEB | QEI_FILTER_ENABLE_QEA, 2249);
SETUP_TIMER_5(T5_INTERNAL | T5_DIV_BY_8);
//! enable_interrupts(INT_TIMER5);
enable_interrupts(INT_IC1);
enable_interrupts(GLOBAL);
cte_velocity_rps = 625000/ENCODER_PPR; //cte_rps = (Operating Frequency/4) / (Timer5 Prescale x PPR)
cte_velocity_rpm = cte_velocity_rps*60;
while(true)
{
output_toggle(LED);
} /*End to while(true)*/
} /*End to main(void)*/
|
main_slave.h
Code: |
#include <18F4431.h>
#device adc=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(clock=20M)
#define LED PIN_C0
#define DELAY 10
|
I send the value RPM_CONSTANT_QEI to SPI communication, I don't put this code to simplify the question but if necessary I'llt.
Thanks for read, any ideas? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Apr 02, 2013 12:25 pm |
|
|
what "works" ????
you never call the result of your QEI function in MAIN after setup
all i see is a program that flashes a led so often it looks like its always on.
also including a floating point DIVISION op in an ISR is a HUGE mistake.
you understand this can be done without a float, outside the ISR, right ? |
|
|
psicko275
Joined: 21 Mar 2013 Posts: 12
|
|
Posted: Tue Apr 02, 2013 1:59 pm |
|
|
thanks for answer me.
asmboy wrote: | what "works" ????
you never call the result of your QEI function in MAIN after setup
all i see is a program that flashes a led so often it looks like its always on.
also including a floating point DIVISION op in an ISR is a HUGE mistake.
you understand this can be done without a float, outside the ISR, right ? |
I say that the variable RPM_CONSTANT_QEI I send to via SPI:
Quote: | I send the value RPM_CONSTANT_QEI to SPI communication, I don't put this code to simplify the question but if necessary I'llt. |
So this float DIVISION in the ISR works! and I'm no expert sorry.
How can I do outside the ISR? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Apr 02, 2013 2:11 pm |
|
|
Store count in a circular buffer, of magic size, and harvest the values from it, to the MAIN using a second pointer var.
Code: |
unsigned int16 ad[16],count[16];
unsigned int8 incp=0,outcp=0;
void IC1_isr()
{
count[incp]=qei_get_count(QEI_GET_VELOCITY_COUNT);
ad[(incp++)] =get_timer5();
incp = incp%16; // index 0 to 15
set_timer5(0);
qei_set_count(0);
}
|
Use OUTCP to decide which items you last pulled from the buffer this creates.
Then do your FP math in MAIN section.
ALSO for BEST resolution you may need to reverse when you load
count[] and ad[] based on which Var has the higher (nominal) received values - as it might be timer5... |
|
|
psicko275
Joined: 21 Mar 2013 Posts: 12
|
|
Posted: Thu Apr 04, 2013 7:07 am |
|
|
Thanks for the FP advice asmboy.
You know how to use the function to get the correct speed?
Code: | qei_get_count(QEI_GET_VELOCITY_COUNT); |
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Thu Apr 04, 2013 11:54 am |
|
|
honestly have never used it to determine speed.
have only used it to count encoder clicks and direction with user quad digital "pot". |
|
|
psicko275
Joined: 21 Mar 2013 Posts: 12
|
|
Posted: Thu Apr 04, 2013 3:28 pm |
|
|
thanks for help me!
asmboy wrote: | honestly have never used it to determine speed.
have only used it to count encoder clicks and direction with user quad digital "pot". |
I'm waiting for more answers! |
|
|
psicko275
Joined: 21 Mar 2013 Posts: 12
|
|
Posted: Thu Apr 11, 2013 6:39 am |
|
|
Anyone? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
|
psicko275
Joined: 21 Mar 2013 Posts: 12
|
|
Posted: Mon Apr 15, 2013 12:19 pm |
|
|
Yes in this page I write but anyone answer me my doubt.
thanks! |
|
|
|