TOP

Cómo generar música con un PIC

En esta entrada os explicaré como generar música con un PIC. La idea está sacada de este blog picrobot
Yo trataré de que se entienda mejor la idea y con un código más claro.
Si queremos generar música debemos generar sonidos.


Pero...¿Qué es un sonido?
Un sonido se trata de una onda de presión generada por un cuerpo en vibración que se propaga por un fluido.Tres características básicas del sonido son:
-La intensidad (Lo "fuerte" que se escucha el sonido)
-El tono (La frecuencia del sonido: a mayor frecuencia mas agudo y a menor frecuencia  mas grave)
-La duración (Cuanto dura el sonido)


Para generar un sonido con un PIC obviamente necesitaremos el PIC y un componente que reproduzca esas ondas audibles, el altavoz.
Si ponemos en alto "X" tiempo un pin del PIC y luego en bajo ese tiempo y repetimos esa secuencia, tendremos una onda. (Una onda cuadrada que se puede asemejar a una onda senoidal)


Asi que:
-El tiempo en alto(o bajo) será medio periodo de esta y con ello podremos calcular la frecuencia, es decir el tono.
-La intensidad del sonido será el voltaje que le suministremos al altavoz.
-Y la duración será cuanto tiempo repetiremos la secuencia de alto y bajo.

Ahora bien para generar música no basta con hacer sonidos con las frecuencias que nos de la gana ya que lo mas seguro es que no suene bien, si no que los sonidos deben de tener el tono adecuado, es decir, aquí es donde actúan las notas musicales. 




 Decir que dividimos el espectro audible (de 20 Hz a 20 KHz) en octavas, y las octavas en notas (Si me equivoco en algo que alguien me corrija que no soy experto en música :P).  Tenemos 7 notas musicales  (Do, Re Mi, Fa, Sol, La, Si) , cada una de ellas tendrá una frecuencia determinada. La octava inferior  de una nota tendrán la mitad de frecuencia y la octava superior tendrá el doble de frecuencia.
Por ejemplo la nota "La"  de la tercera octava tiene una frecuencia de 440 Hz, la cuarta octava tiene 880 Hz y la segunda octava 220 Hz. (A partir de esta nota se calculan las demás con unos cálculos)
(Para quién le interese saber más que lea este artículo http://latecladeescape.com/t/Frecuencia+de+las+notas+musicales)

A nosotros solo nos interesarán las primeras 6 octavas ya que por encima de la sexta no se escucha bien con el PIC.
Estas son las frecuencias de cada nota (en Hz):


0
1
2
3
4
5
6
DO
32,70
65,40
130,81
261,62
523,25
1046,50
2093,00
DO#
34,64
69,29
138,59
277,18
554,36
1108,73
2217,46
RE
36,70
73,41
146,83
293,66
587,32
1174,65
2349,31
RE#
38,89
77,78
155,56
311,12
622,25
1244,50
2489,01
MI
41,20
82,40
164,81
329,62
659,25
1318,51
2637,02
FA
43,65
87,30
174,61
349,22
698,45
1396,91
2793,82
FA#
46,24
92,49
184,99
369,99
739,98
1479,97
2959,95
SOL
48,99
97,99
195,99
391,99
783,99
1567,98
3135,96
SOL#
51,91
103,82
207,65
415,30
830,60
1661,21
3322,43
LA
55,00
110,00
220,00
440,00
880,00
1760,00
3520,00
LA#
58,27
116,54
233,08
466,16
932,32
1864,65
3729,31
SI
61,73
123,47
246,94
493,88
987,76
1975,53
3951,06


Para no cargar el PIC con cálculos matemáticos pasamos la frecuencia ya a su equivalencia a T/2 que debe estar en alto o en bajo el PIC (en microsegundos) :


0
1
2
3
4
5
6
DO
15289,02
7644,51
3822,25
1911,12
955,56
477,78
238,89
DO#
14430,91
7215,45
3607,72
1803,86
901,93
450,96
225,48
RE
13620,97
6810,48
3405,24
1702,62
851,31
425,65
212,82
RE#
12856,48
6428,24
3214,12
1607,06
803,53
401,76
200,88
MI
12134,90
6067,45
3033,72
1516,86
758,43
379,21
189,60
FA
11453,82
5726,91
2863,45
1431,72
715,86
357,93
178,96
FA#
10810,97
5405,48
2702,74
1351,37
675,68
337,84
168,92
SOL
10204,20
5102,10
2551,05
1275,52
637,76
318,88
159,44
SOL#
9631,48
4815,74
2407,87
1203,93
601,96
300,98
150,49
LA
9090,90
4545,45
2272,72
1136,36
568,18
284,09
142,04
LA#
8580,67
4290,33
2145,16
1072,58
536,29
268,14
134,07
SI
8099,07
4049,53
2024,76
1012,38
506,19
253,09
126,54


Si habéis entendido lo anterior no será nada difícil entender el código para reproducir música con el PIC.

Funciones que realizaremos:
-Función para reproducir un sonido dada la nota musical (el tono) con su octava y la duración de esta.
-Función para reproducir una canción. (En esta función pondremos los diferentes sonidos (Usando la función anterior) con las diferente pausas para generar la canción).

Para que sea más fácil crear la canción crearemos un vector global con los tiempos de los medios periodos de las notas de la octava 0. Y  para no tener que recordar en que posición del vector están las notas crearemos un define asignando las posiciones del vector con una palabra (el nombre de las notas).



#define nDO     0    // DO
#define nDO_    1    // DO#
#define nRE     2    // RE
#define nRE_    3    // RE#
#define nMI     4    // MI
#define nFA     5    // FA
#define nFA_    6    // FA#
#define nSOL    7    // SOL
#define nSOL_   8    // SOL#
#define nLA     9    // LA
#define nLA_    10   // LA#
#define nSI     11   // SI


int16 FreqNota[12]={  // retardos entre estado alto
                            // y bajo para generar las notas
15289, // DO
14430, // DO#
13620, // RE
12856, // RE#
12134, // MI
11453, // FA
10810, // FA#
10204, // SOL
9631,  // SOL#
9090,  // LA
8580,  // LA#
8099   // SI
};




Pasaremos ahora a la función para generar un sonido con la nota y la duración de esta:

void play(int8 nota, int8 octava, int32 tiempo){ //Tiempo en ms
   int16 i;
   int16 espera;
   int16 vueltas;
   

   espera=FreqNota[nota]; /*Calculamos T/2 que le corresponden a la nota*/
   espera>>=(octava);     /*Calculamos su correspondiente octava
                          /*>>= es desplazamiento a la derecha, lo mismo que si     hiciésemos
                          espera/2 tantas veces como pone despues de  >>= , asi nos ahorramos calculos*/
   
vueltas=(tiempo*1000)/(espera*2); /*Calcula cuantas vueltas tiene que dar el    bucle siguiente, multiplicamos el tiempo por 1000 para pasarlo a us*/
   
   for(i=0; i< vueltas; i++){
      output_high(Altavoz); /*Ponemos en alto el Altavoz*/
      delay_us(espera);     /*Lo dejamos durante el tiempo calculado*/
      output_low(Altavoz);  /*Ponemos en bajo el Altavoz*/
      delay_us(espera);     /*Lo dejamos durante el tiempo calculado*/
   }

}

El único problema que tiene la función anterior es que si la canción es muy larga no entrará en la ROM del PIC debido a que para calcular el tiempo utilizo enteros de 32 bits. (si se usan enteros de 16 bits no podremos hacer la cuenta de  vueltas=(tiempo*1000)/(espera*2); ya que si el tiempo es mayor de 65 ms
al hacer tiempo*1000 sobrepasaremos el tamaño de 16 bits).
(Si vais a hacer un proyecto y le queréis poner una música, ojo con la memoria)
Esto se puede solucionar como el código del blog picrobot que permite hacer canciones de mayor tamaño en menos espacio, aunque el código es un poco mas lioso y largo:


void Play(int nota, int octava, int16 duracion){
 int16 fn;

 int16 mS_Transcurridos=0;  // Contadores necesarios
                            // para controlar la duración
 int16 CiclosL=0;           // Contandor de uS

 fn=FreqNota[nota];         // Define los retardos para generar
                            // la frecuencia de cada nota
 fn>>=(octava);             // Adapta la frecuencia a la octava actual
                            // haciendo una rotación
                            // a la derecha por octava
do{

    output_high(Speaker);   // Genera la frecuancia
    delay_us(fn);           // con los retardos mientras
    CiclosL+=(fn);          // aumenta el contador de 
                            // ciclos transcurridos
    output_low(Speaker);    // en dos partes para repartir el
    delay_us(fn);           // trabajo entre estado alto y bajo.
    CiclosL+=(fn);          //
    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.
}


Ya solo queda crear una función para reproducir la canción. La idea es ir poniendo las notas usando la función anterior con las pausas adecuadas para que suene bien la canción.
Aquí tenéis un ejemplo de la canción Pop Corn:


void PlayCancion(){
        //POP CORN
        play (nDO   ,5,166);
        play (nLA_  ,4,166);
        play (nDO   ,5,166);
        play (nSOL  ,4,166);
        play (nRE_  ,4,166);
        play (nSOL  ,4,166);
        play (nDO   ,4,166);
        delay_ms (166);
        play (nDO   ,5,166);
        play (nLA_  ,4,166);
        play (nDO   ,5,166);
        play (nSOL  ,4,166);
        play (nRE_  ,4,166);
        play (nSOL  ,4,166);
        play (nDO   ,4,166);
        delay_ms (166);
        play (nDO   ,5,166);
        play (nRE   ,5,166);
        play (nRE_  ,5,166);
        play (nRE   ,5,166);
        play (nRE_  ,5,166);
        play (nDO   ,5,166);
        play (nRE   ,5,166);
        play (nDO   ,5,166);
        play (nRE   ,5,166);
        play (nLA_  ,4,166);
        play (nDO   ,5,166);
        play (nLA_  ,4,166);
        play (nDO   ,5,166);
        play (nSOL_ ,4,166);
        play (nDO   ,5,166);
        
  }


Yo he utilizado el PIC16F88 y he adaptado la canción de Super Mario Bros I de NES  al PIC.
Por si alguien quiere el código con la canción lo dejo aquí:

DESCARGAR

Decir que la canción no se escucha perfecta porque la duración de las notas las hice a oído.
Aquí podéis ver el resultado:
Espero que os haya gustado la entrada.
¡Un Saludo!

5 comentarios:

  1. Hola les dejo mis videos de el uso de PIC para reproducir melodias
    http://www.youtube.com/watch?v=I699YIQdYYc

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

    Saludos

  2. Hola como haria para usar sensores infrarojos ya q estos se manejan por frecuencia como seria tendo un modulo detector de obstaculos pero no he podido hacer q el pic reconozca esa frecuencia

  3. Hola buenas.
    No se nada de programación, pero me gustaria poder quemar en PIC melodias personalizadas con la ayuda de algún amigo músico, toda esta información me va genial, pero dado mi nivel de desconocimiento necesito saber el programa en el que insertar todos estos códigos i poder quemar en PIC.
    Espero alguna respuesta, y gracias por todo

  4. gracias

  5. Hola puedo correr este código en mplab?

Publicar un comentario