Help needed with ADCIN Averaging Routine


Closed Thread
Results 1 to 5 of 5
  1. #1
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    166

    Default Help needed with ADCIN Averaging Routine

    Hi All,

    My latest project is a temperature controlled switch using PIC16F684 and an LM35DZ.
    The LM35DZ output is 10mV per degree celcius. The routine is designed such that a relay is energised when the ambient temperature exceeds a pre-set temperature. The relay is de-energised once the ambient temperature drops below the pre-set temperature (less 1 degree hysteresis to stop relay chatter). All works well with my code for a short period of time (5-10 minutes) but then something strange happens with the display temperature - the temperature displays a random value (eg 4.7) instead of the correct value (eg 25.0) even though the voltage at the ADC input pin is correct (eg 250mV).

    To help stabilise the result from the LM35DZ output I averaged 1000 samples in a While...Wend loop. I suspect the problem I am experiencing has something to do with this averaging routine, and I have been over it a dozen times, but I can't work out what goes wrong. As stated above, the routine works for a period of time but then falls over. I am investigating an alternate averaging routine but for my own sanity I need to find out why this routine fails after a short time. My code is as follows:


    Code:
    '****************************************************************
    '*  Name    : TempCont.pbp                                      *
    '*  Author  : Barry Phillips                                    *
    '*  Notice  : Copyright (c) 2012 Baztronics                     *
    '*          : All Rights Reserved                               *
    '*  Date    : 16/12/2012                                        *
    '*  Version : 1.0                                               *
    '*  Notes   : Temperature Controlled Switch                     *
    '*          :                                                   *
    '****************************************************************
    ' PicBasic Pro program to display temperature from LM35DZ with
    ' 10-bit A/D conversion on LCD using PIC16F684 and switch relay on
    ' if ambient temperature is greater than temperature setting.
    '
    ' LM35DZ output is 10mV per degree celcius
    '
    ' 10-bit ADC equates to 4.88mV per step. For this application total accuracy
    ' has been forgone for simplicity and it is assumed that 1 step equates to 
    ' 5mV or 0.5 degree celcius. The displayed temperature is calculated by 
    ' ADCIN value multiplied by 5 (Adval*5).       
    '
    ' Connect LM35DZ to RA0 (Pin 13)
    ' Connect switch "Up" to RA3 (Pin 4) 10k Pull-Up to +5V
    ' Connect switch "Down" to RA4 (Pin 3) 10k Pull-Up to +5V
    ' Connect switch "Bypass" to RA5 (Pin 2) 10k Pull-Up to +5V
    ' Connect LED to RC5 (Pin 5) via 470R to +5V
    ' Connect Relay drive to RC4 (Pin 6)
    ' Connect LCD D4 to RC0 (Pin 10)
    ' Connect LCD D5 to RC1 (Pin 9)
    ' Connect LCD D6 to RC2 (Pin 8) 
    ' Connect LCD D7 to RC3 (Pin 7)
    ' Connect LCD R/S to RA1 (Pin 12)
    ' Connect LCD E to RA2 (Pin 11)
    
    ' Define LCD registers and bits
    Define	LCD_DREG	PORTC
    Define	LCD_DBIT	0
    Define	LCD_RSREG	PORTA
    Define	LCD_RSBIT	1
    Define	LCD_EREG	PORTA
    Define	LCD_EBIT	2
    Define	LCD_BITS	4
    Define	LCD_LINES	2
    
    CMCON0 = %00000111		' Disable comparators
    ANSEL = %00000001		' Set AN0 as analogue input
    TRISA = %00111001	    ' Set PORTA.0, PORTA.3 - .5 to input, all others output
    TRISC = 0			    ' Set PORTC as output
    high PORTC.5            ' Ensure LED turned off
    low PORTC.4             ' Ensure Relay is turned off
    ADCON1 = %01010000	    ' Set A/D clock Fosc/16
    ADCON0 = %10000001	    ' Right justify result
    						' Set Vref = Vdd
    						' Select channel AN0
    						' Turn on A/D converter
    						
    OSCCON = %01110001      ' Set clock frequency to 8MHz
    define OSC  8
                            
    ' Define ADCIN parameters
    Define	ADC_BITS	10	' Set number of bits in result
    Define	ADC_CLOCK	3	' Set clock source (3=rc)
    Define	ADC_SAMPLEUS 50	' Set sampling time in uS
    
    Pause   100             ' Wait 0.1 second
    
    ' Set up variables
    adval   var word        'ADCIN variable
    Temp    var word        'Temperature variable
    Tempset var word        'Temperature setting variable
    avecount var word       'Temperature average counter
    tempsum var word        'Temperature averaging variable
    B4  var byte            'Bypass flag
    Tempup var PORTA.4      'Define Tempup switch port
    Tempdown var PORTA.3    'Define Tempdown switch port
    Bypass var PORTA.5      'Define Bypass switch port
    LED1 var    PORTC.5     'Define LED port output
    Relay var   PORTC.4     'Define Relay port output
    DATA    @1, 50          'Store 50 in EEPROM location 1
    READ    1, Tempset      'Read EEPROM location 1 and save to Tempset
    B4 = 0                  'Reset bypass flag
    high LED1               'Ensure LED is off
    low Relay               'Ensure Relay is off
    
    Lcdout $fe, 1		     'Clear LCD
    LCDOUT $FE, $80, "   BAZTRONICS"
    LCDOUT $FE, $C0, "TEMP. CONTROLLER"
    pause 3000              'Pause 3 seconds
    LCDOUT $FE, 1           'Clear LCD
    
    Again:
        avecount = 1                            'Reset averaging counter
        tempsum = 0                             'Reset averaging variable
        while avecount<1001                     'Loop 1000 times
            ADCIN 0, adval		                'Read channel 0 to adval
            tempsum = tempsum + adval           'sum temp average reading
            avecount = avecount + 1             'Increment counter
            if Bypass = 0 then manual           'Poll Bypass switch
            If B4 = 0 then                      'If Bypass not activated
                if Tempup = 0 then Upstep       'Poll "Up" switch
                if Tempdown = 0 then Downstep   'Poll "Down" switch
            endif
        wend
        Temp = tempsum/200
    	Lcdout $FE, $80
        LCDOUT "  Temp: ", DEC Temp/10, ".", DEC1 Temp,$DF, "C  "'Display Temp
        If B4 = 1 then                          'Test Bypass flag status
            goto Again
        Else
            LCDOUT $FE, $C0+1     'Move cursor to beginning of second line
            lcdout "  Set: ", dec tempset/2, ".", dec1 tempset*5,$DF, "C  "'Display Tempset
        endif
        If temp>tempset*5 then  'Test ambient temperature vs temperature setting
            low LED1            'Turn on LED
            high Relay          'Turn on relay
            LCDOUT $FE, $C0, $DB
        endif
        if Temp < (tempset-2)*5 then'Test ambient temperature vs temperature setting    
            high LED1           'Turn off LED
            low Relay           'Turn off relay
            LCDOUT $FE, $C0, " "
        endif       
    Goto Again		            'Do it forever
    
    Upstep:
        If Tempset<99 then
            Tempset = Tempset + 1   'Increment temperature setting
        else
            Tempset = Tempset       'Set Tempset upper limit
        endif
        LCDOUT $FE, $C0+1           'Move cursor to beginning of second line
        lcdout "  Set: ", dec tempset/2, ".", dec1 tempset*5,$DF,"C  "'Display Tempset
        WRITE 1, Tempset            'Store new Tempset to EEPROM location 1
        Pause 250                   'Pause 250ms for switch debounce
        goto Again
        
    Downstep:
        if Tempset>2 then
            Tempset = Tempset - 1   'Decrement temperature setting
        else
            Tempset = Tempset       'Set Tempset lower limit
        endif
        LCDOUT $FE, $C0+1           'Move cursor to beginning of second line
        lcdout "  Set: ", dec tempset/2, ".", dec1 tempset*5,$DF, "C  "'Display Tempset
        WRITE 1, Tempset            'Store new Tempset to EEPROM location 1
        pause 250                   'Pause 250ms for switch debounce
        goto again
        
    Manual:
        If B4 = 0 then
            B4 = 1                      'Set Bypass flag
            low LED1                    'Turn on LED
            high Relay                  'Turn on Relay
            LCDOUT $FE, $C0+1           ' Move cursor to beginning of second line
            lcdout "  BYPASS MODE  "    'Display Bypass Mode message
        else
            B4 = 0                      'Reset Bypass flag
            high LED1                   'Turn off LED
            low Relay                   'Turn off Relay
            LCDOUT $FE, $C0+1           'Move cursor to beginning of second line
            lcdout "  Set: ", dec tempset/2, ".", dec1 tempset*5,$DF, "C  "'Display Tempset
        endif
        Pause 250                       'Pause 250ms for switch debounce
        do while Bypass = 0             'Loop until Bypass switch is released
        Loop
        goto again
           
    End
    Any assistance would be greatly appreciated.

    Cheers
    Barry
    VK2XBP

  2. #2
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default Re: Help needed with ADCIN Averaging Routine

    Just thinking out loud. At first glance, it looks like an overflow is breaking the average.

    You are averaging 1000 samples of a 10bit value. Assuming the value you want to reach as in your text is 25.0(or 250 counts) in 1000 iterations, the variable for tempsum should be at lease 250x1000 = 250000 big. or, it should be bigger than a word sized variable (max 65535)

    You could try an alternate averaging technique called moving average which works continuously per sample and is not delayed by waiting for 1000 readings.

    Vout = (Vout * 3 + Adcin )/4

    Here, you are continuously averaging the readings like you would do 4 of them together. You could change the formula to any value you want to speed up / slow down the averaging. The numbers should always be (Vout * (n-1) + adc)/n

    Hope that helps

  3. #3
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    166


    Did you find this post helpful? Yes | No

    Default Re: Help needed with ADCIN Averaging Routine

    Hi Jerson,

    Thanks for the quick reply.

    I did the maths again for a 25.0 C reading and all looked good. The ADC result for a temperature of 25.0C is 50 and after summing 1000 measurements the result is less that 65535.
    That's when it hit me - yesterday was a very hot day with temps over 35.0C. The ADC result for a temperature of 35.0C is 70 and summing 1000 measurements creates the overflow.

    So simple! I don't know why the answer eluded me for so long

    As mentioned in my previous posting, I was investigating alternate averaging routines and the moving average routine was the one I was looking to employ in this project. For now I will just back off the number of loops in the averaging routine to make sure no overflow occurs at temps up to 50C. I will look at modifying the routine using Darrel's DT_Analog with Hysteresis routine after Christmas.

    My mind is at rest and I can pack away the straight jacket (for now at least...)

    Cheers
    Barry
    VK2XBP

  4. #4
    Join Date
    Oct 2009
    Location
    Utah, USA
    Posts
    427


    Did you find this post helpful? Yes | No

    Default Re: Help needed with ADCIN Averaging Routine

    There may be something here...
    http://www.pbpgroup.com/modules/wfse...hp?articleid=7
    that will help you with the averaging.

    Darrel's premis is that if you want to average several items together then do the math in a sort of "reverse" fashion. ie. instead of adding 3 values together then dividing by 3. first divide each value by 3 then add them together. This will help of avoid overflow situations.

    He does a much better job of explaining though.
    Dwight
    These PIC's are like intricate puzzles just waiting for one to discover their secrets and MASTER their capabilities.

  5. #5
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default Re: Help needed with ADCIN Averaging Routine

    Hi Heckler

    You got to be careful using that technique with integer math. It is workable if you use floating point operations. Been there.....

    Cheers

Similar Threads

  1. incPID Routine - Help Needed
    By Aussie Barry in forum mel PIC BASIC Pro
    Replies: 63
    Last Post: - 26th September 2013, 12:31
  2. Darrel's latest 16 bit averaging routine?
    By jellis00 in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 17th October 2009, 01:57
  3. ADC Averaging
    By Sach_1979 in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 21st September 2009, 06:53
  4. Darrel's Averaging Routine
    By Andy Wood in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 27th June 2008, 23:24
  5. adc averaging readings
    By amgen in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 21st June 2006, 00:57

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