Problem: ADC with microphone input (PIC18F4550)

Discussion in 'Embedded Systems and Microcontrollers' started by DrStu, Dec 12, 2008.

  1. DrStu

    Thread Starter New Member

    Dec 11, 2008
    uC - PIC18F4550 (Compiler: MPLAB MC18)

    I'm trying to build a simple circuit using the built in ADC of the PIC to convert the analog values from an electret microphone.

    - Light up an LED if the sound amplitude is above a certain level

    Brief Block Diagram:
    Mic -----> Amplifier -----> PIC

    So far i've not been able to make the PIC work with the mic. Unsure whether the problem is in the amplifier stage or the coding of the ADC. Btw, i've tested the ADC using DC voltage and it works fine. (LED lights when ADC connected to +5V DC and vice versa). It just wouldn't work with the mic.

    Circuit Used:
    (Using the general purpose amplifier from this site)

    Code ( (Unknown Language)):
    2. #include <p18cxxx.h>
    3. #include <adc.h>
    5. //Global Variables
    6. int ADC_Output=0;
    8. #pragma config FOSC = HS
    9. #pragma config WDT = OFF /* Turn the watchdog timer off */
    10. #pragma config LVP = OFF /* Turns Low Voltage Programming off */
    11. #pragma config MCLRE = ON /* To enable MCLR - To enable PIC reset */
    13. void main()
    14. {
    16.     TRISA = 0xFF;
    18.     TRISC = 0x00; /*Configure Port C as All Output*/
    19.     LATC = 0x00;
    21.     // configure A/D convertor
    22.     OpenADC( ADC_FOSC_16     &
    23.          ADC_RIGHT_JUST &
    24.          ADC_12_TAD,
    25.          ADC_CH0     &
    26.          ADC_INT_OFF ,
    27.          ADC_VREFPLUS_VDD);
    29.     while (1)
    30.     {
    31.         ConvertADC(); // Start conversion
    32.         while( BusyADC() ); // Wait for completion
    33.         ADC_Output = ReadADC(); // Read result
    34.         if (ADC_Output>512){
    35.             LATC=0b11111111;
    36.         }
    37.         else {
    38.             LATC=0b00000000;
    39.         }
    40.     }
    41. }
    Any help would be much appreciated. I'm not very familiar with audio signals (as in mic and the amplifier stage). Thx! ....Very Very Much!
  2. mik3

    Senior Member

    Feb 4, 2008
    You need to use a peak detector after the amplifier as to store the highest value of the DC varying signal of the voice (microphone). Another way, is to make your program to turn on the led once it senses the voltage over the limit for one instance and leave it on until you press a reset button.
    Now, your circuit turns on the led just for a tiny time interval (time the voltage goes above the limit) and you can't see it. Thus, make the changes mentioned earlier.
  3. DrStu

    Thread Starter New Member

    Dec 11, 2008
    gee thx! i think i get da point.... i think i didnt get it that the output was in AC all da while :)P oscciloscope at home to observe it)

    anyway, is it possible to rectify the problem inside the pic coding instead of building a peak detector/rectifier? like...getting the difference between the instantaneous value and the center reference value....and use the average of like 20 of these values...or sth like that?
  4. DrStu

    Thread Starter New Member

    Dec 11, 2008
    sth i would like to know about the ADC configuration bits of the ADC...

    wad "A/D Acquisition Time" and "A/D Conversion Clock"is best for audio sampling? (dat best suits my project)
  5. beenthere

    Retired Moderator

    Apr 20, 2004
    That decision is yours to make. If you wish to go for voice only, the highest frequency needs to be only 6 KHz or so. Nyquist strongly suggests sampling at twice the rate of the signal, so something like 12 KHz, or every 83 us.

    Full audio pushes the upper limit to around 20 KHz, or every 50 us. The industry uses 22.5 KHz.

    Your A to D is going to output 10 bits/conversion, which is not really going to give good fidelity on playback. 16 bits is pretty much the minimum for that.
  6. mik3

    Senior Member

    Feb 4, 2008
    You can do it by programming but you have to ensure the voltage on the adc input does not go negative (clamp it). To do it, you have to compare the read value from the adc with the next value and if it is greater then you continou to read the values. However, if it is less than the current value you keep the current value as the peak value. Then you start the same process again.
  7. DrStu

    Thread Starter New Member

    Dec 11, 2008
    thx beenthere :) ...i do understand wad uve said about the sampling frequency thing.....but what i dun get is actually the "A/D Acquisition Time" and "A/D Conversion Clock" ......i've read through the datasheet for the PIC18F4550 and was very confused about how to configure these 2..... what i understand is u can calculate the conversion time (and thus the conversion frequency) through these 2 parameters.....and also that the "acquisition time" must be long enuf to charge up the capacitor of the sample and hold circuit of the a/d......

    or simply...i juz dun get da whole picture of it :) ....say i would like to sample at do i calculate the ideal "A/D Acquisition Time" and "A/D Conversion Clock" if im running my PIC at 20MHz?

    i'm not actually trying to record and playback audio....juz trying to show the sound level by lighting up LEDs (i know theres a specific IC for this...but this is juz a part of my PIC project) ..thx!
  8. DrStu

    Thread Starter New Member

    Dec 11, 2008
    0 i am using the LM386 audio amplifier...the output is already biased to 1/2 of the supply voltage (2.5V in my case) my adc input does not go below 0V

    so the way i understand it....this is the "Software Peak Detector" right?

    Currently i'm trying out "software averaging" ...and yet the output is not wad i expect (its reading a constant 5V) ....any ideas? ...
    this is my ADC coding:
    Code ( (Unknown Language)):
    2. OpenADC( ADC_FOSC_2     &
    3.          ADC_RIGHT_JUST &
    4.          ADC_8_TAD,
    5.          ADC_CH0        &
    6.          ADC_INT_OFF ,
    7.          ADC_VREFPLUS_VDD);
    9. while (1)
    10. {
    11.     int i;
    12.     Sum=0;
    14.     LATC=0b00000000;
    16.     for (i=0; i<10; i++){
    17.         Delay10TCYx( 5 ); // Delay for 50TCY
    18.         ConvertADC(); // Start conversion
    19.         while( BusyADC() ); // Wait for completion
    20.         ADC_Output = ReadADC(); // Read result
    22.         if (ADC_Output>512+100){
    23.             ADC_Output=ADC_Output-512-100;
    24.             //LATCbits.LATC0 = 1;
    25.         }
    26.         else if (ADC_Output<512-100){
    27.             ADC_Output=512-ADC_Output-100;
    28.             //LATCbits.LATC1 = 1;
    29.         }
    30.         else{
    31.             ADC_Output=0;
    32.             //LATCbits.LATC1 = 1;
    33.         }
    35.         Sum=Sum+ADC_Output;
    37.         Delay1KTCYx( 5 ); // Delay for 1ms
    38.     }
    40.     Sum=Sum/10;
    42.         if (Sum<100){
    43.             LATCbits.LATC0 = 1;
    44.             Delay10KTCYx( 500 );
    45.         }
    46.         else if (Sum <250) {
    47.             LATCbits.LATC1 = 1;
    48.             Delay10KTCYx( 500 );
    49.         }
    50.         else{
    51.             LATCbits.LATC2 =1;
    52.             Delay10KTCYx( 500 );
    53.         }
    54.     }
    ath wrong with my coding part? any help VERY MUCH appreaciated :)
  9. mik3

    Senior Member

    Feb 4, 2008
    You don't need any averaging code. Just read the input and when the voltage goes above a certain limit the PIC will perform the appropriate function.
  10. beenthere

    Retired Moderator

    Apr 20, 2004
    By just determining the volume peaks, you also don't need to worry about the sampling rate. That is only necessary for accurate reproduction.

    Get the apparatus working and then you can experiment with sampling rate to see what is actually necessary.