Étape 3: Le code et les fichiers Wav
Le code est issu Adafruit et c’est partis respectables et a été modifiée. J’ai ajouté un octet de bouton et son 4e. J’ai changé les octets sonores à la mienne, et j’ai changé les yeux du tour au triangle.Ce Instructable suppose que vous savez déjà comment travailler avec arduino, (code d’installation, bibliothèque, etc.)
LE CODE.
Vous pouvez copier et coller le code ci-dessous dans l’IDE arduino ou cliquez sur le fichier.
Visage citrouille Costume
Cette esquisse a été légèrement modifiée de l’original
créateur, comme indiqué ci-dessous. Profitez!!
croquis de l’exemple « wavface » de Adafruit I2C 8 x 8 LED sacs à dos
et le bouclier de la vague :
//
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
//
Nécessite Adafruit_LEDBackpack, bibliothèques Adafruit_GFX et WaveHC
bibliothèques.
//
Ce croquis montre animation synchronisée à peu près à préenregistrés
discours. Il est assez complexe et peut être écrasante pour novice
programmeurs, qui veulent démarrer avec l’exemple de « matrix8x8 »
et puis « roboface » avant de travailler par le biais de ce code. En outre, une grande partie
des observations relatives à l’animation du visage ont été dépouillé
par souci de concision... fais allusion à l’esquisse de « roboface » si vous avez un
Comment fonctionne cette partie des questions.
//
Matériel supplémentaire requis : sons sont déclenchent à l’aide de trois
normalement ouvert contact momentané raccordés aux broches de Digital, 6, 7, 8
et GND (p. ex. www.adafruit.com/products/1009)
//
Adafruit investit temps et ressources fournissant ce code source ouvert,
Merci de soutenir Adafruit et open source hardware en achetant
produits de Adafruit !
//
Écrit par P. Burgess pour Adafruit Industries, pièces adaptées de
« PiSpeakHC » croquis fourni avec la bibliothèque WaveHC.
La licence BSD, tout le texte ci-dessus doit figurer dans toute redistribution.
#include < Arduino.h >
#include < Wire.h >
#include « Adafruit_LEDBackpack.h »
#include « Adafruit_GFX.h »
#include < WaveHC.h >
#include < WaveUtil.h >
Ces fichiers WAV doivent être sous le niveau de la racine de la carte SD :
Char PROGMEM
[wav0] = "HALLOW~1.wav",
[wav1] = "LOOKIN~1.wav",
[wav2] = "THISPM~1.wav",
wav3 [] = "TRKORTRT.wav", / / ajouté cette ligne 03/08/13
* wavname [] = {wav1, wav2, wav0, wav3} ; wav3 ajouté à cette ligne 03/08/13
PROGMEM fait de fréquentes apparitions tout au long de ce code, la raison étant que
la bibliothèque de carte SD nécessite paraisons de précieux RAM (ce qui laisse très peu de
nos propres croquis). PROGMEM nous permet de mettre des données fixes en mémoire flash de programme,
ce qui est beaucoup plus spacieux. Tables de chaînes sont paritcularly méchant.
Voir www.arduino.cc/en/Reference/PROGMEM pour plus d’informations.
Carte de SdReader ; Cet objet conserve les informations de la carte
Vol FatVolume ; Il conserve les informations pour la partition sur la carte
FatReader racine ; Il conserve les informations pour le répertoire racine de volumes
Fichier FatReader ; Cet objet représente le fichier WAV pour une phrase
WaveHC vague ; Un objet vague unique--un seul son est joué à la fois
Macro pour mettre les messages d’erreur dans la mémoire flash
#define error(msg) error_P(PSTR(msg))
Parce que les deux yeux matrices partagent la même adresse, seulement quatre
objets de matrice sont nécessaires pour les cinq affichages :
#define MATRIX_EYES 0
#define MATRIX_MOUTH_LEFT 1
#define MATRIX_MOUTH_MIDDLE 2
#define MATRIX_MOUTH_RIGHT 3
Matrice de Adafruit_8x8matrix [4] ; Tableau d’objets Adafruit_8x8matrix
Plutôt que d’assigner des adresses de matrice séquentiellement dans une boucle, chaque
a une tache dans ce tableau. Cela le rend plus facile si vous par inadvertance
installer un ou plusieurs matrices dans la mauvaise position physique--
re-commander les adresses dans ce tableau et vous pouvez toujours consulter
matrices par index ci-dessus, aucun autre code ou câblage ne doit changer.
const uint8_t PROGMEM matrixAddr [] = {0 x 70, 0x71, 0 x 72, 0x73} ;
const uint8_t PROGMEM / / Bitmaps sont stockés dans la mémoire programme
blinkImg [] [8] = {/ / l’oeil images d’animation
{B00000001, / / ouvrir complètement les yeux
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, / / fermer complètement les yeux
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000}},
mouthImg [] [24] = {/ / bouche d’images d’animation
{B00000000, B00000000, B00000000, / / position A la bouche
B00000000, B00000000, B00000000,
B01111111, B11111111, B11111110,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000},
{B00000000, B00000000, B00000000, / / position de bouche B
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00000111, B00000000, B11100000,
B00000000, B11111111, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000},
{B00000000, B00000000, B00000000, / / position de bouche C
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00001000, B00000000, B00010000,
B00000110, B00000000, B01100000,
B00000001, B11000011, B10000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000},
{B00000000, B00000000, B00000000, / / position de bouche 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, / / bouche position E
B00000000, B00111100, B00000000,
B00011111, B11000011, B11111000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000},
{B00000000, B00111100, B00000000, / / position de bouche F
B00000000, B11000011, B00000000,
B00001111, B00000000, B11110000,
B00000001, B00000000, B10000000,
B00000000, B11000011, B00000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000}} ;
Séquences d’animation correspondant à chaque WAV. Premier numéro en
chaque paire est un index de bitmap de bouche. Second numéro est la cale
temps (en images). 255 marque la fin de la liste.
Il n’y a pas de « magie » ici, le logiciel ne tire bouche
position du bruit... les tableaux ont été déterminées à la main,
a l’instar des animateurs le faire. Plus d’explication ici :
http://www.idleworm.com/How/ANM/03t/talk1.shtml
const uint8_t PROGMEM
SEQ1 [] = {0, 2, 2, 5, 5, 3, 3, 7, / / "Happy Halloween" / / connecté à wav 0 ci-dessus
4, 5, 3, 4, 2, 5, 4, 3, 255},
SEQ2 [] = {0, 1, 3, 5, 1, 5, 4, 2, / / "Hay, ce que tu regardes?" connecté au format wav 1 ci-dessus
3, 2, 1, 2, 4, 4, 1, 3,
4, 2, 255},
Seq3 [] = {0, 1, 1, 2, 3, 6, 2, 5, / / "qui a deux pouces et veut des bonbons, ce potiron" / / connecté à wav 2 ci-dessus
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" / / connecté à wav 3 ci-dessus
4, 5, 255},
* anim [] = {seq1, seq2, seq3 seq4} ; seq 4 ici a ajouté 03/08/13
uint8_t
blinkIndex [] PROGMEM = {1, 2, 3, 4, 3, 2, 1}, / / Blink séquence bitmap
blinkCountdown = 100, / / compte à rebours jusqu'à la prochaine clin (en images)
gazeCountdown = 75, / / compte à rebours pour le prochain mouvement des yeux
gazeFrames = 50, / / durée des mouvements oculaires (plus petit = plus vite)
mouthPos = 0, / / Current image numéro pour la bouche
mouthCountdown = 10, / / changer de compte à rebours jusqu'à la prochaine bouche
newPos = 255, / / nouvelle bouche position pour le frame en cours
* seq, / / Animation de séquences en cours de lecture arrière
idx, / / Current array index dans la séquence d’animation
prevBtn = 99, / touche # enfoncée sur la dernière itération de loop() /
btnCount = 0 ; Nombre d’itérations même bouton a eu lieu
int8_t
eyeX = 3, eyeY = 3, / / position des yeux courant
newX = 3, newY = 3, / / position des yeux ensuite
dX = 0, dY = 0 ; Distance d’avant la nouvelle position
void setup() {}
Serial.Begin(9600) ;
PgmPrintln ("visage WAV") ;
erreur if(!Card.init()) ("carte init. a échoué!") ;
erreur if(!vol.init(Card)) ("aucune partition!") ;
erreur if(!root.openRoot(vol)) ("Impossible d’ouvrir dir") ;
PgmPrintln ("fichiers trouvés:") ;
root.ls() ;
Générateur de nombres aléatoires graine d’une entrée analogique non utilisée :
randomSeed(analogRead(A0)) ;
Instanciez et initialisez chaque objet matrix :
pour (uint8_t i = 0; i < 4; i ++) {}
matrice [i] = Adafruit_8x8matrix() ;
matrice [i] .begin (pgm_read_byte (& matrixAddr[i])) ;
}
Activez les résistances de pull-up sur quatre (changé à quatre) bouton entrées.
Autre extrémité de chaque bouton, puis se connecte à GND.
pour (uint8_t j’ai = 6; i < = 9; i ++) {//i < = 8 changé à 8 9/3/13
pinMode (i, entrée) ;
digitalWrite (i, HIGH) ; Activez pullup
}
}
void loop() {}
uint8_t i ;
Attirer le œil dans l’état actuel de la blinkyness (aucun élève).
Matrix[MATRIX_EYES].Clear() ;
matrice [MATRIX_EYES] .drawBitmap (0, 0,
[blinkImg
(blinkCountdown < sizeof(blinkIndex)) ? Actuellement clignote ?
pgm_read_byte (& blinkIndex[blinkCountdown]): / / Oui, chercher bitmap #
0 / / non, afficher bitmap 0
], 8, 8, LED_ON) ;
Compteur de clignement décrémentation. À la fin, définir une heure aléatoire pour prochain clignotement.
Si (--blinkCountdown == 0) blinkCountdown = aléatoire (5, 180) ;
Si (--gazeCountdown < = gazeFrames) {}
Les yeux sont en mouvement - dessiner élève en position intermédiaire
(.fillRect) matrice [MATRIX_EYES]
newX - (dX * gazeCountdown / gazeFrames),
newY - (dY * gazeCountdown / gazeFrames),
2, 2, LED_OFF) ;
if(gazeCountdown == 0) {/ / dernier cadre ?
eyeX = newX ; eyeY = newY ; Oui. Quoi de neuf est vieille, alors...
{/ / Pick postes au hasard jusqu'à ce que l’un est dans le cercle de l’oeil
newX = random(7) ; newY = random(7) ;
dX = newX - 3 ; dY = newY - 3 ;
} tandis que ((dX * dX + dY * dY) > = 10) ; Merci Pythagore
dX = newX - eyeX ; Distance horizontale à déplacer
dY = newY - eyeY ; Distance verticale pour déplacer
gazeFrames = random (3, 15) ; Durée des mouvements oculaires
gazeCountdown = random (gazeFrames, 120) ; Compter jusqu'à la fin du prochain mouvement
}
} else {}
Pas en mouvement encore--attirer l’élève à une position statique actuelle
matrice [MATRIX_EYES] .fillRect (eyeX, eyeY, 2, 2, LED_OFF) ;
}
Boutons de numérisation, 6, 7, 8, 9, à la recherche de la première touche enfoncée... ajouté #9 8/3/13
pour (i = 0 ; (j’ai < 4) & & (digitalRead(i+6) == haute) ; i++); (j’ai < 3 changé 4 8/3/13
if(i < 4) {/ / quelque chose enfoncée ? Oui ! (j’ai changé de < 3 4 8/3/13
if(i == prevBtn) {/ / de même que la dernière fois que nous avons vérifié ? Bon !
Si (++ btnCount == 4) {/ / 3 passes à « debounce » bouton entrée / / == passe de 3 à 4
playfile ((char *) pgm_read_word(&wavname[i])); Début WAV
Rechercher animation séquence # correspondant à cette WAV...
Seq = (uint8_t *) pgm_read_word(&anim[i]);
idx = 0 ; Commencer au premier octet de données
newPos = pgm_read_byte (& seq[idx++]) ; Bouche initiale pos
mouthCountdown = pgm_read_byte (& seq[idx++]) ; Indisponibilité pour pos
}
} else btnCount = 0 ; Bouton différent qu’avant - chef de départ plus
prevBtn = i ;
} else prevBtn = 99 ; Aucune pression sur les boutons
Si (newPos! = 255) {/ / est la bouche en mouvement ?
Si (--mouthCountdown == 0) {/ / compte à rebours des cadres à la position suivante
newPos = pgm_read_byte (& seq[idx++]) ; Nouvelle position de la bouche
if(newPos == 255) {/ / fin de la liste ?
mouthPos = 0 ; La valeur Oui, bouche en position neutre
} else {}
mouthPos = newPos ; Set de bouche à la nouvelle position
mouthCountdown = pgm_read_byte (& seq[idx++]) ; Lire indisponibilité
}
}
} else mouthPos = 0 ; Bouche pas en mouvement--sur position neutre
drawMouth(mouthImg[mouthPos]) ;
Actualiser toutes les matrices en une seule passe rapide
pour (uint8_t i = 0; i < 4; i ++) matrix[i].writeDisplay() ;
Delay(20) ;
}
Image de bouche de tirage sur trois écrans adjacents
void drawMouth (const uint8_t * img) {}
pour (uint8_t i = 0; i < 3; i ++) {}
matrice [MATRIX_MOUTH_LEFT + i].clear() ;
matrice [MATRIX_MOUTH_LEFT + i] .drawBitmap (i * -8, 0, img, 24, 8, LED_ON) ;
}
}
void error_P (const char * str) {}
PgmPrint ("erreur:") ;
SerialPrint_P(str) ;
sdErrorCheck() ;
while(1) ;
}
message d’erreur d’impression et en cas d’erreur d’e/s SD
void sdErrorCheck(void) {}
Si (! card.errorCode()) retourner ;
PgmPrint ("\r\nSD I/O erreur:") ;
Serial.Print(Card.ErrorCode(), HEX) ;
PgmPrint (",") ;
Serial.println(Card.ErrorData(), HEX) ;
while(1) ;
}
Ouvrir et commencer à jouer un fichier WAV
void playfile (const char * nom) {}
char nom [13] ; 8.3 + NUL
if(Wave.IsPlaying) wave.stop() ; Arrêter tous les cours de lecture WAV
strcpy_P (filename, nom) ; Copiez le nom de PROGMEM dans la mémoire vive
Si (! file.open (racine, filename)) {}
PgmPrint ("Impossible d’ouvrir le fichier") ;
Serial.Print(fileName) ;
retour ;
}
{if(!Wave.Create(file))}
PgmPrintln ("pas un valide" WAV") ;
retour ;
}
Wave.Play() ;
}