Scaling ADC Result to a Set Range - Page 2


Closed Thread
Page 2 of 2 FirstFirst 12
Results 41 to 45 of 45
  1. #41


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    Quote Originally Posted by richard View Post
    for what its worth I tried your code cleaned up a bit and slightly changed to suit a 16f1825
    and it works perfectly with nice steady results , could you have a noisy pot or power supply ?


    Code:
    '****************************************************************
    '*  Name    : Nacelle_Steady-On_Lights_12F1840_16Mhz_Int.pbp    *
    '*  Author  : Ross A. Waddell                                   *
    '*  Notice  : Copyright (c) 2016                                *
    '*          : All Rights Reserved                               *
    '*  Date    : 02/02/2016                                        *
    '*  Version : 1.0                                               *
    '*  Notes   : Steady-on nacelle engine lights (TOS Enterprise)  *
    '*          :                                                   *
    '****************************************************************
    #CONFIG
                 __config        _CONFIG1,    _FOSC_INTOSC & _CP_OFF & _WDTE_ON  &  _PWRTE_ON  &  _MCLRE_ON  & _CLKOUTEN_OFF
                  __config      _CONFIG2, _PLLEN_ON & _LVP_OFF            
    #ENDCONFIG
     
    OSCCON=$70 
    DEFINE OSC 32
    
    ANSELA    = %00001000        ; Analog on PORTA.4(AN3) only
    
    ADCON1    = %10100000        ; Right-justified results in 10-bits; Fosc/32 as timer;
                                 ; VREF is connected to VDD
    
    TRISA     = %111110	     ' Make all pins input except for RA0 (ser out)
    trisc=   %11011111                            '  ccp1
    
    ADCInVal       VAR WORD      ; stores ADCIN result read from trim pot
    LEDBrVal       VAR WORD
    FadeInPause    CON 25        ; Pause during LED fade in
    
    i              VAR WORD
    
    ' ***************************************************************
    ' Set up PWM on CCP1
    ' ***************************************************************
    
    CCP1CON = %00001100          ; Use CCP1 in PWM mode
    
    ' Set duty cycle registers initially to 0
    CCP1CON.4 = 0
    CCP1CON.5 = 0
    CCPR1L    = 0
     lata.0=1
     pause 2000
    ' ************************
    ' CCP1 uses TMR2
    ' ************************
                           
    T2CON   = %00000110         ; Timer2 on with 1:16 prescaler
    PR2     = 255               ; For 16Mhz OSC the desired output freq of 976.563Hz
                                ; is achieved with this PR2 value (10-bit resolution
                                ; with 1:16 prescaler)
                                
    MaxDuty       VAR WORD      ; According to Darrel:
                                ;   MaxDuty = (PR2 + 1) * 4
    
    MaxDuty = (PR2 + 1) * 4     ; 1024
    MinDuty       CON 0         ; Minimum brightness for this application
    MaxADCVal     CON 1023      ; 255 for 8-bit; 1023 for 10-bit
    compVal       VAR WORD      ; stores last-changed ADC value
    
    
    CounterA      var BYTE		' Just a BYTE Temporary working variable
    DataW         var WORD		' Just a WORD Temporary working variable
    RawData       var WORD [16]	' Array holding ADC Result
    
    
     serout2 PORTA.0,84, ["ready",13,10 ]
    
    
    
    GOSUB DO_ADCIN_Chk
    LEDBrVal = ADCInVal
    compVal = LEDBrVal
    
    FOR i = 0 to LEDBrVal
        CCP1CON.4 = i.0
        CCP1CON.5 = i.1
        CCPR1L    = i >> 2 
                
        pause FadeInPause
    
      
    NEXT i
    
    
    Main:
        GOSUB DO_ADCIN_Chk
        PAUSE 100
    
        IF ADCInVal <> compVal THEN
        
            LEDBrVal = ADCInVal
            compVal = LEDBrVal
            gosub ChngLEDBrightness
        ENDIF
    GOTO Main
    
    '*********** Read ADC or USART Rc inputs *******************************
    Do_ADCIN_Chk:
    '	Stuff 16 Element WORD Array full of ADC values
    '	----------------------------------------------
    	For CounterA=0 to 15
            ADCON0    = %00001101 ' Select Channe3, Turn-On A/D
    	
    		Pauseus 50			     ' Wait for channel to setup
            ADCON0.1 = 1			 ' Start conversion
    		While ADCON0.1=1:Wend	 ' Wait for conversion
    		DataW.HighByte=ADRESH	 ' Read variable from ADC and save
    		DataW.LowByte=ADRESL
    		RawData(CounterA)=DataW
    	Next CounterA
    
    '	Sort ADC Input
    '	--------------
    	CounterA=0
        GetADCSortLoop:
    	If RawData(CounterA+1) < RawData(CounterA) then
    		DataW=RawData(CounterA)
    		RawData(CounterA)=RawData(CounterA+1)
    		RawData(CounterA+1)=DataW
    		If CounterA>0 then CounterA=CounterA-2
    	endif
    	CounterA=CounterA+1
    	If CounterA < 15 then goto GetADCSortLoop
    
    '	Quanticise, discarding top and bottom FOUR elements
    '	----------------------------------------------------
    	DataW=0
    	For CounterA=4 to 11
    		DataW=DataW+RawData(CounterA)
    	Next CounterA
    	ADCInVal=DataW>>3			' Divide Result by EIGHT
    
         serout2 PORTA.0,84, ["adc ",#ADCInVal,13,10 ]
    
    return
    
    
    '*********** Set duty registers ****************************************
    ChngLEDBrightness:
        CCP1CON.4 = LEDBrVal.0
        CCP1CON.5 = LEDBrVal.1
        CCPR1L    = LEDBrVal >> 2
        
    RETURN
    The 5V voltage regulator is a linear switching one from Pololu and the voltmeter output looks rock solid. It could be the pot, though - it's a sliding one from Sparkfun. i'll try with a traditional trim pot and see if it behaves any different.

    EDIT: just tried a trim pot that has previously worked fine and the same thing is happening. Am I doing anything wrong with the 10-bit ADC aspect? Could it be the PIC itself?
    Last edited by RossWaddell; - 18th February 2016 at 03:11.

  2. #42


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    Switched to using a 16F1825 that was previously rock solid and it's still jumping around like crazy. Could it be this 5V switching voltage regulator? This code was what I used previously to test 10-bit ADC and is what I just loaded onto the 16F1825:

    Code:
    ' ****************************************************************
    ' PIC16F1825
    ' ****************************************************************
    
    #DEFINE USE_LCD_FOR_DEBUG   ; comment out for non-debug use
    
    ' Vdd      -> pin 1         -> +5V   
    ' RC5/Rx   -> pin 5         -> EUSART receive
    ' RC4/Tx   -> pin 6         -> EUSART transmit (LCD)
    ' RA1      -> pin 12        -> trim pot input (1 uF electrolytic cap?)
    ' Vss      -> pin 14        -> GND
       
    DEFINE OSC 16               ; Set oscillator 16Mhz
    
    ' ***************************************************************
    ' EUSART Settings for Tx/Rc (e.g. LCD)
    ' ***************************************************************
    
    ' > use Mister E PIC Multi-Calc application to get register/DEFINE settings
    ' > as the values are dependent on the OSC and desired baud rate
    
    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 160      ' 9600 Baud @ 16MHz, -0.08%
                                   
    ' ***************************************************************
    ' 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
    pause 100
    
    APFCON0.2 = 0               ; Tx on RC4 for LCD display
    APFCON0.7 = 0               ; Rx on RC5
    
    ' Some LCD serial modules need inverted data, some do not
    ' Enable the line below if needed, but for SparkFun SerLCD it should be
    ' commented out
    
    'BAUDCON.4 = 1               ; Transmit inverted data to the Tx pin  
    
    ' From Mister E's Multi-Calc (EUSART):
    ' *****************************************************************
    SPBRGH    = 1
    BAUDCON.3 = 1               ' Enable 16 bit baudrate generator
    ' *****************************************************************
    
    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    = %10010000       ; Right-justified results in 10-bits; Fosc/8 as timer
    
    #IFDEF USE_LCD_FOR_DEBUG
    '   Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395)
    '   (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf' 
    '   for list of control codes)
        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
        LCD_BR_CMD CON 124       ' command character for adjusting backlight brightness
        LCD_BR_LVL CON 140       ' 140==40%
    #ENDIF
    
    ' Should only need to do this one time to adjust backlight brightness
    '#IFDEF USE_LCD_FOR_DEBUG
    '    HSEROUT [LCD_BR_CMD, LCD_BR_LVL]
    '    PAUSE 5
    '#ENDIF
    
    #IFDEF USE_LCD_FOR_DEBUG
        pause 1000
        HSEROUT [LCD_INST, LCD_CLR, "LCD Init"]
        pause 5
        HSEROUT [LCD_INST, LCD_L2, "SerLCD_V2_5"]
        pause 500
    #ENDIF
    
    ADCInVal       VAR WORD      ; stores ADCIN result read from trim pot
    compVal        VAR WORD      ; stores last-changed ADC value
    
    GOSUB Do_ADC
    compVal = ADCInVal           ; set initial compare value
     
    #IFDEF USE_LCD_FOR_DEBUG
        HSEROUT [LCD_INST, LCD_CLR]
        pause 5
        HSEROUT ["ADCInVal=",DEC ADCInVal,"  "]
        pause 500
    #ENDIF
                                                               
    Main:
        gosub Do_ADC
        pause 100
    
        If (compVal > (ADCInVal + 1)) or (compVal < (ADCInVal - 1)) THEn
            ' If this method of reading ADC is as rock-solid as it appears.
            ' then I can remove the +/- 1 before doing anything; it would be
            ' IF ADCInVal <> compVal
            
            ' DO SOMETHING HERE        
            compVal = ADCInVal
            
            #IFDEF USE_LCD_FOR_DEBUG
                HSEROUT [LCD_INST, LCD_CLR]
                pause 5
                HSEROUT ["new ADCInVal", LCD_INST, LCD_L2, DEC ADCInVal, "  "]
            #ENDIF
        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.HighBYTE = ADRESH
        ADCInVal.LOWBYTE = ADRESL
    return
    EDIT: Tried the standard 7805 voltage reg approach and it's more stable but still jumps around by 3-4. Could it be the settings for my serial LCD on EUSART Tx?
    Last edited by RossWaddell; - 19th February 2016 at 00:17.

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


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    I 'm using a pickit2 to power this test so an 0,1 are unavailable (used by pickit) so I changed code to use an3
    and debug via serout . needless to say it works just fine.

    you may need an oscilloscope to look at your an input and power supply for noise (dvm's won't do it)
    have you installed bypass caps on the regulator input/output and the pic vdd pin ?
    a bit of c across the pot wiper to gnd won't hurt either


    Code:
    ' ****************************************************************
    ' PIC16F1825
    ' ****************************************************************
    ;#DEFINE USE_LCD_FOR_DEBUG   ; comment out for non-debug use
    ' Vdd      -> pin 1         -> +5V   
    ' RC5/Rx   -> pin 5         -> EUSART receive
    ' RC4/Tx   -> pin 6         -> EUSART transmit (LCD)
    ' RA1      -> pin 12        -> trim pot input (1 uF electrolytic cap?)
    ' Vss      -> pin 14        -> GND
       
    DEFINE OSC 16               ; Set oscillator 16Mhz
    ' ***************************************************************
    ' EUSART Settings for Tx/Rc (e.g. LCD)
    ' ***************************************************************
    ' > use Mister E PIC Multi-Calc application to get register/DEFINE settings
    ' > as the values are dependent on the OSC and desired baud rate
    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 160      ' 9600 Baud @ 16MHz, -0.08%
                                   
    ' ***************************************************************
    ' Device Fuses
    ' ***************************************************************
    #CONFIG
       __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _CPD_OFF
       __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF
    #ENDCONFIG
    ' ***************************************************************
    ' Initialization
    ' ***************************************************************
    OSCCON    = %01111000       ; 16MHz internal osc
    pause 100
    APFCON0.2 = 0               ; Tx on RC4 for LCD display
    APFCON0.7 = 0               ; Rx on RC5
    ' Some LCD serial modules need inverted data, some do not
    ' Enable the line below if needed, but for SparkFun SerLCD it should be
    ' commented out
    'BAUDCON.4 = 1               ; Transmit inverted data to the Tx pin  
    ' From Mister E's Multi-Calc (EUSART):
    ' *****************************************************************
    SPBRGH    = 1
    BAUDCON.3 = 1               ' Enable 16 bit baudrate generator
    ' *****************************************************************
    ANSELC    = 0               ; Digital only for all PortC pins
    TRISC     = 0               ; Make all PORTC pins output
    ANSELA    = %00001000        ; Analog on PORTA.4(AN3) only
    ADCON1    = %10100000        ; Right-justified results in 10-bits; Fosc/32 as timer;
                                 ; VREF is connected to VDD
    TRISA     = %111110      ' Make all pins output except for RA1 (trim pot input)
    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    = %10010000       ; Right-justified results in 10-bits; Fosc/8 as timer
    #IFDEF USE_LCD_FOR_DEBUG
    '   Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395)
    '   (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf' 
    '   for list of control codes)
        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
        LCD_BR_CMD CON 124       ' command character for adjusting backlight brightness
        LCD_BR_LVL CON 140       ' 140==40%
    #ENDIF
    ' Should only need to do this one time to adjust backlight brightness
    '#IFDEF USE_LCD_FOR_DEBUG
    '    HSEROUT [LCD_BR_CMD, LCD_BR_LVL]
    '    PAUSE 5
    '#ENDIF
    #IFDEF USE_LCD_FOR_DEBUG
        pause 1000
        HSEROUT [LCD_INST, LCD_CLR, "LCD Init"]
        pause 5
        HSEROUT [LCD_INST, LCD_L2, "SerLCD_V2_5"]
        pause 500
    #ENDIF
    ADCInVal       VAR WORD      ; stores ADCIN result read from trim pot
    compVal        VAR WORD      ; stores last-changed ADC value
    GOSUB Do_ADC
    compVal = ADCInVal           ; set initial compare value
     
    #IFDEF USE_LCD_FOR_DEBUG
        HSEROUT [LCD_INST, LCD_CLR]
        pause 5
        HSEROUT ["ADCInVal=",DEC ADCInVal,"  "]
        pause 500
    #ENDIF
    
     lata.0=1
     pause 2000
     serout2 PORTA.0,84, ["ready",13,10 ] 
                                                              
    Main:
        gosub Do_ADC
        pause 100
        If (compVal > (ADCInVal + 1)) or (compVal < (ADCInVal - 1)) THEn
            ' If this method of reading ADC is as rock-solid as it appears.
            ' then I can remove the +/- 1 before doing anything; it would be
            ' IF ADCInVal <> compVal
            
            ' DO SOMETHING HERE        
            compVal = ADCInVal
            
            #IFDEF USE_LCD_FOR_DEBUG
                HSEROUT [LCD_INST, LCD_CLR]
                pause 5
                HSEROUT ["new ADCInVal", LCD_INST, LCD_L2, DEC ADCInVal, "  "]
            #ENDIF
            
            
        endif
     
    GOTO Main
    Do_ADC:
        ADCON0    = %00001101 ' Select Channel 3, Turn-On A/D
        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.HighBYTE = ADRESH
        ADCInVal.LOWBYTE = ADRESL
        
         serout2 PORTA.0,84, ["adc ",#ADCInVal,13,10 ]
        
    return
    Last edited by richard; - 19th February 2016 at 01:01. Reason: typo

  4. #44


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    At 8-bit ADC it works much better; very little (if any) variation. Since I only need to adjust the brightness between 75-100% maybe 8-bit will be OK.

  5. #45


    Did you find this post helpful? Yes | No

    Default Re: Scaling ADC Result to a Set Range

    Could the 0.1uF cap across Vdd/GND have an effect here? I just swapped out the one on the breadboard for another and now the readings seem stable.

Similar Threads

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

Members who have read this thread : 2

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