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

    since I might have to change that constant of 39332, how did you arrive at that value?

  2. #2


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    Your formula works, Henrik - not that should come as a surprise. Knowing how you arrived at that constant in the expression would help me me adjust for different resolutions.

    Here's the code I used to test Henrik's formula:

    Code:
    #DEFINE USE_LCD_FOR_DEBUG   ; comment out for non-debug use
       
    ' ***************************************************************
    ' Pin Connections
    ' ***************************************************************
    
    ' Vdd      -> pin 1         -> +5V   
    ' RC4/Tx   -> pin 6         -> EUSART transmit (LCD)
    ' RA1      -> pin 12        -> trim pot input
    ' Vss      -> pin 14        -> GND
       
    DEFINE OSC 16               ; Set oscillator 16Mhz
    
    DEFINE HSER_TXSTA   20h     ; Set transmit status and control register
    DEFINE HSER_BAUD    2400    ; Set baud rate
                                   
    ' ***************************************************************
    ' Device Fuses
    ' ***************************************************************
    
    #CONFIG
       __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
       __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF
    #ENDCONFIG
    
    ' ***************************************************************
    ' Initialization
    ' ***************************************************************
    
    OSCCON    = %01111000       ; 16MHz internal osc
    
    APFCON0.2 = 0               ; Tx on RC4 for LCD display
    APFCON0.7 = 0               ; Rx on RC5
    
    BAUDCON.4 = 1               ; Transmit inverted data to the Tx pin
    
    ANSELC    = 0               ; Digital only for all PortC pins
    TRISC     = 0               ; Make all PORTC pins output
    
    TRISA     = %00000010	    ; Make all pins output except for RA1 (trim pot input)
    ANSELA    = %00000010       ; Analog on PORTA.1 (AN1) only
    
    FVRCON    = 0               ; Fixed Voltage Reference is disabled
    ADCON0    = %00000101       ; ADC enabled on AN1 (RA1) only; ADC conversion enabled
    PAUSEUS 20                  ; wait for the analog switch 'glitch' to die down
    ADCON1    = %00110000       ; Left-justified results in 8-bits; Frc as timer
     
    #IFDEF USE_LCD_FOR_DEBUG
        LCD_INST   CON 254       ' instruction
        LCD_CLR    CON 1         ' Clear screen
        LCD_L1     CON 128       ' LCD line 1
        LCD_L2     CON 192       ' LCD line 2
    #ENDIF
    
    MotorDuty   VAR BYTE        ; Actual duty cycle for motor
    ADCInVal    VAR BYTE        ; stores ADCIN result read from trim pot
    MinDuty     CON 100         ; Minimum speed to rotate motor for this application
                                                                  
    Main:
        gosub Do_ADC
        pause 100
        GOSUB Map_ADC_Val_to_PWM_Duty
     
    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
        MotorDuty = (ADCInVal ** 39322) + MinDuty  ' Same as 100 + ADCInValue * 0.600006 but likely faster than 100+ADCInValue*6/10
        
        #IFDEF USE_LCD_FOR_DEBUG
            HSEROUT [LCD_INST, LCD_CLR]
            pause 5
    '        HSEROUT ["ADCInVal=", DEC ADCInVal, "       ", 13, 10] ; Send text followed by carriage return and linefeed
            HSEROUT ["ADCInVal=", DEC ADCInVal, "       ", 13, 10, "MotorDuty=", DEC MotorDuty]
    '        pause 5
    '        HSEROUT ["MotorDuty=", DEC MotorDuty, "       "] ; Send text followed by carriage return and linefeed
        #ENDIF
    
        RETURN
    Here's the annoying part - no matter how many searches I do here I can't find the syntax to print on the 2nd line of the LCD. With the above the screen just seems to flicker (which also doesn't make sense - with the ADC method here it usually results in a rock-solid value; in other words, it doesn't change until I actually move the wiper arm. I know it's unrelated to the original post, but any ideas?

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    Hi,
    Think of the ** operator as multiplying by units of 1/65536. 0.6*65536=39322.

    As for printing to second line of the LCD you're obviously using some sort of serial interface display(?) which I know nothing about but if I'd make a guess based on your defined constants you'd do something like
    Code:
    HSEROUT[LCD_INST, LCD_L2, "2d Line"]
    /Henrik.

  4. #4


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    Thanks Henrik. You'd think I would have noticed that constant. Changing the HSEROUT to this:

    Code:
    #DEFINE USE_LCD_FOR_DEBUG   ; comment out for non-debug use
    
    ' ***************************************************************
    ' Pin Connections
    ' ***************************************************************
    
    ' Vdd      -> pin 1         -> +5V   
    ' RC4/Tx   -> pin 6         -> EUSART transmit (LCD)
    ' RA1      -> pin 12        -> trim pot input
    ' Vss      -> pin 14        -> GND
       
    DEFINE OSC 16               ; Set oscillator 16Mhz
    
    DEFINE HSER_TXSTA   20h     ; Set transmit status and control register
    DEFINE HSER_BAUD    2400    ; Set baud rate
                                   
    ' ***************************************************************
    ' Device Fuses
    ' ***************************************************************
    
    #CONFIG
       __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
       __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF
    #ENDCONFIG
    
    ' ***************************************************************
    ' Initialization
    ' ***************************************************************
    
    OSCCON    = %01111000       ; 16MHz internal osc
    
    APFCON0.2 = 0               ; Tx on RC4 for LCD display
    APFCON0.7 = 0               ; Rx on RC5
    
    BAUDCON.4 = 1               ; Transmit inverted data to the Tx pin
    
    ANSELC    = 0               ; Digital only for all PortC pins
    TRISC     = 0               ; Make all PORTC pins output
    
    TRISA     = %00000010	    ; Make all pins output except for RA1 (trim pot input)
    ANSELA    = %00000010       ; Analog on PORTA.1 (AN1) only
    
    FVRCON    = 0               ; Fixed Voltage Reference is disabled
    ADCON0    = %00000101       ; ADC enabled on AN1 (RA1) only; ADC conversion enabled
    PAUSEUS 20                  ; wait for the analog switch 'glitch' to die down
    ADCON1    = %00110000       ; Left-justified results in 8-bits; Frc as timer
     
    #IFDEF USE_LCD_FOR_DEBUG
        LCD_INST   CON 254       ' instruction
        LCD_CLR    CON 1         ' Clear screen
        LCD_L1     CON 128       ' LCD line 1
        LCD_L2     CON 192       ' LCD line 2
    #ENDIF
    
    MotorDuty   VAR BYTE        ; Actual duty cycle for motor
    ADCInVal    VAR BYTE        ; stores ADCIN result read from trim pot
    MinDuty     CON 100         ; Minimum speed to rotate motor for this application
                                                                  
    Main:
        gosub Do_ADC
        pause 100
        GOSUB Map_ADC_Val_to_PWM_Duty
     
    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
        MotorDuty = (ADCInVal ** 39322) + MinDuty  ' Same as 100 + ADCInValue * 0.600006 but likely faster than 100+ADCInValue*6/10
        
        #IFDEF USE_LCD_FOR_DEBUG
            HSEROUT [LCD_INST, LCD_CLR]
            pause 5
    '        HSEROUT ["ADCInVal=", DEC ADCInVal, "       ", 13, 10] ; Send text followed by carriage return and linefeed
            HSEROUT ["ADCInVal=", DEC ADCInVal, "       ", LCD_L2, "MotorDuty=", DEC MotorDuty, "       ", 13, 10]
    '        pause 5
    '        HSEROUT ["MotorDuty=", DEC MotorDuty, "       "] ; Send text followed by carriage return and linefeed
        #ENDIF
    
        RETURN
    I can now see the 2nd line, but it's not starting at the first character position and there's a weird character there before 'MotorDuty'. It might be related to the spaces after the first line, but I'm not sure. Also, the first line seems to be refreshing/fluttering even when I'm not moving the trim pot. I have to admit, I use my serial LCD so infrequently that I'm a noobie where it comes to this.

    Here's a video of what the screen looks like.

  5. #5
    Join Date
    May 2013
    Location
    australia
    Posts
    2,645


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    try
    HSEROUT ["ADCInVal=", DEC ADCInVal, " ", LCD_INST,LCD_L2, "MotorDuty=", DEC MotorDuty, " ",13,10]




  6. #6


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    I used the HSEROUT line exactly as above and when I turn on the power:

    Name:  IMG_3667.JPG
Views: 1257
Size:  109.9 KB

    Then, as I turn the trim pot wiper:

    Name:  IMG_3669.JPG
Views: 1262
Size:  113.4 KB

    The serial LCD is 2400 baud by default and that's what I have set in code, but maybe there's some timing issues?

  7. #7


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    If I'm using a PIC16F1825 how do I know whether to use the USART or EUSART settings from Mister E's PIC Multi-Calc application? This is what I have set currently:

    Code:
    DEFINE OSC 16               ; Set oscillator 16Mhz
    
    DEFINE HSER_TXSTA   20h     ; Set transmit status and control register
    DEFINE HSER_BAUD    2400    ; Set baud rate
    DEFINE HSER_CLROERR 1
    
    OSCCON    = %01111000       ; 16MHz internal osc
    
    PAUSE 100
    
    APFCON0.2 = 0               ; Tx on RC4 for LCD display
    APFCON0.7 = 0               ; Rx on RC5
    
    BAUDCON.4 = 1               ; Transmit inverted data to the Tx pin
    I see that Mister E's app doesn't use DEFINE HSER_BAUD. For USART I get:

    Code:
    DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
    DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
    DEFINE HSER_SPBRG 103 ' 2400 Baud @ 16MHz, 0.17%
    DEFINE HSER_CLROERR 1 ' Clear overflow automatically
    For EUSART:

    Code:
    DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
    DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
    DEFINE HSER_CLROERR 1 ' Clear overflow automatically
    DEFINE HSER_SPBRG 130 ' 2400 Baud @ 16MHz, 0.0%
    SPBRGH = 6
    BAUDCON.3 = 1         ' Enable 16 bit baudrate generator
    Which should I use? And should I continue to use DEFINE HSER_BAUD which I think I got from this board a ling time ago?

  8. #8
    Join Date
    May 2013
    Location
    australia
    Posts
    2,645


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    either setting will work the 0% error eusart option is probably best ,
    if you set the baudrate regs manually ie
    DEFINE HSER_SPBRG 130 ' 2400 Baud @ 16MHz, 0.0%/SPBRGH = 6
    or
    DEFINE HSER_SPBRG 103 ' 2400 Baud @ 16MHz, 0.17%

    then DEFINE HSER_BAUD should not be used ,it may cause your setting to be overwritten

    ps
    baudrate error is not your display problem, you need to find out
    1. how to initialise your display and how long it takes to happen
    2. how to send control codes to the display ( seems $fe is not correct)

    do you have any docs for the display / or a model no ?

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