Montaje 5: Simón

Requisitos:

  • 4 LEDs, 4 resistencias de 220 ohmios
  • 4 pulsadores, 4 resistencias de 1Kohmio.
  • 1 zumbador.
  • 1 optoacoplador y 1 resistencia de 220 ohmios.
  • 1 juguete de bazar (teléfono móvil falso con melodía digital).

Planteamiento: “Simón” es uno de los primeros juguetes digitales domésticos. Se trata de un aparato que propone una melodía, y el jugador ha de repetirla. Si el jugador la acierta, propone una melodía un poco más larga, y así sucesivamente hasta una melodía de 10 notas.

Cuando el jugador acierta en una melodía de 10 notas, se repite el juego partiendo otra vez de una sola nota, sólo que más deprisa.

Presentación: Uso de un optoacoplador para disparar un circuito eléctrico separado.

Este montaje se basa en los dos ejercicios anteriores: Ejercicio 18: replay? y cerradura digital de seguridad?.

El bucle maestro del programa, loop() cuenta casi toda la historia: primero se llama al procedimiento inicio() que es el que inicializa la semilla para el generador de secuencias de números pseudoaleatorios, y también el que hace la “demo” no interactiva, la rueda de luces y tonos que anima a los jugadores a que pulsen una tecla. Esto sólo sucede antes de la primera ronda, y para controlar esto usamos la variable t.

Cuando los jugadores han pulsado cualquier tecla, inicio() devuelve el control a loop(), tras haber inicializado las dos cadenas, una correspondiente a las luces, y otra correspondiente a los tonos. Tras un breve retardo, play() reproduce una serie de notas de la cadena, tantas como corresponda para nuestra ronda: (una para la primera ronda, una serie de dos para la segunda ronda, etc.). La variable que usamos para saber cuántas notas corresponde tocar en cada ronda se llama serie.

Por conveniencia, play() mide el tiempo del tono musical con el periodo de la oscilación de la onda cuadrada. Esto da lugar a que los tonos duren más cuanto más graves son, dado que en realidad se está contando un número fijo de oscilaciones de la onda cuadrada, y los tonos más graves tienen un período más largo. Esto se podría arreglar modificando el número de oscilaciones según la frecuencia del tono, y quizá sea un buen ejercicio para proponer a alumnos avanzados.

Tras reproducir la serie de sonidos corresponde al jugador introducir sus pulsaciones con guardapuls(). Aquí el código es idéntico al que hacíamos en el ejercicio “cerradura”, sólo que el número de pulsaciones viene dado por el turno.

El procedimiento guardapuls() recoge tantas pulsaciones como corresponda según la ronda. Aquí de nuevo usamos el tono como temporizador para el encendido del diodo luminoso, y el jugador tiene que esperar a que termine cada nota antes de pulsar la siguiente tecla, o se arriesga a que no se guarde su siguiente pulsación. Tras el procedimiento compruebapuls(), que de nuevo es el equivalente al del ejercicio de la cerradura de combinación, viene compruebaserie(), que sólo deja pasar de serie si el número de aciertos es el mismo que el de la serie (esto es, todos). Si los aciertos son todos, pasa a la siguiente ronda.

Por último, pasaronda() comprueba si es la última ronda. Si no es así, el programa continúa y se vuelve al inicio del bucle loop (). Si se trata de la última ronda, se dispara la melodía de un juguete de bazar mediante un opto-acoplador, y se reinicializan las variables para que en la siguiente ronda el programa se comporte como si fuera la primera, pero con la variable “tiempo” más reducida, con lo que el juguete funciona más deprisa.

Variantes posibles:

  • El juguete que hemos realizado no se comporta exactamente igual que un Simón comercial. La comprobación de las pulsaciones podría hacerse con cada nota en lugar de todas al final, de modo que el Simón no dejara continuar en caso de error, y obligara a comenzar la secuencia otra vez. Se puede buscar un Simón comercial e intentar copiarlo en todas sus características.
  • Como hemos visto, los tonos se realizan mandando una onda cuadrada a un zumbador. Los alumnos más avezados podrían intentar hacer que los tonos tuvieran la misma duración.

VIDEOS DEL MONTAJE DEL SIMÓN BASADOS EN LOS EJERCICIOS PREVIOS:

 VIDEO 1 DEL MONTAJE 5: Flash
 VIDEO 2 DEL MONTAJE 5: Dispara el flash
 VIDEO 3 DEL MONTAJE 5: Ruleta luminosa
 VIDEO 4 DEL MONTAJE 5: Interruptor del intermintente
 VIDEO 5 DEL MONTAJE 5: Para la ruleta y gana
 VIDEO 6 DEL MONTAJE 5: Para ese despertador
 VIDEO 7 DEL MONTAJE 5: Escala musical
 VIDEO 8 DEL MONTAJE 5: Sirena
 VIDEO 9 DEL MONTAJE 5: Para la ruleta musical
 VIDEO 10 DEL MONTAJE 5: Timbre musical
 VIDEO 11 DEL MONTAJE 5: Llave nuclear
 VIDEO 12 DEL MONTAJE 5: Luz interior de un coche
 VIDEO 13 DEL MONTAJE 5: Ruleta musical aleatoria
 VIDEO 14 DEL MONTAJE 5: Música automática
 VIDEO 15 DEL MONTAJE 5: Replay

VIDEOS DEL MONTAJE FINAL DEL SIMÓN:

 MONTAJE 5: Simón montado en una Protoboard
 MONTAJE 5: Simón - Inicio
 MONTAJE 5: Simón - Final y reinicio

CODIGO FUENTE

 Copyright (C) 2006  Juan Carlos Alonso de Mena
 This program is free software; you can redistribute it and/or modify it under the terms
 of the GNU General Public License as published by the Free Software Foundation;
 See the GNU General Public License for more details?

 int cadenaLeds[] ={6,7,8,9};                  // cadena con los pins a los que se  conectan los leds
 int cadenaPuls[]={2, 3, 4, 5};                // cadena con los pins a los que se conectan los pulsadores
 int notas[] = {1915,  1519,  1275,  1014};    // cadena con las frecuencias de las notas
 int psrnum=0;                                 // variable que almacena el nº pseudoaleatorio
 int color=0;                                  // variable que almacena el nº pseudoaleatorio acotado entre 0 y 3
 int serieLeds[] = {0,0,0,0,0,0,0,0,0,0};      // cadena con los pins de los leds que forman la serie
 int seriePuls[] = {0,0,0,0,0,0,0,0,0,0};      // cadena con los pins de los pulsadores que forman cada intento
 int serieNotas[] = {0,0,0,0,0,0,0,0,0,0};     // cadena con las frecuencias de las notas que forman la serie
 int n= 0;                                     // 3 variables usadas como contadores
 int cont=0;
 int m=0;
 int ini= 0;                                   // variable que almacena la semilla del generador de números pseudoaleatorios
 int zumb=10;                                  // variable con el pin al que se conecta el zumbador  
 int opto=12;                                  // variable con el pin al que se conecta el optoacloplador
 int tiempo=200;                               // variable que marca el ritmo al que se sucede la serie
 int serie=1;                                  // variable que usamos como contador para la longitud de la serie
 int c=0;                                      // variable que guarda el nº de aciertos 
 int t=0;                                      // variable que indica si es el comienzo de una ronda
 //--------------------------------------------------------------------------------------------

 void setup(){
   for (n=0;n<4;n++) {                         //Establece los pins a los que están conectados los pulsadores como entradas
     pinMode(cadenaPuls[n], INPUT);
   }
   for (n=0;n<4;n++) {                         //Establece los pins a los que están conectados los leds como salidas
     pinMode(cadenaLeds[n], OUTPUT);
   }
   pinMode(zumb, OUTPUT);                      //Establece el pin al que está conectado el zumbador como salida
   pinMode(opto, OUTPUT);                      //Establece el pin al que está conectado el optoacoplador como salida
 }
 //--------------------------------------------------------------------------------------------

 void demo(){                                  //Ruleta de presentación 
   for (n=0;n<4;n++) {
     digitalWrite(cadenaLeds[n],HIGH);
     for(cont=0;cont<=100;cont++){      
       digitalWrite(zumb,HIGH);
       delayMicroseconds(notas[n]);
       digitalWrite(zumb, LOW);
       delayMicroseconds(notas[n]);
     }
     digitalWrite(cadenaLeds[n],LOW);
     delay(100);
   }
 }
  //--------------------------------------------------------------------------------------------

 randomize(int data){                          //Función del generador de números pseudoaleatorios
   return ((1664525*data)%1023);
 }

 void randomserie(){
   for(n=0;n<11;n++){                                
     psrnum=randomize(psrnum);                 //Generador de números pseudoaleatorios
     color=abs(psrnum)%4;                      //Acota los números pseudoaleatorios entre 0 y 3 incluídos
     serieLeds[n]=cadenaLeds[color];           //Forma la serie de leds tomando las salidas digitales de las posiciones en la cadena
     serieNotas[n]=notas[color];               //Forma la serie de notas tomando las salidas digitales de las posiciones en la cadena
   }
 }

 //----------------------------------------------------------------------------------------------

 void inicio(){
   if(t==0){                                   //Si es el comienzo de una ronda
     delay(300);
     while((digitalRead(2)==LOW)&&(digitalRead(3)==LOW)&&(digitalRead(4)==LOW)&&(digitalRead(5)==LOW)){    //Espera a que se pulse alguno
       ini=ini+1;                              //Va acumulando valores para la semilla del pseudorandom
       demo();                                 //Pone en marcha la ruleta de presentación
     }                                         //En cuanto se pulsa algún pulsador:
     psrnum= randomize(ini);                   //Genera el primer nº pseudoaleatorio a partir de la semilla
     randomserie();                            //Produce la serie psudoaleatoria
   }                                                   
 }

//----------------------------------------------------------------------------------------------

 void play(){
   for(n=0;n<serie;n++){
     digitalWrite(serieLeds[n],HIGH);          //Enciende el led
     for(cont=0;cont<(tiempo/2);cont++){       //Da la nota
       digitalWrite(zumb,HIGH);                //Envía un pulso al pin del zumbador con la frecuencia guardada
       delayMicroseconds(serieNotas[n]);       // en la posición correspondiente de la cadena
       digitalWrite(zumb,LOW);
       delayMicroseconds(serieNotas[n]);
     }
     digitalWrite(serieLeds[n],LOW);           //Apaga el led
     delay(tiempo);                            //Espera un poco a que se ilumine el siguiente
   }
 }

 //------------------------------------------------------------------------------------------

 void replay(){                                //Para depurar, comprueba que la serie de pulsaciones se ha guardado bien 
   digitalWrite(seriePuls[n],HIGH);
   for(cont=0;cont<(tiempo/2);cont++){      
     digitalWrite(zumb,HIGH);
     delayMicroseconds(notas[seriePuls[n]-6]);
     digitalWrite(zumb,LOW);
     delayMicroseconds(notas[seriePuls[n]-6]);
   }
   digitalWrite(seriePuls[n],LOW);
   delay(tiempo);
 }

 //------------------------------------------------------------------------------------------

 void flash(){                                 //Con un for no destellean a la vez
   for(n=0;n<4;n++){
     digitalWrite(cadenaLeds[n],HIGH);
   }
   delay(100);
   for(n=0;n<4;n++){ 
     digitalWrite(cadenaLeds[n],LOW);
   }
   delay(100);
 }

 //------------------------------------------------------------------------------------------

 void guardapuls(){
   for(m=0;m<serie;m++){
     while((digitalRead(2)==LOW)&&(digitalRead(3)==LOW)&&(digitalRead(4)==LOW)&&(digitalRead(5)==LOW)){    //Esperando que se pulse
       delay(100);
     }
     for(n=0;n<4;n++){
       if(digitalRead(cadenaPuls[n])==HIGH){   //Al pulsar, se ilumina el led y suena la nota
         digitalWrite(cadenaLeds[n],HIGH);
         for(cont=0;cont<(tiempo/2);cont++){      
           digitalWrite(zumb,HIGH);
           delayMicroseconds(notas[n]);
           digitalWrite(zumb,LOW);
           delayMicroseconds(notas[n]);
         }
         digitalWrite(cadenaLeds[n],LOW);   
         seriePuls[m]=cadenaPuls[n]+4;         //Traducción del pulsador al led que lo acompaña
         delay(200);
       }
     }
   }
 }

//------------------------------------------------------------------------------------------

 void compruebapuls(){
   for(n=0;n<serie;n++){
     //replay();                               // para comprobar que se están guardando bien las series
     if(seriePuls[n]==serieLeds[n]){           //Si hemos pulsado el correcto
       c=c+1;                                  //aumenta en uno la cuenta de los aciertos
     }
     else{
     }
   }
 }

 //------------------------------------------------------------------------------------------

 void pasaronda(){
   if(serie==11){
     while((digitalRead(2)==LOW)&&(digitalRead(3)==LOW)&&(digitalRead(4)==LOW)&&(digitalRead(5)==LOW)){
       digitalWrite(opto,HIGH);
       flash();
       flash();
       flash();
       digitalWrite(opto,LOW);
       flash();
       delay(2000);
       flash();
     }
     delay(5000);
     serie=1;                                  //Reseteo del contador de la longitud de la serie
     t=0;                                      //Reseteo de inicio de ronda
     tiempo=tiempo-50;                         //Acelera el ritmo
   }
 }

//------------------------------------------------------------------------------------------

 void compruebaserie(){
   if (c==serie){                              //Si los aciertos son todos
     serie=serie+1;                            //Aumenta el contador de la longitud de la serie
     for(m=0;m<10;m++){
       flash();
     }
     pasaronda();                              //Comprueba si ha terminado una ronda, y si es así pasa a la siguiente
   }
 }

 //------------------------------------------------------------------------------------------

 void loop(){
   inicio();
   delay(500);
   play();
   t=t+1;                                      //Para distinguir, con t=0, el comienzo de cada ronda de 10 series
   for(m=0;m<5;m++){
     flash();
   }
   guardapuls();
   compruebapuls();
   compruebaserie();
   c=0;                                        //Resetea la cuenta de aciertos de cada serie
   delay(500);
 }

Volver?

  Copyright (c) 2006  Juan Carlos Alonso de Mena

  Permission is granted to copy, distribute and/or modify this document under the terms of 
 the GNU Free Documentation License, Version 1.2 or any later version published by the
 Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no
 Back-Cover Texts.  A copy of the license is included in the section entitled 
 GNU Free Documentation License?.