#include #include #include #include #include #include #pragma config WDT = OFF, OSC = INTIO2, FSCM = OFF, IESO = OFF, LVP = OFF, MCLRE = OFF, STVR = OFF, DEBUG = OFF, WRT0 = OFF, WRT1 = OFF, CP0 = OFF, CP1 = OFF, CPD = OFF, BOR = OFF #define NUMPERIODS 4 #define RELAYPIN LATBbits.LATB3 #define PUSHBUTTON PORTBbits.RB4 unsigned char i; unsigned char j; unsigned int counts[NUMPERIODS];//will hold the number of 0-to-1 transitions in five 0.1 second timespans unsigned char isawhistle; unsigned char lightison = 0; char statechangecount = 5; //without this, after the light switched, it would quickly switch back again the next time it checks if you're whistling. You need it to ignore whistling for about a half second to give you a chance to stop whistling. char step=0; void main (void) { OSCCON = 0x70; //set it to use the 8MHz internal clock. ADCON1 = 0x7F; //set all ADC-capable pins to NOT be analog inputs, just digital IO. INTCON2bits.RBPU = 0; //PORTB pullup resistors enabled DDRB=0xFF; //all inputs DDRA=0b00010000; DDRAbits.RA4=1; //this pin is the "external oscillator" input of Timer0. The comparator connects here, and Timer0 counts the number of 0 to 1 transitions. DDRAbits.RA0=0; //will light an LED when a tone is detected. DDRBbits.RB3=0;//runs the relay DDRBbits.RB4=1;//for an alternative pushbutton, for people who can't whistle. (I ended up not putting this on the circuit though.) PORTA=0; PORTB=0; OpenTimer0( TIMER_INT_OFF & T0_16BIT & T0_SOURCE_EXT & //this setting means it is really just counting the number of 0 to 1 transitions on pin RA4 T0_EDGE_RISE & T0_PS_1_1 ); while(1) { for(j=0; j 1.15*counts[i-1]) || (counts[i] < 0.85*counts[i-1]) ) //if this is false, then they ARE within 15% of each other. { isawhistle = 0; } } if((counts[2] < 90) || (counts[2] > 270))//in a 0.1 second timespan, this corresponds to a frequency range of 900 to 2700 Hz, which includes the range I can whistle but should exclude most noise. If counts[2] is within the range, then the others are close also. { isawhistle = 0; } if((statechangecount == 0) && ( (isawhistle == 1) || (PUSHBUTTON == 0)) ) //I turned on the weak pullup resistors, so the pushbutton will connect between the pin and ground, so when it's on, the pin sees 0V. { LATAbits.LATA0 = 1;//lights an LED momentarily to indicate a whistle was detected, for debugging. if(lightison == 1) //if the light is on, turn it off, and vice versa. { lightison = 0; RELAYPIN = 0; statechangecount = 5; } else { lightison = 1; RELAYPIN = 1; statechangecount = 5; } } else { LATAbits.LATA0 = 0; } if(statechangecount > 0) { statechangecount--; } } } }