PIC pulse problem

Discussion in 'Embedded Systems and Microcontrollers' started by SnydeMz, Nov 7, 2010.

  1. SnydeMz

    Thread Starter New Member

    Nov 7, 2010
    Im a computer engineer who recently started working with PIC microchip controllers. Im currently working on a project that involves taking signals from the odometer sensor in the instrumentation panel of a car and based on those signals gives high signals on 4 different outputs of the controller. I have a complex problem involving the above. The sensor gives an output in terms of pulses...5 pulses represent a kilometer travelled. I want to measure distance travelled and based on this give output signals representing distance. For 3000km this gives 600 pulses, 5000km gives 1000 pulses, 10000km gives 2000 pulses and 15000km gives 3000 pulses. I have written code for the chip such that an input representing say 3000km(600 pulses) gives an output of a high signal on one of the output pins and so on and so forth for the rest of the distances. Now the challenge is making sure that the chip is able to distinguish between the number of pulses. How can this be achieved electronically...I have heard the term 'digital frequency divider' in some forums but have no idea what that is. please someone shed some light on this issue.
  2. mik3

    Senior Member

    Feb 4, 2008
    Use one input pin to read the pulses. According to your description, each pulse corresponds to 200m. Thus, each time the PIC receives a pulse increment a variable, which represents distance traveled, by 200.
  3. SnydeMz

    Thread Starter New Member

    Nov 7, 2010
    i get that i can use an input pin for the pulses..if i increment a variable.. i will have to write the code such that when the variable is incremented such that it hits a certain value , say if the variable is incremented until it is equal to 15000(for case 1:3000km are repd by 15000 pulses) then output a high signal on one input pin. This would be easy if I was using C or any other language...How do I achieve this in assembly? Specifically im using the PIC16F88/PIC16F84.
  4. Markd77

    Senior Member

    Sep 7, 2009
  5. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    Is there anything preventing you from using C?

    Sourceboost C has a free compiler (for non commercial use), as well as a couple other compilers. There are limitations on them, but for your application, you wouldn't be near those limits.
  6. mik3

    Senior Member

    Feb 4, 2008
    There is a compare command, which can compare two values (registers), in assembly too.
  7. Markd77

    Senior Member

    Sep 7, 2009
    I've stripped out a lot of unnecessary code and added a little just before "loop" to preset the counter. It should go to ";TMR1 interrupt" after 15000 pulses.
    I haven't tested it, it's for the wrong PIC and there is a lot of unnecessary code left, but the general idea is there.

    The PIC16F88 would be fine, I wouldn't reccomend the PIC16F84 because it's old, expensive and doesen't have a timer1.

    Code ( (Unknown Language)):
    2.         LIST P=16F628, R=DEC  
    4.         #include "P16F628.INC"  
    6.         __config  _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON
    8.         CBLOCK 0x20             ;variables
    10.     count
    11.     count2
    13.     eetemp
    14.     PORTAbuffer
    15.     PORTBbuffer
    16.     iTMR0countH
    17.     iTMR0countM
    18.     iTMR0countL                ;TMR0 value
    19.     TMPH
    20.     TMPL
    21.     TMR1MSB
    22.     period
    23.     dutysamplecountH
    24.     dutysamplecountL
    25.     duty_H
    26.     duty_L
    27.     indutyH                    ;samples of input to get avg duty
    28.     indutyM
    29.     indutyL
    30.     prescale
    31.     usartdone
    32.     freqdone
    33.     usartrxcount
    34.     usartrxbuf:10
    35.     digitcount
    36.     setstate                    ;0
    37.     H_byte
    38.     M_byte
    39.     L_byte
    40.     H_temp
    41.     L_temp
    42.     R0
    43.     R1
    44.     R2
    45.     R3
    46.     temp
    47.         ENDC
    49.     CBLOCK 0x70
    50.     W_TEMP
    51.     STATUS_TEMP
    52.     ENDC
    56.     ORG    0x000          
    57.     goto init
    60.     org 0x004    ;interrupt goes here
    61.     MOVWF W_TEMP ; Copy W to TEMP register,
    62.     SWAPF STATUS, W ; Swap status to be saved into W
    63.     MOVWF STATUS_TEMP ; Save status to STATUS_TEMP register
    64.     BCF STATUS, RP0                ;bank 0
    65.     btfss INTCON, T0IF                ;timer0 interrupt flag
    66.     goto notTMR0
    68. notTMR0
    70.     btfss PIR1, TMR1IF
    71.     goto notTMR1
    72. ;TMR1 interrupt
    77.     ;insert code here
    81.     bcf T1CON, TMR1ON            ;stop timer to safely write
    82.     movlw 0xC5                :load with 0xC567 (=0xFFFF - decimal 15000)
    83.     movwf TMR1H
    84.     movlw 0x67
    85.     movwf TMR1L
    86.     bsf T1CON, TMR1ON            ;restart timer
    87.     bcf PIR1, TMR1IF
    89.     goto endint
    91. notTMR1
    94. endint
    95.      ; should configure Bank as required
    96.      ;
    97.     SWAPF STATUS_TEMP,W     ; Swap nibbles in STATUS_TEMP register
    98.     ; and place result into W
    99.     MOVWF STATUS             ; Move W into STATUS register
    100.     ; (sets bank to original state)
    101.     SWAPF W_TEMP, F         ; Swap nibbles in W_TEMP and place result in W_TEMP
    102.     SWAPF W_TEMP, W         ; Swap nibbles in W_TEMP and place result into W
    104.     retfie
    107. init
    109.     CLRWDT ;Clear WDT and
    110.     ;prescaler
    111.     BSF STATUS, RP0
    112.     MOVLW b'11011111' ;Select TMR0, and internal clock source
    113.     MOVWF OPTION_REG
    114.     BCF STATUS, RP0
    117.     movlw 7
    118.     movwf CMCON             ;comparators off
    119.     movlw b'00000000'       ;porta outputs
    120.     movwf PORTA
    122.     movlw b'00000100'       ; RB2(TX)=1 others are 0
    123.     movwf PORTB
    125.     bsf STATUS,RP0          ; page 1
    127.     movlw B'00100001'
    128.     movwf PIE1                ;USART receive and TMR1 int enabled    
    130.     movlw 0x00
    131.     movwf TRISA             ; portA all pins output
    133.     movlw b'11110010'       ; RB7-RB4 and RB1(RX)=input, others output
    134.     movwf TRISB
    139.     movlw 0x19                  ; 9600 baud, no Parity, 1 stop bit        
    140.     movwf SPBRG
    141.     movlw b'00100100'      
    142.     movwf TXSTA  
    143.     bcf STATUS,RP0
    144.     movlw b'10010000'      
    145.     movwf RCSTA
    146.     clrf count
    147. wait  
    148.     decfsz count,F            ;pause just in case
    149.     goto wait
    153.     movlw b'11100000'        ;timer0, peripherals and global interrupts on
    154.     movwf INTCON
    156.     clrf setstate
    157.     clrf usartdone
    158.     clrf period
    159.     clrf duty_H
    160.     clrf duty_L
    161.     clrf prescale
    162.     incf prescale, F            ;prescale = 1
    163.     movlw 0x04
    164.     movwf iTMR0countH
    165.     movlw 0xD1
    166.     movwf iTMR0countM
    167.     movlw 0x85
    168.     movwf TMR0
    169.     movlw d'64'
    170.     movwf dutysamplecountH
    171.     clrf dutysamplecountL
    172.     movlw b'00001111'
    173.     movwf T1CON
    174.     bsf STATUS, RP0                    ;setup PWM
    175.     clrf PR2
    176.     bcf STATUS, RP0
    177.     clrf CCPR1L
    178.     movlw b'00001100'
    179.     movwf CCP1CON
    180.     bsf STATUS, RP0
    181.     bcf TRISB, 3
    182.     bcf STATUS, RP0
    183.     movlw b'00000100'
    184.     movwf T2CON
    186.     bcf T1CON, TMR1ON            ;stop timer to safely write
    187.     movlw 0xC5                :load with 0xC567 (=0xFFFF - decimal 15000)
    188.     movwf TMR1H
    189.     movlw 0x67
    190.     movwf TMR1L
    191.     bsf T1CON, TMR1ON            ;restart timer
    194. loop
    196.     ;optional code here
    199.     goto loop
    203.     END
    Last edited: Nov 10, 2010
  8. eblc1388

    Senior Member

    Nov 28, 2008
    3000Km or 15000Km is a long distance for a car to travel and it will certainly takes a long time.

    Make sure that the power supply is never turn off or the PIC never reset during the travel or else :)

    This is how I will be tackling the problem.

    Usually in this type of situation the value represent "total distance travel" will be saved to a non-volatile memory location inside the PIC and if the difference between the new/saved value is more than 4(1Km traveled), then the non-volatile location is updated accordingly.

    The value is also updated to the non-volatile memory if it remains stable for a long time, say after 1 minutes.

    On PIC power up, a check is done to see if a CLEAR key is also being pressed. If so, the memory will be cleared. Otherwise the stored value is loaded into the current memory for subsequent increment.

    I would usually keep seven extra copies of the total distance traveled in the EEPROM in a circular array, each differs in value normally by 5 or less. As a result I can then discard/repair any bad data on power up if the value is out side this range. The value of these eight copies are read and the highest one is loaded as the current value. The next EEPROM write will update the next location of the circular array.

    When a new pulse has come in via the odometer, the PIC memory value is immediately incremented and a one minute timer started/restarted. The timing counts would be decremented on every timer interrupt until it reaches zero where then a time_expired flag will be set.The time_expire flag will never get set if the pulses are coming in more frequent than one per minute.

    Here is a flowchart of the program, created using the free Diagram Designer.

    Last edited: Nov 11, 2010