/********************************************************************** 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 ); }