1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

RPM Counter (Project Started PIC16F877A)

Discussion in 'Microcontrollers' started by Ayne, Mar 31, 2007.

  1. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    Microcontroller = PIC16F877A
    Compiler = MikroBasic
    Output on PC through SerialPort (cuz i have not LCD)
    Crystal Frequency = 20MHz
    Instruction Cycle Time = 200 nano Seconds

    For lower Speed, I will do: Measuring the Period of a
    Square Wave

    For Higher Speed, I will do: Measuring the Period of a
    Square Wave with Averaging

    First About Hardware:-I am using a comparator LM393.
    [​IMG]
    As light strike on PhotoDiode, comparator's output goes LOW to HIGH. We will count time periode b/w two Egdes and measure RPM according to it.


    Second: About Method of Measuring RPM.
    PIC will be in Capture Mode.
    It will capture Time b/w two edges and convert this time into RPM.

    I am using TIMER1 with 1:8 Prescale value.
    Instruction Cycle Time = 200 nano Seconds.
    TIMER1 value = 1 means 1.6 microSeconds has been elapsed because of 1:8 PreScaler. Am i right!!!
    Now some math:
    x is the time periode "T". x is the time b/w the two Edges and it's value in 1.6 microSeconds
    [​IMG]

    Now Program
    Code (text):
    program RPM_Counter

    ' variables declaration
    Dim i, j, UART_Byte, Over_Flow, Averaging As Byte
    Dim Digit as Byte[5]
    Dim T As Longint[2]
    Dim Capture As word absolute $15
    Dim RPM, Period As Longint

    'sub procedure procedure_name ' procedures declaration
    sub procedure interrupt

     if TestBit(PIR1,CCP1IF) = 1 then     'Capture mode Interrupt Flag
      IF i > 1 Then
       i = 0
      End if
     
      T[i] = ( (Over_Flow *  65535) +  Capture )
       
      Inc(i)
      PIR1.CCP1IF = 0
     end if

     if TestBit(PIR1,TMR1IF) = 1 then     'TMR1 Interrupt Flag
      Inc(Over_Flow)
      PIR1.TMR1IF = 0
     end if
     
    end sub

    Sub procedure Delay_313
     Delay_ms(313)
    End Sub
    'end sub


    'sub function function_name ' functions declaration

    'end sub
    main:                       ' main program body
     Delay_313                  'For Stability in Supply
     TRISC   = 255              ' PORTC all Inputs
     PORTC   = 0                ' PORTC = 0
     T1CON   = %00110000        'TIMER1 CONTROL REGISTER
     CCP1CON = %00000101
     INTCON.GIE  = 1
     INTCON.PEIE = 1
     Averaging   = 0
     USART_init(19200) ' initialize USART module
     
    Reset_All:
     PIE1.CCP1IE  = 0           'CCP1 Interrupt Enable bit
     T1CON.TMR1ON = 0           'Timer1 On bit
     TMR1H        = 0
     TMR1L        = 0
     Over_Flow    = 0
     
    ReStart:
     T1CON.TMR1ON = 1           'Timer1 On bit
     PIE1.CCP1IE  = 1           'CCP1 Interrupt Enable bit
     Delay_313                  'Aquire The values of T0 and T2

    Convert_RPM:
     Period = T[1] - T[0]       'Subtract saved captured time (T0) from
                                'captured time (T1) and store
     
     IF Averaging = 1 Then      'if CCP1CON = every 16 edge the divide by 16
        Period = Period / 16
     End IF
     
     IF Period < 75000 Then    ' If RPM > 500 then next time
     CCP1CON = %00000111       ' Caculate every 16th Egde
     Averaging = 1             ' and Measure RPM with Averaging
     else                      ' IF RPM < 500 then next time
     CCP1CON = %00000101       ' calculate every rising edge
     Averaging = 0             ' Measure RPM without Averaging
     End If
     
     RPM = 37500000 / Period   'Convert Time Period in Round/Minute

    Into_Digit:
     Digit[0] = RPM Div 10000 mod 10
     Digit[1] = RPM Div 1000  mod 10
     Digit[2] = RPM Div 100   mod 10
     Digit[3] = RPM Div 10    mod 10
     Digit[4] = RPM           mod 10
     
    UsartWrite:
       Usart_Write(0x52)                   ' "R" For indication of RPM
       For j = 0 To 4 step 1
       UART_Byte = Digit[j] + 48           ' Add 48 for converting into ASCII
       Usart_Write(UART_Byte)
       Next j
       Usart_Write(0x0D)                   'CR
       Usart_Write(0x0A)                   'LF

    Goto Reset_All
    end. ' end of program
    This Program has been compiled. Not Tested yet on PIC.

    Am I Right!!! :confused:
    Muhammad Ahmed. ;)
     
  2. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    Ooo Yes.
    It is my 350 Post.

    Plz Find the Error in above project and i will try to remove them.
     
  3. gramo

    gramo New Member

    Joined:
    Oct 2, 2006
    Messages:
    1,221
    Likes:
    23
    Location:
    Newcastle, Australia
    Perhaps analyzing your own code would be a great place to start.

    Simulate it in real life, grind out a few errors, and then ask everyone to have a look.

    Asking people to find errors in a large program that we have had no involvement in is like asking what a painting looks like with the paint in tins still :p

    Unless of course people have a spare hour or two too delve into your train of thought and programming techniques
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.

    The problem
    Code (text):
    Connected to COM2
    Received: R00867

    Received: R0/*(-

    Received: R00(*)

    Received: R01682

    Received: R0/*)'

    Received: R00(*)

    Received: R01679

    Received: R00867

    Received: R00(*(

    Received: R01680

    Received: R00867

    Received: R0/*)'

    Received: R01681

    Received: R00867

    Received: R0/*(.

    Received: R00(*)

    Received: R00867

    Received: R0/*)'

    Received: R00(*)

    Received: R01679

    Received: R00867

    Received: R00(*(

    Received: R01681

    Received: R00867

    Received: R0/*(0

    Received: R01681

    Received: R00867

    Received: R0/*(.

    Received: R00(*)

    Received: R00867

    Received: R0/*)'

    Received: R00(**

    Received: R01679

    Received: R00867

    Received: R00(*(

    Received: R01681

    Received: R00867

    Received: R0/*(0
    I am receiving this.
    I make astable circuit with 555 timer and feed it's output to PIC
    The frequency is 15.15Hz and it means RPM 909..
    I am receiving different valuse and aproxx vale is R00867.

    Now the main problem is when i use every 16 edge and divide by 16 the result no be the same..
     
  6. gramo

    gramo New Member

    Joined:
    Oct 2, 2006
    Messages:
    1,221
    Likes:
    23
    Location:
    Newcastle, Australia
    Did you see my RPM program in a different recent thread? It was compiled in Proton+

    It can be easily modified to allow a UART output. I have sim'd the circuit too 30000 RPM, but it should go much faster than that.

    No need to make things complicated when theres easier, faster ways to do something
     
  7. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    Infact my Problem is, I am learning.
    Yes u r right, we can do this with ease.. (one thing more ur Proton+ is Jungly).
    But i want to di this with Measuring the Period of a Square Wave
     
  8. blueroomelectronics

    blueroomelectronics Well-Known Member

    Joined:
    Jan 21, 2007
    Messages:
    12,536
    Likes:
    170
    Location:
    Toronto, Canada
    I found in my opto RPM counter on the Mongoose; I could hook the opto directly to an I/O pin. I use a 4.7K pulldown on the emitters (not a pullup) and tie the collectors to +5. It goes from GND to 4.2V nicely. I tried using the built in comparators but didn't need them. I use RB4&5 as they will cause IRQ on change.
    PS the gears are IR transparent, black paint on both sides works perfectly.
    [​IMG]
     
    Last edited: Mar 31, 2007
  9. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    blueroomelectronics
    What is ur Method of measuring RPM??
    Time periode b/w pulses ???
    OR
    Pulsed received in Known Time???
     
  10. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    How u guys Measure the periode of a square wave?

    Am i Right?
    On first Intrupt i will start TIMER1 module and on seconed intrupt i will get the value of TIMER1H and TIMER1L. and store it into T. Now T is the time periode of our Input wave.
    Intrupt means Intrupt on every rising edge.

    Thanks
     
  11. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,161
    Likes:
    340
    Location:
    Brisbane Australia
    The capture function of the CCP module is designed to do exactly this.

    Mike.
     
  12. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    Yes i am using capture function of the CCP module.

    But i want to know that how u guys use Capture function ???

    In above program i am also using Capture function but result are not right.

    Any one have example related to Capture function plz share.
     
    Last edited: Mar 31, 2007
  13. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,161
    Likes:
    340
    Location:
    Brisbane Australia
    Sorry, I should have looked at your code first. Having now looked at your code, I notice that you don't clear Timer1 when a capture occurs. Timer1 is not automatically reset to zero. A better way is to subtract the timer value from the previous value.

    Mike
     
  14. gramo

    gramo New Member

    Joined:
    Oct 2, 2006
    Messages:
    1,221
    Likes:
    23
    Location:
    Newcastle, Australia
    I wouldnt use the external clock for TMR1 in this application, you have no means by calculating the time period unless you use another TMR for a time reference. Just use the internal clock for TMR1 and an input from a pin to act as the signal

    Code (text):
    Device = 16F877
    Xtal = 4
               
    Dim uS as DWord
    Dim Took_To_Long as Bit

    Symbol GIE = INTCON.7               ' Global Interrupt Enable Bit

    Symbol Timer1 = TMR1L.WORD          ' A special way of addressing both TMR1L and TMR1H with one register
    Symbol TMR1_Enable = PIE1.0         ' TMR1 interrupt enable
    Symbol TMR1_Overflow = PIR1.0           ' TMR1 overflow flag
    Symbol TMR1_On = T1CON.0            ' Enables TMR1 to start incrementing

    Declare SERIAL_BAUD 19200
    Declare RSOUT_PIN PORTA.1
    Declare RSOUT_MODE TRUE
    Declare RSOUT_PACE 5
               
    ON_INTERRUPT Int_Sub

    Goto Initialization        
               
    Int_Sub:
       
        GIE = 0        
               
        If TMR1_Overflow = 1 And TMR1_Enable = 1 Then
            Took_To_Long = 1
            TMR1_Overflow = 0
        EndIf  
       
        GIE = 1
       
        Context Restore
       
    Initialization:

        ALL_DIGITAL = True
       
        High PORTA.1
        TRISA.0 = 1
       
        TMR1_Enable = 0
        GIE = 0
           
        INTCON.6 = 1        ' Peripheral Interrupts

        T1CON.1 = 0     ' 1 = External clock from pin RC0/T1OSO/T1CKI (on the rising edge)
                    ' 0 = Internal clock (FOSC/4)

        T1CON.2 = 1     ' 1 = Do not synchronize external clock input
                    ' 0 = Synchronize external clock input
                    ' When T1CON.1 = 0;
                    '   this bit is ignored. Timer1 uses the internal clock when TMR1CS = 0.
                           
        T1CON.4 = 1     ' 11 = 1:8 prescale value
        T1CON.5 = 1     ' 10 = 1:4 prescale value
                    ' 01 = 1:2 prescale value
                    ' 00 = 1:1 prescale value
        TMR1_Overflow = 0
       
        RSOUT "On",13
       
        TMR1_On = 0         ' Disable TMR1 counting    
        TMR1_Enable = 1         ' Enable TMR1 interrupts
        GIE = 1             ' Enable Global Interrputs         
       
    Main:

        Repeat

        Until PORTA.0 = 0       ' Wait for PORTA.0 to go Low
       
        Repeat

        Until PORTA.0 = 1       ' Wait for PORTA.0 to go high
       
        ' The above two loops ensure we are not entering a pulse mid way, but on
        '   an actual rising edge
       
        Timer1 = 0          ' Reset TMR1                         
        TMR1_On = 1         ' Enable TMR1 counting             

        Repeat

        Until PORTA.0 = 0 Or Took_To_Long = 1

        Repeat

        Until PORTA.0 = 1 Or Took_To_Long = 1

        ' The above 2 Repeat loops wait for a full cycle to occur
       
        TMR1_On = 0         ' Disable TMR1 counting

        If Took_To_Long = 1 Then    ' Check if a time out occured
            Took_To_Long = 0
            Goto Main
        Else
            Timer1 = Timer1 - 2 ' Number of instructions that are executed while timed
                        '  outside of pulse period
            uS = Timer1 * 8     ' 1:8 prescaler & 4Mhz clock there for uS = Timer1 * 8
            RSOut "Period = ", Dec uS, " uS", 13
            RSOut "Frequency = ", Dec(1000000 / uS), " Hz", 13
            RSOut "RPM = ", Dec(1000000 / uS * 60), 13, 13
            Goto Main
        EndIf

     
    Watch the program in action here

    With a 4Mhz OSC and a TMR1 prescale of 1:8, every increment of TMR1 = 1/8th uS. This means that the longest period allowed is 8 * 65535 = 524280uS, or around 1/2 a second. If this occurs, the Took_To_Long flag will be set.

    The faster the pulses comming in, the less accurate the program will become. Its like any sampling program that doesnt use interrupts too catch changes.

    Notice that I first I wait for the input to go from low to high. This is so that I am deffinetly starting from a rising edge, and not jumping in half way.

    Then I wait for that signal to go from high to low and stop the clock. Easy.

    A little math and an output to see the result, presto.
     
    Last edited: Apr 1, 2007
  15. blueroomelectronics

    blueroomelectronics Well-Known Member

    Joined:
    Jan 21, 2007
    Messages:
    12,536
    Likes:
    170
    Location:
    Toronto, Canada
    Simple edge triggered pulse counting over time.

    You can count low to high and high to low transistions, so 6 per rotation.

    The motor is 12500RPM at 3V no load.
    Gear reduction is 4.25:1 to the crown gear, then 3:1 for the sensor gear, and two more 3:1 till it hits the wheels.

    Therefore the sensor gear rotates once every 12.75 rotations of the main motor and 9 times faster than the wheel axle. With three marking on the sensor gear we can see 54 edge transitions per whell rotation.

    From the motors point of view...

    12500 rpm (more with higher voltage but this is the rated speed at 3V)
    So 12500/4.25/3 = 980.4 RPM on the sensor gear.
    980.4 / 60 (for rotations per second) = 16.34
    now multiply that by the 3 black markings each with 2 edges
    16.34*3*2= 98 Hz, not too fast for a PIC to count.
    Using RB4,5 change on interrupt should be a breeze to keep up.

    PS I'm using both PWM channels to control the dual motor(s) speed, so I don't have the luxury of the CCP capture mode.

    If 98Hz is too fast or slow add/remove black bands from the gear. I used 3 positions as there are three little circular indents on those gears make it easy to draw the hand painted (with black sharpie paint marker) stripes.
    [​IMG]
     
    Last edited: Apr 1, 2007
  16. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    TIMER1 with 1:8 Prescale value.
    Crystal Frequency = 20MHz
    TIMER1 using internal clock cycle(Instruction Cycle).
    Then
    increment of TMR1 = ???

    My bad math says it is about 1.6 microSeconds... Am I Right!!!
     
  17. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,161
    Likes:
    340
    Location:
    Brisbane Australia
    Yes, it will be 1.6uS. Have you added code to zero timer1 in your interrupt as I suggested earlier.

    Mike.
     
  18. gramo

    gramo New Member

    Joined:
    Oct 2, 2006
    Messages:
    1,221
    Likes:
    23
    Location:
    Newcastle, Australia
    20Mhz, therefor Instruction frequency = FOSC / 4
    Thats 5,000,000 instructions a second

    Remembering that TMR1 increments per instruction, but with a prescaler, therefor

    1:1 = 200nS
    1:2 = 400nS
    1:4 = 800nS
    1:8 = 1600nS

    Edit: - I missed your post pom, sorry
     
    Last edited: Apr 1, 2007
  19. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    Now see on math.
    x is the value of TIMER1, elapsed b/w two Low to High Edges.
    [​IMG]

    I add zero zero value into TIMER1L and TIMER1H every time at startup of the loop..

    Now on ur suggestion i will add zero zero value into TIMER1L and TIMER1H on interrupt.
     
  20. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    What is the minimum range of traditional Tacho Meters???
    I am asking this because i never see any tachometer. and here is no posibility to see the ranges of a traditional Tacho Meter.

    Now i made some changes in my program and it is runing Smoothly. But code i will paste here with improved efficiency later.
     
  21. Ayne

    Ayne New Member

    Joined:
    Apr 30, 2006
    Messages:
    415
    Likes:
    0
    Location:
    Multan, Pakistan.
    My readings are right.
    but they are roling near and near.... It is right!!

    Ur sugestions
     

Share This Page