CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Problem with tach routine

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
sadlpx



Joined: 19 Feb 2004
Posts: 23

View user's profile Send private message

Problem with tach routine
PostPosted: Sun Jul 08, 2012 8:58 am     Reply with quote

Attached is my code routine for a frequency meter/ tachometer . It compiles and runs well with about 5% error (on the low side) up to about 1800HZ (1.8kHz). Running an internal 4mHZ clock

I've a square wave freq generator and got a good scope to measure the signal.

Accuracy just goes away (wanders all over). Does not seem to be math or interrupt related as I can change the sample time from 1/4 sec to 4 sec with appropriate math and the problem seem stable.

Guessing it the clock speed but can anyone else see anything wrong with my code:
Code:

// ========================================================================
//
//   File...... PIC frequency Meter.c
//   Purpose... Create Frequency / RPM meter
//   Author.... Porter Sadler
//   E-mail.... p.sad52@hotmail.com
//   Started... 19 August, 2009
//   Updated...
//
//   PIC - 18F4620
//   CCS compiler - 4.096
// =========================================================================


/* -----[ Program Description ]---------------------------------------------
 * SIMPLE SERIAL FREQUENCY METER
 *
 * The original program counts the interrupts for one second. 
 * It then disables the interrupts and write the count
 * to the RS232 communication line (LCD) and then finally
 * re-enables the interrupts and repeat.
 * Frequency is the direct count, RPM is number * 60.
 *   
 * input signal on the RB0 pin * * PIC16F73A * 4 Mhz crystal, HS clock   
 * PORTB.0, in  : counter input
 * PORTB.1, out : RS232 tx
 *
 * 
 * Author : Bruno Gavand, november 2005
 * see more details on www.micro-examples.com
 *
 */
//-----[ Revision History ]------------------------------------------------


// -----[ INCLUDES ]-------------------------------------------------
#include "RPM Gauge timer.h"
//#include <stdio.h>
//#include <string.h>




// -----[ I/O Definitions ]-------------------------------------------------
#define   LED_Green pin_B3              // PIN_B3
#define   LED_Red1  PIN_B2              // PIN_B2
#define   LED_Red2  PIN_B2

//******   LCD I/O  ******
// This uses the CCS FLexLCD4020.c module.
// The pin outs are random pins (not sequenced)
// IF you want only a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line. Doing so will save one PIC
// pin, but at the cost of losing the ability to read from
// the LCD. It also makes the write time a little longer
// because a STATIC delay must be used, instead of polling
// the LCD's busy bit. Normally a 6-pin interface is only
// used IF you are running out of PIC pins, and you need
// to use as few as possible FOR the LCD.
//
#define LCD_DB4 PIN_D7
#define LCD_DB5 PIN_D6
#define LCD_DB6 PIN_D5
#define LCD_DB7 PIN_D4
#define LCD_RS PIN_D2
// #define LCD_RW PIN_E1
#define LCD_E PIN_D3
 

#include "Flex LCD\Flex_LCD.c"

//-----[ RAW Variables ]------------------------------------------------

unsigned int16  cntr ;       // number of RB0 transition
unsigned int16  RPM ;        // cntr * 60 get RPM
unsigned int16  req_tics;    // number of required ticks per second
unsigned int16  ovrflw ;     // number of timer0 overflows

float fcntr;

// -----[ Constants ]-------------------------------------------------------

#define    Tics_4Mhz   3906/4
#define    Tics_10Mhz  9765/4
#define    Tics_16Mhz 15625/4
#define    Tics_20Mhz 19531/4

//' -----[ EEPROM Data ]-----------------------------------------------------

//' -----[ Interrupt Routines ]--------------------------------------------------
/*
 * Timer TMR0 is incremented once every 4 clock cycles -- increments/sec).
 * TMR0 is set up 8 bit timer
 * The interrupt routine is called when TMR0 resets from 255 to 0
 *
 * Other options based on clock chosen
 *  4 Mhz / 4 / 256 =   3,906 tic interrupts /second,
 * 10 Mhz / 4 / 256 =   9,765 tic interrupts /second
 * 16 Mhz / 4 / 256 =  15,625 tic interrupts /second,
 * 20 Mhz / 4 / 256 =  19,531 tic interrupts /second
 *
 * Interrupt is called at timer rollover (bit T0IF set)
 */
#INT_RTCC                        //Interrupt procedure
void clock_isr(void)
{                                //called every time RTCC
   ovrflw++;
}

 
// at each RB0 transition, with bit INTF set
// external interrupt when button pushed and released
#INT_EXT
void ext_isr(void)
{
    cntr++ ; 
}

//' -----[ Functions ]----------------------------------------------------



//' -----[ Initialization ]--------------------------------------------------



// -----[ MAIN Program Code ]----------------------------------------------------

void main()
{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1|RTCC_8_BIT);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
//   ext_int_edge(H_TO_L);      // init interrupt triggering for button press

   clear_interrupt(INT_EXT);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   set_timer0(0);

   // TODO: USER CODE!!
   lcd_init();
   printf (lcd_putc, "\f"); // Clear display  fputc (0x12, LCD)
   delay_ms (50);
 
 // title splash screen 500 MS
   lcd_gotoxy(1,1);
   printf(lcd_putc, "RPM/Frequency");
   lcd_gotoxy(1,2);
   printf(lcd_putc, "Meter");
   delay_ms(500);
   printf (lcd_putc, "\f");  // Clear display  fputc (0x12, LCD
   
   //  This line decided by clock speed
   req_tics = Tics_4Mhz;
   enable_interrupts(INT_RTCC);
 
   WHILE (1)        // main program loop
   { 
      cntr   = 0; // clear counters
      ovrflw = 0 ;               

      enable_interrupts(GLOBAL);
      output_high(LED_green);
      while(ovrflw <  req_tics/2) ;  // run for 1/2 sec.
      output_low(LED_green);
      disable_interrupts(GLOBAL);

      output_high(LED_Red1);
      lcd_gotoxy(0,1);
      cntr = cntr*2;             //  adjust for 1 sec
      RPM = (cntr * 60);
      printf(lcd_putc, "RPM = %4Lu ", RPM);
      fcntr = ((float)cntr);
      lcd_gotoxy(0,2);
      printf(lcd_putc, " Hz = %5.1f  ", fcntr);
      delay_ms (10);
     
      lcd_gotoxy(16,1);
      if (cntr > 1800)
          printf(lcd_putc, "over");
      else   
          printf(lcd_putc, "    ");
      output_low (LED_Red1);
    }
}
//***************
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Sun Jul 08, 2012 12:46 pm     Reply with quote

Seriously, use the hardware.
Use the CCP to do the counting.

Problem is it takes significant time to get into and out of an interrupt routine. Typically about 60 instructions. Updating a 16bit counter, in an interrupt routine, will take perhaps 70 instructions in all. Add the time needed for testing counters, and the arithmetic in your test and you are just running out of time.

You could get significantly faster, by not using the interrupt at all. Just looping testing the input bit, until the counter overflows. Don't do maths in the loop test, just test for the timer interrupt becoming set, presetting the counter to give the required timeout.

Best Wishes
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Jul 08, 2012 1:59 pm     Reply with quote

Or use something based on the CCS example EX_FREQC.

It's already done for you.

Mike
sadlpx



Joined: 19 Feb 2004
Posts: 23

View user's profile Send private message

PostPosted: Mon Jul 09, 2012 6:25 am     Reply with quote

Guys thanks for the help.

Mike - Board /program up and running as example
ex-freqc.c ( timing/LCD good).
New problem - hardware - having trouble with my input using pin_c0.
When I hookup my input line its pulled low (oscope) and does not count.

Originally hardware using Pin_B0.

1) Am I forced to C0 (pin 15) or can I use B0 by changing
to #bit t1_overflow=0x0b.0 as my input ?

2) Is there something I'm not configuring right?
Do I need pullup on C0 ????

Feeling stupid here
temtronic



Joined: 01 Jul 2010
Posts: 9225
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 09, 2012 6:32 am     Reply with quote

knowledge is power !
You should read look at the datasheet to confirm that C0 is the only pin tied to the counter peripheral.Some of the newer PICs can be configured like a PLA so it is important to read the datasheets !
yes, I know there's like 300-400 pages...but the internal design of the PIC is in the first few pages.Also read the counter-timer section while you're thumbing through the information.
the more you read the more you'll understand how the PIC works.AND the better the programmer you'll become.

you should always have pullups. generally 4k7 or 10k0 is fine when running at 5 volt Vss.This pullup helps ensure the PIC only sees 'good' zero-to-5volt transistions on an input pin.

hth
jay
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Mon Jul 09, 2012 1:33 pm     Reply with quote

Like temtronic says, you really need to learn how to navigate your way round the microchip data sheets, the CCS manual and the CCS .h files.

You will need a pull-up if your oscillator output is open collector/drain.

In the CCS example EX_FREQ pin C0 is being used as an external input to timer1.

Timer1 is then being used to count the input pulses.

Migrating to your 18F4620 may create timing errors because of the way that EX_FREQ does gating.

With the 18F4620 you can't use C0 as timer1 input (it's only a timer1 output), you could use C1 (it's all in the data sheets).

Earlier this year I suggested an alternative gating scheme which is more portable between processors.

http://www.ccsinfo.com/forum/viewtopic.php?t=47653
http://www.ccsinfo.com/forum/viewtopic.php?t=47375

Give it a try, and excuse me being cynical.

Mike
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group