Jump to content
Sign in to follow this  
dj sures

Engine Rpm With 16f684

Recommended Posts

HEy there . as the title says . I have made a little app that i was expirementing with to count engine rpm . i originally wrote the program using the 16F84 . but i realized later, that i have a 16F684 :( .

 

anyway, it uses an hardware interrupt on one pin . the datasheet of 16F684 says RA2/Int . So i enabled the interrupt and made the function, but it doesn't seem to be getting executed .

 

I didn't want to ask for assistance, looks like i'll need to .

 

// For PIC16F684
#pragma CLOCK_FREQ	4000000

#include <system.h>
#include <boostc.h>

// Outputs
#define STATUS_LED			5

// Application Constants
#define LOOP_DELAY_US		100
#define RPM_COUNT_LIMIT		2000

// Global Variables
unsigned char rpsCounter = 0;

void interrupt( void ) {

rpsCounter++;
clear_bit(intcon, INTF);
}

void main() {

unsigned char currentRPS = 0;
unsigned int  loopCount  = 0;

trisa = 0b00011111;
trisc = 0b11111111;

set_bit(intcon, INTE);
set_bit(intcon, GIE);

set_bit(porta, STATUS_LED);

while (1) {

	if (loopCount > RPM_COUNT_LIMIT) {

		if (test_bit(porta, STATUS_LED))
			clear_bit(porta, STATUS_LED);
		else
			set_bit(porta, STATUS_LED);

		currentRPS = rpsCounter;
		loopCount 	= 0;
		rpsCounter  = 0;
	}

	loopCount++;
	delay_us(LOOP_DELAY_US);
}
}

Share this post


Link to post
Share on other sites
HEy there . as the title says . I have made a little app that i was expirementing with to count engine rpm . i originally wrote the program using the 16F84 . but i realized later, that i have a 16F684 :( .

 

anyway, it uses an hardware interrupt on one pin . the datasheet of 16F684 says RA2/Int . So i enabled the interrupt and made the function, but it doesn't seem to be getting executed .

 

I didn't want to ask for assistance, looks like i'll need to .

 

I don't quite understand how your program works.

Mine (below) works by counting the number of pulses in a given fixed time interval.

To get RPMyou might count how many revs you get in a minute, then you have there answer. To get a faster update you could count how many revs you get in a second and them multiply this value by 60. In the program below I count pulses in 10ms and then add two zeroes to the output value to give a value in Hz (cycles per second).

 

////////////////////////////////////////////////////////////////////////////
// PIC18 TMR0 counter mode test - Simple Frequency Counter
////////////////////////////////////////////////////////////////////////////
// Author(s): David Hobday
// Date: 15 April 2005
//
// Copyright (c) 2004-2005 Pavel Baranov
// Copyright (c) 2004-2005 David Hobday
//
// Objective
// =========
// To test:
// 1) 16 bit counter mode operation, ie external clock source on RA4
//
// Hardware
// ========
// Target Device: PIC18F452
// This code was written to run under SourceBoost Debugger/simulator,
// but was also checked against the Microchip PICDEM2 PLUS board.
//
// 
// Revisions
// =========
// V1.0.0 - Initial version
//
//

#include <system.h>


// These setting are for the PICDEM2 PLUS board!
#define LCD_ARGS  1, /* Interface type: mode 0 = 8bit, 1 = 4bit(low nibble), 2 = 4bit(upper nibble) */ \
   1,               /* Use busy signal: 1 = use busy, 0 = use time delays */                          \
   PORTD, TRISD,    /* Data port and data port tris register */                                       \
   PORTA, TRISA,    /* Control port and control port tris register */                                 \
   3,               /* Bit number of control port is connected to RS */                               \
   2,               /* Bit number of control port is connected to RW */                               \
   1                /* Bit number of control port is connected to Enable */

#include <lcd_driver.h>  // LCD template code
#include <system.h>

// set device configuration
#pragma DATA    _CONFIG1H, _OSCS_OFF_1H & _HS_OSC_1H
#pragma DATA    _CONFIG2L, _BOR_ON_2L & _BORV_20_2L & _PWRT_OFF_2L
#pragma DATA    _CONFIG2H, _WDT_OFF_2H & _WDTPS_128_2H
#pragma DATA    _CONFIG3H, _CCP2MX_ON_3H
#pragma DATA    _CONFIG4L, _STVR_ON_4L & _LVP_OFF_4L & _DEBUG_OFF_4L
#pragma DATA    _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L
#pragma DATA    _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
#pragma DATA    _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L
#pragma DATA    _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
#pragma DATA    _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L
#pragma DATA    _CONFIG7H, _EBTRB_OFF_7H

#pragma CLOCK_FREQ 4000000


volatile bit giel @  INTCON.GIEL;
volatile bit gieh @  INTCON.GIEH;
volatile bit ipen @RCON.IPEN;
volatile bit rb0 @PORTB.0;
volatile bit ra4 @PORTA.4;
volatile bit tmr0ip @INTCON2.TMR0IP;
volatile bit tmr0if @INTCON.TMR0IF;
volatile bit tmr0ie @INTCON.TMR0IE;
volatile bit t08bit @T0CON.T08BIT;
volatile bit t0psa @T0CON.PSA;
volatile bit t0cs @T0CON.T0CS;
volatile bit t0On @T0CON.TMR0ON;


void main()
{
trisb = 0x01;		//configure port B
latb = 0;		//clear port B
int interruptCntSnap;

adcon1 = 00001110b; // Bit 0 is an analog input for the A/D, the 1's are digital inputs.
lcd_setup();
lcd_clear();

// configure Timer0 - generates interrupt after 16384K (4 * 64 * 65536) clock cycles
t0On = 1; // timer on;
t08bit = 0; // 16 bit mode
t0cs = 1; // external closk

// generates interrupt every 65536 or 256 * 4 (prescaler)  * 4 Clocks (Fosc/4) = 
// @ 4MHz, this is 
t0psa = 1; // prescaler disabled

///////////////////////////////////////////
// 16 bit timer read
///////////////////////////////////////////
// Determine external frequency by counting pulses in a fixed time period

while( 1 )
{
	tmr0h = 0;
	tmr0l = 0;

	delay_ms( 10 );

	int freq = (tmr0h << 8) + tmr0l;

	lcd_gotoxy( 0, 0 );
	lprintf( "Freq:%05d00 Hz", freq );	
}
}

 

Regards

Dave

Share this post


Link to post
Share on other sites
I don't quite understand how your program works.

Mine (below) works by counting the number of pulses in a given fixed time interval.

To get RPMyou might count how many revs you get in a minute, then you have there answer. To get a faster update you could count how many revs you get in a second and them multiply this value by 60. In the program below I count pulses in 10ms and then add two zeroes to the output value to give a value in Hz (cycles per second).

 

hey dave, the main program loop has an IF condition that will be enterred when 1 second has passed . then it figures out how many times the interrupt has been executed since the last second .

 

as it stands, there is no display of the value . i'm using breakpoints and looking at the values . but the interrupt never gets executed . do you know why?

 

it worked fine on the 16f84 . it's not working on the 16f684 .. i would like to use ra2/int

Share this post


Link to post
Share on other sites
To get RPMyou might count how many revs you get in a minute, then you have there answer. To get a faster update you could count how many revs you get in a second and them multiply this value by 60. In the program below I count pulses in 10ms and then add two zeroes to the output value to give a value in Hz (cycles per second).

 

Measuring the number of pulses for 1sec(RPS) & then multiplying with 60 to get RPM will result in a lot of error especially when the RPM of the motor gets low, say 300 RPM.

Let's say we get 50 RPS on one occasion & 51 RPS in the next then your RPM meter will jump from 300RPM to 360 RPM which is unacceptable.

 

To get a precise RPM reading you need to determine the time between two pulses.

Once you have this time t, frecuency can be calculated using f=1/t. If this results in floating point calculation then make it 1000000/t or try using the fp library available as down load. You can use tmr0 in counter mode to count pulses and tmr1 in timer mode to time the interval between pulses.

 

Regards

Raghunathan.

Share this post


Link to post
Share on other sites

To get RPMyou might count how many revs you get in a minute, then you have there answer. To get a faster update you could count how many revs you get in a second and them multiply this value by 60. In the program below I count pulses in 10ms and then add two zeroes to the output value to give a value in Hz (cycles per second).

 

Measuring the number of pulses for 1sec(RPS) & then multiplying with 60 to get RPM will result in a lot of error especially when the RPM of the motor gets low, say 300 RPM.

Let's say we get 50 RPS on one occasion & 51 RPS in the next then your RPM meter will jump from 300RPM to 360 RPM which is unacceptable.

 

To get a precise RPM reading you need to determine the time between two pulses.

Once you have this time t, frecuency can be calculated using f=1/t. If this results in floating point calculation then make it 1000000/t or try using the fp library available as down load. You can use tmr0 in counter mode to count pulses and tmr1 in timer mode to time the interval between pulses.

 

Regards

Raghunathan.

 

 

okay . this is testing . and i will do that . but again, how come the interrupt doesn't work?

Share this post


Link to post
Share on other sites

You say you are using breakpoints to check for the interrupt. I assume you are simulating. If so, are you simulating the input to RA2/INT?

Share this post


Link to post
Share on other sites
You say you are using breakpoints to check for the interrupt.  I assume you are simulating.  If so, are you simulating the input to RA2/INT?

 

you bet . on the simulator i have set the button array to portA . and i press the 3rd button from the right . which should be RA2 ?

 

the breakpoint in the interrupt() doesn't get hit . and neither does the rpsCounter get incremented .

Share this post


Link to post
Share on other sites
You say you are using breakpoints to check for the interrupt.  I assume you are simulating.  If so, are you simulating the input to RA2/INT?

 

you bet . on the simulator i have set the button array to portA . and i press the 3rd button from the right . which should be RA2 ?

 

the breakpoint in the interrupt() doesn't get hit . and neither does the rpsCounter get incremented .

It looks like you need to disable the analog function blocks.

 

Try:

#include <system.h>
#include <boostc.h>

// For PIC16F684
#pragma CLOCK_FREQ    4000000
#pragma DATA _CONFIG, _CP_OFF & _PWRTE_OFF & _INTOSC & _WDT_OFF


// Outputs
#define STATUS_LED            5

// Application Constants
#define LOOP_DELAY_US        100
#define RPM_COUNT_LIMIT        2000

// Global Variables
unsigned char rpsCounter = 0;

void interrupt( void ) {

   rpsCounter++;
   clear_bit(intcon, INTF);
}

void main() {

   unsigned char currentRPS = 0;
   unsigned int  loopCount  = 0;

   /* added 2007-MAR-28 to enable digital I/O on port A */
   porta = 0;
   cmcon0 = 0x07;
   ansel = 0;
   /* end of added code */

   trisa = 0b00011111;
   trisc = 0b11111111;

   set_bit(intcon, INTE);
   set_bit(intcon, GIE);
           
   set_bit(porta, STATUS_LED);

   while (1) {
       
       if (loopCount > RPM_COUNT_LIMIT) {
       
           if (test_bit(porta, STATUS_LED))
               clear_bit(porta, STATUS_LED);
           else
               set_bit(porta, STATUS_LED);

           currentRPS = rpsCounter;
           loopCount     = 0;
           rpsCounter  = 0;
       }
       
       loopCount++;
       delay_us(LOOP_DELAY_US);
   }
}

Using "delay_us();" to create your RPM count sample period is very wrong.

 

This will make a very inacurate time base for sampling your RPM counter.

Share this post


Link to post
Share on other sites
It looks like you need to disable the analog function blocks.

 

oh great thank you . i am going to work on an analog expirement next . so this assistance is helping me learn . i will research examples before i ask any more questions :(

 

 

This will make a very inacurate time base for sampling your RPM counter.

 

ah i see . i'm starting to understand why . thanx for the heads up . i will use the timer . my issue with using a timer to begin with was unaware of it's existence or usage . i will examine the previous code example and utilize that method .

 

thanx for all your help

Share this post


Link to post
Share on other sites

cac001,

Using "delay_us();" to create your RPM count sample period is very wrong.

It depends on the exact application. It certainly is readily understandable (for a newbie), but with the potential for great inaccuracy.

 

Regards

Dave

Share this post


Link to post
Share on other sites

sorry to come with this . but i have added the appropiate suggestions to trigger my interrupt, and it still doesn't work .

 

Again, here is my code . i really can't figure out why my interrupt doesn't work :~(

 

// For PIC16F684
#pragma CLOCK_FREQ    4000000

#include <system.h>
#include <boostc.h>

// Inputs
#define RPM_SIGNAL			0

// Outputs
#define RPM_LED         4
#define STATUS_LED			5

// Application Constants
#define LOOP_DELAY_US		100
#define RPM_COUNT_LIMIT		2000

// Global Variables
unsigned char rpsCounter = 0;

void interrupt( void ) {

rpsCounter++;
clear_bit(intcon, INTF);
set_bit(porta, RPM_LED);
}

void main() {

unsigned char currentRPS = 0;
unsigned int  loopCount  = 0;

porta   = 0;
cmcon0  = 0x07;
ansel   = 0;

trisa = 0b001111;
trisc = 0b111111;

set_bit(intcon, INTE);
set_bit(intcon, GIE);
clear_bit(intcon, INTF);

set_bit(porta, STATUS_LED);

while (1) {

   if (loopCount > RPM_COUNT_LIMIT) {

		if (test_bit(porta, STATUS_LED))
			clear_bit(porta, STATUS_LED);
		else
			set_bit(porta, STATUS_LED);

		currentRPS 	= rpsCounter;
		loopCount 	= 0;
		rpsCounter  = 0;
	}

	loopCount++;
	delay_us(LOOP_DELAY_US);
}
}

Share this post


Link to post
Share on other sites

I ran the program . and watched the registers . and compared them all to the datasheet for the 16F684 . I'm at my witts end of why the interrupt won't work . Can someone help me verify if this is a simulator issue? Thanx

 

Here are my real time values....

INTCON 144 (10010000)
gie 1
peie 0
t0ie 0
inte 1
raie 0
t0if 0
intf 0
raif 0

PIE1 0

TRISA 15 (00001111)

TRISC 63 (00111111)

OPTION_REG 255 (11111111)
* datasheet defines RAPU, sourceboost defines NOT_RAPU

IOC 15 (00001111)
* datasheet defines IOCA, sourceboost defines IOC

CMCON0 7 (00000111)

CMCON1 0

VRCON 0

ANS 0

ADCON0 0

ADCON1 0

CCP1CON 0

ANSEL 0

Share this post


Link to post
Share on other sites

Looks like a SourceBoost simulator issue to me.

 

The MPLAB simulator works, but it is a pain to setup a stimulus file if you have never done it before.

Edited by cac001

Share this post


Link to post
Share on other sites
Looks like a SourceBoost simulator issue to me.

 

The MPLAB simulator works, but it is a pain to setup a stimulus file if you have never done it before.

 

 

okay *phew* . it's good to know that i'm not crazy . i have wasted about 10 hours on this . lol . trying different combinations and reading the datasheet pdf over and over again . and i could not figure out what was wrong .

 

the problem i noticed with the MBLAB IDE is it doesn't have a C Compiler for the PIC16F . can you add a c compiler to the mblab ide?

Share this post


Link to post
Share on other sites

Yes, there should be a screen that pops up when you install SourceBoost to "integrate" BoostC with MPLAB.

 

This works most of the time. Sometimes you will need to do the integration manually.

 

There is probably a FAQ here somewhere on how to do it.

 

Dave, any hints?

 

P.S. Do not depend on my opinion as a sanity check. You may still be crazy. :rolleyes:

Edited by cac001

Share this post


Link to post
Share on other sites
sorry to come with this . but i have added the appropiate suggestions to trigger my interrupt, and it still doesn't work .

 

Again, here is my code . i really can't figure out why my interrupt doesn't work :~(

 

// For PIC16F684
#pragma CLOCK_FREQ    4000000

#include <system.h>
#include <boostc.h>

// Inputs
#define RPM_SIGNAL            0

// Outputs
#define RPM_LED         4
#define STATUS_LED            5

// Application Constants
#define LOOP_DELAY_US        100
#define RPM_COUNT_LIMIT        2000

// Global Variables
unsigned char rpsCounter = 0;

void interrupt( void ) {

    rpsCounter++;
    clear_bit(intcon, INTF);
    set_bit(porta, RPM_LED);
}

void main() {

    unsigned char currentRPS = 0;
    unsigned int  loopCount  = 0;

    porta   = 0;
    cmcon0  = 0x07;
    ansel   = 0;

    trisa = 0b001111;
    trisc = 0b111111;

    set_bit(intcon, INTE);
    set_bit(intcon, GIE);
    clear_bit(intcon, INTF);
            
    set_bit(porta, STATUS_LED);
                
    while (1) {
        
   if (loopCount > RPM_COUNT_LIMIT) {
        
            if (test_bit(porta, STATUS_LED))
                clear_bit(porta, STATUS_LED);
            else
                set_bit(porta, STATUS_LED);

            currentRPS     = rpsCounter;
            loopCount     = 0;
            rpsCounter  = 0;
        }
        
        loopCount++;
        delay_us(LOOP_DELAY_US);
    }
}

 

I understand that you are using int0 or interrupt on RB0(INTE) to read the pulse, but where is the option register config bits?

YOU need to set the edge trigger bit INTEDG of option register (rising edge or falling edge).

 

Regards.

Raghunathan

Share this post


Link to post
Share on other sites

/me chuckles

 

i take it ra68gi did not actually look at the datasheet for this chip?

The 16F684 does not have a PortB only A and C.

 

He is probably right about the " INTEDG of option register" part though.

Edited by emte

Share this post


Link to post
Share on other sites
/me chuckles

 

i take it ra68gi did not actually look at the datasheet for this chip?

The 16F684 does not have a PortB only A and C.

 

He is probably right about the " INTEDG of option register" part though.

 

 

but the INTDEG defines wether the interrupt will trigger on rising or falling edge . either way, the interrupt should have triggered .

Share this post


Link to post
Share on other sites
but the INTDEG defines wether the interrupt will trigger on rising or falling edge . either way, the interrupt should have triggered .

Yes the SourceBoost simulator should have interrupted. That it does not looks like a bug.

 

Perhaps the SourceBoost simulator only accepts an external interrupt on RB0 even if the current target device does not have a PORTB.

 

Use the PM button on this post and send me an email address and I will send you a MPLAB project that runs in the Microchip simulator.

Share this post


Link to post
Share on other sites
but the INTDEG defines wether the interrupt will trigger on rising or falling edge . either way, the interrupt should have triggered .

Yes the SourceBoost simulator should have interrupted. That it does not looks like a bug.

 

Perhaps the SourceBoost simulator only accepts an external interrupt on RB0 even if the current target device does not have a PORTB.

 

Use the PM button on this post and send me an email address and I will send you a MPLAB project that runs in the Microchip simulator.

 

 

Thanx cac001 .

 

I decided to grow up and be a big boy by using the 16F877a from now on . The sourceboost simulator gives me no trouble with that chipset . and a thoroughly enjoy the speed increase . The extra bits also helps :(

 

i am using the timer now to calculate RPM using your suggestions . Thank you guys . It works wonderful .

 

My next project to learn is the ADC . i have been reading the datasheet and i'm slowly beginning to understand .

 

i'll keep chugging at it a bit longer before/if i have any questions .

 

thanx again for your help cats .

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...