// freq_detector_own_isr // Kevin Karplus // 2014 Apr 5 // This program is intended to be used as a "capacitive touch sensor" // with an external relaxation oscillator whose frequency // varies with the capacitance of a touch. // The program expects a periodic square wave on pin PTD4 with a frequency between // about 400Hz and 800kHz. (LOW_FREQ_LIMIT and HIGH_FREQ_LIMIT). // On reset, it displays a yellow light, then measures the frequency to store as the "off" frequency. // // If the frequency is out of range (say for a disconnected input), then the light is set to red, // and the off frequency checked again. // Otherwise the LED is turned blue. // // After initialization, if the program detects a frequency 20% less than the initial freq, // it turns the light green, // turning it blue again when the the frequency increases to 90% of the original frequency. // // No floating-point is used, just integer arithmetic. // // Frequency measurements are made by counting the number of rising and falling edges // in one cycle of the mains frequency (1/60 sec), giving somewhat poor resolution at lower // frequencies. // The counting time is chosen to that frequency modulation by the mains voltages is averaged out. // // This version of the code uses my own setup for the interrupt service routine, because InterruptIn has // too much overhead. I can go to over 800kHz (1.6e6 interrupts/second) with this setup, // but only about 40kHz (80e3) interrupts/sec with mbed's InterruptIn. #include "mbed.h" Serial host(USBTX, USBRX); // for communicating with the host computer #define PCR_PORT_TO_USE (PORTD->PCR[4]) // pin PTD4 is the pin to use #define MAINS_FREQ (60) // frequency of electrical mains in Hz #define COUNTING_TIME (1000000/MAINS_FREQ) // duration in usec of one period of electrical mains // off_frequency must be between LOW_FREQ_LIMIT and HIGH_FREQ_LIMIT for program to accept it #define LOW_FREQ_LIMIT (400) #define HIGH_FREQ_LIMIT (800000) // on-board RGB LED PwmOut rled(LED_RED); PwmOut gled(LED_GREEN); PwmOut bled(LED_BLUE); #define PWM_PERIOD (255) // for the on-board LEDs in microseconds // Set the RGB led color to R,G,B with 0 being off and PWM_PERIOD being full-on void set_RGB_color(uint8_t R, uint8_t G, uint8_t B) { rled.pulsewidth_us(PWM_PERIOD-R); gled.pulsewidth_us(PWM_PERIOD-G); bled.pulsewidth_us(PWM_PERIOD-B); } // InterruptIn square_in(PTD4); volatile uint32_t edges_counted; uint32_t low_freq_threshold, high_freq_threshold; // thresholds for detecting frequency changes extern "C"{ // interrupt routine that counts edges into edges_counted void PORTD_IRQHandler(void) { edges_counted++; PCR_PORT_TO_USE |= PORT_PCR_ISF_MASK; } } // return the frequency for the square_in input in Hz uint32_t frequency(void) { PCR_PORT_TO_USE &= ~PORT_PCR_IRQC_MASK; // disable interrupts on pin PTD4 edges_counted=0; PCR_PORT_TO_USE |= PORT_PCR_ISF_MASK | PORT_PCR_IRQC(11); // clear interrupt for PTD4, and enable interrupt on either edge wait_us(COUNTING_TIME); PCR_PORT_TO_USE &= ~PORT_PCR_IRQC_MASK; // disable interrupts on pin PTD4 uint32_t freq=edges_counted*MAINS_FREQ/2; return freq; } int main() { rled.period_us(PWM_PERIOD); gled.period_us(PWM_PERIOD); bled.period_us(PWM_PERIOD); set_RGB_color(255,255,0); // set light to yellow SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; // make sure port D has clocks on PCR_PORT_TO_USE &= ~PORT_PCR_MUX_MASK; // clearing the MUX field PCR_PORT_TO_USE |= PORT_PCR_MUX(1); // Setting pin as GPIO FPTD->PDDR &= ~ (1<<4); // make sure pin is input pin NVIC_EnableIRQ(PORTD_IRQn); // enable interrupts for port D host.baud(115200); host.printf("# starting"); __enable_irq(); uint32_t off_frequency= frequency(); while ( off_frequencyHIGH_FREQ_LIMIT) { // timed out. set color to red and keep trying set_RGB_color(255,0,0); host.printf("# FREQ out of range: %luHz\n", off_frequency); off_frequency= frequency(); } uint32_t low_freq= 8*off_frequency/10; // 80% of off_frequency uint32_t high_freq= 9*off_frequency/10; // 90% of off_frequency host.printf("# off= %luHz lo_thresh=%luHz hi_thresh=%luHz\n",off_frequency, low_freq, high_freq); while(1) { uint32_t freq=frequency(); host.printf("%lu Hz\n",freq); if (freq < low_freq) { // low_fequency found, turn LED green set_RGB_color(0,255,0); } else if (freq >= high_freq) { // high frequency found, turn LED blue again set_RGB_color(0,0,255); } } }