Scaling ADC Result to a Set Range


Closed Thread
Results 1 to 40 of 45

Hybrid View

  1. #1


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    I found the math behind the Arduino map function and have replicated it in a subroutine in PBP:

    Code:
    PR2     = 62                ; For 16Mhz OSC the desired output freq of 15,873Hz is
                                ; achieved with this PR2 value (8-bit resolution
                                ; with 1:4 prescaler)
                                
                                ; PWM freq must be ~ 16-20kHz to reduce noise
    MinDuty     CON 100         ; Minimum speed to rotate motor for this application
    MaxDuty     VAR WORD        ; According to Darrel:
                                ;   MaxDuty = (PR2 + 1) * 4
    
    MaxDuty = (PR2 + 1) * 4     ; 252 but with prescaler resolution it's actually 250
    MotorDuty   VAR WORD        ; Actual duty cycle for motor
    MaxADCVal   CON 255         ; 255 for 8-bit; 1023 for 10-bit
    ADCInVal    VAR BYTE        ; stores ADCIN result read from trim pot
    compVal     VAR BYTE        ; stores last-changed ADC value
    
    Main:
        gosub Do_ADC
        pause 100
    
        If ADCInVal <> compVal Then
            #IFDEF USE_LCD_FOR_DEBUG
                HSEROUT [LCD_INST, LCD_CLR]
                pause 5
                HSEROUT ["new ADCInVal=", DEC ADCInVal, "       ", 13, 10] ; Send text followed by carriage return and linefeed
            #ENDIF
            
            GOSUB Map_ADC_Val_to_PWM_Duty
            gosub ChngMotorHPWM
            compVal = ADCInVal
        endif
    
     
    GOTO Main
    
    Do_ADC:
        PAUSEUS 50              ' Wait for A/D channel acquisition time
        ADCON0.1 = 1            ' Start conversion
        
        WHILE ADCON0.1 = 1      ' Wait for it to complete
        WEND
    
        ADCInVal = ADRESH
    
        return
    
    Map_ADC_Val_to_PWM_Duty:
    '   Arduino Map function to emulate:
    '   ===============================
    '   map(value, fromLow, fromHigh, toLow, toHigh)
    
    '   long map(long x, long in_min, long in_max, long out_min, long out_max)
    '   {
    '     return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    '   }
    
        MotorDuty = (ADCInVal - 0) * (MaxDuty - MinDuty)/(MaxADCVal - 0) + MinDuty
    
        #IFDEF USE_LCD_FOR_DEBUG
            HSEROUT [LCD_INST, LCD_CLR]
            pause 5
            HSEROUT ["MotorDuty=", DEC MotorDuty, "       ", 13, 10] ; Send text followed by carriage return and linefeed
            pause 1500
            HSEROUT [LCD_INST, LCD_CLR]
        #ENDIF
    
        RETURN
    It doesn't look like this is working as expected - any ideas?

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,627


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    Hi,
    I don't know exactly how you expect it to work but if Iäm not mistaken your formula, when re-written looks like:
    Code:
    MotorDuty = ADCInVAL * 252 / 255 + 100
    When ADCInVal = 1 Motor Duty will be 100
    When ADCInVAL = 255 MotorDuty will be 352

    Is that what you're seeing?

    /Henrik.

  3. #3
    Join Date
    May 2013
    Location
    australia
    Posts
    2,721


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    (MaxDuty - MinDuty) would be 250(2)-100= 150

    this would make more sense if your pwm value is a byte
    it now becomes
    Code:
    MotorDuty = ADCInVAL */ 150(2) + 100

    not knowing whats in the sub ChngMotorHPWM

    snippets lead to speculation

  4. #4


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    I'm using 8-bit resolution for PWM so it should be a byte but I have the variable defined as WORD in case the math takes it over 255:

    Code:
    MotorDuty   VAR WORD        ; Actual duty cycle for motor
    
    ChngMotorHPWM:
    
        CCP3CON.4 = MotorDuty.0
        CCP3CON.5 = MotorDuty.1
        CCPR3L    = MotorDuty >> 2
    
        CCP4CON.4 = MotorDuty.0
        CCP4CON.5 = MotorDuty.1
        CCPR4L    = MotorDuty >> 2
        
        RETURN
    Do you think the issue would be resolved if I change the datatype of MotorDuty to BYTE? I was also thinking I might switch to 10-bit resolution for both ADC and PWM to get the finest grain control of the motor speed, but that may be overkill.

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,627


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    > Do you think the issue would be resolved....

    What issue? What exactly is it that doesn't work the way you expect? What do you expect and what does it do?

    75% dutycycle (8bit resolution) +/-25% from an 8bit ADC readin:
    Code:
    PWMDuty = 191 + (64 - ADCValue >> 1)
    191 is 75% of 255, your initial PWM duty cycle. When ADCvalue (BYTE) is 0 PWMDuty (BYTE) will be 255=100%. When ADCValue is 255 PWMDuty will be 127=50%.

    /Henrik.

    /Henrik.

  6. #6


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    The goal is to scale the ADC values of 0-255 to a range of duty cycles appropriate for my project (100-252 with the chosen prescaler). If I manually calculate the results are correct:
    • ADCInVal =0 yields 100
    • ADCInVal=127 yields 175
    • ADCinVal=255 yields 252

    But perhaps I don't have the order right in the expression because I don't see those results with the above code.

  7. #7


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    from excel chart, multiply adc val by .6 and add 100........ but can't mult decimal so multiply by 6 then divide by 10 then add 100
    Attached Images Attached Images  
    Last edited by amgen; - 29th October 2015 at 21:03.

Similar Threads

  1. Replies: 4
    Last Post: - 27th January 2015, 15:34
  2. Replies: 4
    Last Post: - 30th May 2012, 08:28
  3. Converting 10bit ADC result to 8 bit
    By jmgelba in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 5th March 2012, 20:38
  4. strange A2D 5V scaling result - 16F819
    By Max Power in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 8th April 2010, 02:28
  5. Scaling ADC values
    By purkolator in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 29th November 2007, 05:14

Members who have read this thread : 0

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