Tachometer
Tachometer
Hello, can anyone help me? I want to make a tachometer myself with 16F877 but I don't have big knowledges about the uC. Can you post some code example please.
Thank you!
Thank you!
Re: Tachometer
You will need a pulse counter or a frequency meter. We are preparing the examples for both for the next release. If someone else has a handy example, please do post it.wwwhelp wrote:Hello, can anyone help me? I want to make a tachometer myself with 16F877 but I don't have big knowledges about the uC. Can you post some code example please.
Tachometer Code for PIC18F452
Here is tachometer code that measures the period between pulses (assuming one pulse per revolution - but can be easily modified for a different number). It uses the CCP modules to measure the period and then converts it to RPM and displays the results. The LCD initialization needs to be changed to match your set up. It has been adapated from my Electronic Fuel Injection monitoring system.
It uses Unit Tach_Acq to actually acquire the pulse train. Also uses the PIC 18F452 default configuration of MP3 compiler. Shouldn't be too hard to convert to your chip if it has the CCP module. Could be made simpler - but this is what I had handy. Hope it helps.
It uses Unit Tach_Acq to actually acquire the pulse train. Also uses the PIC 18F452 default configuration of MP3 compiler. Shouldn't be too hard to convert to your chip if it has the CCP module. Could be made simpler - but this is what I had handy. Hope it helps.
Code: Select all
program Tach;
//Program measures the rotation period based on a pulse input and calculates RPM
//NOTE: Interrupt Procedure is NOT used as the CCP2 interrupt flag is set regardless
//of whether interrupt is enabled. Since the flag - CCP2IF is check in the CCP2_Call loop, there is no
//need for the MP3 Interrupt Procedure.
uses Tach_Acq; //Determines rotation period time based on Timer TMR1
//Note this works for an 18F452 with a 4 Mhz crystal
//MP3 Default Configuration for 19F452 chip was used for chip configuration
////Note: 18F452 Chip is configured so that CCP2 is on pin RC1
// rather than RB3 __CONFIG _CONFIG3H_OFF
//Pulse train must be +5V (Pluse logic High) and 0 volts (Pulse Logic Low)
Procedure Initialize_LCD; //This must be tailored for your particular LCD set up
begin
LCD8_Config(PORTC,PORTD,6,4,5,7,6,5,4,3,2,1,0); //RS,EN,RW Data Use in Real Fuel board Initialze LCD through PORTs
LCD8_Cmd(Lcd_Clear);//Clear LCD display
LCD8_Cmd(Lcd_Cursor_Off);//Turn visible cursor off
end;
Procedure Initialize_Ports;
begin
TRISD:= $00; //Set all PORTD for output
PORTD:= $00;
TRISC:= $02; // 0000 0010 Set bit RC1 for CCP2 input, RC6,4,5(Rs/En/RW) LCD control Output
end;
Procedure Initialize_Timer_CCP;
begin
INTCON := $00; //Disable all Interrupts for initialization of other registers
T3CON := $00; //0000 0000 was $C0 Sets Timer1 as source clock for CCP1 and CCP2 leaves timer3 off
CCP2CON:= $07; //Initially Set CCP2 for 16th Rising Edge Capture
T1CON := $01; //set for 8 bit time read, prescaler of 1 and turn timer 1 on
TMR1L := $00; //zero timer registers
TMR1H := $00;
end;
Procedure Display_RPM(RPM:word);
var Txt: array[6] of char;
Txtstr: array[8] of char;
begin
TxtStr := 'RPM = ';
LCD8_OUT(1,1,Txtstr);
Wordtostr(RPM,Txt);
LCD8_OUT(1,9,Txt);
end;
Procedure CCP2_Call; //Calls CCP2_RPM to get pulse interval of rotation period then calculates and displays RPM
Var
Rot_P_L :byte; //Bytes to hold rotation period time from CCP2_RPM
Rot_P_H :byte;
R_Period :Word; //Holds rotation period time calculated
RPM :word; //Holds RPM value calculated
Begin
Rot_P_L := 0;
Rot_P_H := 0;
If testbit(PIR2,CCP2IF) = 1 then //If CCP2 flag is set then pulse has triggered CCP2 module
begin
ccp2_RPM( Rot_P_H,Rot_P_L); //Calls to Data_Acq unit for pulse measurements
if (CCP2CON = $07) AND (CCP2IF = 0) then // update viariable values after finished with entire time sequence
begin
R_Period := 00;
R_period := Word(Rot_P_H shl 8) OR Rot_P_L; //combined hi and low byte of rotation period into word
RPM := 60000000 div R_Period ; //Calculate RPM (period is in usec this turns it into revs/min) // 6.25 lbs auto gasoline/gallon US 100 LL Aviation fuel maybe 5.97 lbs
Display_RPM(RPM); //Displays Operational Data
end; //If (CCP2CON =7 .....
ClearBit(PIR2,CCP2IF);//Clear ccp2 Flag for next cycle
end;
end;
begin //Main part of program
Initialize_Ports;
Initialize_LCD;
Initialize_Timer_CCP;
Repeat //Loop forever calling CCP2_Call to determine rotation period and calculate RPM
CCP2_call;
until true = false;
end.
unit Tach_Acq;
implementation
Procedure ccp2_RPM(Var Rot_P_H,Rot_P_L:byte);//CCP2_Fuel;
//This procedure is to measure the period of a pulse train to pin RC2.
// The rotation period of the engine is determined by the duration of pulse Low Logic + Pulse High Logic.
// Note: The procedure is set up to interrupt on the 16th rising edge of a pulse CCPXCON := 07
//**************************** Start of timing sequence *********************************************************
// <----------------------------- 16th RE -----------_->
// '''''''''''| |'''''''''''| |''''''''''' '''''''| |'''''''
// |.......| |.......| |.......|
// 16thRE FE RE 16thRE Repeating
// start Time Stop Time
//****************************************************************************************************************
//*********************************************************************
//Note: 18F452 Chip is configured so that CCP2 is on pin RC1 rather than RB3 __CONFIG _CONFIG3H_OFF
//*********************************************************************
Var
Pulse_HSL :byte; //Hold Rise Edge time for start of timing sequence
Pulse_HSH :byte;
Pulse_LSL :byte; //Hold Falling Edge time for start of Injector Pulse timing
Pulse_LSH :byte;
Pulse_EL :byte; //Rising Edge End of Time Sequence = Pulse High + Pulse Low time
Pulse_EH :byte;
TPulse_EL :byte; //Rising Edge End of Time Sequence = Pulse High + Pulse Low time
TPulse_EH :byte; //Save time for calculations;
begin //Start measurement with pulse going low (falling), end measurement with pulse going high (rising)
ClearBit(INTCON,GIE); //clear GIE to prevent further interupts while handling this one
if TestBit(PIR2,CCP2IF) = 1 then //Is it CCP2 Interrupt?
begin //Yes, it is CCP2 Interrup. This section determines which module processes the request, Start_Time, Fall_Edge or Rise_Edge
case CCP2CON of
$04: //if falling edge of pulse then this is the beginning of the measurement of the Pulse Low duratio
begin
Pulse_LSL := CCPR2L; //Get start time of low Logic zero
Pulse_LSH := CCPR2H;
SetBit(CCP2CON,CCP2M0); //ReSet for Rising Edge Capture on next entry into ISR
CCP2CON := $05;
ClearBit(PIR2,CCP2IF); //Clear in case of false interrupt when changin mode
end;
$05: //If 1st Rising edge after Fallin edge then timing sequence is complete - calculate time internvals
//Find Rotation Period - Rot_PX
//Find Injector Pulse time - PW_X
begin
Pulse_EL := CCPR2L; //Get time of second Rising Edge
Pulse_EH := CCPR2H;
TPulse_EL:=Pulse_EL; //Hold time value
TPulse_EH:=Pulse_EH;
Rot_P_L := Pulse_EL - Pulse_HSL; //Calculate Rotation Time = Time Pulse HI + Time Pulse Lo
If TestBit(STATUS,C) = 0 then
Pulse_EH := Pulse_EH - 1;
Rot_P_H := Pulse_EH - Pulse_HSH;
CCP2CON := $07; //was $07 Set for 16th Rising edge Interrupt
ClearBit(PIR2,CCP2IF); //Clear possible supurious Interrupt caused by changing CCP interrupt mode
end;
//This completes timing sequence - Leave and wait for next 16th Rising Edge of pulse train
$07: //******* Captures Start time of pulse sequence (Rising edge *****************************************************=
begin
Pulse_HSL := CCPR2L; //Get captured pulse high start time low byte *******Change back to CCPR1L *****
Pulse_HSH := CCPR2H; //Get captured time high byte
CCP2CON := $04; //These two register configuration operations accomplish the same purpose
ClearBit(PIR2,CCP2IF); //Reset to preclude False Interrupt
end;
end;//case
end; // end of IF Statement CCP2_Inj
end;
end.
Rotary_Ed
Matthews, NC USA
Rv-6A N494BW Rotary Powered
Matthews, NC USA
Rv-6A N494BW Rotary Powered
Re: Tachometer Code for PIC18F452
Thanks Ed, I will steal this code of yours for an example and put it in the next release.
(I will write the reply to that email of yours - I am just away from my PC too often.)
(I will write the reply to that email of yours - I am just away from my PC too often.)
-
- Posts: 300
- Joined: 18 Aug 2004 11:55
- Location: Lwr Sackville, Nova Scotia, Canada
Works
Great! work Ed. Thanks! for sharing. I tried it and everything compiled fine (second try). Charlie, did you make a seperate unit for Tach_Acq? Also, when you save that unit ensure it got saved in the right location with the main project. The first time I tried it , my unit got saved with some example that I ws working on a few days ago. Once I noticed that glitch I just saved it to the current project and it worked GREAT!!!!!!!!!!!!!!!!!!!
Tachometer Code for PIC18F452
Hi Charlie (Neighbor), As Bob points out (but I failed to), the Tach_Acq portion needs to be compiled as a separate Unit. Although, with a bit of work, it could be combined into one segment of code in the main program.
I recompiled it this morning and it worked on my machine. I have a pulse generator that I use to simulate the tach pulse signal and it responds with the rpm value being displayed. I might mention that if you do not have a signal hooked up to your chip, the LCD will not have anything to display. I probably should have coded in a text message line such as "MP Tachometer" so that you would know it had programmed the chip properly - but just didn't think of it at the time.
Also, this is written for a 18F452 chip - so different chips might cause some compiler errors.
Thanks Bob, glad to share it, I've enjoyed learning to program the microchip using MikroPascal.
I recompiled it this morning and it worked on my machine. I have a pulse generator that I use to simulate the tach pulse signal and it responds with the rpm value being displayed. I might mention that if you do not have a signal hooked up to your chip, the LCD will not have anything to display. I probably should have coded in a text message line such as "MP Tachometer" so that you would know it had programmed the chip properly - but just didn't think of it at the time.
Also, this is written for a 18F452 chip - so different chips might cause some compiler errors.
Thanks Bob, glad to share it, I've enjoyed learning to program the microchip using MikroPascal.
Rotary_Ed
Matthews, NC USA
Rv-6A N494BW Rotary Powered
Matthews, NC USA
Rv-6A N494BW Rotary Powered
Tach for MP -Zristic
Hi Z,
Yes, feel free to adapt it as an example. As you know my coding can be somewhat unorthdox, so do not hesitate to change it to make it clearer or conform with good programing practices.
I realize you are very busy, so no need to reply to my personal message. Just wanted you to know you had not been forgotten.
Best Regards
Yes, feel free to adapt it as an example. As you know my coding can be somewhat unorthdox, so do not hesitate to change it to make it clearer or conform with good programing practices.
I realize you are very busy, so no need to reply to my personal message. Just wanted you to know you had not been forgotten.
Best Regards
Rotary_Ed
Matthews, NC USA
Rv-6A N494BW Rotary Powered
Matthews, NC USA
Rv-6A N494BW Rotary Powered
Improved Tachometer Code for PIC18F452
I realized that I had a deal of unneeded code and comments from my original program included in the Tach code, so I cleaned it up a bit to make it clearer. I made two functional changes. I changed the CCP2 initialization so that it captures and calculates rotation period based the 4th rising pulse edge(CCP2CON := $06) rather than the 16th (CCP2CON := $07). I also added a Title line to the code which displays on LCD whether or not you have a pulse signal hooked to CCP2 (PORTC.RC1). This should indicate the program has compiled properly. RPM will not be displayed unless you have a pulse signal to CCP2.
As noted before, the code has two sections, a main program section Tach.ppas and a Unit Tech_Acq.ppas.
As noted before, the code has two sections, a main program section Tach.ppas and a Unit Tech_Acq.ppas.
Code: Select all
program Tach;
//Program measures the rotation period based on a pulse input and calculates RPM
//NOTE: Interrupt Procedure is NOT used as the CCP2 interrupt flag is set regardless
//of whether interrupt is enabled. Since the CCP2IF is checked in the Main repeat loop, there is no
//need for the MP3 Interrup Procedure.
uses Tach_Acq; //Determines rotation period time based on Timer TMR1
//Note this works for an 18F452 with a 4 Mhz crystal
//MP3 Default Configuration for 19F452 chip was used for chip configuration
////Note: 18F452 Chip is configured so that CCP2 is on pin RC1
// rather than RB3 __CONFIG _CONFIG3H_OFF
//Pulse train must be +5V (Pluse logic High) and 0 volts (Pulse Logic Low)
Procedure Initialize_LCD; //This must be tailored for your particular LCD set up
begin
LCD8_Config(PORTC,PORTD,6,4,5,7,6,5,4,3,2,1,0); //RS,EN,RW Data Use in Real Fuel board Initialze LCD through PORTs
LCD8_Cmd(Lcd_Clear);//Clear LCD display
LCD8_Cmd(Lcd_Cursor_Off);//Turn visible cursor off
end;
Procedure Initialize_Ports;
begin
TRISD:= $00; //Set all PORTD for output
PORTD:= $00;
TRISC:= $02; // 0000 0010 Set bit RC1 for CCP2 input, RC6,4,5(Rs/En/RW) LCD control Output
//Note: this may need to be changed to match your board wiring
end;
Procedure Initialize_Timer_CCP;
begin
INTCON := $00; //Disable all Interrupts for initialization of other registers
T3CON := $00; //0000 0000 was $C0 Sets Timer1 as source clock for CCP1 and CCP2 leaves timer3 off
CCP2CON:= $06; //set for 4th rising edge, $07 Initially Set CCP2 for 16th Rising Edge Capture
T1CON := $01; //set for 8 bit time read, prescaler of 1 and turn timer 1 on
TMR1L := $00; //zero timer registers
TMR1H := $00;
end;
Procedure Display_Title;
var Txtstr:array[16] of char;
begin
TxtStr := ' MP3 Tach Code'; //Displayed even when Tach pulse train is not ON
LCD8_OUT(1,1,TxtStr);
end;
Procedure Display_RPM(RPM:word);
var Txt: array[6] of char;
Txtstr: array[8] of char;
begin
Txt := ' '; //Intialize Txt
TxtStr := ' RPM = '; //Displayed when Pulse train to CCP2 is active
LCD8_OUT(2,1,Txtstr);
Wordtostr(RPM,Txt);
LCD8_OUT(2,9,Txt);
end;
Procedure CCP2_Call; //Calls CCP2_RPM to get pulse interval of rotation period then calculates and displays RPM
Var
Rot_P_L :byte; //Bytes to hold rotation period time from CCP2_RPM
Rot_P_H :byte;
R_Period :Word; //Holds rotation period time calculated
RPM :word; //Holds RPM value calculated
Begin
Rot_P_L := 0;//Variables for Rotation Period Time
Rot_P_H := 0;
If testbit(PIR2,CCP2IF) = 1 then //If CCP2 flag is set then pulse has triggered CCP2 module
begin
ccp2_RPM( Rot_P_H,Rot_P_L); //Calls to Data_Acq unit for pulse measurements
if (CCP2CON = $06) AND (CCP2IF = 0) then //update viariable values after finished with entire time sequence
begin
R_Period := 00;
R_period := Word(Rot_P_H shl 8) OR Rot_P_L; //combined hi and low byte of rotation period into word
RPM := 60000000 div R_Period ; //Calculate RPM (period is in clock cycles this turns it into revs/min)
//Conversion value valid for a 4 Mhz oscillator frequency ONLY
Display_RPM(RPM); //Displays RPM Data
end; //If (CCP2CON =7 .....
ClearBit(PIR2,CCP2IF);//Clear ccp2 Flag for next cycle
end;
end;
begin //Main part of program
Initialize_Ports;
Initialize_LCD;
Initialize_Timer_CCP;
Display_Title; //Display title of program on LCD
Repeat //Loop forever calling CCP2_Call to determine rotation period and calculate RPM
CCP2_call; //Call for Data and display RPM based on CCP2 module response to a pulse train
until true = false;
end.
//Create a separate UNIT for the following code
unit Tach_Acq;
implementation
Procedure ccp2_RPM(Var Rot_P_H,Rot_P_L:byte);//CCP2_Fuel;
//This procedure is to measure the period of a pulse train to pin RC2.
// The rotation period of the engine is determined by the duration of pulse Low Logic + Pulse High Logic.
// Note: The procedure is set up to interrupt on the 16th rising edge of a pulse CCPXCON := 07
//**************************** Start of timing sequence *********************************************************
// <----------------------- 4th or 16th RE -----------_->
// '''''''''''| |'''''''''''| |''''''''''' '''''''| |'''''''
// |.......| |.......| |.......|
// 16thRE FE RE 16thRE Repeating
// start Time Stop Time
//****************************************************************************************************************
//*********************************************************************
//Note: 18F452 Chip is configured so that CCP2 is on pin RC1 rather than RB3 __CONFIG _CONFIG3H_OFF
//*********************************************************************
//The rising edge CCP2 capture may be set as either CCP2Con := $06 (every 4th rising edge) or
// CCP2Con := $07 (every 16th rising pules). Must also reset value in main pgrom in CCP2 Initialization procedure
//and CCP2_Call Procedure (where If statement signifies end of timeing sequence)
Var
Pulse_HSL :byte; //Hold Rise Edge time for start of timing sequence
Pulse_HSH :byte;
Pulse_EL :byte; //Next Rising Edge for End of Time Sequence
Pulse_EH :byte;
begin //Start measurement with pulse going low (falling), end measurement with pulse going high (rising)
ClearBit(INTCON,GIE); //clear GIE to prevent further interupts while handling this one
if TestBit(PIR2,CCP2IF) = 1 then //Is it CCP2 Interrupt?
begin //Yes, it is CCP2 Interrup.
// The CASE section determines which code section processes the request, Start_Time, Fall_Edge or 2nd Rise_Edge
case CCP2CON of //Note: CCP2CON := $06 (4th Rising edge) could also use $07 (16th rising edge)
$06: //This STARTS TIMING SEQUENCE, get start time of every 4th rising edge - Leave and wait for next falling ($04) Edge of pulse train
//******* Captures Start time of pulse sequence (Rising edge *****************************************************=
begin
Pulse_HSL := CCPR2L; //Get captured pulse high start time low byte *******Change back to CCPR1L *****
Pulse_HSH := CCPR2H; //Get captured time high byte
CCP2CON := $04; //Set to capture next Falling edge
ClearBit(PIR2,CCP2IF); //Reset to preclude False Interrupt
end;
$04: //This detects the falling edge simply to know to reset CCP2 module to intercept next Rising edge ($05)
//This is next falling edge of pulse, so reset for next rising edge($05 - which will end period measurement)
//All this does, on detection of the falling edge, is to reset the CCP2 module for next Rising Edge
begin
CCP2CON := $05; //ReSet for Rising Edge Capture on next entry into this CCP2_RPM Routine
ClearBit(PIR2,CCP2IF); //Clear in case of false interrupt when changin mode
end;
$05: //This ENDS TIMING SEQUENCE
// 2nd Rising edge (1st after Fallin edge) so timing sequence is complete - calculate time internvals
//Find Rotation Period - Rot_P_X
begin
Pulse_EL := CCPR2L; //Get time of second Rising Edge
Pulse_EH := CCPR2H;
Rot_P_L := Pulse_EL - Pulse_HSL; //Calculate Rotation Time = Time Pulse HI + Time Pulse Lo
If TestBit(STATUS,C) = 0 then
Pulse_EH := Pulse_EH - 1;
Rot_P_H := Pulse_EH - Pulse_HSH;
CCP2CON := $06; //Set to start next timing cycle on 4th rising edge was $07 Set for 16th Rising edge Interrupt
ClearBit(PIR2,CCP2IF); //Clear possible supurious Interrupt caused by changing CCP interrupt mode
end;
end;//case
end; // end of IF Statement CCP2_Inj
end;
end.
Rotary_Ed
Matthews, NC USA
Rv-6A N494BW Rotary Powered
Matthews, NC USA
Rv-6A N494BW Rotary Powered
-
- Posts: 300
- Joined: 18 Aug 2004 11:55
- Location: Lwr Sackville, Nova Scotia, Canada
How to Create a new unit
Charlie,
One way to do it:
Open your Tach project. Then select "File" "new" You will see from the tabs at the top of the MP software that you have a new unit. (it may be called unit2 or 3 etc.. From there you can paste in Ed's code for the Tach_Acq unit. Then go to File save as. Save the name as Tach_Acq (change ot from the unit name given when it's created)
You can save it to your project folder so that the compiler knows where it is.
Now you can compile it.
One way to do it:
Open your Tach project. Then select "File" "new" You will see from the tabs at the top of the MP software that you have a new unit. (it may be called unit2 or 3 etc.. From there you can paste in Ed's code for the Tach_Acq unit. Then go to File save as. Save the name as Tach_Acq (change ot from the unit name given when it's created)
You can save it to your project folder so that the compiler knows where it is.
Now you can compile it.
-
- Posts: 300
- Joined: 18 Aug 2004 11:55
- Location: Lwr Sackville, Nova Scotia, Canada
Ensure you included
You have to put "uses Tach_Acq; " (without the quotes ) in the main unit.
===============================================
program Tach;
///begin
//////program Tach;
//Program measures the rotation period based on a pulse input and calculates RPM
//NOTE: Interrupt Procedure is NOT used as the CCP2 interrupt flag is set regardless
//of whether interrupt is enabled. Since the flag - CCP2IF is check in the CCP2_Call loop, there is no
//need for the MP3 Interrupt Procedure.
uses Tach_Acq; //// //Determines rotation period time based on Timer TMR1
//N
===============================================
program Tach;
///begin
//////program Tach;
//Program measures the rotation period based on a pulse input and calculates RPM
//NOTE: Interrupt Procedure is NOT used as the CCP2 interrupt flag is set regardless
//of whether interrupt is enabled. Since the flag - CCP2IF is check in the CCP2_Call loop, there is no
//need for the MP3 Interrupt Procedure.
uses Tach_Acq; //// //Determines rotation period time based on Timer TMR1
//N