Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Audio Spectrum Analyzer on a 16F877

Status
Not open for further replies.

Dmax

New Member
I have a grid of 15 by 21 Leds, I’m using a pic16F877 to drive the Leds, one column at a time from left to right, I have an
audio signal going into the pic and output level shown by the Leds, the display looks some what like an oscilloscope. the unit sample's the audio data at 42K using a16bit ADC it then passes the data to a 1Mb chip then on the next loop of the ram it gets read out to a DAC . anyway I have the pic and ram ADC and DAC all workign fine what I need to work on now is the software filter, What I would like to do is make the display show frequency levels across each column of Leds starting from bass frequency’s on the left up to the higher frequency’s on the right , like a Audio Spectrum Analyzer ,

Ive beed told I may probably need to implement multiple bandpass filters in the software , something like ;

FILT <-- FILT + FF(NEW - FILT)

This forms a single pole low pass filter where NEW is a new sample being accumulated into filter FILT. FF is the filter fraction .

thing is I have never wrote code for a digital filter before
I can use a Pic18F442 if the 16F877 is to slow , anyway has anyone here done anything like this and could maybe give me a few tips on wirting the code for the BandPass filter part ,, thanks for reading and all the best :)
 
What you're looking for is called FFT (Fast Fourier Transform), a very complicated maths method. If you look on the PICList there's a spectrum analyser project, which feeds a VGA monitor - it uses a PIC17C756 running at 32MHz.

Have a look at .

Good luck!, please post and let us know how you get on.
 
Thanks for the reply I had a look at that page and that looks great but I have no way of programing the PIC17C756 and FFT is a bit over my head right now , Im goin to see if I can follow the code and see if I can work some of it out , once again thanks for your input :)
 
I wrote a FFT program in pascal , i know it wont help with your pic problem , but if you can follow pascal you could maybe use the routine for your PIC..
 
yes that would be great anything could help me at this point :)
could you email the code to me or can you post it up here ?
Thanks for your help williB :)
 
Dmax said:
Thanks for the reply I had a look at that page and that looks great but I have no way of programing the PIC17C756 and FFT is a bit over my head right now , Im goin to see if I can follow the code and see if I can work some of it out , once again thanks for your input :)

Presumably you could move the code to an 18F PIC?, having proven working PIC assembler to do the FFT is likely to be a lot more help than Pascal code, where you've got to try and convert it to assembler.

But as I said, it's a very complicated subject!.
 
FFT pretty much pushes the PIC to the limits. PicSpect was written by Robert Lacostes, pretty much the top few experts in embedded programming. The problem with FFT is that it takes up a lot of execution time, a lot of memory, and since it must be real time, you'll easily find yourself running out of clock cycles for any decent frequency range.
 
this is it..
It really is a lot of fun to play around with..


Code:
{This program does a Fast Fourier Transform , Decimation in Frequency .. 
it works with a data set of powers of two..It can work in real time ,
 but the data window has to be in a power of 2..It has been a while 
since i looked at it and ten years since i wrote it..
Changing N , changes the number of samples , puting in 1024 for 
example will give you 512 unique output points ,in procedure scope you 
could uncomment the mirror image for a textbook output..this program just
works with data ..ie no graphics..
procedure sinewave creates a file of four different frequencies 63 , 31 ,
15 & 7  for testing purposes.. 
procedure squarewave doesnt use a disk file..
Bit Reverse or Reorder is my own idea it is an assembly program to 
reorder the twiddle factors and you must assemble it into an object file before compiling in pascal ..and have it in the same directory as FFT..
if you have any questions i'll try to answer them 
Reference : Digital Signal Processing Design Chapter 5 Spectral Analysis and the FFT
sorry i didnt write down the author..}

Program FFT(Input,Output,Indata,Outdata);
Const
   N = 256;
   Max= 2* N-1;
Type
   signal= array[0..Max] Of Real;
Var
  X:Signal;
  Outdata:Text;

{----------------------------  Square Wave --------------------------------}

Procedure SquareWave;  { Input Array }
Var
  I:Integer;
Begin
     For I:=0 To N Div 2-1 Do
      Begin
        X[2*I]    := 1.0;
        X[2*I+1]  := 0.0;
      End;

     For I:=N Div 2 To N-1 Do
      Begin
        X[2*I]:= 0;
        X[2*I+1]:= 0;
      End;
End;

{-----------------------------  Sine Wave  -------------------------------}
Procedure SineWave;
Var
Y,A:Real;
I:Integer;
Begin
    Assign(Outdata,'Scope1.dat');
    Rewrite(outdata);
    For I:= 0 to N-1 Do
      Begin
       A:= 2*Pi*I/N;

       X[2*I]:= sin(63 *2*Pi*I/N)+
                sin(31 *2*Pi*I/N)+
                sin(15 *2*Pi*I/N)+
                sin(7  *2*Pi*I/N);

        X[2*I+1]:=0;
        Y:= 20*X[2*I];
        Writeln(Outdata,Round(Y));
      End;
      close(outdata);
End;




{-----------------------  Butterfly  -------------------------------------}
Procedure Butterfly2f(Var x:Signal; p,q:Integer; wr,wi:Real);
{ Radix 2 DIF butterfly }
Var
tr,ti:Real;
Begin
tr:=       x[2*p]  - x[2*q];
ti:=       x[2*p+1]- x[2*q+1];
x[2*p]:=   x[2*p]  + x[2*q];
X[2*p+1]:= x[2*p+1]+ x[2*q+1];
x[2*q]:=   tr*wr - ti*wi;
x[2*q+1]:= tr*wi + ti*wr;
End;

{--------------------------  DIF FFT  ------------------------------------}
Procedure FFTdif(Var X:Signal; N:Integer);
{  Radix 2 DIF FFT }
Var
P,q,n1,n2,j:Integer;
wr,wi:Real;
Begin
  n2:= N;
  Repeat
      n1:=n2;
      n2:= n2 div 2;
      j:=0;
      repeat
          wr:=  Cos(2*Pi*j/n1);
          wi:= -Sin(2*Pi*j/n1);
          p:=j;
          Repeat
              q:= p + n2;
              butterfly2f(x,p,q,wr,wi);
              p:=p + n1;
          until p >= n;
          j := j + 1;
      until j = n2;
  until n2=1;
End;

{-------------------------------  Bit Reverse  ------------------------------}

{$L Reorder}
Function Reorder(I,P:word): word; external;
{ external assembly function reorder.obj }

{-------------------------------  Screen  ------------------------------------}

Procedure Screen;
Var
I,J:Integer;
 Begin
   Writeln;

   Writeln('   N      Xout(r)       Xout(i)       Magnitude ');
   Writeln;
   For J:=0 To N-1 Do
     Begin
       I:=Reorder(J,N);
       Write(J:4{,Xin[2*I]:14:6,Xin[2*I+1]:14:6});
       Write(X[2*I]:14:6,X[2*I+1]:14:6);
       Writeln(Sqrt(Sqr(X[2*I]) + Sqr(X[2*I+1]) ):14:6);
     End;
 End;

{-------------------------------  Scope disk file  -------------------------------}
Procedure Scope;
Var
I,J:Integer;
Magnitude:Real;
Begin
   Assign(Outdata,'Scope0.dat');
   Rewrite(Outdata);

{   For J:= N Div 2 To N-1 Do
     Begin
       I:=Reorder(J,N);
       Magnitude:= Sqrt(Sqr(X[2*I]) + Sqr(X[2*I+1]));
       Writeln(Outdata,Round(Magnitude));
     End;
}
   For J:= 0 To N Div 2 -1  Do
     Begin
       I:=Reorder(J,N);
       Magnitude:= Sqrt(Sqr(X[2*I]) + Sqr(X[2*I+1]));
       Writeln(Outdata,Round(Magnitude));
     End;
   Close(Outdata);
End;


{-------------------------------  FFT MAIN  ---------------------------------}
Begin
     { SquareWave; }
     SineWave;
     FFTdif(X,N);
    { Screen; }
     Scope;
End.
Code:
CODE    Segment Word Public
        Assume CS:Code
        Public Reorder
Reorder Proc near
        Push BP
        Mov bp,sp
        Mov ax,ss:[BP+6]  ; Index
        mov cx,ss:[BP+4]  ; Points in fft
        shr cx,1          ; divide cx by 2
        xor bx,bx         ; clear bx
L1:
        rcr ax,1          ; rotate bit into carry flag
        rcl bx,1          ; rotate bit in carry to bx
        shr cx,1          ; shift bit in cx till zero
        jnz L1

        Mov AX,BX
        Mov SP,BP
        Pop BP
        Ret 4
Reorder Endp
Code    Ends
        end
 
This is a project I gave up on as life got in the way and it was a little over my head at the time, anyway I got it working using the FFT code by written by Robert Lacostes as he converted it for the Pic 18F chips so this made things so much easer for me. I ended up using a 18F4550 chip running at 40mhz and with a display of 12x32 red leds so far everything run fine :)
 
Wow, 11+ years!

Now that is a long running project. Well done.

JimB
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top