Étape 5: Arduino Sketch
Le sketch Arduino contient une machine à États non plus à l’écoute des commandes série à analyser, ou lance une session d’acquisition de données. Acquisition de données se produit sous la forme de bord déclenché par échantillonnage ou basés sur le temps du scrutin. Interrogation base de temps peut être trigged par une arête montante ou descendante.
J’ai créé le code pour utiliser les broches Arduino Uno suivantes (ne doit ne pas pour être confondu avec les broches ATmega) :
- Broche 2: Interruption 0, la détente
- Broche 8: Canal 1
- Broche 9: Canal 2
- Broche 10 : Canal 3
- Broche 11 : Channel 4
Boucle de commande
La boucle de commande série interroge le port série et attend pour les caractères d’arriver. Chaque commande est une chaîne de caractères se terminant par « % ». Lorsqu’une « % » est analysée, le tampon de la chaîne actuelle est expédié au routeur. (Le client JavaScript enverra une seule grande chaîne avec toutes les commandes.)
Commandes :
- Réinitialiser %: effacer les variables globales de contexte
- ch {} 1-4 %: activer les canaux 1, 2, 3 ou 4
- temps %n%: régler l’heure de l’échantillon à « n » microsecondes.
- limiten%: limiter le nombre d’échantillons d’octet à ' n '. J’ai ajouté ceci pour me donner un moyen de gérer le temps de l’échantillon, puisque je ne peux pas l’interrompre sans perte de données
- % en hausse: l’échantillon sur le front de la détente
- % de chute: l’échantillon sur le front descendant du déclencheur (échantillonnage Remarque fonctionne sur les deux côtés, ils ne sont pas mutex)
- une fois %: effectuer un One-Shot trigger qui commence le mode d’interrogation
- commencer %: compiler options ci-dessus dans les variables globales, définir les pointeurs de fonction et les rappels et commencer la boucle d’échantillonnage
Après avoir reçu la commande start % , l’esquisse configure les variables du contexte global et commutateurs de commande l’analyse à l’échantillonnage. Il ne peut être interrompue jusqu'à ce qu’il remplit et retourne les données, sauf si vous faites un hard reset bouton ou de puissance.
Temps d’échantillonnage
Si l’utilisateur n’a pas sélectionné tout déclenchement, l’esquisse détermine quelle routine de temps il doit utiliser. Il y en a trois :
- Aussi vite que possible : cela n’a aucun délai pour la vitesse maximale
- delay_ms(): cet exemple utilise la fonction delay()
- delay_us(): cet exemple utilise la fonction delayMicroseconds() , qui a une limite maximum de 16 383 US.
L’esquisse affecte le bon fonctionnement à un pointeur fonction plutôt qu’avec if/else instructions conditionnelles, Cela accélère l’exécution et permet de mieux abstraction.
One-Shot Trigger
Si l’utilisateur a sélectionné mode One-Shot, une routine de service d’interruption (ISR) est définie sur INT0 (le déclencheur), pour soit en hausse, chute, ou changement. L’ISR utilisera ensuite détacher l’interruption et appellera basés sur le temps d’échantillonnage définies ci-dessus.
-Déclenchement à bord
Bord-déclenchée l’échantillonnage ignore les routines de temps basé et recueille un échantillon par gâchette. Le sketch s’adapte sur un ISR INT0 similaire au mode One-Shot, mais au lieu de détacher l’interruption et l’appel de la routine basée sur le temps, qu’elle perçoit simplement un échantillon par interruption. Comme vous pouvez le dire, si les interruptions arrivent plus vite que le code peut traiter, les données seront perdues. La limite est d’environ 20us en raison de la grande quantité de code dans les routines de l’échantillon.
Échantillonnage des données
Toutes les méthodes d’invocation d’échantillonnage utilisent les mêmes fonctions d’acquisition de données de bas niveau.
Essayer de limiter les frais généraux, j’ai écrit quatre différentes routines d’échantillonnage basé sur le nombre de canaux sélectionnés et appellent un pointeur de fonction au lieu d’if/else. Chaque routine a ses propres optimisations. Le gestionnaire de commandes Démarrer % définit le pointeur de fonction appropriée.
Le croquis stocke les échantillons dans une mémoire tampon d’octets [1080]. Cela se traduit par bit 8640 échantillons pour un canal. Le nombre d’échantillons d’octet doit être divisible par 2, 3 et 4. Étant donné que je suis d’accueillir 1, 2, 3 ou 4 canaux à être actif, j’ai besoin de partitionner le tableau buffer afin que je ne dois pas effectuer tout contrôle limite spéciale. Faire la taille divisible par 12 est le meilleur moyen de gérer cela. Je ne faire respecter dans le code, mais je le fais dans l’interface HTML5 : Remarquez que le contrôle d’échantillons incrémente de 96 (12 * 8) et s’arrête à 8640 (1080 * 8). Comme la lecture des morceaux, ils sont décalés et emballés dans chaque octet. Après chaque 8 bits, un octet est stocké à l’index et l’indice est incrémenté. Lorsque l’index est égale à la profondeur de stockage, échantillonnage complète et les données sont envoyées. Si un canal est sélectionné, les données sont écrites sur tampon [index]. Si deux canaux sont sélectionnés, octets sont écrits dans la mémoire tampon [index] et tampon [index + offset_2] ; offset_2 = MAX_BYTE_SAMPLES * 1 / 2 et l’indice est la moitié de ce qu’il est en mode monocanal. Écriture de trois canaux de buffer [index], tampon [index + offset_2] et [index + offset_3] ; offset_2 = MAX_BYTE_SAMPLES * 1 / 3 et offset_3 = MAX_BYTE_SAMPLES * 2 / 3, index est 1/3 de celui-ci est la valeur max dans un canal mode, etc..
Une fois le le tampon se remplit ou l’index dépasse la limite %, stopper les routines de l’échantillon et les données sont envoyées en retour.
Envoi de données
Les données envoient routine retourne le nombre d’échantillons prélevés (divisé par le nombre de canaux utilisés) et des données binaires des canaux. Étant donné que l’utilisateur peut sélectionner n’importe quelle configuration de canaux, cette routine décode les canaux utilisés et les étiquettes en conséquence (un peu compliquée, en fait, je sais il y a une solution plus rapide là-bas...). Il crochets également la transmission avec begindata et enddata pour aider le serveur à coordonner son analyseur.
Remarque
Vous remarquerez peut-être des variables globales gratuites. Je l’ai fait parce que je suis en train d’obtenir une poignée sur la façon de minimiser l’empreinte mémoire pour faire place à plus grande capacité de l’échantillon. Un secteur qui a besoin de travail : J’ai utilisé un grand nombre d’objets String qui croissent et se rétrécir, et j’ai beaucoup de débogage char * chaînes circulent là-dedans. J’ai évité d’utiliser malloc() et déclaré la solution tampon dans le tas. J’ai trouvé que 1080 octets est le plus que je peux utiliser fiable sans s’écraser l’esquisse. Ma liste de tâches inclut comprendre la gestion de la mémoire mieux sur l’ATmega et avr-mec / gcc et ré-écriture de ce croquis pour être plus prévisible WRT utilisation de la mémoire.