AdaFruit Wave Shield WaveHC 6

De MCHobby - Wiki
Sauter à la navigation Sauter à la recherche

Avoir plus de RAM et de Flash!

Note MCHobby: Les plateformes Arduino sont maintenant distribuée avec un ATmega328.

Cette section n'est vraiment pertinente que si vous ne possédez pas d'ATmega328.

Avant d'essayer de jouer de l'audio, vous aurez besoin de faire un peu de place

la mémoire RAM d'Arduino, cela évitera que cela se termine en vilain

dépassement de pile (stack-overflow). Manquer de mémoire RAM est difficile à déboguer et frustrant, d'autant plus si vous disposez d'un ATMega168

Suivez ces instructions (anglais) pour savoir comment avoir plus

de RAM en réduisant la taille de la mémoire tampon de la librairie série (Serial library).

Vous n'aurez pas besoin de faire cela si vous avez un ATmega328.

Notez que la librairie est vraiment grosse (approximativement 10K). Si vous voulez faire beaucoup plus avec Arduino, il est vivement conseillé de faire un Upgrade vers un ATmega328. Ce shield a été développé en prévoyant la disponibilité d'un ATmega328.

Introduction à play6_hc.pde

Ceci est un tutoriel pour la librairie waveHC. Vous pouvez télécharger le fichier play6_hc.pde play6_hc.pde ici

Ce tutoriel un détaillé et un peu intimidant. Mais attardez vous puisque la plupart du code peut être dupliqué d'un sketch à l'autre.

Assurez vosu que vous avez installé la librairie en la téléchargeant depuis le lien ci dessus et placé dans un sous-répertoire WaveHC de votre répertoire "libraries".

Nous avons placé ce sketch en bas de cet article au cas où vous en auriez besoin.

Initialiser la carte

Les tâches complexes nécessaires au rendu musical est assuré par Arduino. Cela nous épargne d'avoir recours à un décodeur MP3ou autre circuit dédicacé. Cela signifie plus de contrôle et de flexibilité mais aussi pas de firmware!

Faisons donc un tour d'horizon du sketch "dapHC.pde". C'est un sketch de type "Digital Audio Player" (dap) utilisant la librairie Wave HC. Nous avions écrit ce projet pour l'utilisé avec notre librairie Adafruit AF_Wave mais Mr. Fat16 à réalisé un fantastique travail en réécrivant notre code en le rendant plus rapide, plus petit et meilleur. Donc nous allons utiliser sa librairie pour ce tutoriel :)

Téléchargez le sketch dapHC.pde et prenez le temps de le lire. La première chose dont nous avons besoin sont quelques objets. La partie la plus difficile est de dialoguer avec la carte. Toutes les cartes sont fabriquée et formattées différemment (juste un peu). Et le formatage repose sur différentes couches - le format de la carte - Le format de la partition et le formatage du système de fichier.

Au début du sketch nous avons l' #include qui incorpore le fichier d'entête de la librairie (fichier header) files ainsi qu'un objet card qui stocke les information concernant la carte, un autre vol relatif à la partition (partition volume) et le système de fichier root.

Nous avons aussi un objet f qui maintient les information du fichier coutant et un objet wave qui gère un simple fichier wave.

#include "WaveUtil.h"
#include "WaveHC.h"


SdReader card;    // Objet qui maintient les information sur la carte SD
FatVolume vol;    // Maintient les informations sur la partition de la carte
FatReader root;   // Maintient les informations sur le système de fichier de la carte
FatReader f;      // Maintient les informations sur le fichier que nous jouons


WaveHC wave;      // C'est le seul objet (audio) wave, puisque nous jouons un seul morceau à la fois

#define DEBOUNCE 100  // déparasitage bouton

La première chose à faire est d'initialiser la carte SD pour faire des lectures. C'est un processus qui se réalise en plusieurs étapes. Dans la fonction setup vous pouvez voir les différentes vérification qui sont faites par le processus d'initialisation.

Voici les étapes:

  1. Initialisation et affichage sur la connexion série pour indiquer que nous démarrons (OPTIONNEL)
  2. Vérifier la quantité de mémoire disponible après avoir utilisé la mémoire tampon pour stocker les données audio du Wave, faite en sorte qu'il reste plus de 100 octets (bytes) et gardez un oeil dessus si vous modifiez votre code. Ce test peut être enlevé, il n'est destiné qu'a votre information (OPTIONNEL)
  3. Initialise les pin modes pour le DAC (lignes de contrôles du DAC). Cela ne devrait pas être modifié à moins que vous ayez aussi modifié la librairie. Il est certainement préférable de les garder tels quels.
  4. Initialiser la carte SD et vérifier qu'elle réponde. Nous essayons de l'adresser à 8MHz. Si vous disposez d'un Shield Wave 1.0 vous pourriez avoir besoin d'utiliser le mode 4MHz (dé-commentez/re-commentez la ligne appropriée en fonction de la méthode utilisée). Si la carte ne s'initialise pas, alors afficher une erreur et arrêter.
  5. Autoriser la lecture de bloc partiel. Certaines cartes SD n'apprécient pas vraiment. Commenter en priorité cette ligne si vous avez des problèmes! (OPTIONNEL)
  6. Essayer de trouver la partition FAT dans les 5 premiers slots. Vous avez bien formatez votre carte en FAT n'est-ce pas? S'il ne peut pas trouver la partition FAT il affichera un message d'erreur. En cas de problème, assurez vous que vous avez bien formaté la carte en FAT (quitte à re-formater la carte).
  7. Affiche le type de partition FAT qui a été trouvée (OPTIONNEL)
  8. Essaye d'ouvrir le répertoire racine. Si cela ne fonctionne pas, c'est que quelque-chose s'est mal déroulé au cours du formatage. Essayer de formater la carte une fois de plus!
void setup() {
  // intialisation du port série
  Serial.begin(9600);
  putstring_nl("WaveHC avec 6 boutons");
  
   putstring("Free RAM: ");       // Aide au débogage, ce n'est pas bien de ne plus avoir de RAM
  Serial.println(freeRam());      // Si c'est en dessous de 150 octets (bytes) nous aurons des soucis!
  
  // Initialise les pins de sortie pour le contrôle DAC control. 
  // Ces pins sont aussi définies dans la librairie
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
 
  // LED sur pin13 
  pinMode(13, OUTPUT);
 
  // Activer la résistance Pull-Up sur les broches des boutons (entrée analogiques)
  digitalWrite(14, HIGH);
  digitalWrite(15, HIGH);
  digitalWrite(16, HIGH);
  digitalWrite(17, HIGH);
  digitalWrite(18, HIGH);
  digitalWrite(19, HIGH);
 
  //  if (!card.init(true)) { //SPI cadencé à 4 MHz (à utiliser si 8MHz ne fonctionne pas)
  if (!card.init()) {         //SPI cadencé ) 8 MHz (le plus rapide par défaut!)  
    putstring_nl("Echec init. carte!");  // Qlque chose va de travers, affichons donc pourquoi
    sdErrorCheck();
    while(1);                            // Et 'arrêter' (ne rien faire!)
  }
  
  // Activer l'optimisation de lecture - Certaines cartes ne répondent pas. 
  // Désactivez la ligne suivante si vous rencontrez des problèmes
  card.partialBlockRead(true);
 
  // Recherhe de la partition FAT!
  uint8_t part;
  for (part = 0; part < 5; part++) {     // Recherche dans les 5 premiers slots
    if (vol.init(card, part)) 
      break;                             // Trouvez? alors sortir de la boucle
  }
  if (part == 5) {                       // Pas trouvé de partition FAT?  :(
    putstring_nl("Partition FAT invalide!");
    sdErrorCheck();                      // Qlque chose va de travers, afficher pourquoi
    while(1);                            // Et 'Arrêter' - (ne rien faire)!
  }
  
  // Indiquons à l'utilisateur ce que nous avons trouvé
  putstring("Utiliser partition ");
  Serial.print(part, DEC);
  putstring(", type de FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 ou FAT32?
  
  // Ourvir le répertoire racine
  if (!root.openRoot(vol)) {
    putstring_nl("Echec ouverture rep. racine!"); // Qlqchose ne fonctionne pas,
    while(1);                                     // alors 'arrêter' (ne plus rien faire)!
  }
  
  // Whoaw! Nous avons réaliser toutes les étapes.
  putstring_nl("Prêt!");
  dirLevel = 0;
}

Interfaçage des boutons

Nous voulons jouer un son à chaque fois qu'un bouton est pressé Nous allons utiliser une fonction nommée check_switches() qui passe les 6 boutons en revue (digital de 14 à 20) pour voir si ils ont été pressés. Si c'est le ca, nous complètement jouons le fichier SOUND1.WAV (par exemple). La fonction que nous appelons pour jouer le morceau s'appelle playcomplete() et nous passons le nom du fichier Wave en paramètre (entre guillemet, comme ci-dessous).

void loop() {
  // retirez le commentaire de la ligne ci-dessous pour voir si la loop() fonctionne.
  // Si la loop ne fonctionne pas, c'est qu'il y a un problème d’initialisation de la carte SD.
  //putstring(".");            
  switch (check_switches()) {
    case 1:
      playcomplete("SOUND1.WAV");
      break;
    case 2:
      playcomplete("SOUND2.WAV");
      break;
    case 3:
      playcomplete("SOUND3.WAV");
      break;
    case 4:
      playcomplete("SOUND4.WAV");
      break;
    case 5:
      playcomplete("SOUND5.WAV");
      break;
    case 6:
      playcomplete("SOUND6.WAV");
  }
}

byte check_switches()
{
  static byte previous[6];
  static long time[6];
  byte reading;
  byte pressed;
  byte index;
  pressed = 0;

  for (byte index = 0; index < 6; ++index) {
    reading = digitalRead(14 + index);
    if (reading == LOW && previous[index] == HIGH && millis() - time[index] > DEBOUNCE)
    {
      // switch pressed
      time[index] = millis();
      pressed = index + 1;
      break;
    }
    previous[index] = reading;
  }
  // return switch number (1 - 6)
  return (pressed);
}

les fonctions Playcomplete et Playfile

Voici le code correspondant à l'ouverture de fichier et au rendu audio de celui-ci.

Playcomplete est une fonction vraiment simple. Elle appelle la fonction qui commence à jouer le fichier audio et qui démarre un boucle d'attente (boucle qui ne fait rien).

Playfile est une fonction importante. Elle trouve le fichier et le joue.

Voici plus de détails sur la fonction Playfile:

  1. Elle vérifie si un fichier est déjà entrain d'être joué. Si c'est le cas, elle le stoppe.
  2. Elle ouvre ensuite le répertoire racine (root) et recherche le fichier avec le nom attendu. Si le fichier n'est pas trouver alors l'exécution de la fonction est interrompu (instruction "return")
  3. Si le fichier est trouvé, elle essaye de l'ouvrir avec l'objet Wave (qui vérifie si l'entête wave est bien présente). Si ce n'est pas le cas alors l'exécution de la fonction est interrompu (instruction "return")
  4. Si l'opération fonctionne alors la fonction commence à jouer le fichier
// Joue un fichier entier jusqu'à la fin sans faire de pause.
void playcomplete(char *name) {
  // Appelle la fonction (dite "helper") pour trouver et jouer le fichier
  playfile(name);
  while (wave.isplaying) {
  // Ne rien faire tant que le fichier est joué
  }
  // Maintenant, le fichier est terminé
}

void playfile(char *name) {
  // Vérifier si l'objet wave fait déjà quelque chose
  if (wave.isplaying) {// Joue déja un morceur, on l'arrête!
    wave.stop(); // arrêter le morceau
  }
  // Chercher dans le répertoire racine et ouvrir le fichier
  if (!f.open(root, name)) {
    putstring("Echec ouverture fichier "); Serial.print(name); return;
  }
  // OK, lire le fichier et le transformer en objet Wave
  if (!wave.create(f)) {
    putstring_nl("Fichier WAV invalide"); return;
  }
  
  // Tout s'est bien passé! Commence la lecture
  wave.play();
}

play6_hc.pde

Note de MCHobby:

Voici le contenu complet du projet.

Cette fois, les commentaires ne sont pas traduits. Pour plus de détails sur le fonctionnement, vous pouvez vous référez au explications ci-dessus où les commentaires ont étés traduits.

#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"


SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card
FatReader f;      // This holds the information for the file we're play

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

#define DEBOUNCE 100  // button debouncer

// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
{
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end); 
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval); 
  }
  return free_memory; 
} 

void sdErrorCheck(void)
{
  if (!card.errorCode()) return;
  putstring("\n\rSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  putstring(", ");
  Serial.println(card.errorData(), HEX);
  while(1);
}

void setup() {
  // set up serial port
  Serial.begin(9600);
  putstring_nl("WaveHC with 6 buttons");
  
   putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
  Serial.println(freeRam());      // if this is under 150 bytes it may spell trouble!
  
  // Set the output pins for the DAC control. This pins are defined in the library
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
 
  // pin13 LED
  pinMode(13, OUTPUT);
 
  // enable pull-up resistors on switch pins (analog inputs)
  digitalWrite(14, HIGH);
  digitalWrite(15, HIGH);
  digitalWrite(16, HIGH);
  digitalWrite(17, HIGH);
  digitalWrite(18, HIGH);
  digitalWrite(19, HIGH);
 
  //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
  if (!card.init()) {         //play with 8 MHz spi (default faster!)  
    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
    sdErrorCheck();
    while(1);                            // then 'halt' - do nothing!
  }
  
  // enable optimize read - some cards may timeout. Disable if you're having problems
  card.partialBlockRead(true);
 
// Now we will look for a FAT partition!
  uint8_t part;
  for (part = 0; part < 5; part++) {     // we have up to 5 slots to look in
    if (vol.init(card, part)) 
      break;                             // we found one, lets bail
  }
  if (part == 5) {                       // if we ended up not finding one  :(
    putstring_nl("No valid FAT partition!");
    sdErrorCheck();      // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!
  }
  
  // Lets tell the user about what we found
  putstring("Using partition ");
  Serial.print(part, DEC);
  putstring(", type is FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?
  
  // Try to open the root directory
  if (!root.openRoot(vol)) {
    putstring_nl("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!
  }
  
  // Whew! We got past the tough parts.
  putstring_nl("Ready!");
}

void loop() {
  //putstring(".");            // uncomment this to see if the loop isnt running
  switch (check_switches()) {
    case 1:
      playcomplete("SOUND1.WAV");
      break;
    case 2:
      playcomplete("SOUND2.WAV");
      break;
    case 3:
      playcomplete("SOUND3.WAV");
      break;
    case 4:
      playcomplete("SOUND4.WAV");
      break;
    case 5:
      playcomplete("SOUND5.WAV");
      break;
    case 6:
      playcomplete("SOUND6.WAV");
  }
}

byte check_switches()
{
  static byte previous[6];
  static long time[6];
  byte reading;
  byte pressed;
  byte index;
  pressed = 0;

  for (byte index = 0; index < 6; ++index) {
    reading = digitalRead(14 + index);
    if (reading == LOW && previous[index] == HIGH && millis() - time[index] > DEBOUNCE)
    {
      // switch pressed
      time[index] = millis();
      pressed = index + 1;
      break;
    }
    previous[index] = reading;
  }
  // return switch number (1 - 6)
  return (pressed);
}


// Plays a full file from beginning to end with no pause.
void playcomplete(char *name) {
  // call our helper to find and play this name
  playfile(name);
  while (wave.isplaying) {
  // do nothing while its playing
  }
  // now its done playing
}

void playfile(char *name) {
  // see if the wave object is currently doing something
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  }
  // look in the root directory and open the file
  if (!f.open(root, name)) {
    putstring("Couldn't open file "); Serial.print(name); return;
  }
  // OK read the file and turn it into a wave object
  if (!wave.create(f)) {
    putstring_nl("Not a valid WAV"); return;
  }
  
  // ok time to play! start playback
  wave.play();
}


Source: Wave Shield créé par LadyAda pour AdaFruit. Crédit: AdaFruit.com.

Traduit par Meurisse D. pour MCHobby.be.

Traduit avec l'autorisation d'AdaFruit Industries - Translated with the permission from Adafruit Industries - www.adafruit.com

Toute référence, mention ou extrait de cette traduction doit être explicitement accompagné du texte suivant : «  Traduction par MCHobby (www.MCHobby.be) - Vente de kit et composants » avec un lien vers la source (donc cette page) et ce quelque soit le média utilisé.

L'utilisation commercial de la traduction (texte) et/ou réalisation, même partielle, pourrait être soumis à redevance. Dans tous les cas de figures, vous devez également obtenir l'accord du(des) détenteur initial des droits. Celui de MC Hobby s'arrêtant au travail de traduction proprement dit.