Rough 'n Ready Audio Frequency extraction with a PIC


Closed Thread
Results 1 to 34 of 34

Hybrid View

  1. #1
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    I just noticed that my answer will overflow when at the higher frequencies. So for a single decimal point it should stay within limits throughout the range you gave in post 1.

    Code:
    b=5000
    c=1000
    dummy = b * c       '5,000,000 
     frequency = div32 mytime
    LCDOut dec frequency/10,".",dec frequency//10," Hertz"
    Last edited by ScaleRobotics; - 28th August 2010 at 17:40.
    http://www.scalerobotics.com

  2. #2
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Cool Walter.

    All is well (± 0.1Hz)...


    154.3Hz
    154.3Hz
    154.3Hz
    154.3Hz
    154.3Hz
    154.3Hz
    154.2Hz
    154.2Hz
    154.3Hz
    154.3Hz
    154.3Hz
    154.3Hz


    So, for anyone who may find this thread via a search, to summarize here's the code to frequency detect audio signals fed into pin 7 of a 16f690 (using the PIC's internal comparator to generate interrupts, which are in turn 'timed' successively)....

    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)
    '10   RB7     HSEROUT Pin (fed into Pickit2's pin 4 to display data onsreen via the Pickit2's UART tool)
    '19   RA0      Ext VREF for Comparator1   
    ' 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
    
    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
    
    'these two below will later set the dummy variable to total  5,000,000 in the interrupt handler for DIV32 to use
    b = 5000   
    c = 1000
    
    MyTime = 0 'clear down Mytime, prior to starting.
              
    INCLUDE "DT_INTS-14.bas"     ' Base Interrupt System  PO90OOO9
    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 - this one means 2us between successive 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
    
    
    
    'Main body of (dummy) 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       '5,000,000 
            frequency = div32 mytime ' this convertes to Hz, but with no decimal points
            HSEROUT [dec frequency/10,".",dec frequency//10,"Hz",13, 10]   .....this places a decimal point in the right place to make the reading easier on the eye.
            endif 
    @ INT_RETURN
    Note: for the comparator to have something to erhm 'compare' against, I've still not got the PIC's internal voltage reference to work yet, so I was feeding 1/2 VCC externally into the 16F690's RA0 Pin 19 (the bolded bit in this command sets this up.... CM1CON0 = %11100011 )
    Last edited by HankMcSpank; - 28th August 2010 at 18:40.

  3. #3
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    To get more resolution/accuracy for calculating phase, I really need to crank the OSC up to 20Mhz (ie use an ext oscillator).

    Ok, the lowest note on a guitar is about 82Hz (std tuning)

    Is my line of thinking correct here.?...

    One full cycle @82hz takes 0.012195122 seconds

    One PIC clock cycle @20Mhz is 0.000000125 seconds.

    therefore the number of clock cycles that will occure when a note of 82Hz is played will be 243,902.

    I'm using a 16F690, which has a 16 bit timer - a 16 bit timer will over flow at a count of 65536 - alas this number is smaller than 243,902.

    therefore to be able to count 82Hz at 20Mhz, I need a tmr overflow interrupt handler to increment a variable with each tmr overflow (ie count the number of tmr overflows). therefore at 82Hz signal and 20Mhz clock a 16 bit timer will over flow 3 times.

    So (you still awake at the back?), to get the true total number of PIC clock counts @ 82Hz, I need to multiply the stored tmr overflow (3) count by 65536 & then add in the existing tmr count number. chunky numbers in play for a device costing $2.

    Is the PIC gonna start struggling with the above...or will it take it in its stride? (is there a better route I should wrt all of this?!!)
    Last edited by HankMcSpank; - 8th September 2010 at 12:32.

Similar Threads

  1. Measuring change of frequency with PIC
    By Aussie in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 19th July 2007, 02:47
  2. PIC Audio
    By toofastdave in forum mel PIC BASIC Pro
    Replies: 28
    Last Post: - 27th June 2007, 14:49
  3. Pic driven digital audio delay
    By skimask in forum Off Topic
    Replies: 12
    Last Post: - 19th April 2007, 21:42
  4. Audio Encoding and playback in a PIC
    By Rob in forum mel PIC BASIC Pro
    Replies: 8
    Last Post: - 24th March 2005, 09:56
  5. Frequency Counter using PIC and PicBasic
    By PICtron in forum mel PIC BASIC Pro
    Replies: 31
    Last Post: - 28th January 2005, 07: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