Rough 'n Ready Audio Frequency extraction with a PIC


Closed Thread
Results 1 to 34 of 34

Hybrid View

  1. #1
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Ok, a wet VAc has sorted most of my carpet problems, but going straight to the manual for info about using DIV32 has seemingly brought more jitter to the fore....

    First here's what I'm doing....

    Code:
    @ __CONFIG _FCMEN_OFF & _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOR_OFF & _PWRTE_OFF
    
    '***********************************************************************************************
    
    '16F690 Pin Connections....
    ' PIN# NAME     USE & CONNECTION
    '  1   Vdd      +5VDC power supply   
    '  7   RC3      C12IN3- (external comparator input)     
    '  20  Vss      Ground
    '*************************************************************************************
    DEFINE  OSC 4          ' set Oscillator at 4Mhz.
    DEFINE  NO_CLRWDT 1   ' PBP doesn't clear WDT automatically
    DEFINE HSER_SPBRG 25   'HSEROUT Stuff.
    DEFINE HSER_TXSTA 24h  'HSEROUT Stuff.
    DEFINE HSER_CLROERR 1  'HSEROUT Stuff.
    
    txsta = %10100100       'setup the tx register
    RCSTA.7 = 1             ' Enable RB7 for TX USART
    INTCON.0 = 0            ' clears the RABIF Flag (to 0), COULD be 1 on reset (unique to F690)
    ANSEL      = 0    'disable AtoD.
    ANSELH     = 0    'disable AtoD.
    CM2CON0 = 0   'turn off comparator 2.
    
    'Turn on & Set up Comparator 1
    CM1CON0 = %11100011    'Comparator ext op pin disabled (op of comparator avaible internally only), compare against external VREF
    VRCON = %0100001       'turn on internal reference
    TRISA.2 = 0            'allow the comparator 1 output pin as an output
    
    MyTime       var  word    ' used to amalgamate TMR1 High & Low Bytes.
    Frequency    var  word    'used to convert the count to frequency.
    
    ' the following is pretty much a straight lift from the compiler manual (DIV32 section)
    a Var Word
    b Var Word
    c Var Word
    dummy Var Word
    b = 500
    c = 1000
              
    INCLUDE "DT_INTS-14.bas"     ' Base Interrupt System
    INCLUDE "ReEnterPBP.bas"     ' Include if using PBP interrupts
    
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   CMP1_INT,  _Comp1_Int,   PBP,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    T1CON = $11               ; Prescaler setting 2us between clocks
    
    @ INT_ENABLE  CMP1_INT     ; enable Comparator 1 interrupts
    
    T1CON.0=0 'stop the timer
    TMR1H = 0 'Set the high part of the timer value to 0
    TMR1L = 0 'Set the low part of the timer value to 0
    
    MyTime = 0 'clear down Mttime, prior to starting.
    
    
    'Main body of Code*********************************************************************************************
    Main:
            pause 10
            goto Main
            end
       
    'Comparator1 Interrupt Handler+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++        
    Comp1_Int:
            if T1CON.0= 0 then 'if timer1 is not running...
            TMR1H = 0 'Set the high part of the timer value to 0
            TMR1L = 0 'Set the low part of the timer value to 0 
            T1CON.0= 1  'start timer
            else        'therefore if it is running, stop the timer & calculate the number of 'clock' counts between comparator interrupts....
            T1CON.0= 0  'stop the timer
            MyTime.Lowbyte = TMR1L 'puts the timer's low byte in MyTime's lower 8 bits 
            MyTime.Highbyte = TMR1H 'puts the timer's high byte in MyTime's upper 8 bits
    
            dummy = b * c '  'a straight lift from the compiler manual (DIV32 section)
            a = DIV32 MYTIME  'use the DIV32 to divide 50,000,000 by the comparator 'time between counts' 
            hserout ["Comparator1_Count = ", dec MyTime, 9, "Frequency = ", dec a,13, 10]       
            endif
            
    @ INT_RETURN

    ....& here's the onscreen hserout data....

    (just to remind you 'Comparator1_Count' is the 'number of clocks' counted between successive comparator interrupts - and the frequency is the DIV32 result of 500000 divided by comparator1_count number )

    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1959 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1959 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255



    (FWIW My sig gen was showing 255.2Hz on its LED display & using a calculator to divide 500000 by the 'average' comparator1_count of say 1960, works out at 255.1Hz)

    so as a percentage the 'variance/jitter' on the lefthand figure (Comparator1_Count) is miniscule....but using the DIV32 seems crank up the 'error' when converted to Hertz? (eg 254, 255, 255, 254)

    What am I doing wrong?!
    Last edited by HankMcSpank; - 28th August 2010 at 00:52.

  2. #2
    Join Date
    Feb 2010
    Location
    USA, New England
    Posts
    164


    Did you find this post helpful? Yes | No

    Default

    HankMcSpank,

    I suspect you are expecting to see a rounded final value when in fact your final value is truncated.

    1960/500,000 = 255.102, PBP truncates to 255 (same as rounding)
    1961/500,000 = 254.972, PBP truncates to 254 (would round to 255!)


    If you add "half of a whole value" before truncating it is the same as rounding. You can't add 0.5 to the DIV32 result because we aren't using floating point. So we add it before the division:

    1960/500,500 = 255.488, PBP truncates to 255
    1961/500,500 = 255.227, PBP truncates to 255 (all is good)


    You've may still have some granularity issues but this should get you closer.

    I remember hearing a long while back that "floating point math is for weenies who can't think big." 8^)

    Best Regards,
    Paul

  3. #3
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Hi Paul,

    I was aware that the PIC simply threw the decimal portion away, but I'm no mathmetician & just wanted to clarify that I wasn't approaching this incorrectly!

    Thank you for your suggestion...but my goal here is simply to detect the frequency remaining the same for a set length of time (ie the guitar player is 'holding' a note for more than x seconds)....so I don't actually even need to convert to hertz - for simplicity, I can just work in counts.

    It might be handy one day to detect the actual 'Note Played'. when I think my approach would be along the lines of a monster lookup table (with a 'window' either side of the centre frequency for each note)...

    Code:
                      Hertz     Clock Count
    
    	 (from ) 	78	6410  
    Open	E	82.41	6067
    	 (to) 	84.85	5893  
    			
    	 	84.86	5892
    Fret 1	F	87.31	5727
    	 	89.90	5562
    			
    	 	89.91	5561
    Fret 2	F#	92.50	5405
    		95.24	5250
    			
    	 	95.25	5249
    Fret 3	G	98.00	5102
    		100.91	4955
    			
    	 	100.92	4954
    Fret 4	G#	103.83	4816
    		106.91	4677
    			
    	 	106.92	4676
    Fret 5	A	110.00	4545
    	 	113.26	4415
    			
    	 	113.27	4414
    Fret 6	A#	116.54	4290
    	 	120.00	4167
    & so on (I guess Hertz could be derived to decimal points using an even bigger lookup table?!)


    PS Once you get to the highest note on the fretboard (E on the 24th fret - 1318.5Hz) , the compartor clock count between interrupts comes down to something around 379....so it might be worth messing with the prescaler to give a bit more granularity)
    Last edited by HankMcSpank; - 28th August 2010 at 11:26.

Similar Threads

  1. Measuring change of frequency with PIC
    By Aussie in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 19th July 2007, 01:47
  2. PIC Audio
    By toofastdave in forum mel PIC BASIC Pro
    Replies: 28
    Last Post: - 27th June 2007, 13:49
  3. Pic driven digital audio delay
    By skimask in forum Off Topic
    Replies: 12
    Last Post: - 19th April 2007, 20:42
  4. Audio Encoding and playback in a PIC
    By Rob in forum mel PIC BASIC Pro
    Replies: 8
    Last Post: - 24th March 2005, 08:56
  5. Frequency Counter using PIC and PicBasic
    By PICtron in forum mel PIC BASIC Pro
    Replies: 31
    Last Post: - 28th January 2005, 06:20

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