Low frequency audio level detector using PIC ADC?


Closed Thread
Results 1 to 40 of 69

Hybrid View

  1. #1
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    thanks bert...slight oversight in my previous (noe edited)...the toggle frequency on my scope is HALF the interrupt frequency!

    Re the pseudo cap - a peak detect cicuit (the end goal here)....it's basically a diode followed by a cap...when the incoming ac signal is higher in magnitude in voltage than that across the cap the diode allows it through...and the cap's voltage increases......when the incoming signal is lower the diode switches off....the cap holds the voltage, but for this circuit to be useful, we actually add in a resistor to discharge it at the designer's choice.....hence wanting to decrement the ADCsample variable when the incoming signal is lower.

    http://hades.mech.northwestern.edu/i...#Peak_Detector

  2. #2
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    ok, despite far too loong trying, i can't get into the interrupt, do my stuff & get out fast enough (for the sample rate I need)....so i'm officially parking the interrupt method of taking ADC samples at a high frequency.

    So back to what languer recommended to me earlier - using the special event trigger to do ADC in background hw.

    this from the data sheet (http://ww1.microchip.com/downloads/e...Doc/41419A.pdf page 216 23.2.4 SPECIAL EVENT TRIGGER )...

    "When Special Event Trigger mode is chosen(CCPxM<3:0> = 1011), the CCPx module does the following:
    • Resets Timer1
    • Starts an ADC conversion if ADC is enabled
    The CCPx module does not assert control of the CCPxpin in this mode.
    The Special Event Trigger output of the CCP occursimmediately upon a match between the TMR1H,TMR1L register pair and the CCPRxH, CCPRxL register pair. The TMR1H, TMR1L register pair is not reset until the next rising edge of the Timer1 clock. The Special
    Event Trigger output starts an A/D conversion (if the A/D module is enabled). This allows the CCPRxH, CCPRxL register pair to effectively provide a 16-bit programmable
    period register for Timer1."


    After an hour of dicking about - I've got it working but would like confirmation how to set the sampling frequency - So I'm back to maths again!

    Ok, with an 8Mhz clock, I now know that we get 2MIPs.....therefore will the Timer1 increment with each instruction clock cycle? so - 1/2,000000? ...that's every 500ns?). If so, to get a sampling frequency of say 40khz, this would mean an ADC sample needed every 25uS, therefore every (25us/500ns) 50 instruction cycles. is it just a matter then of setting CCPR4H = 0 and CCPR4H = 50 for the Timer1H & Timer1L registers to match ???
    Last edited by HankMcSpank; - 22nd February 2011 at 00:52.

  3. #3
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    YES, See how easy it is
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  4. #4
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Quote Originally Posted by cncmachineguy View Post
    YES, See how easy it is
    thanks for bearing with me Bert ...it seems to be working a treat - ie Im feeding an AC signal of 5V peak to peak into an analogue pin...and the PIC is extracting the signal's peak level in real time.....just like a hardware peak detector (but better as the 'charge time' is essentially instant, and the 'discharge time' linear & changeable on the fly).

    FWIW, I'm also reversing the ADC reading from the negative half of the incoming AC signal (ie readings below 128) to give a smoother overall reading (essentially full wave rectification in software)

    the special event trigger was absolutely key in getting this to work without using interrupts ....a hearty thanks to languer too :-)
    Last edited by HankMcSpank; - 22nd February 2011 at 19:52.

  5. #5
    Join Date
    Nov 2007
    Location
    Lake Villa Il.
    Posts
    40


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Hi Hank,
    That is great that you got it to work! Is there a chance that you could post a working version in the code examples section for the rest of us? It is still a little foggy to me.......

    Thank you,
    Sneaky-geek

  6. #6
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Quote Originally Posted by Sneaky-geek View Post
    Hi Hank,
    That is great that you got it to work! Is there a chance that you could post a working version in the code examples section for the rest of us? It is still a little foggy to me.......

    Thank you,
    Sneaky-geek
    Sure, at the risk of being ridiculed for my elementary coding (I'll always be a n00b!), here you go..

    Code:
    '16F1828 Pin Connections*********************************************
                    ' PIN# NAME  USE & CONNECTION
                    '1   Vdd     +5VDC power supply
    TrisC.3 = 1     '7   RC3     AN7 ADC iN
    TrisB.7 = 0     '10  RB7     HSEROUT pin
                    '20  Vss     Ground
    ''*****************************************************************
    @ __CONFIG _CONFIG1, _FCMEN_OFF & _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOREN_OFF & _PWRTE_OFF & _LVP_OFF
    @ __CONFIG _CONFIG2, _LVP_OFF
    
    Osccon = %01110010      'Osc 8Mhz
    
    DEFINE  OSC 8
    DEFINE  NO_CLRWDT 1   ' PBP doesn't clear WDT automatically
    
    ' HW Serial port setup - 115200 @ 8Mhz***********************************
    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 16  ' 115200 Baud @ 8MHz, 2.12%
    SPBRGH = 0
    BAUDCON.3 = 1         ' Enable 16 bit baudrate generator
    '********************************************************************
    
    CM1CON0 = 0   ' COMPARATORS OFF
    CM2CON0 = 0   ' COMPARATORS OFF
    
    ADCON0 = %00011101      'SET AN7 as selected ADC input + ON
    ADCON1 = 0
    
    ANSELA     = 0          ; All Port A ports digital
    ANSELB     = 0          ; All Port B ports digital
    ANSELC     = %00001000  'Analogue pin on RC3 (AN7)
    
    CCP4CON = %0001011     'set CCP4 into special event timer mode
    
    TMR1H = 0       ' set timer1 counter registers to zero            
    TMR1L = 0
    
    CCPR4H = 0       ' preset for timer1 match (MSB register) when timer1 TMR1H & TMR1L match these two regsiters, an ADC sample occurs in hardware
    CCPR4L = 50      ' preset for timer1 match (LSB register)  lower value = higher sampling rate (40Khz here - I think!)
    
    T1CON.0 = 1         ' set timer1 on
    
    count1 var byte
    rolling_peak var BYTE
    present_sample var BYTE
    
    rolling_peak = 0
    present_sample= 0
    count1 = 0
    
    '**********ok that's all the config out the way, let's start***************************************
    
    main:
        count1 = count1 +1                       
        present_sample = ADRESH              'copy the ADC value as taken in the background (by the special event trigger) into a variable
        IF  present_sample < 128 then         'if it's less than 128, then this the waveform has entered the negative part of its cycle.
        present_sample = (127 - present_sample)   'therefore  let's make it positive! (just like a full wave rectifier)
        else 
        present_sample = present_sample -128   ' if it' not in the negative cycle (as checked above), then we're in the positrive part of the cycle, so let's rebase everyting down to 0
        endif
    
        IF present_sample >= rolling_peak THEN 'if the present sample is equal or bigger than the last sample - keep it
        rolling_peak = present_sample
        else                            'if the present sample is not equal or bigger than the last, start decrementing (discharging)
        if count1 =  10 then             ' this count will set the decrement ('discharge') rate (lower is faster)
        rolling_peak = rolling_peak -1   
        count1 = 0
        endif
        endif
        HSEROUT [dec rolling_peak, 13, 10]   'lets make sure everything looks ok on screen
        goto main
    The above sets a 16f1828 up to take ADC samples using the special event trigger ...if using the exact code above, your AC input signal goes in on pin 7 (max 'peak to peak' amplitude being your VCC level - best to amplify your signal for presenting into the pin so that 'max peak to peak' of your incoming signal is as near your VCC voltage as possible - you'll achieve max resolution then) ....your AC signal should be sitting an a DC level of half your PIC's VCC (ie positive cycle go from ADC values of 128->255. negative cycles go from 127->0 - the zero crossing point is an ADC value of about 128)

    I should emphasise that I've not used it in anger yet....there may well be some bugs to flush out - & I'm sure it can be improved (feel free anyone to outline how I can make it slicker anyone!), but it works approx ±1 jitter @7 bits...seems to be reasonably ok upto 20khz...which suggests my sampling frequency in the code is higher than I think it is (btw you lose 1 bit of ADC resolution by flipping the negative cycle up into positive territory...this is a sacrifice worth making as you'll get less 'psuedo ripple' when otherwise the value of the ensuing decrements during the negative cycles would kick in - you can always use 10 bits for your ADC, if so, then you'll lose you one bit, therefore a max 512 values up for grabs) ...

    5V peak to peak @300hz....



    Here's approx 2.5V peak to peak @20khz (a tad more jitter), it should read 64, but I reckon the discrepancy can be accounted for with the DC not being exactly 2.5V that the AC signal sits on (&/or my Chinese USB scope might not be that accurate!)



    One last point - despite the thread title, this detects 'peak' not RMS (& peak is what I need in the end...if you need RMS multiply the result by .707 ....or rather use a workaround for the lack of floating point)
    Last edited by HankMcSpank; - 23rd February 2011 at 01:23.

  7. #7
    Join Date
    Jul 2003
    Location
    USA - Arizona
    Posts
    156


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Hats off to you Hank, most excellent project.

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