+ Reply to Thread
Page 1 of 2
1 2 Last
Results 1 to 15 of 26

Thread: Voltage to frequency converter with PIC

  1. #1
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default Voltage to frequency converter with PIC

    Hello guys,

    I am looking for PIC implementation for voltage to frequency converter (VFC).
    Program must generate square wave signal with equal time ON/OFF based on the value from analog input.
    10V = about 50KHz
    0V = OFF
    10mV= 50Hz (lovest resolution of the input)

    Linearity and repeatability is important, max frequency can be 30KHz and higher.

    Response time can be up to 0.5 sec, lower is better.

    I have available PICs to try: 12F675, 16F628, 16F670, but can obtain any other, if necesary.

    Actually my task is a little more complicated, but if I find this, I'll ask the rest.

    Thanks


  2. #2
    csaba911 Good csaba911 Good csaba911 Good
    Join Date
    Jul 2003
    Location
    Canada
    Posts
    218

    Default

    If you use a voltage divider to make the 10V down to 5V, you can use PIC with 10bit AD.
    10bit has 1024 variance, 0=0hz, 1=50 Hz, 2=100 Hz 1023= 51150 Hz/51.15kHz.
    If you have Picbasic, Picbasic have FREQOUT command, FREQOUT Pin , Period , Freq.
    I think one of the disadvantages of Picbasic is, it wont start a new AD reading until its finish the freqout routine.
    Code:
    FREQOUT PORTA.0, 100,1000
    
    makes on PORTA bit0 for 100ms 1000hz.
    Possible in assembler you can make you own timing to have constant freq on the pin you want, and initiate the AD in your delay cycle.

    In case if you already know all of this, then what is you question :?:


    I hope this help.

    STEVE

  3. #3
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Thank s for the idea.
    5V is not a problem - I have active absolute value circuit involved anyway, so I just change gain value.

    FREQOUT will be a problem.
    Technically I need to do a couple more things while generatin pulse train.
    One of them is to generate 3 more pulse trains of the same frequency with 90 deg phase shift each.
    I probably need some kind of timer interrupt routine or so.

    In case if you already know all of this, then what is you question
    I am just looking for ideas and examples.

    This circuit is working for a while with descrete ICs with total cost over $25. (VFC320 chip)
    I am sure I can make it with PIC for much less with less ICs involved.

  4. #4
    Super Moderator Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent Nigel Goodwin Excellent
    Join Date
    Nov 2003
    Location
    Derbyshire, UK
    Posts
    29,793

    Default

    Perhaps you had better let us know what you are trying to do?, there may be a simpler way?.

    Certainly if you are introducing lots more requirements you are likely to start running short of cycles.
    PIC programmer software, and PIC Tutorials at:
    http://www.winpicprog.co.uk

  5. #5
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Nigel

    This device is incremental encoder simulator.

    I think PIC should be fast enough to handle this.

    One addtional requirement is to switch phase of outputs 2 and 4 if another descrete input is ON

    IN=off - seq 0-90-180-270
    IN=ON - seq 0-270-180-90

    That is it, no more features.

  6. #6
    motion Newbie
    Join Date
    Jul 2003
    Location
    Quezon City.PH
    Posts
    560

    Default

    An incremental encoder normally has two outputs with the ff. sequence

    output1 - 0110011001100110.....
    output2 - 0011001100110011.....

    When a switch is ON, the sequence is reversed

    output1 - 0011001100110011.....
    output2 - 0110011001100110.....

    In addition, you want the encoder to step through the sequence at a rate adjustable from 0Hz to 50Khz in 50Hz steps. The adjustment is through an an analog voltage input. Is this what you need?

    This is doable except that at the highest frequecies, the speed adjustment may not be smooth. That is, changing the speed from 49050Hz to 50000Hz might not be easily done.
    "Having to do with Motion Control"

  7. #7
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Motion,
    This is exactly what I need.
    Thank you for making my idea clear.


    The only minor addition to these 2 pulse trains - I want to have 2 more trains with "NOT" value for two main channels.

    Like I said: I have this device working using very expensive VFC 320, couple triggers and XOR ICs.
    I just want to simplify the design.

    If this works, next step will be to simulate SSI interface encoder, but this is a future project.

  8. #8
    motion Newbie
    Join Date
    Jul 2003
    Location
    Quezon City.PH
    Posts
    560

    Default

    Let me outline the solution I have in mind. There are two parts to the program. The first part is generating the encoder sequence at a set frequency. The second part is reading from an analog input, perform A/D conversion, and translating the result to a frequency setting used in the first part.

    The way to generate the sequence is through interrupts. 50Khz is a relatively high rate and a 20Mhz PIC16F628 should give you enough headroom. The ff. steps are needed to setup:

    a. Setup CCP1CON register for "compare mode, trigger special event". I.E., initialize CCP1CON to 00001011B.
    b. Initialize TMR1CON with the value 00010001 (TMR1ON and 1:2 prescale). This will supply a 2.5Mhz clock to TMR1 from a 20Mhz oscillator.
    c. Initialize CCPR1H,CCPR1L with the value 50. This will give an initial interrupt rate of 50KHz. To get an interrupt rate of 50Hz, the registers should be intialized to 50. To get a specific frequency, a suitable value from 50-50,000 should be entered. Notice there are 1000 values. A lookup table is best to achieve a linear relationship to the analog input. However, this exceeds the capacity of the PIC. You may have to limit the table to 500 items and interpolate in-between values.
    d. Enable interrupts for the CCP1 by setting CCP1IE bit in PIE1 register. When everthing is all setup, enable interrupts by setting GIE and PEIE in the INTCON register.

    The following is a sample interrupt service routine:

    Code:
    ;=======================================
             ORG      4
    
    INT_SERVE:                             ; 2
             MOVWF    TEMP_W
             SWAPF    STATUS,W
             CLRF     STATUS         ; Select RAM BANK0
             MOVWF    TEMP_S
             MOVF     PCLATH,W
             MOVWF    TPCLATH
             CLRF     PCLATH
    ;--------------------------------------------------
             BTFSC    SELECT_PIN
             INCF     PHASE_CNT,F
             BTFSS    SELECT_PIN
             DECF     PHASE_CNT,F
    ;
             CALL     GET_PHASE            ; 8
             MOVWF    PORTB
    ;--------------------------------------------------
    UPD_TIMER:
             BTFSS    UPD_TMR_VAL
             GOTO     UPD_TIMER_END
             BCF      UPD_TMR_VAL
    ;
             MOVF     TMR_VAL,W
             MOVWF    CCPR1L
             MOVF     TMR_VAL+1,W
             MOVWF    CCPR1H
    UPD_TIMER_END:
    ;--------------------------------------------------
    INT_SERVE_END:
             BCF      PIR1,CCP1IF
    ;
             MOVF     TPCLATH,W
             MOVWF    PCLATH
             SWAPF    TEMP_S,W
             MOVWF    STATUS
             SWAPF    TEMP_W,F
             SWAPF    TEMP_W,W
    ;
             RETFIE                        ; 2
    ;=======================================
    GET_PHASE:
             MOVF     PHASE_CNT,W
             ANDLW    B'00000011'
             ADDWF    PCL,F
             RETLW    B'00000101'
             RETLW    B'00001001'
             RETLW    B'00001010'
             RETLW    B'00000110'
    ;--------------------------------------------------
    
    The ISR uses 38 instruction cycles or 7.6usec. At 50Khz interrupt rate, there are 100 or 20usec instruction steps between interrupts. This gives a utilization of 38% of CPU cycles for pulse generation.
    "Having to do with Motion Control"

  9. #9
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Motion:
    Thanks for great idea, I think this is exactly what I was looking for.
    I never used a timer interrupt, and had some filling that I must use it.

    I have to look at the lookup table, 500 values may not be enough.
    I will look at 2 different ways: use a formula or get a higher capacity PIC.

    I will try it in the next few days and let you know.

  10. #10
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Just a quick update:
    I was going over the program last night - I think it will do the job, I will modify interruput routie a little and add analog input readings.

    Questions for far:

    - Timer value updated only at the interrupt routine (ccpr1l, ccpr1h):
    Can this be done in the main program?
    I see the reaction time issue at the low speeds and at speed "0"

    - What is a max value in ccpr1l? 2^16-1= 65535?
    If yes I will need to set only CCPR1L for all dividers leaving CCPR1H=0.
    This will reduce a lookup table size from 2000 to 1000 values.

    Thanks

  11. #11
    motion Newbie
    Join Date
    Jul 2003
    Location
    Quezon City.PH
    Posts
    560

    Default

    Quote Originally Posted by Andy_123
    Just a quick update:
    I was going over the program last night - I think it will do the job, I will modify interruput routie a little and add analog input readings.
    I would recommend to add the analog input readings on the main program instead of the ISR. The interrupts occur at varying rate. The A/D conversion is completed asynchronous to this.

    I would also recommend to average the analog readings over several samples to reduce the effect of noise. This is possible because you can make up to 50K samples/sec.

    Let me answer the second question first.

    - What is a max value in ccpr1l? 2^16-1= 65535?
    If yes I will need to set only CCPR1L for all dividers leaving CCPR1H=0.
    This will reduce a lookup table size from 2000 to 1000 values.
    The maximum value is 65535. If CCPR1H is fixed at 0, the maximum value of the pair becomes 255. Therefore the minimum frequency is 2,500,000/255=9.8Khz. To generate 50Hz, you would need a value of 50,000 or CCPR1H=0C3h, CCPR1L=50h.

    - Timer value updated only at the interrupt routine (ccpr1l, ccpr1h):
    Can this be done in the main program?
    I see the reaction time issue at the low speeds and at speed "0"
    If you write to CCPR1 in the main program, an interrupt can occur while writing to one register only (partial update of CCPR1 registers). Writing within the interrupt service routine guarantees both registers can be updated before the next interrupt occurs.

    I understand at low speed, it will take longer before CCPR1 is written. However, rapidly changing CCPR1 will not speed up the response because the value of CCPR1 is only used when a match with TMR1 occurs.

    The frequency divider method works from 50Hz-50Khz speeds. At speed 0, the TMR1 can be turned OFF and turned back ON when the speed is non-zero. Even at 50Hz, the update time is 0.02sec which is faster than your requirement.
    "Having to do with Motion Control"

  12. #12
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Project is on hold today: nice warm day outside - spring clean-up time 8)

    I would recommend to add the analog input readings on the main program instead of the ISR
    Yes, this is what I was planning to do, I just did not worded it correctly.
    Analog goes to the main routine.

    The maximum value is 65535. If CCPR1H is fixed at 0, the maximum value of the pair becomes 255. Therefore the minimum frequency is 2,500,000/255=9.8Khz. To generate 50Hz, you would need a value of 50,000 or CCPR1H=0C3h, CCPR1L=50h.
    I did not realise that CCPR1H and CCPR1L are 8 bit each - my mistake, I will be using both.

    I see the reason why you are not updating timer values in the main program, I agree.

    One more thing I am not sure:
    It takes 4 interrupts to generate a complete sequence, right?
    With max interrupt rate of 50kHz we can generate only 12.5Khz stream not 50Khz.
    If this is correct what will be the best way to correct it: change value in CCPR1?

  13. #13
    motion Newbie
    Join Date
    Jul 2003
    Location
    Quezon City.PH
    Posts
    560

    Default

    It takes 4 interrupts to generate a complete sequence, right?
    With max interrupt rate of 50kHz we can generate only 12.5Khz stream not 50Khz.
    If this is correct what will be the best way to correct it: change value in CCPR1?
    If you change the prescale value of TMR1 from 1:2 to 1:1, you could double the speed. This will increase the CPU utilization to 80%. Quadrupling the frequency would push it beyond the PIC16F628's capability.

    You may change to a PIC18F242. The speed of the chip is double that of the PIC16F628. In addition to the increased storage for the look-up table, it has the TABLRD instruction to allow reading of the entire 16-bit program memory word. Added to that, optimizations with context saving will reduce ISR service time and CPU utilization.
    "Having to do with Motion Control"

  14. #14
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Update:
    I just completed testing of interrupt routine without analog portion.
    Everything works as expected:
    I tested with 16F628 and 20 Mhz oscillator.
    With divider 50 (32hex) it generates 4 pulse trains at 12.5MHz as expected - 80 usec period - measurements with 2 channel oscilloscope.

    Also tested 3 other dividers: 500, 5000 and 50000 everythig works fine.

    Now before I add analog reading, I need to see how I can reduce interrupt routine to minimize CPU usage, so I can increase frequency
    I really need at least 33kHz (50kHz was my goal)
    I will be ordering 18F242 as recommended, but I hope I can use 16F628.

    Any ideas how can I trim interrupt routine? Do I really need to save STATUS and PCLATH?

    Edit: just ralized that 16F628 does not have analog inputs :roll:
    Will try to move to 16F870 until 242 arrives

    Thanks for help!!!

  15. #15
    Andy_123 Newbie
    Join Date
    Feb 2004
    Location
    Cleveland, Ohio, USA
    Posts
    115

    Default

    Motion:
    Do you have any interrupt handling examples for 18F242 similar to one above for 16F628?

    18F242 is much more powerfull and I see that I can use some extended commands to reduce
    execution time, espcially fast stack operations, and table handling.

    I am expecting 18F242 in a few days, so I need program change.

    Thanks.

+ Reply to Thread
Page 1 of 2
1 2 Last

Tags for this Thread