On 1/12/07, alan smith wrote: > I'm sure this has been done before....measuring the RPMs of a flywheel, but just looking for a sanity check. Sure has. > Lets say you have a hall sensor pickup on a flywheel that is giving you around 5000 pulses/sec from the teeth. > > So thats 5000Hz or 200uS between edges. A 4MHz PIC has an internal cycle time of 1uS so it can easily count these, but better yet is to use TMR0 and the prescaler so you can get a reasonable number using the 1:128 and get out 39 Hz when you use a 1 second interupt to read the TMR0 value. Here are some code fragments that I use... Hopefully the formatting doesn't get too trashed. I use TMR0 and a software high byte. The variable names and macro usage should be obvious. I read the values every 1/10 second, but every second would work too, it would just change the constants used converting to RPM. The code also does very simple averaging and replaces a divide by a multiply and shift. It works fine for display of RPM from a car flywheel based inductive sensor. Enjoy, Orin. ; Somewhere in the interrupt handler: btfsc INTCON, T0IF ; Check if Timer 0 Overflowed goto IRQ_T0I ; yes, go handle it ; Handle other interrupts ;-------------------------------------------------------------- ; Timer0 Overflow ;-------------------------------------------------------------- IRQ_T0I bsf INTR_FLAGS, IF_HANDLED bcf INTCON, T0IF ; Clear the interrupt incf COUNTER_HIGH, F ; Increment Counter ; go back to main interrupt handler ;-------------------------------------------------------------- ; Timer 0 Handling ;-------------------------------------------------------------- ; ; Clear_Timer - Clear SW and HW timer ; ClearTimer DisableInterrupts bcf STATUS, RP0 ; Bank 0 clrf TMR0 bcf INTCON, T0IF clrf COUNTER_HIGH EnableInterrupts return ; ; Read_Timer - Put timer value in indirect location ; Assumes FSR has the desired location ; ; Note: Call with interrupts ENABLED ; Trashes FSR ReadTimer incf FSR, F movf COUNTER_HIGH, W ; Get high byte movwf INDF decf FSR, F movf TMR0, W ; Get low byte movwf INDF incf FSR, F movf COUNTER_HIGH, W ; Re-Read high byte subwf INDF, W ; W = first - second btfsc STATUS, Z ; Same high byte? return ; yes, clean read ; No, re-read timer subwf INDF, f ; Works out to 'second' decf FSR, F ; Re-read low byte movf TMR0, W movwf INDF return ;-------------------------------------------------------------- ; Calculate RPM (runs every 100mS) ; ; Get Flywheel tooth count as quickly as possible ; movlw ACCaLO ; ACCa is new count movwf FSR call ReadTimer ; Get flywheel tooth count MovWord ACCaLO, ACCbLO ; ACCb = ACCa SubWord ACCaLO, PrevTeeth ; ACCa -= PrevTeeth MovWord ACCbLO, PrevTeeth ; PrevTeeth = ACCb AddWord ACCaLO, PrevAvg ; ACCa = (ACCa + PrevAvg)/2 bcf STATUS, C rrf ACCaHI, F rrf ACCaLO, F MovWord ACCaLO, PrevAvg ; PrevAvg = ACCa ; ; RPM is flywheel tooth difference * 40 / 9 ; ; To turn this into a binary fraction of 1000 RPM, ; we multiply by 65536/1000, giving the 1000 digit ; and two bytes of mantissa. Subsequent multiplies of ; the mantissa by 10 give the 100, 10 and units digits. ; (40/9)*(65536/1000) is 291.27. We round this ; to 291.25 and note that ; it is 1165/4. So we multiply by 1165 then divide by 4. ; We could pick other combinations, but this one is ; accurate enough, doesn't overflow for expected RPM values ; and replaces the divide with 2 shifts. ; Resolution is (291.25 * 1000) mod 65536, about 4 RPM. ; There is no attempt to display > 9999 RPM. movlw 0x8D ; Multiply by 291.25 by first movwf ACCbLO ; multiplying by 1165 then... movlw 0x4 movwf ACCbHI call D_mpyS bcf STATUS, C ; ...dividing by 4 rrf ACCbLO, F rrf ACCcHI, F rrf ACCcLO, F bcf STATUS, C rrf ACCbLO, F rrf ACCcHI, F rrf ACCcLO, F -- http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist