/**********************************************************************
dtachc.c
This is a tachometer for a diesel engine in which there is no tach pulse
available because there is no spark ignition system. Instead, a pulse
is taken off the alternator. The number of poles in the alternator
and the crank-to-alternator pulley ratio must be factored into the code.
+5
|
14
----------
| |-12-- LCD D4
| |-3--- LCD D5
| |-2--- LCD D6
ALT IN ----9-| |-1--- LCD D7
| 16F628 |-18-- LCD EN
| |-17-- LCD RS
| |
| |
4MHz XTAL-15-| |
XTAL-16-| |
----------
5
|
Gnd
***************************************************************************/
#include < 16F628.h >
#include < jonsinc.h >
#fuses XT, NOPROTECT, PUT, NOWDT, BROWNOUT, MCLR, NOLVP
// LCD STUFF
#define LCD_D4 PIN_B6
#define LCD_D5 PIN_A4
#define LCD_D6 PIN_A3
#define LCD_D7 PIN_A2
#define LCD_EN PIN_A1
#define LCD_RS PIN_A0
#define FIRST_LINE 0x00
#define SECOND_LINE 0x40
#define CLEAR_DISP 0x01
#define CURS_ON 0x0e
#define CURS_OFF 0x0c
#define START_TACH 0
#define RUN_TACH 1
#define DONE_TACH 2
// Pulley factor is alternator pulley diameter divided by crank pulley diameter
#define PULLEY_FACTOR 1.0
// Obtain from manufacturers data sheet (6, 8, 10, etc.)
#define ALTERNATOR_POLES 10
#use delay ( clock=4000000 )
#use standard_io ( A )
#use standard_io ( B )
// proto statements
void LCD_Init ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar ( unsigned int cX );
void LCD_PutCmd ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData ( unsigned int cX );
// Global variables
static char cTimerCount, cOneSecondFlag, cState;
static long iCount;
//************************************************************************
// INTERRUPT ROUTINES
#int_ccp1
void CCP1Interrupt ( void )
{
if ( cState == RUN_TACH ) // second edge
{
iCount = CCP_1; // get capture value
cState = DONE_TACH; // prevent further processing during this interrupt
}
if ( cState == START_TACH ) // first edge
{
set_timer1 ( 0 ); // restart timer on this edge
cState = RUN_TACH;
}
}
//*****************************************************************
// MAIN CODE
void main ( void )
{
char cCnt;
float fRpm;
int32 int32Count;
// SETUP TIMER 1
setup_timer_1 ( T1_INTERNAL );
// SETUP CCP1
setup_ccp1 ( CCP_CAPTURE_RE ); // capture every rising edge
// INITIAL MESSAGE
delay_ms ( 200 ); // wait enough time after Vdd rise
LCD_Init();
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( FIRST_LINE + 3 );
printf ( LCD_PutChar, "TACHOMETER" );
// ENABLE INTERRUPTS
enable_interrupts ( INT_CCP1 ); // CCP1 interrupt
enable_interrupts ( GLOBAL ); // enable all interrupts
cState = DONE_TACH;
while ( TRUE )
{
int32Count = 0;
for ( cCnt = 0; cCnt < 20; cCnt++ ) // accumulate 20 readings
{
cState = START_TACH; // allow interrupt to start
while ( cState != DONE_TACH ) // wait for timing to complete
{
if ( get_timer1() > 60000 ) // timeout counter
{
iCount = 0; // zero everything out
int32Count = 0;
break; // don't wait any longer
}
}
int32Count += iCount; // otherwise accumulate
}
int32Count /= 20; // get average of those 20 readings
fRpm = 1 / ( float ) int32Count; // period in uS
fRpm *= 1000000; // period in seconds
fRpm *= 60; // period in minutes
fRpm /= ALTERNATOR_POLES; // adjust for number of poles in alternator
fRpm *= PULLEY_FACTOR; // adjust for pulley ratio
LCD_SetPosition ( SECOND_LINE + 4 );
printf ( LCD_PutChar, "%05.0f RPM ", fRpm );
}
}
//*****************************************************************************
void LCD_Init ( void )
{
LCD_SetData ( 0x00 );
output_low ( LCD_RS );
LCD_SetData ( 0x03 ); // init with specific nibbles to start 4-bit mode
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); // set 4-bit interface
LCD_PulseEnable(); // send dual nibbles hereafter, MSN first
LCD_PutCmd ( 0x2C ); // function set (all lines, 5x7 characters)
LCD_PutCmd ( 0x0C ); // display ON, cursor off, no blink
LCD_PutCmd ( 0x01 ); // clear display
LCD_PutCmd ( 0x06 ); // entry mode set, increment
}
void LCD_SetPosition ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}
void LCD_PutChar ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
output_high ( LCD_RS );
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
output_low ( LCD_RS );
}
void LCD_PutCmd ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
}
void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 10 );
output_low ( LCD_EN );
delay_ms ( 5 );
}
void LCD_SetData ( unsigned int cX )
{
output_bit ( LCD_D4, cX & 0x01 );
output_bit ( LCD_D5, cX & 0x02 );
output_bit ( LCD_D6, cX & 0x04 );
output_bit ( LCD_D7, cX & 0x08 );
}