PWM _ Duty Cycle in Tenths


Closed Thread
Results 1 to 12 of 12
  1. #1
    rwskinner's Avatar
    rwskinner Guest

    Default PWM _ Duty Cycle in Tenths

    I need to be able to get duty cycle of a PWM signal in Tenths. I currently am getting the duty cycle but only the whole number.

    I get 37% instead of 37.2 %

    Here is my code, any help is appreciated.
    This program gets the duty cycle from the input, displays it, then converts it to a 0-5 vdc output using RC.

    Here is the Clip.....

    DEFINE OSC 20

    'Frequency Input Channels

    'Voltage output channels
    VOut1 VAR PORTA.0

    'Variables and Constants

    pHigh VAR WORD ' W3 high pulse width
    pLow VAR WORD ' W2 low pulse width
    period VAR WORD ' cycle time (high + low)
    T2 VAR WORD
    T3 VAR WORD
    Channel VAR BYTE
    PulseLen CON 30 'Pulsein Time Less than 30 causes no readings
    'Setup Max Channels to Scan
    ' -------------------------------------------------------------------------
    DEFINE DEBUG_REG PORTB
    DEFINE DEBUG_BIT 7
    DEFINE DEBUG_BAUD 38400
    DEFINE DEBUG_MODE 1
    DEFINE PULSIN_MAX 750

    'Set initial pin states
    Output VOut1

    'MAIN

    Loop:
    T2 = 0
    T3 = 0

    PulsIn F_pin1, 1, pHigh ' get high portion of input
    PulsIn F_pin1, 0, pLow ' get low portion of input
    Period = pHigh + pLow ' calculate cycle width

    IF Period = 0 Then
    Period = 0
    T2 = 0
    T3 = 0
    GoTo DoIt
    EndIF

    t2 = plow
    t3 = phigh
    t3 = t2 + t3
    t3 = t3 / 10
    t2 = t2 * 10
    t2 = t2/t3

    DoIt:

    Debug "Ch#:",#channel," DC:",#t2,13,10

    t2 = t2 * 255 ' Converts % Duty cycle to a 255 step resolution
    t2 = t2 / 100

    PWM VOut1, t2,PulseLen
    GoTo Loop

  2. #2
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    PWM is based on zero to 100%... you're aware that you're not going to get too many tenths if you're using 256 bit resolution?

    The best is 100/256 or steps of around 0.39%... falls well short of tenths.

    I would suggest using a PIC with hardware PWM as it's 10-bit and you'll get tenths of a percent there (100/1024=0.0976% steps).

    Melanie

  3. #3
    rwskinner's Avatar
    rwskinner Guest


    Did you find this post helpful? Yes | No

    Default

    I measuring a 02 sensor which outputs 30% duty cycle at 0% oxygen and outputs 80% duty cycle at 21% oxygen. I then measure the duty cycle and convert it to 0-5 volts.

    We read the % oxygen in tenths ie. 8.5% oxygen.

    I can order a pic with hardware PWM I'll just have to look and see what best fits my needs. I have 4 channels to monitor.

    Is there a better way to accomplish what I'm doing?

    Thanks

  4. #4
    rwskinner's Avatar
    rwskinner Guest


    Did you find this post helpful? Yes | No

    Default

    Melanie,

    Although I don't know much I thought hardware PWM was for outputting a PWM signal in the background. I'll have to look more because even the datasheets at Microchip talk about outputting a pwm but nothing about measuring pwm in.

    Any specific chip you'd advise me to look at? BTW, this has absolutely nothing to do with Life support. It's measuring Exhaust o2 levels of engines.

    Richard

  5. #5
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    My oversight, assumed it was PWM Output that you needed the tenths accuracy.

    Is your problem with Pulsin or with the subsequent math?

    If it's with the math, then you simply need to scale it up by a factor of ten, so that your division doesn't give you 37.2 (which because of integer math will truncate to 37), but result in 372. Therefore instead of 0-100, internally in your code you will work 0-1000 knowing that the least significant digit is TENTH's, and when outputting you can then place your decimal point appropriately.

  6. #6
    rwskinner's Avatar
    rwskinner Guest


    Did you find this post helpful? Yes | No

    Default

    Yes, it's the math. I can read the pulsin okay by scaling one of the values up by a factor of ten to give me tenths. That worked fine.

    Follow me here a second and see if this solution holds water. Haven't tried it yet, but it appears it will work.

    Here is the deal.
    On Reading the input....
    The valid pulsin will always be from 30% to 80% duty cycle - so that gives me a total difference of 50% (remember that 30% dc is 0% o2 and 80% dc is 21% o2)

    Scaling the Value on the out put.
    0 -21% is the value I'm trying to represent on the output, so 21% O2 is at 80% duty cycle. 21% / 256 steps gives me my 1/10 of a percent resolution.

    Output = 0% o2 = 0 vdc
    21% o2 = 5vdc

    So to get around the 8 bit resolution, instead of me outputting a voltage representing the input duty cycle of 0-100% I'd be better off reading the duty cycle coming in, converting it to %o2, then outputting the voltage based on a scale of 0-21%

    That should give me slightly better than 0.1% resolution.


    Knowing all of that, now the math....
    Example:
    Sensor o2 = 10.5%
    Sensor Duty Cycle in should be = 55%

    Get Ratios and scale it....
    Input Duty Cycle - StartDutyCycle = FinalDutyCycleVar
    55 - 30 = 25

    Display to lcd.....
    25 x 42 = 1050 or 10.50% o2


    Setup for pwm output..... 0=0 21% = 5vdc
    25 x 256 = 6400
    6400 / 50 = 128

    128 steps of PWM Out = 2.5 volts which represents 10.5%


    WhaLa, looks okay.
    @ 21% there is not a 16 bit overflow so that should be okay

    See any problems?
    Richard

  7. #7
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    Well yes, so 0-100% PWM Output which is 0-5v which is 0-21% of O2. Sensible to concentrate operation to just the important bits you need.

    First problem I see is right at the beginning where your math is insufficient for 0.1% resolution...

    example1:

    InputDutyCycle=55

    55-30=25. Multiplied by 42 gives 1050 (or 10.50%)

    example 2:

    InputDutyCycle=56

    50-30=26. Multiplied by 42 gives 1092 (or 10.92%).

    You can see this isn't good enough. The Math getting the resultant into InputDutyCycle should give you a result which is at least a factor of five (at a minimum) bigger to get anywhere close to your resolution. Basically your scale of 30-80 (0-50) is too small... your math getting to here needs a far bigger scale (at least 0-210 for 0.1% resolution).

    What is your PWM frequency or give me some typical values for PulseHigh and PulseLow and I'll show you how to achieve this.

  8. #8
    rwskinner's Avatar
    rwskinner Guest


    Did you find this post helpful? Yes | No

    Default

    Normally it's at 550hz although some modules output at 850hz. The manufacturer doesn't understand why.

    I knew the math I put up was still based on whole numbers.
    Sorry it was a typo, but I'm very curious what you have up your sleeve, maybe I'll learn something new "again" and I'm sure it will look much neater as well <grin>


    PulsIn F_pin1, 1, pHigh ' get high portion of input
    PulsIn F_pin1, 0, pLow ' get low portion of input

    ' calculate cycle width
    Period = pHigh + pLow

    'Display Zero - Avoid rest of Math
    IF Period = 0 Then
    Steps = 0
    Period = 0
    DutyCycle = 0
    Oxygen = 0
    GoTo DoIt
    EndIF

    '*****************************************
    'Calculate Duty Cycle in format 37.7% = 377
    t2 = plow
    t3 = phigh
    t3 = t2 + t3
    t3 = t3 / 10
    t2 = t2 * 100
    DutyCycle = t2/t3 'Duty Cycle Value



    'Actual Duty Cycle is Zero then Display Zero'
    IF DutyCycle < 301 Then
    Steps = 0
    Period = 0
    DutyCycle = 0
    Oxygen = 0
    GoTo DoIt
    EndIF



    '*************************************
    'Calculate % Oxygen

    TmpVar = DutyCycle - 300 'TmpVar = 377 - 300 = 77
    Oxygen = TmpVar * 42 '77 * 42 = 3234 or 3.234% o2
    OxygenTens = Oxygen // 1000
    Oxygen = Oxygen / 1000

    'Scale PWM Output Steps for % of oxygen

    TmpVar = DutyCycle - 300 '377 - 300 = 77
    TmpVar1 = TmpVar // 10 '77 // 10 = Remainder of 7
    TmpVar = TmpVar / 10 '77 / 10 = 7 We loose too much here so get remainder and add back
    TmpVar = TmpVar * 256 '7 * 256 = 1792
    TmpVar1 = TmpVar1 * 256 '7 * 256 = 1792
    TmpVar1 = TmpVar / 10 '1792 / 10 = 179
    TmpVar = TmpVar + TmpVar1 'Add remainder 179 back
    TmpVar = TmpVar / 50 '1971 / 50 = 39 Steps
    Steps = TmpVar

    DoIt:

    PWM VOut1, Steps, PulseLen

    Debug " 02: ", #Oxygen,".",#OxygenTens," Steps: ",#Steps, " Duty: ",#DutyCycle, 13,10
    Toggle LED

    GoTo Loop

  9. #9
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    First some hard facts that need to be understood with a worst-case scenario - that 850Hz PWM...

    The period of 850Hz is 1.17ms (1170uS). The resolution of Pulsin at 4MHz is 10uS. That gives us 117 counts (1170/10) for a 4MHz PIC for 100% input period. But we're only interested in 50% of that (30-80% PWM giving 0-21%O2). That means we've only got a maximum range of 58 steps to play with across the scale. 21%O2 divided by 58 steps gives us a resolution of 0.362% which falls short of your required 0.1%. You can't use a 4MHz PIC if you're playing with Pulsin.

    At 20MHz, Pulsin returns steps of 2uS. That gives us 585 steps for 100% input period, but again we're only interested in 50% of that, so we have 292 steps to play with. 21%O2 divided by 292 steps gives us increments of 0.07% and we're in business to achieve your 0.1% accuracy requirement. So you've got to use a 20MHz PIC if you want to play with Pulsin or use another method of measuring your pulse period.

    Working the figures backwards you can calculate that we need a minimum of 210 counts at 50% Input PWM to maintain 0.1% resolution of 21%O2. 420 counts is 100% multiplied by 2uS (Pulsin resolution at 20MHz) gives you a maximum PWM ceiling of 1190Hz above which we lose 0.1% accuracy in our results. So that is our upper-ceiling for PWM frequency...

    The lower-ceiling is determined by our math... in so far that we must never spill out of a word variable (unless it is a prelude to a DIV32 statement). So let's now plan for a worst-case lower-end scenario say 400Hz PWM...

    400Hz has a period of 2.5mS or a Pulsin period count of 1250 (remember our 2uS count of a 20MHz PIC). We can multiply our Period count by up to 52 times before we spill out of a word, let's say 50 to make the figures nice and easy to play with. We'll call this Melanie's maximum multiplyer (MMM).

    Now having calculated our operational limits we set them aside and start to do some code... remember, we have four possible error conditions that we have to trap before we are confident that everything is going to run smoothly...

    1. Input PWM frequency is under 400Hz
    2. Input PWM frequency is over 1190Hz
    3. Input PWM Percentage exceeds 80% (greater than 21%O2)
    4. Input PWM Percentage is below 30% (less than 0%O2)

    Fist let's get some data... and your code here is fine...

    PulsIn F_pin1, 1, pHigh ' get high portion of input
    PulsIn F_pin1, 0, pLow ' get low portion of input
    Period = pHigh + pLow
    If Period < 420 then goto ErrorPWMtooHigh
    If Period > 1250 then goto ErrorPWMtooLow

    Those two extra lines trap any Period frequency exceptions and make sure the data we're playing with is within our pre-calculated, pre-determined play range. Error conditions 1 & 2 are now accounted for.

    Normally, to get a percentage the formula would be pHigh*100/Period. But we MUST have greater accuracy, preferably to two decimal places if we can get away with it and still NOT spill out of a Word Variable. First we'll deal with Error condition 3 (>80% Input PWM). All Temp (Temporary) variables are WORDS... and notice I avoid integer DIVISION wherever possible to prevent the introduction of math errors...

    TempA = Period*40

    Why 40? If MMM is 50, mutiplying by 40 is the equivallent of a scaled up 80%. Now to continue...

    TempB=pHigh*50
    If TempB > TempA then goto ErrorO2tooHigh

    What the two lines above have done is to trap the error if the input PWM exceeds 80%. Error condition 3 is now accounted for. Finally...

    TempA = Period*15

    Why 15? If MMM is 50, multiplying by 15 is the equivallent of a scaled up 30%. To continue...

    If TempA > TempB then ErrorO2TooLow

    With those lines above we've trapped any possibility of the inputPWM falling below the illegal 30% value... Error condition 4 is now trapped. We can now continue safe in the knowledge that nothing from this point onwards (short of you not paying your electricity bill) can wreck your day... so...

    TempB=TempB-TempA

    Now we've extracted out the bottom 30% leaving a pure input value referenced to zero. Remember TempB at this point has a range from zero (minimum 0%O2) to Period*25 (maximum 21%O2) - that's because 80%-30% equals 50% (our operational span) therefore 25 is 50% of our MMM.

    Now we need to produce a 0-100% PWM Output value for your 0-5v Output...

    TempA=Period*25

    Notice that TempA will always be a 15 bit unsigned integer satisfying the requirement of the DIV32 divisor...

    TempC=TempB*100
    TempD=DIV32 TempA

    TempD at this point is a WORD value ranging from 0-100 which can be used for your PWM Output (use Hardware PWM in preference rather than software PWM because the software PWM requires constant polling otherwise it will decay).

    If you need a whole BYTE (0-255) value for TempD representing 0-100% PWM then simply do this instead...

    TempC=TempB*255
    TempD=DIV32 TempA

    Finally say we need to produce a 0-21.00% LCD Output as well (to two decimal places)...

    TempC=TempB*2100
    TempE=DIV32 TempA
    LCDOut #TempE/100,".",#TempE DIG 1,#TempE DIG 0

    And note the above LCDOut line is the only place we've used an integer divide. Errors at a minimum, accuracy at a maximum.

    Clear as the driven slush...

    Melanie

  10. #10
    rwskinner's Avatar
    rwskinner Guest


    Did you find this post helpful? Yes | No

    Default

    Thanks Melanie, It seems to work fine after a minor modification. It was reading backwards so I changed:

    TempB = pHigh * 50 to

    TempB = pLow * 50

    and it's working. I have to study the math. You gave good explanations which each and I "Really" do appreciate the help.
    I just want to make sure I understand each step because I haven't ever used the Div32 before.

    How bad is it going to screw things up when I put a calibrate routine in there.

    Say for example, when clean air calibrating, 21% o2 actually is 83% duty cycle. I can subtract 50 from the reading and save that as a base subtract value right. In other words, simply subtract 33 instead of 30 from the duty cycle, hum, that doesn't look right.....

  11. #11
    Join Date
    Jul 2003
    Posts
    2,358


    Did you find this post helpful? Yes | No

    Default

    How does your Calibration affect the operation... does it...

    Say clean Air is 83%...

    (a) Change the SIZE of the span (eg 0%O2 is still 30% but 21%O2 is now 83%, so the span is now 53%), or...

    (b) Change the REFERENCE of the Span (eg 0%O2 is 33% and 21%O2 is 83%, so you still have 50% total span, but the Reference has moved).

    and Finally...

    What is the maximum Calibration deviation you are likely to encounter?

  12. #12
    rwskinner's Avatar
    rwskinner Guest


    Did you find this post helpful? Yes | No

    Default

    I suspect the range moves to 33 to 83% but Honestly I'm not sure so I'll have to run more test with the sensor and remote computer.

    The manufacturer only states, valid data is represented with a duty cycle of 30 to 80% which porportonal to the percent of oxygen.

    We are tapping into the signal of a 02 sensor tied into an onboard engine control computer and transmitting the information via satellite to our terminal. We are trying to have our display read the same as the onboard computers display.

    How the onboard computer calibrates..... Actual details totally unknown. We know that when it "does" calibrate, it's done by pressing a button while in clean air (21%) and it sits there for 2 minutes, then exits calibration mode. At that point, their display then shows 21%.

    Our plans were to tie into their button, wait the two minutes, then also record the high range so we are calibrated the same.

    We know that it can't simulate 0% Oxygen and it's only looking at Clean Air at 21%, waits 2 minutes for the sensor to settle.

    Guessing, it's storing the max value and adjusting it to 21% however I will need to run several more test to see how it's output matchs a graph to be sure.

    I justed tested a sensor that was actually installed and noticed 40.1% dc = 6.95% o2, which does not follow our chart, however I know for a fact that the sensor was not in "pure" clean air when it was calibrated so it is off.

    Even though that is the case, we need to be off the same amount so we see the same reading as the onboard computer.

    At this point, it would be best for me to take even more readings with my frequency meter during a calibration process to see how much the signal actually varies and then go from there.

Similar Threads

  1. Variable PWM PIC18F2431
    By trr1985 in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 12th June 2009, 06:03
  2. Replies: 9
    Last Post: - 8th October 2008, 11:15
  3. PWM PIN(S), DUTY, CYCLE ?Plural possible?
    By earltyso in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 17th November 2007, 20:41
  4. HPWM the old fashioned way
    By Srigopal007 in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 19th November 2004, 19:09
  5. Duty Cycle Dilemmas
    By crankshaft in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 27th February 2003, 12:40

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts