Étape 3: Arduino Code - Détails
Structure de commandement et de message tel que décrit à l’étape précédente
Paramètres de la série : COM11 9600 8 N 1
\r ou \n à la fin de ligne de commande
Bluetooth est sur la broche 0 & 1 @ vitesse 9600
Structure de commande / / CMD RED| GREEN| JAUNE = COMPILATION ON| HORS
CMD TMAX| SECONDES = valeur
CMD secondes = valeur
STATUT DE CMD
Structure des messages de statut
STATUT RED| GREEN| YELLOW| TMIN| TMAX| SECONDS| TEMP| Haut de cuisse = valeur
Initialisation des variables nécessaires pour contrôler la température
flotteur maxTemp = 30,0 ; Allumez la tête temp > maxTemp
int maxTempSensor = (int) ((maxTemp/100 +.5) * 204.8) ;
flotteur de température = 0.0 ;
maxTemp a plus tard peut être changé, mais le programme a besoin de commencer avec une valeur par défaut. maxTempSensor est la conversion de maxTemp pour les 0-1023 plage fournie par le convertisseur ADC Arduino ; Comparaison de température est effectuée par une routine d’interruption que nous voulons aussi vite que possible : il est plus efficace de directement comparer l’entier sortie Pin valeur plutôt que de la température de flotteur. Nous voulons toujours de rendre compte de la température et le programme il va stocker dans la variable portant le même nom.
Si vous n’êtes pas familier avec la formule de conversion de température, vous pouvez jeter un oeil ici.
maxSeconds peut également être modifié avec une commande, mais encore une fois nous avons besoin d’une valeur par défaut
int maxSeconds = 10 ; Envoyer message d’état de chaque maxSeconds
Déclarations de constantes de Pin
const int ledPin = 13 ; température dirigée
const int tempPin = A0 ; Pin d’entrée analogique de la sonde température T36
const int led1Pin = 3 ; Jaune
const int led2Pin = 4 ; Vert
const int led3Pin = 5 ; Rouge
Variables utilisées dans la routine d’interruption et accessible depuis l’extérieur
tempVal volatile int ;
secondes de volatile int = 0 ;
volatil tempHigh booléen = false ;
volatil statusReport booléen = false ;
Volatile est un mot clé spécial qui empêche le compilateur d’effectuer certaines opérations d’optimisation : toutes les variables sont modifiés dans une routine d’interruption et sont également accessibles en dehors de celui-ci doivent être déclarés comme volatile à signaler que leur valeur peut changer à tout moment et pour s’assurer plus tard, correct, valeur est lue de la mémoire si nécessaire.
Variables de chaîne de commande (il seront expliquées plus tard)
String inputString = "" ;
Chaîne de commande = "" ;
Valeur de chaîne = "" ;
stringComplete booléen = false ;
La fonction setup()
void setup() {}
Démarrer la connexion série
Serial.Begin(9600) ;
Serial.Print ("Max T:") ;
Serial.Print(maxTemp) ;
Serial.Print ("capteur:") ;
Serial.println(maxTempSensor) ;
inputString.reserve(50) ; pinMode (ledPin, sortie) ; pinMode (led1Pin, sortie) ;
Command.Reserve(50) ;
value.Reserve(50) ;
digitalWrite (ledPin, basse) ;
pinMode (led2Pin, sortie) ;
pinMode (led3Pin, sortie) ;
digitalWrite (led1Pin, basse) ;
digitalWrite (led2Pin, basse) ;
digitalWrite (led3Pin, basse) ;
La méthode de la réserve d’une chaîne alloue le nombre d’octets fourni comme argument.
Le code suivant est nécessaire pour initialiser l’interruption timer et réglez-le au feu toutes les secondes, le plus lent que Arduino peut faire ; pour des informations détaillées, voir ici.
CLI() ; désactiver les interruptions globales initialiser le Timer1 pour interruption @ 1000 msec Comparez Set match Registre au comte de minuterie désiré : SEI() ; activer les interruptions globales
TCCR1A = 0 ; tout registre TCCR1A la valeur 0
TCCR1B = 0 ; même chose pour TCCR1B
OCR1A = 15624 ; activer le mode de la CCT :
TCCR1B | = (1 << WGM12) ;
Définissez les bits de CS10 et CS12 pour 1024 Prédiviseur :
TCCR1B | = (1 << CS10) ;
TCCR1B | = (1 << CS12) ;
activer minuteur comparer interruption :
TIMSK1 | = (1 << OCIE1A) ;
}
La routine d’interruption du timer : nous ne pouvons pas changer son nom, mais le contenu est entièrement personnalisable.
ISR(TIMER1_COMPA_vect) Si (tempVal > maxTempSensor) {}
{
tempVal = analogRead(tempPin) ;
digitalWrite (ledPin, HIGH) ;
tempHigh = true ;
}
else {}
digitalWrite (ledPin, basse) ;
tempHigh = false ;
}
La valeur de la température - ou, comme nous l’avons vu ses 0-1023 représentation entière - est lue à partir du capteur et est comparée à la la valeur seuil : lorsque au-dessus du haut est allumée et tempHigh est définie sur true, sinon la LED est éteinte andtempHigh est définie sur false.
Si (secondes ++ > = maxSeconds) {}
statusReport = true ;
secondes = 0 ;
}
}
N’oubliez pas que l’interruption est déclenchée à chaque seconde, mais nous voulons signaler l’état du système moins fréquemment : la variable secondes est incrémentée à chaque itération jusqu'à ce qu’il atteigne les valeurs lorsque le rapport est attendu ; Cela se fera plus tard dans la boucle principale en cochant le drapeau statusReport. En règle générale, ne jamais faire quelque chose si lent de ces données par écrit à la série de dans une routine d’interruption.
La fonction loop() interprète et exécute les commandes lorsque reçu, il signale ensuite l’État si le drapeau est hissé par interruption de la minuterie. Pour lire une chaîne de la mémoire tampon série, loop() s’appuie sur la fonction serialEvent() qui sera définie à la fin : cette routine est exécutée entre chaque exécution de loop(). Il n’est pas largement documentée et elle ne s’applique probablement à tous les modèles de l’Arduino ; dans tous les cas, il n’est pas difficile nicher son contenu au sein de la grande boucle (voir la fin de l’étape de thi).
void loop() {} Si {(stringComplete)
int intValue = 0 ;
Serial.println(InputString) ;
stringOK booléen = false ;
Si (inputString.startsWith ("CMD")) {}
inputString = inputString.substring(4) ;
Tout d’abord, nous vérifions si la chaîne reçue commence par « CMD »: Si donc nous pouvons ignorer les quatre premiers caractères, sinon nous allons plus tard déclenche une erreur.
int pos = inputString.indexOf('=') ;
Si (pos > -1) {}
commande = inputString.substring (0, pos) ;
valeur = inputString.substring (pos + 1, inputString.length()-1) ; extrait de commande jusqu'à \n exclues
Il existe deux types de commandes : ceux définissant une valeur, où nous trouverons « = » séparer la paire de valeur variable + et ceux où la commande est une directive unique (statut). Si « = » est présent au pos, la chaîne est divisée en commande (partie gauche) et la valeur (partie droite), laisser tomber les deux le « = » entre les deux et le caractère de fin de ligne à la fin.
Si (command.equals("RED")) {/ / rouge = compilation ON| HORS
value.Equals("on") ? digitalWrite (led3Pin, HIGH): digitalWrite (led3Pin, basse) ;
stringOK = true ;
}
ElseIf (command.equals("GREEN")) {/ / vert = compilation ON| HORS
value.Equals("on") ? digitalWrite (led2Pin, HIGH): digitalWrite (led2Pin, basse) ;
stringOK = true ;
}
ElseIf (command.equals("YELLOW")) {/ / jaune = compilation ON| HORS
value.Equals("on") ? digitalWrite (led1Pin, HIGH): digitalWrite (led1Pin, basse) ;
stringOK = true ;
}
Nous examinons et exécuter les commandes de LED ; Notez que le code vérifie uniquement valeur ON: Si vous écrivez vert = ASD, elle sera interprétée comme vert = OFF. Il n’est pas parfait, mais il garde les choses beaucoup plus simple. stringOK = true est définie, chaque fois qu’une commande est reconnue et exécutée afin que les commandes mal seront signalés par la suite.
ElseIf (command.equals("TMAX")) {/ / TMAX = valeur
intValue = value.toInt() ;
si (intValue > 0) {
maxTemp = (float) intValue ;
maxTempSensor = (int) ((maxTemp/100 +.5) * 204.8);
stringOK = true ;
}
}
ElseIf (command.equals("SECONDS")) {/ / secondes = valeur
intValue = value.toInt() ;
si (intValue > 0) {
maxSeconds = intValue ;
stringOK = true ;
}
}
Lorsque la valeur doit être un nombre, il faut convertir il et c’est vraiment un certain nombre de test. Dans le cas de MaxTemp, nous calculons aussi la valeur de la sonde comme expliqué dans la section définition de la variable
} / / pos > -1
ElseIf (inputString.startsWith("STATUS")) {
Serial.print ("statut rouge =");
Serial.println(digitalRead(led3Pin)) ;
Serial.print ("état vert =");
Serial.println(digitalRead(led2Pin)) ;
Serial.print ("statut jaune =");
Serial.println(digitalRead(led1Pin)) ;
Serial.print ("statut TMAX =");
Serial.println(maxTemp) ;
Serial.print ("statut secondes =");
Serial.println(maxSeconds) ;
Serial.print ("TEMP STATUS =");
Serial.println(temperature) ;
Serial.print ("statut cuisse =");
Serial.println(tempHigh) ;
stringOK = true ;
} / / inputString.startsWith("STATUS")
Si la commande est statut, le programme fournit simplement toutes les informations à sériel.
} / / inputString.startsWith ("CMD")
stringOK ? Serial.println ("commande exécutée"): Serial.println ("commande non valide");
Signal si une commande valide ou non valide a été reçue.
effacer la chaîne pour la prochaine itération
inputString = "";
stringComplete = false ;
} / / stringComplete
Variables internes pour l’itération suivante de la commande.
Si {(statusReport)
température = (tempVal * 0.0048828125 -.5) * 100 ;
Serial.print ("TEMP STATUS =");
Serial.println(temperature) ;
Serial.print ("statut cuisse =");
Serial.println(tempHigh) ;
statusReport = false ;
}
}
Si la routine d’interruption a hissé le drapeau de statusReport, quelques informations sont affichées dans la série et le drapeau est effacé.
Notez que la valeur de la température actuelle est calculée à ce stade : par conséquent, si vous émettez une commande de statut entre l’intervalle de statusReport, vous obtiendrez l’ancienne valeur de la température.
Comme déjà indiqué, serialEvent() se produit chaque fois qu’un nouveau données vient dans le RX série de matériel. Cette routine est exécutée entre chaque séries de loop() de temps, donc à l’aide de retard à l’intérieur de la boucle peut retarder la réponse. Multiples d’octets de données soient disponibles.
void serialEvent() {}
tandis que (Serial.available()) {}
Obtenez le nouveau octet :
char inChar = (char)Serial.read() ;
Ajoutez-le à l’inputString :
inputString += inChar ;
Si le caractère entrant est un saut de ligne ou un retour chariot, définir un indicateur
ainsi, la boucle principale peut faire quelque chose :
Si (inChar == « \n » || inChar == « \r ») {}
stringComplete = true ;
}
}
}
Chaque octet est lire numéro de série et ajouté à la chaîne d’entrée jusqu'à « \n » ou « \r » est rencontrée pour indiquer la fin de la chaîne : dans ce cas l’indicateur de stringComplete, qui est vérifiée par loop(), est défini. Les retours chariot, \r et saut de ligne, \n, s’assure que le code est capable de détecter la fin de la chaîne d’une variété d’entrées, y compris les autres terminaux série que l’Arduino IDE Serial Monitor.
Note au sujet de Bluetooth et de série
Dans beaucoup d’exemples, dont celui de vendeur JY-MCU, vous pouvez trouver le module Bluetooth connecté sur différentes broches numériques de l’Arduino (eg. 10 et 11) et accessibles via la bibliothèque de SoftwareSerial. D’après les résultats de mes tests, SoftwareSerial fonctionne parfaitement lorsque le module est utilisé pour envoyer des informations uniquement, mais l’Arduino Uno n’est pas rapide assez lorsqu’il reçoit des commandes. Je n’a pas essayer de réduire la vitesse de la connexion SoftwareSerial (dans les exemples, il est souvent fixé à 2400bps) parce que l’app MIT AppInventor ne semble pas soutenir paramètre de vitesse de connexion Bluetooth.
Avec SoftwareSerial, serialEvent() ne fonctionnera pas : on a besoin de le renommer (eg. mySerialEvent()) et l’appeler explicitement au début de loop().