• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Quadrature Encoder Interface module question

Status
Not open for further replies.

Cantafford

Member
Hello,

I have a question regarding the QEI module. I'm just learning to use it. I'm using PIC18f2431 and I've just finished reading it's datasheet section about this module.

I got lost here:



Here is what I understood from that section I snapshoted. Please correct me if I'm wrong. I guess I'm.

Fpos = position count rate. This can be proportional to 2 or 4 depending if I configure the QEI to work in "2x Update mode" or "4x Update mode". But what exactly is it. My goal is to get the RPM from this formula and display it on an LCD. What do I need to put in my formula for Fpos? Is it the time difference it takes for the QEI to make an increment/decrement in the POSCNT register?
D = datasheet says number of incremental lines in incremental encoder. I'm not sure what this means. Does it mean that if I have an incremental encoder with 10 divisions my D in that formula will be 2 to the power of 10 = 1024?

Also. Doesn't the frequency at which my ucontroller is working affect that formula at all?
 

ericgibbs

Well-Known Member
Most Helpful Member
hi,
Ref the 16 bit POScnt , this is an Up/Dwn counter which counts the QEA & QEB pulse edges.

When *2 POScnt uses the leading rising edge and falling edge of the QEA pulse to count and *4 POScnt uses the leading and falling edges of both QEA and QEB the pulses to count.

You load from the program the MAXcnt register, this will be used to compare the POSCnt and MAXcnt and raise an Event flag at Zero and when POS=MAX.

OK.?
 

Cantafford

Member
Hello,

Thank you very much for your answer. I'm sorry I did not reply to you earlier I was out of town.

I have read what you said and now my questions have cleared. I have understood this module.

I wrote a piece of code in which I'm doing the following:
- I assigned value of MAXNT to 240(that is the number of pulses per revolution for my encoder - I'm simulating it in proteus)
- I configured the QEI module in x4 mode and every time POSCNT reaches MAXCNT an interrupt is generated and I'm incrementing the value of a counter(which is the number of rotations)
- I configured TMR0 to give an overflow at every second. In this ISR I'm reading the value of counter in a variable speed(and so I get RPS) and then clear the counter to get a new value.
- The priority for QEI module is low and priority for TMR0 is high.

I cannot get the Timer0 to interrupt at 1 second. I have calculated everything like this.

The calculations for the TMR0 were like this:
- Internall OSC is 4Mhz. So my Fcy = 4Mhz/1 = 1Mhz. Tcy = 1us.
- Prescaler period = 16*1us = 16us.
- Overflow period = 16us * 2^16 =~ 1 sec(tmr0 was configured as 16bit timer)
However I get overflows very frequent not at 1 second as I should(or at least I think I should) get.

Code:
/*
 * File:   main.c
 * Author: Paul
 *
 * Created on April 17, 2017, 12:39 PM
 */

#include "header.h"
#include <stdio.h>
#include <stdlib.h>
#include <delays.h>
#include <xlcd.h>

void init_XLCD(void);              //Initialize LCD display
void DelayFor18TCY( void );        //18 cycles delay
void DelayPORXLCD (void);          // Delay of 15ms
void DelayXLCD (void);             // Delay of 5ms
void configureQEI();
void configureIntrs();
void configureTMR0();

long long int speed;
long long int counter = 0;

void main(void) 
{
  OSCCON = 0x6F; // 4Mhz internal oscillator
  ANSEL0 = 0x00; // Analog input disabled for EA and QEB. They are digital 
  TRISAbits.TRISA0 = 0;

  configureQEI();
  configureIntrs();
  configureTMR0();

   
  while(1)
  {
     
  }
}

void init_XLCD(void)                //Initialize LCD display
{
    OpenXLCD(FOUR_BIT&LINES_5X7);  //configure LCD in 4-bit Data Interface mode
                                     //and 5x7 characters, multiple line display
    while(BusyXLCD());             //Check if the LCD controller is not busy
                                     //before writing some commands?
    WriteCmdXLCD(0x06);            // move cursor right, don?t shift display
    WriteCmdXLCD(0x0C);            //turn display on without cursor
   
    putrsXLCD("LCD");          //Display "Hello World"
    SetDDRamAddr(0x40);            //shift cursor to beginning of second line
    putrsXLCD("Initialisation");      //Display "LCD display"
    for(int i=0; i<50; i++) __delay_ms(5);
    WriteCmdXLCD(0x01); // clear screen
 }
void DelayFor18TCY( void )         //18 cycles delay
{
//Delay10TCYx(20);
Nop( ); Nop( ); Nop( ); Nop( ); // 18 cycle delay
Nop( ); Nop( ); Nop( ); Nop( );
Nop( ); Nop( ); Nop( ); Nop( );
Nop( ); Nop( );
return;
}

void DelayPORXLCD (void)          // Delay of 15ms
{
Delay1KTCYx(30);
}

void DelayXLCD (void)            // Delay of 5ms
{
Delay1KTCYx(10);
}

void configureQEI()
{
  QEICONbits.QEIM2 = 1; // QEI enabled in 4x Update mode; position counter
  QEICONbits.QEIM1 = 1; // is reset on 
  QEICONbits.QEIM0 = 0; // period match(POSCNT = MAXCNT)
  MAXCNTL = 240;        // load value maxcount(number of pulses per revolution)
}

void configureIntrs()
{
    INTCONbits.GIE = 1;      // enable all interrupts
    INTCONbits.PEIE = 1;     // enable pheripheral interrupts
    INTCONbits.TMR0IE = 1;   // enable TMR0 overflow interrupt
    INTCON2bits.TMR0IP = 1;  // TMR0 overflow priority set to high
   
    RCONbits.IPEN = 1;       // enable priority lvls on interrupts
    PIE3bits.IC2QEIE = 1;    // enable QEI interrupts  

}

void configureTMR0()
{
    T0CONbits.T016BIT = 1;   // Timer0 is set as 16 bit counter
    T0CONbits.T0CS = 0;      // Timer0 clock source is FOSC/4
    T0CONbits.PSA = 0;       // Timer0 prescaler active
    T0CONbits.T0PS2 = 0;     // prescale value 
    T0CONbits.T0PS2 = 0;     // set to:
    T0CONbits.T0PS2 = 1;     // 1:16
    T0CONbits.TMR0ON = 1;    // enable Timer0
}


void interrupt ISR_TMR0()
{
    if(TMR0IE && TMR0IF)
    {
       LATAbits.LATA0 ^= 1;
    }
    TMR0IF = 0;
}
And the header.h

Code:
// PIC18F2431 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1H
#pragma config OSC = IRCIO      // Oscillator Selection bits (Internal oscillator block, port function on RA6 and port function on RA7)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = ON        // Internal External Oscillator Switchover bit (Internal External Switchover mode enabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled)
// BORV = No Setting

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDPS = 32768     // Watchdog Timer Postscale Select bits (1:32768)
#pragma config WINEN = OFF      // Watchdog Timer Window Enable bit (WDT window disabled)

// CONFIG3L
#pragma config PWMPIN = OFF     // PWM output pins Reset state control (PWM outputs disabled upon Reset (default))
#pragma config LPOL = HIGH      // Low-Side Transistors Polarity (PWM0, 2, 4 and 6 are active-high)
#pragma config HPOL = HIGH      // High-Side Transistors Polarity (PWM1, 3, 5 and 7 are active-high)
#pragma config T1OSCMX = OFF    // Timer1 Oscillator MUX (Standard (legacy) Timer1 oscillator operation)

// CONFIG3H
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (Disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Low-Voltage ICSP Enable bit (Low-voltage ICSP enabled)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000200-000FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (001000-001FFF) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (002000-002FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (003000-003FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot Block (000000-0001FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000200-000FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (001000-001FFF) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (002000-002FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (003000-003FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0001FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000200-000FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (001000-001FFF) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (002000-002FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (003000-003FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0001FFh) not protected from table reads executed in other blocks)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

#define _XTAL_FREQ 8000000
 
Last edited:

Cantafford

Member
By my calculations I should get a timer0 overflow at ~1 second.
- internal 4mhz oscillator
-1:16 prescaler
-configured as 16 bit timer

I get interrupts way more frequent. Am I wrong in my calculations?

Fosc = 4Mhz => freq = Fosc/4 = 1Mhz => period = 1/1Mhz = 1us
Timer overflow = 65536*1us = 65536us
Prescaler overflow: 65536us * 16 = 1.048.576us =~ 1 second
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Oooh!! Check this out..
You said:
void configureTMR0()
{
T0CONbits.T016BIT = 1; // Timer0 is set as 16 bit counter
T0CONbits.T0CS = 0; // Timer0 clock source is FOSC/4
T0CONbits.PSA = 0; // Timer0 prescaler active
T0CONbits.T0PS2 = 0; // prescale value
T0CONbits.T0PS2 = 0; // set to:
T0CONbits.T0PS2 = 1; // 1:16
T0CONbits.TMR0ON = 1; // enable Timer0
}
T0CONBits T0PSx... copied or what!!!
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
That said... TMRo overflows at 65mS so your config is wrong... T016BIT has to be zero to configure the 16 bit... I know wrong!!!! Very wrong!!

so try this....

C:
void configureTMR0()
{
    T0CONbits.T016BIT = 0;   // Timer0 is set as 16 bit counter
    T0CONbits.T0CS = 0;      // Timer0 clock source is FOSC/4
    T0CONbits.PSA = 0;       // Timer0 prescaler active
    T0CONbits.T0PS0 = 1;     // prescale value
    T0CONbits.T0PS1 = 1;     // set to:
    T0CONbits.T0PS2 = 0;     // 1:16
    T0CONbits.TMR0ON = 1;    // enable Timer0
}
 

Cantafford

Member
That said... TMRo overflows at 65mS so your config is wrong... T016BIT has to be zero to configure the 16 bit... I know wrong!!!! Very wrong!!

so try this....

C:
void configureTMR0()
{
    T0CONbits.T016BIT = 0;   // Timer0 is set as 16 bit counter
    T0CONbits.T0CS = 0;      // Timer0 clock source is FOSC/4
    T0CONbits.PSA = 0;       // Timer0 prescaler active
    T0CONbits.T0PS0 = 1;     // prescale value
    T0CONbits.T0PS1 = 1;     // set to:
    T0CONbits.T0PS2 = 0;     // 1:16
    T0CONbits.TMR0ON = 1;    // enable Timer0
}
Worked. Again sorry for the late reply been very busy lately
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top