go_away

Author Topic: How to capture pulse per second for a DC Geared motor with quadrature encoder  (Read 2939 times)

0 Members and 1 Guest are viewing this topic.

Offline twinsratioTopic starter

  • Jr. Member
  • **
  • Posts: 16
  • Helpful? 0
Hi there,

I have a DC motor speed controller project, my lecturer asked me to capture the pulse per second generated by the motor's encoder using PIC16f887. However, I got not ideas how to start with that....Can someone provides relevant information regarding to this?


Thank you in advance.

Offline waltr

  • Supreme Robot
  • *****
  • Posts: 1,920
  • Helpful? 97
There are several ways to do that with a PIC (or other processor).
1- Set up a hardware timer to time out a period of 1 second. You may need to multiple the timer's period with a software counter to get a one second period.
2- Use an input to capture the rising or falling edge of the encode output.
3- Zero a variable to hold the number of encoder counts and start the 1 second timer.
4- Increment the encoder counter each time the input from the encoder detects a rising edge (this could or a falling edge instead).
5- When the 1 second timer expires you have the number of encoder pulses per second in the encoder count variable.

A quadrature encoder has two output but for this simple task only only of the outputs is needed.

You can also count the number of pulse in say a tenth of a second then multiply by 10 to get pulses per second.

For more on using and programming PIC, see this tutorial:
http://www.gooligum.com.au/tutorials.html

Good luck and have fun.

Offline Soeren

  • Supreme Robot
  • *****
  • Posts: 4,672
  • Helpful? 227
  • Mind Reading: 0.0
Hi,

For a faster update, time the interval between two rising (or falling) edges and take the reciprocal value of that.
For a more steady count with less jitter, make a running average of a number of pulses.
Regards,
Søren

A rather fast and fairly heavy robot with quite large wheels needs what? A lot of power?
Please remember...
Engineering is based on numbers - not adjectives

Offline twinsratioTopic starter

  • Jr. Member
  • **
  • Posts: 16
  • Helpful? 0
Hi there,

I have a code which is a counter that counts the falling or the rising edge generated by the encoder. I set a limit for count, and when the counter reached the limit it lights up a LED.This is just to prove the code is correct to taking the signal from 1 of the encoder channel.
The program is successful, however I need to capture the count in 1 second time using the timer of the MCU. That's mean the counter will count the pulse for 1 second and keep the result for display. How to implement the timer in that case?

#include <pic.h>
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT & BORDIS & LVPDIS );
void main(void)
{
unsigned int d,c,f;

ANSEL =0x00; //’all analogue ports to digital
ANSELH =0x00; //’all analogue ports to digital
TRISD = 0x00; // Set PORTD as Output
TRISC=0xFF;
c=0;


while(1)
   {
      
      f=c+1;
      if ((f>=50)&&(RC3==1)){
      for(d=0;d<5000;d++){}
      PORTD=0x01;
      for(d=0;d<50000;d++){}
      for(d=0;d<50000;d++){}
      c=0;
      }

      if (RC3==1){
      for(d=0;d<5000;d++){}
      PORTD=0x00;

      }
      if (RC3==0){
      for(d=0;d<5000;d++){}
      c=c++;
      }
      

      
   }
}


Please correct if the code need any improvement.

Thank you.

Offline twinsratioTopic starter

  • Jr. Member
  • **
  • Posts: 16
  • Helpful? 0
Hi Waltr,

Thank you for the reply. I really want to know how to implement the step 3-5 into my coding as I'm only able to take the rising or failing edge from the motor encoder.

3-Zero a variable to hold the number of encoder counts and start the 1 second timer.
4- Increment the encoder counter each time the input from the encoder detects a rising edge (this could or a falling edge instead).
5- When the 1 second timer expires you have the number of encoder pulses per second in the encoder count variable.

Please help me on the coding especially implementing the timer. In this case I will use timer0 of the PIC 16F887. Please refer to the code that I have done for the capture of pulse edge and advice on it.

Thank you

Offline waltr

  • Supreme Robot
  • *****
  • Posts: 1,920
  • Helpful? 97
I do use TMR0 for a number of tasks but in particular a "system Tick' used in the Main() loop for launching tasks. Here is how I do this and you can apply this to creating a 1 second timer.

Set up TMR0 to interrupt at some whole division of a second. 25ms, 100ms, 200msec or so.
In the TMR0 ISR:
1- re-load TMR0 taking into account the ISR latency. Use the MPLAB SIMulator and Stop watch to get the TMR0 value correct.
2- set a System Tick flag.
3- clear TMR0IF
4- exit ISR

Now in your main loop, the while(1) loop:
Test for the System Tick flag:
 If TRUE:
1- Increment a software counter
2- clear the System Tick flag
3- Test the software counter for a value that would be the number of TMR0 interrupts to make 1sec (if TMR0 interrupts every 100ms then the count would be 10).
4- If this test is TRUE:
     a- clear the software counter to start timing the next 1 sec interval.
     b- Save the current Encoder count to another variable.
     c- clear the Encoder count.
     d- set a flag to indicate that there is a new Encoder count.

Elsewhere in the main loop or in an ISR:
1- on each encoder transition (high or low) increment the encoder counter.

I would try using one of the PORT B inputs that have IOC and do the encoder pulse counting in an ISR.

Also in the main loop:
1- Test the new encoder value flag
2- get the new encoder value
3- clear the new encoder value flag
4- Use the value in what ever calculations are needed.

The code you posted is ok if the PIC does not need to do much, but is excellent to test reading the encoder pulses. A PIC really can do all sorts of things if any of the Real Time Events are interrupt driven. So one of the next things you need to learn about is using the PICs interrupts. Go back to the Gooligum tutorial and read up on interrupts.
Start with the TMR0 interrupt and get it to provide a System Tick.

Since this is a School assignment I won't write the code for you but here is a link to PIC C code for doing I2C interface to a Compass chip. Look at the third file that contains main() for how I use TMR0 ISR and a flag to signal the counter in main(). There is a good bit of other functions and code in there that could be of use.
http://forum.sparkfun.com/viewtopic.php?f=6&t=22429
« Last Edit: February 16, 2011, 07:08:03 PM by waltr »

Offline twinsratioTopic starter

  • Jr. Member
  • **
  • Posts: 16
  • Helpful? 0
Hi Waltr,

Thank you for reply. Currently I have example of blinking LED program by using timer0 to interrupt. However I do not understand how to implement it to my code.

// PICC301 LED Blinking using Timer
#include <pic.h>
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT & BORDIS);
unsigned int reload=15;
void main(void)
{
ANSEL = 0x00;
TRISC = 0x00;
PORTC = 0x0F;
OPTION = 0x07; // Prescaler=256, PSA=0, T0CS=0
T0IE = 1; // Enable Timer
GIE = 1; // Enable Global Interrupt
while(1){
}
}
static void interrupt
isr(void)
{
if(reload == 0)
{
PORTC ^= 0x0F; // Toggle PORTC
reload = 16;
}
reload--;
T0IF = 0; // Clear Timer Interrupt Flag
}

Is there any way to simplify the code. Please help up in which I'm quite new in PIC.

Thank you.

Offline waltr

  • Supreme Robot
  • *****
  • Posts: 1,920
  • Helpful? 97
Quote
Is there any way to simplify the code.
Not really.
The ISR does the minimum of what you need.
Quote
Please help up in which I'm quite new in PIC.
Grab the code I posted a link to in the SparkFun forum.
Put the files in a folder and create an MPLAB project adding those file to the project.
Then use the MPLAB Simulator to step through the code. Also set break-points and open the Stop watch to check timing.

One thing I see in your code:
Code: [Select]
PORTC ^= 0x0F; // Toggle PORTCThis line reads the PORT, does an XOR with the constant then writes the result back to the PORT. This can cause RMW (Read-Modify-Write) issues. The PIC's data sheet should have info about this in the IO PORTS section. Again check the code I posted a link to for a way to avoid this, "portC_image" in my code. Replace that line with this:
Code: [Select]
portC_image ^= 0x0F;
PORTC = portC_image;

Where portC_image has been defined as:
Code: [Select]
static unsigned char   portC_image;           // port mirror, set/clear bits here then write value to port
                                                                     // to prevent any RMW issues


 


Get Your Ad Here

data_list