Menu

Measuring frequency and RPM

Help
2009-02-06
2013-05-30
  • Nobody/Anonymous

    What would be the best method to capture the RPM for example. intially i wanted to use the Timer function. I read a post by kent_twt4 that said the Timer function can be as must as 20% out? ideally i would like it to be as accurate as possible?

    Would it be possible to count instructions in the loop and deduce the time delay from that?

    Also i have been reading about the timer function in the GCbasic help file and im unsure about a couple of things?

    - what are the prescalers for? (if you could give me an example that would be great)

    - what is the purpose of these 2 lines of code in the given example , see bottom of post

    EPWrite(DataCount, TMR1H)
    EPWrite(DataCount + 1, TMR1L)

    specifically TMR1H & TMR1L bit ?

    Thanks in advance

    Dan

    Taken from Help file:

      'This example will measure that time that a switch stays on for
        #chip 16F819, 20
        #define Switch PORTA.0   

        dir Switch In
        DataCount = 0
        InitTimer Osc, PS1_1/8
       
        Start:
            ClearTimer 1
            Wait until Switch On
            StartTimer 1
            Wait until Switch Off
             StopTimer 1
       
            EPWrite(DataCount, TMR1H)
             EPWrite(DataCount + 1, TMR1L)

        Goto Start

     
    • Nobody/Anonymous

      Hello... i think you should look for information about the timers and how they work. Have a look to datasheets and microchip webpages.

      There are several timers available, depending on the pic you are using...

      You can use some timers as counter, this way you dont need the polling routine... just attach the signal to the required pin and timer count will increase every rising or falling edge.

      You can use another timer as "base time".

      But you need to know how timers work and what are the registers involved ( tmr0,tmr1h,tmr1l.....) and how to use prescaler and postscaler.

       
    • Nobody/Anonymous

      rpm - you could use the optical sensor in a ball mouse??

       
    • Nobody/Anonymous

      I've done something similar recently...a digital tach in fact.

      To my way of thinking a timer is just a counter. If the frequency is fixed, the count indicates time elapsed.

      The inverse is perfect for rpm. Define a time and the counts indicates frequency. Just format the signal for 0-5 volts, and input it to a timer pin. Ask the timer to start, then enter a wait command for the period you want to count for. turn the counter off and read the value like this (example for timer 0):

      countvariable = TMR0

      This will load the contents of the counter into countvariable.

      As far as scaling goes, my chip will count up to 255 max on timer 0 (8 bit), and up to 65k+ on timer 1 (16 bit). Therfore I picked a resonable maximum rpm and equated the sampling time to that max rpm.

      For example, timer 0 and 10krpm max for a v8, with 1 spark every two rpm (HEI gm distributor tach output) will yeild a frequency of 10k/60(min to sec)*4(8cylinders, 4 transitions per revolution) = 666hz. If you sample for 1/3 of a second that yeilds 222 counts. This is pretty good for the top end, but what is the resolution like? 1 count yeilds 45 rpm resoution...not bad.

      I've found this technique to be very good. Also, throw some digital filtering in there to get rid of some of the variance. Ad 5 counts together and divide by 5. Have it rolling so that it continues to update each .33 seconds.

      The prescalars are for faster signals. If you have a 100khz signal you will need to divide the frequency down...this is what the prescalars do. If you look at the basic setup, timer 2 can have a prescalar of 1:1...I suggest you use this. If your frequency is faster then you can use the 16 bit as well for better resolution.

      EPwrite is eprom write if I'm not mistaken, no need to use this. TMR1h is the high 8 bits of timer1's count, TMR1l is the low 8 bits. If you use timer 1, then you have to deal with both if you go over 255 counts.

      If you use word variables pay particular attention to the online help notes in defining them. I didn't, and couldn't figure out why my words acted like bytes....ha ha they end up being bytes if not defined properly.

      Chay

       
    • Nobody/Anonymous

      thanks very much i will have a play and see how i get on.

      Dan

       
    • Nobody/Anonymous

      There is one other technique for RPM...it is to deterine the interval between positive transitions of the signal. This would be a much faster way to do it, because you have 4 (V8) samples per rev. I haven't thought too much about it 'cause my brain is too slow to process much more than .1s anyway!

      But, if it's for an automated system (Fuel map, for example) it would be way faster and therefore better.

      Chay

       
    • Nobody/Anonymous

      I wrote this in my spare time :).

      Do a Cntl A/Cntl C and paste it into a text file so it's readable.

      I don't know if it works, but I'll test it one day soon. It should be a way beter way to go.

      ;This is a new stab at an old problem.

      ; Try to get a good rpm read on the boat.

      ;The technique will be to try to use the time between pulses to determine the rpm. This shoud yeild more
      ;stable and way faster results

      #chip 16f74, 20; chip is obvious, 20 is 20mhz crystal oscillator

      #include    <lowlevel\pwm.h>    ; Required for pwm operation
      #include    <lowlevel\timer.h>    ;required for timer/counter operation

      Dim Count as word            ; Storage for the timer period
      Dim Math as worD            ; Storage for math operations
      dIM maTH2 AS WORD            ; Storage for math operations (mORE STUFF)

      #byte        Success            ;true if timer has done it's job

      #byte        PWMCOUNT        ; Store the duty cycle for the pwm output

      #byte         count1            ;
      #byte         count2            ;
      #byte         count3            ;
      #byte         count4            ;
      #byte         count5            ;

      dir porta.1 in            ;Setup this pin as an input. This will recieve the tach signal

      dir portc.1 out            ; Setup the output pwm pins, physical pin 16, pwm output 2
      dir portc.2 out            ; Setup the other pwm for checking duty cycle on, physical pin 17, pwm out1

      dir porta.0 out            ; setup this pin as an output. It is a test pin to see if chip is running
         
      porta.0 = on            ; Turn pin on as a check point

      pwm1 = 0        ;Initalize to 0 output
      pwm2 = 0        ;

      COUNT1 = 0
      COUNT2 = 0
      COUNT3 = 0
      COUNT4 = 0
      COUNT5 = 0        ;iNITIALIZE TO 0

      InitTimer1 (OSC, PS1_1/4)        ; Bring timer 1 online, use internal oscillator
                          ; With a 20 MHZ oscillator, and a minimum rpm of 500, the prescalar has to
                          ; be pretty big to slow things down enough to get it into a word size
                          ;variable.
                          ;How this works is, the instruction cycle takes 4 clock cycles, which at 20
                          ;mhz = 200ns. The slowest rpm I want to display is 500rpm. So, with 4 sparks
                          ;per rev (V8,HEI) this yeilds 33.3 hz, or 30ms between pulses
                          ;If this takes all 65536 counts in the 16 bit register then each count has to
                          ;take at least 457ns. So, set the prescalar to 1:4 (800ns) and 500 rpm yeilds
                          ;37500 counts, 1000rpm = 18750, etc. So the formula will be:
                          ;rpm = 18750000/counts = rpm. Wow. But, in real life, this will be output by
                          ;the pwm. I will pick a range of 500-6000 rpm, where 6000 = 5 volts output (256)
                          ;so, 500 = 21.3 (Out of 255) output to the pwm.So, if we divide the counts by 100, and
                          ;use the output to the pwm, the formula looks like this:

                          ;7987/(timer counts/100)=pwm counts
                          ;Simple eh?

      ClearTimer (1)                ; Set value to 0, it's ready to go

      STARTMAIN:

      Sub GETTIME                ;Get the first timing interval, results will be contained in TMR1H, and TMR1L

      COUNT = TMR1H                ;pULL THE VALUE OF TMR1H INTO COUNT

      ROTATE COUNT LEFT SIMPLE        ; Shift the data in count to the left 1 place (towards the msb)
      ROTATE COUNT LEFT SIMPLE        ;
      ROTATE COUNT LEFT SIMPLE        ; This moves the lower bytw of data into the high byte's position
      ROTATE COUNT LEFT SIMPLE        ; This is required for a 16 bit number to be made up from
      ROTATE COUNT LEFT SIMPLE        ; two 8 bit numbers
      ROTATE COUNT LEFT SIMPLE        ;
      ROTATE COUNT LEFT SIMPLE        ;
      ROTATE COUNT LEFT SIMPLE        ;
      ROTATE COUNT LEFT SIMPLE        ; It is now shifted 8 places, with the low places being made 0's

      count = count + tmr1l            ; Add in the low byte of data and the counts are complete

      count = count/100            ; Reduce count as per above

      math = 7987/count            ; Math now contains the pwm output duty cycle

      cOUNT5 = COUNT4
      COUNT4 = COUNT3
      COUNT3 = COUNT2
      COUNT2 = COUNT1
      COUNT1 = MATH                ;rolling values for average

      MATH2 = COUNT1

      MATH2 = MATH2 + COUNT2

      MATH2 = MATH2 + COUNT3

      MATH2 = MATH2 + COUNT4

      MATH2 = MATH2 + COUNT5

      MATH2 = MATH2/5

      PWMCOUNT = math2            ; dIGITALLY aVERAGED READING

         
              pwmon; turn on the pwm function (not capture or compare)

              hpwm 1,10,PWMCOUNT        ; set pwm 1 to 10khz
              hpwm 2,10,PWMCOUNT        ; set pwm 2 to 10khz

      GOTO STARTMAIN

      SUB GETTIME:            ;

      Success = 0            ; Set the 'done' latch to 0 to initialize

      WaitHigh:            ; Label to return to if signal is not high

      If porta.1 = on    then        ; The signal is true

             

          StartTimer (1)            ; Start the timer counting

      Stillon:

          If porta.1 = off then            ; The signal has gone false, wait for it to go true again
             
              If porta.1 = on then        ; The signal has gone true again, stop the timer
                 
                  StopTimer(1)        ; Stop the timer
                  success = 1        ; Timing complete       
                  goto done
              end if
             
          endif
          goto Stillon                ;Signal is still true, wait for it to be false

      end if

      Done:

      If success = 0 then goto WaitHigh        ; Timer is not done

      end sub

              pwm1 = count        ;Set up pwm's to varry output
              pwm2 = count
                 
         
              pwmon; turn on the pwm function (not capture or compare)

              hpwm 1,10,PWM1        ; set pwm 1 to 10khz
              hpwm 2,10,PWM2        ; set pwm 2 to 10khz

             

         

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.