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.
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):
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) :
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).
Pasaremos ahora a la función para generar un sonido con la nota y la duración de esta:
espera=FreqNota[nota]; /*Calculamos T/2 que le corresponden a la nota*/
}
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:
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:
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
};
#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.
}
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);
}
//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:
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
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
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
gracias
Hola puedo correr este código en mplab?