Paso 3: El código y archivos Wav
El código es de Adafruit y es respetables partes y ha sido modificado. He añadido un 4 º byte de botón y el sonido. Los bytes de sonido ha cambiado por mi propia y he cambiado los ojos de la ronda a triángulo.Este Instructable asume que usted ya sabe cómo trabajar con arduino, (código de instalación, biblioteca, etc.)
EL CÓDIGO.
Puede copiar y pegar el siguiente código en el IDE de arduino o haga clic en el archivo.
Cara de calabaza disfraz
Este bosquejo se ha cambiado levemente de la original
Creador como se ve abajo. ¡ Disfrute!
sketch de ejemplo 'wavface' para Adafruit I2C mochilas de LED 8 x 8
y protector de la onda:
//
www.Adafruit.com/products/870 www.adafruit.com/products/1049
www.Adafruit.com/products/871 www.adafruit.com/products/1050
www.Adafruit.com/products/872 www.adafruit.com/products/1051
www.Adafruit.com/products/959 www.adafruit.com/products/1052
www.Adafruit.com/products/94
//
Requiere Adafruit_LEDBackpack, Adafruit_GFX bibliotecas y WaveHC
bibliotecas.
//
Este bosquejo muestra animación sincronizada aproximadamente a pregrabadas
discurso. Es bastante complejo y puede ser abrumadora para novatos
programadores, que quieran empezar con el ejemplo 'matrix8x8'
y luego 'roboface' antes de trabajar a través de este código. Además, mucho
de los comentarios relativos a la animación de la cara han sido despojados
aquí por brevedad... Consulte el dibujo de 'roboface' si usted tiene alguna
Preguntas Cómo funciona esa parte.
//
Hardware adicional necesario: sonidos se activan utilizando tres
botones momentánea normalmente abierto conexión a los pines digitales 6, 7, 8
y GND (e.g. www.adafruit.com/products/1009).
//
Adafruit invierte tiempo y recursos que este código de fuente abierto,
por favor apoye Adafruit y hardware de código abierto mediante la compra de
productos de Adafruit.
//
Escrito por P. Burgess por Adafruit Industries, piezas adaptaron de
'PiSpeakHC' bosquejo incluido con la biblioteca de WaveHC.
La licencia BSD, todo el texto anterior debe incluirse en cualquier redistribución.
#include < Arduino.h >
#include < Wire.h >
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include < WaveHC.h >
#include < WaveUtil.h >
Estos archivos WAV deben estar en el nivel raíz de la SD:
Char PROGMEM
wav0 [] = "HALLOW~1.wav",
wav1 [] = "LOOKIN~1.wav",
wav2 [] = "THISPM~1.wav",
wav3 [] = "TRKORTRT.wav", / / añadido esta línea 03/08/13
* wavname [] = {wav0, wav1, wav2, wav3}; wav3 añadido a esta línea 03/08/13
PROGMEM hace frecuentes apariciones a lo largo de este código, razón que
la biblioteca de la tarjeta de SD requiere montones de RAM precioso (dejando muy poco a
nuestro propio bosquejo). PROGMEM nos permite poner datos fijos en la memoria flash de programa,
que es considerablemente más amplio. Tablas de cadenas son paritcularly desagradable.
Consulte www.arduino.cc/en/Reference/PROGMEM para obtener más información.
Tarjeta SdReader; Este objeto contiene la información de la tarjeta
FatVolume vol; Contiene la información de la partición en la tarjeta
FatReader raíz; Esto contiene la información para el directorio de raíz de volúmenes
Archivo FatReader; Este objeto representa el archivo WAV de una frase
Ola WaveHC; Un objeto de simple onda--sólo un sonido se juega a la vez
Macro para poner mensajes de error en memoria flash
#define error(msg) error_P(PSTR(msg))
Porque los dos ojos matrices comparten la misma dirección, sólo cuatro
objetos de la matriz son necesarios para la cinco muestra:
#define MATRIX_EYES 0
#define MATRIX_MOUTH_LEFT 1
#define MATRIX_MOUTH_MIDDLE 2
#define MATRIX_MOUTH_RIGHT 3
Adafruit_8x8matrix matriz [4]; Matriz de objetos Adafruit_8x8matrix
En lugar de asignar direcciones de matriz secuencialmente en un bucle, cada
tiene un lugar en esta matriz. Esto hace más fácil si usted inadvertidamente
instalar una o más matrices en la posición física correcta-
volver a ordenar las direcciones en la tabla y todavía puede hacer referencia a
matrices de índice anterior, ningún otro código o cableado necesita cambiar.
const uint8_t PROGMEM matrixAddr [] = {0x70, 0x71, 0x72, 0x73};
PROGMEM de uint8_t const / / mapas de bits se almacenan en la memoria de programa
[blinkImg] [8] = {/ / ojo cuadros de animación
{B00000001, / / abra completamente el ojo
B00000011,
B00000111,
B00001111,
B00011111,
B00111111,
B01111111,
B11111111},
{B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111,
B00111111,
B01111111},
{B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111,
B00111111},
{B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111},
{B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111},
{B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111},
{B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011},
{B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001},
{B00000000, / / cerrar completamente el ojo
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000}},
[mouthImg] [24] = {/ / boca de cuadros de animación
{B00000000, B00000000 B00000000, / / posición A la boca
B00000000, B00000000 B00000000,
B01111111, B11111111, B11111110,
B00000000, B00000000 B00000000,
B00000000, B00000000 B00000000,
B00000000, B00000000 B00000000,
B00000000, B00000000 B00000000,
B00000000, B00000000, B00000000},
{B00000000, B00000000 B00000000, / boca posición B
B00000000, B00000000 B00000000,
B00111111, B11111111, B11111100,
B00000111, B00000000, B11100000,
B00000000 B00000000, B11111111,
B00000000, B00000000 B00000000,
B00000000, B00000000 B00000000,
B00000000, B00000000, B00000000},
{B00000000, B00000000 B00000000, / boca de posición C
B00000000, B00000000 B00000000,
B00111111, B11111111, B11111100,
B00001000, B00000000, B00010000,
B00000110, B00000000, B01100000,
B00000001, B11000011, B10000000,
B00000000 B00000000, B00111100,
B00000000, B00000000, B00000000},
{B00000000, B00000000 B00000000, / boca de posición D
B00000000, B00000000 B00000000,
B00111111, B11111111, B11111100,
B00100000, B00000000, B00000100,
B00010000, B00000000, B00001000,
B00001100, B00000000, B00110000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000},
{B00000000, B00000000 B00000000, / / boca de posición E
B00000000 B00000000, B00111100,
B00011111, B11000011, B11111000,
B00000011, B10000001, B11000000,
B00000000 B00000000, B01111110,
B00000000, B00000000 B00000000,
B00000000, B00000000 B00000000,
B00000000, B00000000, B00000000},
{B00000000, B00111100, B00000000, / boca posición F
B00000000 B00000000, B11000011,
B00001111, B00000000, B11110000,
B00000001, B00000000, B10000000,
B00000000 B00000000, B11000011,
B00000000 B00000000, B00111100,
B00000000, B00000000 B00000000,
B00000000, B00000000, B00000000}};
Secuencias de animación correspondiente a cada WAV. Primer número de
cada par es un índice de mapa de bits de la boca. Segundo número es la bodega
tiempo (en frames). final de 255 marcas de la lista.
Aquí no hay ninguna 'magia', el software no es derivando boca
posición del sonido... se determinaron las tablas a mano,
como animadores lo hacen. Otra explicación aquí:
http://www.idleworm.com/how/ANM/03T/talk1.shtml
PROGMEM de uint8_t const
sec1 [] = {0, 2, 2, 5, 5, 3, 3, 7, / / "Feliz Halloween" / / conectarse a wav 0 arriba
4, 5, 3, 4, 2, 5, 4, 3, 255},
Sec2 [] = {0, 1, 3, 5, 1, 5, 4, 2, / / "Hay, ¿qué está mirando?" conectado a wav 1 sobre
3, 2, 1, 2, 4, 4, 1, 3,
4, 2, 255}
sec3 [] = {0, 1, 1, 2, 3, 6, 2, 5, / / "que tiene dos pulgares y quiere dulces, esta calabaza" / conectado a wav 2 arriba
0, 1, 4, 4, 5, 2, 1, 5,
3, 6, 1, 4, 5, 3, 4, 2,
3, 6, 4, 2, 255},
seq4 [] = {3, 2, 2, 5, 5, 3, 3, 7, / / «Trick Or Treat"/ / conectarse a wav 3 anterior
4, 5, 255}
* anim [] = {sec1, Sec2, sec3, seq4}; seq 4 aquí ha añadido 03/08/13
uint8_t
[blinkIndex] PROGMEM = {1, 2, 3, 4, 3, 2, 1}, / / parpadear de secuencia de mapa de bits
blinkCountdown = 100, / / cuenta regresiva para el próximo parpadeo (en marcos)
gazeCountdown = 75, / / cuenta regresiva al próximo movimiento ocular
gazeFrames = 50, / / duración del movimiento de ojo (más pequeño = más rápido)
mouthPos = 0, / / número de boca de la imagen actual
mouthCountdown = 10 / / cuenta regresiva para la próxima boca cambio
newPos = 255, / boca nueva posición para el marco actual
* seq, / / actualmente está reproduciendo la secuencia de animación
IDX, / / corriente serie índice dentro de la secuencia de animación
prevBtn = 99, / botón pulsado en última iteración loop() #
btnCount = 0; Número de iteraciones que se ha celebrado el mismo botón
int8_t
eyeX = 3, ojosos = 3, / / corriente ojo posición
newX = 3, newY = 3, / / ojo siguiente posición
dX = 0, dY = 0; Distancia desde antes de la nueva posición
void setup() {}
Serial.Begin(9600);
PgmPrintln "(cara de WAV");
if(!Card.init()) error ("tarjeta init. no se pudo!");
if(!Vol.init(Card)) error ("no hay partición!");
if(!root.openRoot(vol)) error ("no pudo abrir dir");
PgmPrintln ("archivos encontrados:");
root.LS();
Semilla generador de números aleatorios de una entrada analógica no utilizada:
randomSeed(analogRead(A0));
Instanciar e inicializar cada objeto de matriz:
para (uint8_t i = 0; i < 4; i ++) {}
matriz [i] = Adafruit_8x8matrix();
matriz [i] .begin (pgm_read_byte (y matrixAddr[i]));
}
Habilitar las resistencias pull-up en cuatro (cambiado a cuatro) botón entradas.
Otro extremo de cada botón y se conecta a tierra.
para (uint8_t i = 6; i < = 9; i ++) {//i < = 8 a 9 8/3/13
pinMode (, entrada);
digitalWrite (i, alto); Activar subida
}
}
void loop() {}
uint8_t.
Empate del globo ocular en estado actual de la blinkyness (ningún alumno).
Matrix[MATRIX_EYES].Clear();
matriz [MATRIX_EYES] .drawBitmap (0, 0,
[blinkImg
¿(blinkCountdown < sizeof(blinkIndex))? ¿Actualmente parpadea?
pgm_read_byte (& blinkIndex[blinkCountdown]): / / sí, ver # de mapa de bits
0 / / no, mostrar mapas de bits 0
], 8, 8, LED_ON);
Contador de centelleo de decremento. En fin, fijar la hora al azar siguiente parpadeo.
Si (--blinkCountdown == 0) blinkCountdown = random (5, 180);
Si (--gazeCountdown < = gazeFrames) {}
Los ojos están en movimiento - dibujar la pupila en posición provisional
(.fillRect) matriz [MATRIX_EYES]
newX - (dX * gazeCountdown / gazeFrames),
newY - (dY * gazeCountdown / gazeFrames),
2, 2, LED_OFF);
¿if(gazecountdown == 0) {/ / último capítulo?
eyeX = newX; eyeY = newY; Sí. Lo nuevo es viejo, entonces...
{/ / Selección de posiciones al azar hasta que uno está dentro del círculo del ojo
newX = random(7); newY = random(7);
dX = newX - 3; dY = newY - 3;
} mientras que ((dX * dX + dY * dY) > = 10); Gracias Pitágoras
dX = newX - eyeX; Distancia horizontal para mover
dY = newY - eyeY; Distancia vertical para mover
gazeFrames = random (3, 15); Duración del movimiento de ojo
gazeCountdown = random (gazeFrames, 120); Cuenta al final del siguiente movimiento
}
} else {}
No en movimiento dibujar aún--pupila en posición estática actual
matriz [MATRIX_EYES] .fillRect (eyeX, ojosos, 2, 2, LED_OFF);
}
Botones de exploración de 6, 7, 8, 9 en busca de la primera tecla... agregó #9 8/3/13
para (i = 0; (< 4) & & (digitalRead(i+6) == HIGH); i++); (< 3 cambiado a 4 8/3/13
¿if(i < 4) {/ / nada presionado? ¡ Sí! (< 3 cambiado a 4 8/3/13
¿if(i == prevbtn) {/ / igual que la última vez que lo comprobamos? Buena!
Si (++ btnCount == 4) {/ / 3 pases para 'debounce' botón de entrada / / == cambió de 3 a 4
playfile ((char *) pgm_read_word(&wavname[i])); Inicio WAV
Ver animación secuencia # correspondiente a este WAV...
Seq = (uint8_t *) pgm_read_word(&anim[i]);
IDX = 0; Comenzar en el primer byte de datos
newPos = pgm_read_byte (& seq[idx++]); Posición inicial de la boca
mouthCountdown = pgm_read_byte (& seq[idx++]); Tiempo para la posición de espera
}
} else btnCount = 0; Otra tecla que antes - Inicio cuenta sobre
prevBtn = i;
} else prevBtn = 99; Ningún botón pulsado
¿Si (newPos! = 255) {/ / es la boca en movimiento?
Si (--mouthCountdown == 0) {/ / cuenta regresiva marcos a la siguiente posición
newPos = pgm_read_byte (& seq[idx++]); Nueva posición de la boca
¿if(newpos == 255) {/ / el final de la lista?
mouthPos = 0; Sí, ponga la boca en posición neutra
} else {}
mouthPos = newPos; Set boca a nueva posición
mouthCountdown = pgm_read_byte (& seq[idx++]); Tiempo de espera de lectura
}
}
} else mouthPos = 0; Boca no en movimiento, ponga en posición neutra
drawMouth(mouthImg[mouthPos]);
Actualizar todas las matrices en una sola pasada rápida
para (uint8_t i = 0; i < 4; i ++) matrix[i].writeDisplay();
Delay(20);
}
Dibujar la imagen de la boca a través de tres pantallas adyacentes
void drawMouth (uint8_t const * img) {}
para (uint8_t i = 0; i < 3; i ++) {}
matriz [MATRIX_MOUTH_LEFT + i].clear();
matriz [MATRIX_MOUTH_LEFT +] .drawBitmap (i * -8, 0, img, 24, 8, LED_ON);
}
}
void error_P (const char * str) {}
PgmPrint ("Error:");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
imprimir mensaje de error y detener si error E/S SD
void sdErrorCheck(void) {}
Si (! card.errorCode()) retorno;
PgmPrint ("\r\nSD I/O error:");
Serial.Print(Card.ErrorCode(), hexagonal);
PgmPrint (",");
Serial.println(Card.errorData(), hexagonal);
while(1);
}
Abrir y empezar a reproducir un archivo WAV
void playfile (const char * nombre) {}
char nombre [13]; 8.3 + NUL
wave.stop() de if(Wave.IsPlaying); Detener cualquier WAV de reproduciendo actualmente
strcpy_P (nombre de archivo, nombre); Nombre de la copia de la PROGMEM en la RAM
Si (! file.open (raíz, nombre de archivo)) {}
PgmPrint ("no puede abrir archivo");
Serial.Print(FileName);
retorno;
}
{if(!Wave.Create(File))}
PgmPrintln ("no un válido WAV");
retorno;
}
Wave.Play();
}