Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Problem with PIC-Tachometer

Status
Not open for further replies.

edge28

Newbie level 3
Joined
Oct 24, 2011
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,312
Hello,

sorry fo my English. I have the following problem.

I made a induction tachometer with a PIC16F876A (28 pin) and I view the RPM on LCD display. I am attaching the electronic scheme of my circuit. In input to optoisolator 4n35 arrive the pulses induced in a wire wrapped around the spark plug. The maximum induced voltage is about 4V.
The PIC firmware works in this mode:

For each pulse generates an interrupt which goes to increment a counter. After a second multiply the pulses counted for 60 and get the RPMs. In this way the reading is inaccurate because the displayed values ​​fluctuate a lot and reading is not stable. To resolve this problem, I made ​​an average of 4 readings and then I displayed the result on the LCD. In this way the reading is more stable but I always get variations between readings and the next. Basically I would not change between reading and the next if the variation is within + / - 50 rpm.

Example :

- first reading: 1520 RPM
- second reading: 1568 RPM

in this case the value displayed on the LCD must remain 1520 and not 1568 because the variation è < +/- 50 RPM. How can I do to stabilize the reading in C language ?



I use like reference tachometer the "TINY TACH" induction tachometer which is very stable :-(

The firmware of my PIC is the sequent:

Code:
#define COST 120
#define DIFF 120



sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

char txt1[]="Tach/hr";
char txt2[]="wait";
char txt3[]="RPM";
char txt4[]="TACH";

int cnt=0;
int display=0;
int ricevuto=0;
int confermato=0;
int ciclo=0;
int risultato=0;
char minuti=0;
char secondi=0;
char ore=0;
char ore2=0;
char pp[6];
char pp3[3];
char pp4[2];
char pp5[2];
int k=0;
int cont=0;

unsigned int rpm_avg[4];    // last 4 RPM values, used to average them
unsigned int rpm_diff[2];
int differenza;
unsigned char diff;
unsigned char avcount;      // used to average 4 RPM values
unsigned long accum;        // these used for 32bit math to calc RPM
unsigned long math;

void interrupt()
{
 if(INTCON.INTF)
 {
 INTCON.INTF=0;
 ricevuto=1;
 }
  if(INTCON.TMR0IF)
 {
 //TMR0=22;
 TMR0=100;
 INTCON.TMR0IF=0;
 confermato=1;
 }
 
}


void main()

{
  PORTB = 0;               // Initialize PORTB
  PORTC = 0;
  TRISB = 1;               // PORTB is output
  
  math = 2;     // add half the divisor to stop rounding errors
  //Settaggio interrupt
  //OPTION_REG.INTEDG=1;

  OPTION_REG=0xC6;
  secondi=0;
     // setup vars
  avcount = 0;
  diff=0;
  
  rpm_diff[0]=0;
  rpm_diff[1]=0;

  rpm_avg[0] = 0;   // clear average before start
  rpm_avg[1] = 0;
  rpm_avg[2] = 0;
  rpm_avg[3] = 0;
 
  Lcd_Init();                        // Initialize LCD

  Lcd_Cmd(_LCD_CLEAR);                // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);           // Cursor off
  Lcd_Out(1,1,txt1);           // Write text in first row
  Lcd_Out(2,1,txt2);           // Write text in second row
  Delay_ms(500);

  for(k=0; k<3; k++)
  {
   Lcd_Out(2,k+5,".");
   Delay_ms(1000);
  }
   Delay_ms(1000);
   Lcd_Cmd(_LCD_CLEAR);
   Delay_ms(100);


   Lcd_Cmd(_LCD_CLEAR);
   Lcd_Cmd(_LCD_CLEAR);


  ripeti:

Lcd_Out(2,1,txt4);        
   
  INTCON=0xB0;
//TMR0=22;
TMR0=100;


/*----------------------------------------------------------------------------*/
  do{

  }while(ricevuto==0);

  if(ricevuto==1)
 {

   Lcd_Cmd(_LCD_CLEAR);
   Lcd_Cmd(_LCD_CLEAR);
   Lcd_Out(1,1,txt3);

 }

  while(cnt<=6)
  {

  if(ricevuto==1)

  {
  INTCON.GIE=0;
  INTCON.INTE=0;
  cont++;
  ricevuto=0;
  INTCON.GIE=1;
  INTCON.INTE=1;
  }
  if(confermato==1)
  {
  INTCON.GIE=0;
  INTCON.INTE=0;
  confermato=0;
  risultato=cont;
  //TMR0=22;
  TMR0=100;
  cont=0;
  secondi++;
  INTCON.GIE=1;
  INTCON.INTE=1;

    rpm_avg[avcount] = (risultato*60);   // include the new RPM value
    avcount++;
    display++;
    if(display>=5) display=5;
    if(avcount >= 4) avcount = 0;

    // now add the 4 last RPM values
    math = (rpm_avg[0] + rpm_avg[1] + rpm_avg[2] + rpm_avg[3]);
    math += 2;    // add half the divisor to stop rounding errors

    // divide the total by 4 to give an average
    math = (math / 4);
    //risultato = math;
    if(display<5)
    {
      WordToStr(math,pp);
      Lcd_Out(2,1,pp);
    }
        if(display>=5)
    {
      WordToStr(math,pp);
      Lcd_Out(2,1,pp);
    }

 }
     
  if(math<=2)
  {
  cnt++;
  ricevuto=0;
  }
  }

  if(cnt>6)
{
cnt=0;
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CLEAR);
goto ripeti;
}

}


I tried to write code like:

Code:
rpm_diff[diff]=math;
diff++;
if(diff>=1) diff=0;
difference=(rpm_diff[0]-rpm_diff[1]);
if((difference<=50) &&(difference>=-50))
{
asm nop;
}

else ..... displays the result on LCD

but does not work. Continue reading to vary even if the difference between the current and the next is between +/- 50 rpm.
 

Attachments

  • sch.jpg
    sch.jpg
    46.6 KB · Views: 64

I haven't got the same compiler so I can't simulate but the basic method I use is like this:

Start with OldRpm = 0 and accept it may not show the very first reading correctly, store the measured RPM in NewRpm.

1. show the first RPM reading,
2. calculate abs(OldRpm - NewRPM)
3. if the result is > 50 display it, otherwise skip the display routine,
4. OldRPM = NewRpm.
5. loop back to step 2

So the display doesn't actually get updated at all unless the value has changed enough. You could also try a different method which is to sample the RPM over a longer interval so minor changes are made less significant in the total.

Brian.
 
  • Like
Reactions: edge28

    edge28

    Points: 2
    Helpful Answer Positive Rating
Thanks for the answer!!! I think I understand where mistake.

Today I try and see how it behaves.

Of course, other suggestions for this problem are welcome.

Edge
 

Little TIP
Try to don't use a dividing on 8 bit core CPUs. It takes very many cycles.
Dividing by 4 means (value>>2)
by 2 (value>>1) and e.t.c.
Anyway, I can't understand why your code is so long. You need to start the timer and start interrupt on change procedure. By INT increase some value, by timer get this value and if it necessary, set some flag. In main routine checking this flag and if it set, show the value on LCD. Very simple.
 
  • Like
Reactions: edge28

    edge28

    Points: 2
    Helpful Answer Positive Rating
Try to don't use a dividing on 8 bit core CPUs. It takes very many cycles.

Ah, ok. Only by dividing by 4 to get a more accurate reading because the variation between readings and the next is more stable.
In fact the values ​​of rpm are not instantaneously update it (they have a delay of about 3 seconds).

Anyway, I can't understand why your code is so long. You need to start the timer and start interrupt on change procedure. By INT increase some value, by timer get this value and if it necessary, set some flag. In main routine checking this flag and if it set, show the value on LCD. Very simple.

Yes, in fact, the firmware behaves in this mode.

The program seems longer because the "tachometer" is just a sampling of the entire program where you calculate the hours and minutes and stores the result in an EEPROM. When the engine is stopped to be displayed on the display the minutes / hours. When the engine starts after 5 seconds the RPMs must appear on the display.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top