Theremin o Air Violín

Experimentando con el sensor de distancias SRF05 se me ocurrió un sencillo ejercicio: generar una frecuencia de audio variable en función de la distancia leída.

 


Como resultado de ese ejercicio conseguí un extraño instrumento músical que me recordó al Theremin, aunque aprovechándome de la moda de los Air instrumentos, creo que podría bautizarle como Air Violín.

He aquí un vídeo del resultado:

Y aquí el código en C30 para dsPIC33F, en el que utilizamos el módulo InputCapture para leer el SRF05 y el módulo PWM para generar la frecuencia del sonido.

En el ejemplo utilizamos también un display LCD pero no es imprescindible.

#include <p33FJ64MC706.h>
#define __33FJ64MC706_H
_FOSCSEL(1); // OSCILADOR INTERNO CON PLL
_FOSC (195);

#include "LCD_HD44780.h"
#include <stdio.h>
#include <timer.h>
#include <InCap.h>

char firma[] = {'M','i','c','r','o','p','i','c',' ','-',' ','2','0','0','8','\0'};
const proyecto[] = {'I','N','P','U','T',' ','C','A','P','T','U','R','E',' ','\0'};

// Usaremos el módulo Input Capture 1, que está en el pin RD8
#define IC1   PORTDbits.RD8
#define TRIS_IC1 TRISDbits.TRISD8

#define PULSADOR PORTDbits.RD1
#define TRIS_PULS TRISDbits.TRISD1

unsigned int Duracion_Pulso;
unsigned int Int_flag;

void __attribute__((__interrupt__)) _IC1Interrupt(void)
{
if (IC1) {
TMR2=0;
}
else {
Duracion_Pulso=TMR2;
Int_flag = 1;
}
IFS0bits.IC1IF = 0;
}

float MideDistancia() {
TRIS_IC1=0;
IC1=1;
delay_us(10);
IC1=0;
TRIS_IC1=1;
Int_flag=0;
ConfigIntCapture1(IC_INT_PRIOR_1 & IC_INT_ON);

while (!Int_flag);
DisableIntIC1;

return ((float)Duracion_Pulso/32.0);
// según la datasheet del SRF05, la relación entre us y cm es 1/58
// Duración * Prescaler / MIPS / 58
// Duración * 64 / 35.31 / 58
// Duración / 32
}

int Freq (float Nota) {
return (2000-(Nota-5.0)*35.0);
}

void GeneraPWM(int Frecuencia) {
if ((Frecuencia) && (PULSADOR)) {
//OC1CON = 0x000D; // Utilizamos Timer 2 para generar PWM por OC1
PR3 = MIPS * 1000000 / Frecuencia - 1;
OC1RS=PR3/2;
OC1R=0;
}
else
//OC1CON = 0x0000; // Utilizamos Timer 2 para generar PWM por OC1
PR3=0;
}

/***********************************************************************/
int main(void){
/***********************************************************************/
float Distancia, Frecuencia;
int Nota;

// Oscilador interno a 35,34
CLKDIVbits.PLLPRE=2;
CLKDIVbits.PLLPOST=1;
PLLFBD=168;
OSCTUN=38;

// Desactivados pines ADC
AD1PCFGL=0xFFFF;
AD2PCFGL=0xFFFF;

TRIS_IC1=0;
TRIS_PULS=1;

LCD_Inicializacion();
LCD_Goto (1,1);
LCD_EscribeCadena(firma);
LCD_Goto (2,2);
LCD_EscribeConstante(proyecto);
delay_ms(1000);

OpenCapture1(IC_IDLE_STOP & IC_TIMER2_SRC & IC_INT_1CAPTURE & IC_EVERY_EDGE);
T2CON = 0x8020; /* Timer 2 On */
T3CON = 0x8000; /* Timer 3 On */

OC1CON = 0x000D; // Utilizamos Timer 2 para generar PWM por OC1
while(1) {
LCD_Goto (1,2);
Distancia=MideDistancia();
printf ("Dist.: %3.2fcm.",Distancia);
if ((Distancia>5) && (Distancia<40))
Frecuencia = Freq(Distancia);
else
Frecuencia=0;
GeneraPWM(Frecuencia);
delay_ms(20);
};
}

Que lo disfrutes

 

Share