Generar sonido con PIC

En los tiempos que corren estamos acostumbrados a vivir rodeados de tecnología, hoy en día cualquier movil supera en millones de operaciones por segundo al primer ordenador que tuve, hasta un PIC puede funcionar a mas velocidad que un 80286, pero hubo un tiempo en que un teléfono movil no estába al alcance de cualquiera, y en esa época no existían aparatos capaces de brindarnos la experiencia multimedia que hoy damos por sentado de que es así. Y estamos hablando de poco menos de 20 años atras, en esa epoca por lo menos los PC normales, no disponían de una placa de sonido y cualquier juego ejecutaba a duras penas un, a veces, desesperante pitido a modo de música.

Bueno, es por eso que en un arrebato de nostalgia se me ocurrió que podría emular esas "dulces" melodías con un PIC y es por eso que ahora tu estás leyendo esto. Inmediatamente despues me acordé de algo muy importante y es que no tengo ni la mas remota idea de música. Entonces decidí comenzar por el lugar mas obvio, o sea por el principio, fue cuando deduje que para que haya música primero tiene que haber sonido, entonces lo primero que hay que hacer es que el PIC emita algo de sonido controlado, ya habrá tiempo de generar notas musicales.

Primero hay que tener un concepto aunque sea básico de lo que el sonido es, en principio el sonido es un golpe en un medio, en nuestro caso el aire y, dependiendo de la frecuencia de ese "golpe", el sonido producido será mas agudo o mas grave; El oido humano puede percibir sonidos con una frecuencia que está comprendida entre los 20Hz y los 20KHz, en otras palabras que una persona puede escuchar frecuencias de esos golpes desde unas 20 veces por segundo hasta unas 20 mil aproximadamente. Entonces aquí ya tenemos un dato: para generar el sonido con el PIC debemos conectar un altavoz a una salida del microcontrolador y hacer alternar su estado de alto a bajo a una frecuencia determinada. Cuanto mas rápido se varíe el estado mas agudo será el sonido y viceversa.

Para obtener la duración del periodo (estado alto o bajo) para una frecuencia f solo hace falta usar la siguiente formula:

tP = 1
f

Para generar un sonido dentro de los margenes perceptibles, digamos de unos 650Hz realizaremos la siguiente operación:

tP = 1
650
= 0,0015385

El resultado obtenido es el tiempo, en segundos, que debe tardar cada periodo para producir un sonido de 650Hz. En este caso es 1538uS que es la medida que nosotros necesitamos para operar con el PIC, recuerda que un PIC con un cristal corriendo a 4 MHz realiza una operacion cada 1uS.

Cada 1538uS o, lo que es lo mismo, cada 1,538mS se debe producir un cambio de estado del la salida del microcontrolador para producir un sonido a 650Hz, entonces lo que necesitamos ahora es dividir ese valor en 2, una mitad para el estado alto y la otra mitad en estado bajo.

Con todo esto tenemos que: 1538 / 2 = 769, si traducimos esta teoría en lenguaje C quedaría de esta forma:

#include <16f876a.h>          // Tipo de microcontrolador
#use delay(clock=4000000)     // Delay con xtal de 4MHz
#use fast_io(all)             // I/O todas rápidas, de esta forma cuando se
                              // escribe en los puertos, no se configura el tris
                              // acelerando el proceso.  
#fuses HS                     // FUSES cristal HS >=4MHz 
#FUSES NOPUT                  // No power up Timer, no espera a estabilizar la tension 
#FUSES NOBROWNOUT             // No Brown out reset, no se resetea si cae la tension  
#define Speaker   PIN_B0      // Altavoz conectado a RB0  

void main(){
   
   set_tris_b(2); // RB<7:2> Salida RB1 entrada (Pulsador) RB0 Salida (Speaker)
   
   do{                              // Bucle infinito
      
      while(input(PIN_B1)){         // Mientras se presione el
                                    // interruptor conectado a RB1.
                                    
         output_high(Speaker);      // Altavoz encendido
         delay_us(769);             // espera 769 uS
         
         output_low(Speaker);       // Altavoz apagado
         delay_us(769);             // espera 769 uS
      }
      
   }while(true);
}

Este ejemplo lo único que hace es emitir un sonido, ni agudo, ni grave, cuando se activa el pulsador conectado a RB1.

Nuestro PIC acaba de emitir su primer sonido!

Ahora podremos crear una funcion que emita un sonido con la frecuencia y duracion deseados.
El siguiente ejemplo hace sonar una sirena cuando se pulsa un interruptor en RB1.

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//                            PICSirena 1.00                               //
//                   (c) 2010 Gerardo Ariel Ramírez.                       //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//       uControlador: PIC16F876A            Lenguaje: CCS C               //
//               Xtal: 4MHz                                                //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////


#include <16f876a.h>          // Tipo de microcontrolador
   
#use delay(clock=4000000)     // Delay con xtal de 4MHz
#use fast_io(all)             // I/O todas rápidas, de esta forma cuando se
                              // escribe en los puertos, no se configura el tris
                              // acelerando el proceso.

#FUSES HS                     // FUSES cristal HS >=4MHz
#FUSES NOPUT                  // No power up Timer, no espera a estabilizar la tension
#FUSES NOBROWNOUT             // No Brown out reset, no se resetea si cae la tension

#define Speaker   PIN_B0      // Altavoz conectado a RB0

void Sound(int16 frecuencia, int16 duracion);

void main(){
   int t;
   set_tris_b(2);
   
   while(true){      //Bucle infinito
   
      if (input(PIN_B1)){                 // Si se activa el pulsador
      
         for (t=0;t<30;t++)               // Bucle ascendente incrementando la
            sound(((int16)t*15)+1600,20); // frecuencia del sonido
         for (t=30;t>0;t--)               // Bucle decrementando
            sound(((int16)t*15)+1600,20); // la frecuencia del sonido
      
      }
   }
}

void Sound(int16 frecuencia, int16 duracion){
   
   int16 mS_Transcurridos=0;
   int16 CiclosL=0;
   int16 uS;
   int32 tmp;
   
   if (frecuencia>=20&&frecuencia<=20000){ //si la frecuancia se encuentra entre
                                           // los margenes de 20Hz y 20 KHz se ejecuta
      tmp=100000;                          // de los contrario no.
      tmp/=frecuencia;           // convierte los Hz a microsegundos para la pausa
      tmp*=5;   
      uS=tmp;
      do{
         output_high(Speaker);   // Genera la frecuancia deseada
         delay_us(uS);           // con los retardos mientras
         CiclosL+=(uS);          // aumenta el contador de ciclos transcurridos
         output_low(Speaker);    // en dos partes para repartir el 
         delay_us(uS);           // trabajo entre estado alto y bajo.
         CiclosL+=(uS);          // 
         CiclosL+=25;            // Compensador.
         
         while(CiclosL>999){     // Se queda en el bucle mientras CiclosL sea
                                 // menor a 1000 (1 mS)
            CiclosL-=1000;       // Le resta 1000 a CiclosL 
            mS_Transcurridos++;  // y le suma 1 a mS_Transcurridos.
            CiclosL+=25;         // Compensador.
         }
      }while (duracion>mS_Transcurridos);// Repite el bucle hasta que haya pasado el
                                         // tiempo indicado.
   }
}

Desde este link te puedes bajar el proyecto y el hex.

Bueno, hasta aquí hemos llegado, ahora resta por hacer que el PIC reproduzca alguna nota musical e interprete alguna canción, pero eso lo veremos en Generar música con PIC.

20 comentarios:

  1. Anónimo8/12/10

    Hola, Como podria generar un sonido que vaya variando de frecuencia pero en el rango de los ultrasonicos (20K a 60KHz ). ¿Que speaker podria conectar y como?
    Saludos desde Tigre, Buenos Aires, Argentina

    ResponderEliminar
  2. Sólo debes generar la frecuencia deseada y, en lugar de un altavoz normal, utilizar un transductor ultrasónico.

    Si tienes dudas sobre como generar las frecuencia, me avisas.

    Saludos.

    ResponderEliminar
    Respuestas
    1. hola,
      una pregunta como harias para generar sonidos como un laser disparando? es que he bajado sonidos en wav y lo he convertido en binario pero no se como usar esa informacion para generar sonidos,
      me podrias ayudar?
      gracias

      Eliminar
  3. Anónimo31/1/11

    De casualidad tienes el programa en asm, es que en c no entiendo nada.
    Mil gracias

    ResponderEliminar
  4. Dame unos días, y lo posteo.

    De todas formas te cuento que en el programa IC-Prog, hay una opción que, cargando el HEX, te lo convierte a código Assembler. Es bastante genérico, sin nombres de variables, ni nada, pero para tener una idea y, si entiendes ASM, sirve bastante.
    En realidad lo único que hace es "traducir" los opcodes a la sintaxis de ASM.

    Saludos.

    ResponderEliminar
  5. Fijate amigo que en la escuela me dejaron un generador de tonos telefonico con un pic mi pregunta es k si con tu codigo guiandome pueda lograr que se genere un determinado tono con su respectiva frecuencia ej1472hz al momento de tocar un boton y lograr esto con los demas 9 tonos espero ke me puedas ayudar de antemano gracias saludos

    ResponderEliminar
  6. Buenas, en la entrada http://picrobot.blogspot.com/2010/03/picmusic.html puedes observar que está la tabla con las frecuencias de cada nota musical. Si te fijas en FA# en la octava 5.
    Puedes hacerlo modificando los valores para obtener las frecuencias deseadas, el inconveniente es que no podrías ejecutar 2 al mismo tiempo.

    Saludos.

    ResponderEliminar
  7. Anónimo12/4/12

    hola, tu proyecto esta muy interesante al igual que el de generar música con PIC, si podrías subir los archivos a otro servidor distinto a Megaupload. Te lo agradecería

    ResponderEliminar
  8. Anónimo5/4/13

    Hola, muy buena la pagina.
    Necesitaria un programita para un PIC que generara 5 ó 6 tonos secuenciales, de una duración aproximada de entre 30 y 100 ms cada tono, que se activara este tren de tonos al poner un pin a masa y despues volviera a reposo. Desde ya muchas gracias.

    ResponderEliminar
  9. amigo,buen día estoy empezando en esto, es factible que pueda utilizar un pic 18f84a? o en que afectaria, de antemano gracias por dedicar tu tiempo y compartir conocimientos

    ResponderEliminar
  10. Buen día, por favor me podrías decir cuales son las frecuencias de los tonos de ambulancia? muchas gracias

    ResponderEliminar
  11. Hola les dejo los videos de unas melodias reproducidas con PIC

    http://www.youtube.com/watch?v=jZexwvP0FUU

    http://www.youtube.com/watch?v=I699YIQdYYc

    ResponderEliminar
  12. Hola, tienes tutoriales para aprender a programar microcontroladores en C y que compilador me recomiendas. Saludos Excelente tu WEB

    ResponderEliminar
  13. Maravilloso, muy util tu articulo! te felicito!

    ResponderEliminar
  14. hola,
    una pregunta como harias para generar sonidos como un laser disparando? es que he bajado sonidos en wav y lo he convertido en binario pero no se como usar esa informacion para generar sonidos,
    me podrias ayudar?
    gracias

    ResponderEliminar
  15. Hola, un tutorial muy interesante, he comenzado a aprender a programar y un proyecto que quisiera logra es usando un 12f675, generar sonidos usando un buscapolos que funcione con 12 volts. que se genere un sonido alto cuando se detecte un voltaje de 5 volts arriba y un tono bajo al detectar de .5 volts hacia tierra. cualquier ayuda seria de gran utilidad. gracias!

    ResponderEliminar
  16. Muy bueno.... Te agradezco el esfuerzo por mantener este blog.

    ResponderEliminar
  17. hola una pregunta para generar por ejemplo un tono corto un tono largo y dos tonos cortos mas como seria

    ResponderEliminar


Tal vez le interese: