//  Digital Pre-Amplifier

// Will Tang and Clement Yu 

// ECE 476 Spring 2003 Final Project

 

#include <Mega32.h>

#include <stdio.h> // sprintf

#include <delay.h> // delay_ms

#include <stdlib.h>

 

//I like these definitions

#define begin {

#define end   } 

#define LCDwidth 16 //characters        

 

// Low-pass filter state machine

enum { NoPass, LP1, LP2, LP3, LP4, LP5, LP6, LP7 };

 

char Ainl, Ainh, shiftedOut;        //raw A to D number      

unsigned int totalbits, index, lowPassed, State, poles;

unsigned int setlevel, sampCnt, sample, sampDelay;    

int level, maxlevel, noLED, DSPen;

float vin[5], vout[5];  

float a1, a2, a3, a4, a5, b1, b2, b3, b4, b5;

 

void main(void)

begin

 

  // Since Aref is turned on, we must pull the Aref pin off

   ADMUX = 0b11000010;        // Bit 6 set to 0 (ADLAR = 0, ADCL has lower 8 bits, ADCH has upper 2)

 

   // ADC enabled, conversion starts, interrupt disabled, last 3 bits for prescaler division (0b111 = 128)  

   ADCSR = 0b11000111;     // prescaler division (0b111 = 128)

  

   //enable sleep and choose ADC mode       

   MCUCR = 0b01010000;   

                

   // State machine start with no filter

   State = NoPass;

                                  

   // PORTD as PWM output, pin4 (OCR1B)   

   DDRD = 0xff;         

  

   // PORTB as button input 

   DDRB = 0x00;              

  

   // PORTC as a LED display

   DDRC = 0xff;

  

   // init variables

   sampCnt = 0; setlevel = 0; sampDelay = 0;       

   maxlevel = 0; noLED = 0; DSPen = 0;

  

  

   // init DSP vars

   for( index = 0; index < 5; index++)

   {

     vout[index] = 0;

     vin[index] = 0;

   }                        

 

   // PWM    prescaler = 1, 8-bit Fast PWM

   TCCR1A = 0b11110001; 

   TCCR1B = 0b00001001;

 

                 

   #asm

      sei

   #endasm

     

   // measure and display loop

   while (1)

   begin  

   

     //If ADCSR.6 = 1, then the ADC conversion has not been finished, wait in while loop                       

     while( ADCSR.6 != 0 )   

     {

       ;

     }              

   

     // Save 10 conversion bytes after ADC is finished         

     Ainl = ADCL;

     Ainh = ADCH;       

        

     // start conv again              

     ADCSR = ADCSR | 0x40;   

                  

     // 10 bit ADC conversion (ADLAR = 0)                                    

      totalbits = Ainh;

      totalbits = totalbits << 8;

      totalbits = totalbits | (0xff & Ainl);         

 

     // check for button press to change state

     if (PINB != 0xff)

     {     

       if      (PINB == 0b11111110) State = NoPass;

        else if (PINB == 0b11111101) State = LP1;

        else if (PINB == 0b11111011) State = LP2;

        else if (PINB == 0b11110111) State = LP3;

      else if (PINB == 0b11101111) State = LP4;

      else if (PINB == 0b11011111) State = LP5;

        else if (PINB == 0b10111111) State = LP6;

        else if (PINB == 0b01111111) { PORTC = 0xff; State = LP7; } // TURN led off

     } // if

                   

 

     // Do DSP calculations (or no calculations) to sampled values depending on desired state

     switch(State)

     {

       case NoPass:

         noLED = 0;  

         DSPen = 0;

          break;

       case LP1:        

         // DSP low-pass filter coeffs

         // butter(2, .1)

           b1 = 0.0201; b2 = 0.0402; b3 = 0.0201;

           a1 = 1;  a2 = -1.561; a3 = 0.6414; 

         poles = 2;

         noLED = 0;

         DSPen = 1;

         break;

       case LP2:         

         // DSP low-pass filter coeffs

         // butter(2, .2)

           b1 = 0.0675;  b2 = 0.1349; b3 = 0.0675;

         a1 = 1;  a2 = -1.143; a3 = 0.4128; 

         poles = 2;

         noLED = 0;

         DSPen = 1;

         break;

       case LP3:       

         // DSP low-pass filter coeffs

         // butter(3, .2)

          b1 = 0.0181;  b2 = 0.0543; b3 = 0.0543; b4 = 0.0181;

          a1 = 1;  a2 = -1.76; a3 = 1.1829; a4 = -0.2781;  

          poles = 3;

         noLED = 0;

         DSPen = 1;

         break;

       case LP4:      

         // DSP low-pass filter coeffs

         // butter(1, .1)

           b1 = 0.1367;  b2 = 0.1367;

         a1 = 1;  a2 = -0.7265;

         poles = 1;                            

         noLED = 0;

         DSPen = 1;

         break;

       case LP5:

         // DSP low-pass filter coeffs

         // butter(1, .2)

           b1 = 0.2452; b2 = 0.2452;

         a1 = 1; a2 = -0.5095;

         poles = 1;      

         noLED = 0;

         DSPen = 1;

         break;

       case LP6:

         // DSP low-pass filter coeffs

         // butter(1, .5)

           b1 = 0.5; b2 = 0.5;

         a1 = 1; a2 = 0;

         poles = 1;     

         noLED = 0;

         DSPen = 1;

         break;

       case LP7:         

           noLED = 1;        

         break;

            

     } // switch                 

  

     if(DSPen)  // DSP calculations

     {       

  

       // DSP filter calculation

       for(index = 0; index < poles; index++)

       {

         vout[index+1] = vout[index];

         vin[index+1] = vin[index];

       }

       vin[0] = (float) totalbits;

       vout[0] = (b1 * vin[0]) +  (b2 * vin[1]) -  (a2 * vout[1]);    

       switch(poles)

       {

         case 2:

           vout[0] = vout[0] + (b3 * vin[2]) - (a3 * vout[2]);

           break;

         case 3:                                              

           vout[0] = vout[0] + (b3 * vin[2]) + (b4 * vin[3]) - (a3 * vout[2]) - (a4 * vout[3]); 

           break;

         case 4:     

           vout[0] = vout[0] + (b3 * vin[2]) + (b4 * vin[3]) + (b5 *vin[4])

                  - (a3 * vout[2]) - (a4 * vout[3]) - (a5 *vout[4]);         

        }  // switch

 

        

       lowPassed = (int) vout[0]; 

     }// if State                     

     else       // Bypass DSP calculations

     {

       lowPassed = totalbits;     

     }

 

 

     // needed for 8-bit resolution PWM output. Shifted to convert 10-bit ADC input to 8-bit PWM

      shiftedOut = (char) (lowPassed >> 2);

      OCR1BL = shiftedOut;     

 

      // Normalizing samples to a display level   

      if(!noLED)

      {

        sample = shiftedOut;

        if(sample >= 180)  level = 7;

        else if(sample >= 170) level = 6;

        else if(sample >= 160) level = 5;

        else if(sample >= 150) level = 4;

        else if(sample >= 140) level = 3;

        else if(sample >= 130) level = 2;

        else if(sample >= 120) level = 1;

        else if(sample >= 110) level = 0;             

               

       // update the maximum level

       if(maxlevel < level)

       {

         maxlevel = level+1;

       }                           

      

        if(sampDelay++ >= 300)

        {

          sampDelay = 0;   

         maxlevel--;

      

         switch(maxlevel)

          {

            case 0:

              PORTC = ~0b10000000;  break;

            case 1:

              PORTC = ~0b11000000;  break;           

            case 2:

              PORTC = ~0b11100000;  break;           

            case 3:

              PORTC = ~0b11110000;  break; 

            case 4:

              PORTC = ~0b11111000;  break; 

            case 5:

              PORTC = ~0b11111100;  break; 

            case 6:

              PORTC = ~0b11111110;  break; 

            case 7:

              PORTC = ~0b11111111;  break; 

          } // switch

       } // if sampDelay

     } // if !noLED          

    

     PORTA.0 = PORTA ^ 0b00000001;

           

   end

end