|
|
View previous topic :: View next topic |
Author |
Message |
sadlpx
Joined: 19 Feb 2004 Posts: 23
|
Problem with tach routine |
Posted: Sun Jul 08, 2012 8:58 am |
|
|
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
|
|
Posted: Sun Jul 08, 2012 12:46 pm |
|
|
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
|
|
Posted: Sun Jul 08, 2012 1:59 pm |
|
|
Or use something based on the CCS example EX_FREQC.
It's already done for you.
Mike |
|
|
sadlpx
Joined: 19 Feb 2004 Posts: 23
|
|
Posted: Mon Jul 09, 2012 6:25 am |
|
|
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
|
|
Posted: Mon Jul 09, 2012 6:32 am |
|
|
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
|
|
Posted: Mon Jul 09, 2012 1:33 pm |
|
|
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 |
|
|
|
|
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
|