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

    Thanks Henrik! I'll try that tonight.

  2. #2


    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?

  3. #3


    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?

  4. #4
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,604


    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.

  5. #5


    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.

  6. #6
    Join Date
    May 2013
    Location
    australia
    Posts
    2,631


    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]




  7. #7


    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: 1238
Size:  109.9 KB

    Then, as I turn the trim pot wiper:

    Name:  IMG_3669.JPG
Views: 1242
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?

  8. #8


    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?

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