Three-speaker Chladni Patterns
Team Members
- Christopher Chow (Mechanical Engineering, Class of 2010)
- Anup Tapase (Electrical Engineering, Class of 2010)
- Lingyu Xie (Electrical Engineering, Class of 2009)
Overview
Theory
Mechanical Design
Primary Components
Base Box
Three-Speaker Base
Chladni Plate
Electrical Design
Primary Components
Circuit Notes
Circuit Diagram
Code
Main frequency sweep code
#include <18f4520.h> #DEVICE ADC=8 // set ADC to 8 bit accuracy #use delay(clock=40000000) #include "flex_lcd.c" //must include in order to output to LCD #use spi(DO = PIN_A3, CLK = PIN_A2, ENABLE = PIN_A1, BITS = 16, MASTER, ENABLE_ACTIVE = 0, MSB_FIRST, IDLE = 1) int16 freq,target_freq; int16 target_freq_reg, old_target_freq_reg; int8 knob_val=0; void check_input(); void main() { int16 ct; target_freq_reg=2000+16384; // initialize starting frequency of speakers to 298 Hz (non-resonant) old_target_freq_reg=2000+16384; // set old target freq variable to equal target freq setup_adc_ports(AN0); // Set up analog input port as pin A0 setup_adc(ADC_CLOCK_INTERNAL); lcd_init(); // Always call this first. //INITIAL FREQUENCY FOR AD9833 spi_xfer(0b0010000100000000); //format command, output sine wave spi_xfer(target_freq_reg); //1st set of bits, 14 LSB, this range is good enough for our use //send the target frequency register value (freq + 16384) to AD9833 chip spi_xfer(0b0100000000000000); //2nd set of bits, 14 MSB spi_xfer(0b1100000000000000); //phase register: 0 phase shift (B0-B13) spi_xfer(0b0000000000000000); //unformat freq=(float).149011 * (float)(target_freq_reg - 16384); //convert the target freq register value to actual freq value target_freq=freq; // initialize target freq as current freq printf(lcd_putc,"\fFreq: %Lu\n",freq); //display current freq printf(lcd_putc,"Target: %Lu\n",target_freq); //display target freq while(TRUE) { check_input(); //check the knob input to see if target frequency has changed if(old_target_freq_reg != target_freq_reg) //go in here if target freq changed after calling check_input() { if(target_freq_reg > old_target_freq_reg) //sweep up to target freq { for(ct=old_target_freq_reg; ct<=target_freq_reg; ct=ct+7) { spi_xfer(0b0010000100000000); spi_xfer(ct); //set AD9833 frequency to ct, which is freq register that is sweeping up by 7 each time loop is run spi_xfer(0b0100000000000000); spi_xfer(0b1100000000000000); spi_xfer(0b0000000000000000); freq=(float).149011 * (float)(ct - 16384); target_freq=(float).149011 * (float)(target_freq_reg - 16384); printf(lcd_putc,"\fFreq: %Lu\n",freq); //display current freq printf(lcd_putc,"Target: %Lu\n",target_freq); //display target freq check_input(); //see if knob position has selected different target freq delay_ms(90); //delay to allow speakers to play freq for 90 ms + 10 ms (in check_input() function) } old_target_freq_reg = target_freq_reg; //reached target freq, set both variables equal until knob position changed } else if(target_freq_reg < old_target_freq_reg) //sweep down to target freq { for(ct=old_target_freq_reg; ct>=target_freq_reg; ct=ct-7) { spi_xfer(0b0010000100000000); spi_xfer(ct); //set AD9833 frequency to ct, which is freq register that is sweeping down by 7 each time loop is run spi_xfer(0b0100000000000000); spi_xfer(0b1100000000000000); spi_xfer(0b0000000000000000); freq=(float).149011 * (float)(ct - 16384); //convert current freq register value (ct) to frequency value target_freq=(float).149011 * (float)(target_freq_reg - 16384); //convert target freq register to target freq value printf(lcd_putc,"\fFreq: %Lu\n",freq); //display current freq printf(lcd_putc,"Target: %Lu\n",target_freq); //display target freq check_input(); //see if knob position has selected different target freq delay_ms(90); //delay to allow speakers to play freq for 90 ms + 10 ms (in check_input() function) } old_target_freq_reg = target_freq_reg; //reached target freq, set both variables equal until knob position changed } } } }
Checking user input
This function is used to check the knob/potentiometer position at certain points during the changing of frequencies in the main function. It sets the ADC channel to 0 and takes the analog input from pin A0 on the PIC using read_adc(). This input, set to the variable knob_val, is an integer between 0-255 which corresponds to the voltage coming out of the knob/potentiometer, which is 0 if the output is at 0V and 255 if the output is at 5V. By checking if knob_val is between a certain integer range corresponding to the different numbers on the knob (numbered 0-10), the target frequency can be set by the user. Nine target resonant frequencies were programmed in this function based on the good clarity of the shapes they produced on the plate, but more resonant frequencies exist and can be added to the if-statement in this function.
void check_input() //check knob position to see if target freq has changed { set_adc_channel(0); // Set the analog input channel to 0 delay_us(10); // wait 10uS for ADC to settle to a newly selected input knob_val = read_adc(); // Read in knob user input to tell speakers what resonant freq to sweep up to delay_ms(10); // delay 10 ms to allow reading of analog input //check and set target_freq_reg according to knob position (0-255 values split into 9 discrete levels) if (knob_val >= 0 && knob_val< 22 ) target_freq_reg = 2281+16384; //339 Hz else if(knob_val >= 22 && knob_val< 54) target_freq_reg = 3308+16384; //493 Hz else if(knob_val >= 54 && knob_val< 86) target_freq_reg = 3778+16384; //563 Hz else if(knob_val >= 86 && knob_val< 117) target_freq_reg = 3986+16384; //594 Hz else if(knob_val >= 117 && knob_val< 147) target_freq_reg = 4207+16384; //627 Hz else if(knob_val >= 147 && knob_val< 178) target_freq_reg = 4362+16384; //650 Hz else if(knob_val >= 178 && knob_val< 209) target_freq_reg = 5006+16384; //746 Hz else if(knob_val >= 209 && knob_val< 239) target_freq_reg = 5308+16384; //791 Hz else if(knob_val >= 239 && knob_val< 255) target_freq_reg = 5872+16384; //875 Hz }