Paso 3: Código de Arduino - detalles
Estructura de mando y mensaje como se describe en el paso anterior
Parámetros serie: COM11 9600 8 N 1
\r o \n al final de la línea de comandos
Bluetooth es el Pin 0 & 1 @ velocidad 9600
Estructura del comando / / CMD RED| GREEN| AMARILLO = ON|] DE
TMAX| CMD SEGUNDOS = valor
SEGUNDOS de CMD = valor
ESTADO DE CMD
Estructura de mensaje de estado
ESTADO RED| GREEN| YELLOW| TMIN| TMAX| SECONDS| TEMP| MUSLO = valor
Inicialización de variables necesarias para el control de la temperatura
flotador maxTemp = 30.0; encender led cuando temp > maxTemp
int maxTempSensor = (int) ((maxTemp/100 + 5) * 204.8);
Float temperatura = 0.0;
maxTemp puede cambiarse más adelante, pero el programa tiene un valor predeterminado para comenzar con. maxTempSensor es la conversión de maxTemp 0-1023 gama proporcionado por el convertidor ADC Arduino; comparación de la temperatura se realizará por una rutina de interrupción que tan rápido como sea posible: es más eficiente directamente comparar entero salida polos de valor en lugar de la temperatura del flotador. Todavía queremos que informe la temperatura y el programa la guardará en la variable con el mismo nombre.
Si no está familiarizado con la fórmula de conversión de temperatura, puede tener una mirada aquí.
maxSeconds también se puede cambiar con el comando pero otra vez tenemos un defecto
int maxSeconds = 10; Enviar mensaje de estado de cada maxSeconds
Declaraciones de constantes de Pin
const int ledPin = 13; temperatura led
const int tempPin = A0; Clavija de entrada analógica del sensor temperatura de T36
const int led1Pin = 3; Amarillo
const int led2Pin = 4; Verde
const int led3Pin = 5; Rojo
Las variables utilizan en la rutina de interrupción y acceder desde fuera de ella
tempVal int volátiles;
volátil int segundos = 0;
volátil tempHigh boolean = false;
volátil statusReport boolean = false;
Volátil es una palabra clave especial que impide que el compilador realiza ciertas optimizaciones: todas las variables que se modifican dentro de una rutina de interrupción y se acceden también fuera de ella deben ser declaradas como volátil para indicar que su valor puede cambiar en cualquier momento y para asegurarse de que la última, correcto, valor se lee de la memoria cuando sea necesario.
Variables de la cadena de comando (que se explicará más adelante)
String inputString = "";
String comando = "";
Valor de cadena = "";
Boolean stringComplete = false;
La función setup()
void setup() {}
iniciar conexión serie
Serial.Begin(9600);
Serial.Print ("Max T:");
Serial.Print(maxTemp);
Serial.Print ("Sensor:");
Serial.println(maxTempSensor);
inputString.reserve(50); pinMode (ledPin, salida); pinMode (led1Pin, salida);
Command.Reserve(50);
Value.Reserve(50);
digitalWrite (ledPin, LOW);
pinMode (led2Pin, salida);
pinMode (led3Pin, salida);
digitalWrite (led1Pin, bajo);
digitalWrite (led2Pin, bajo);
digitalWrite (led3Pin, bajo);
El método de reserva de una cadena asigna el número de bytes como argumento.
El código siguiente es necesario para inicializar la interrupción de temporizador y ponerlo al fuego cada segundo, el más lento puede hacer Arduino; para obtener información detallada, consulte aquí.
CLI(); deshabilitar las interrupciones globales Inicializa el Timer1 para interrupción @ 1000 mseg compara conjunto registro de partido a cuenta de temporizador deseado: SEI(); activar interrupciones globales
TCCR1A = 0; establece registro TCCR1A todo en 0
TCCR1B = 0; mismo para TCCR1B
OCR1A = 15624; activar el modo de CTC:
TCCR1B | = (1 << WGM12);
Juego de brocas CS10 y CS12 para 1024 prescaler:
TCCR1B | = (1 << CS10);
TCCR1B | = (1 << CS12);
habilitar interrupción de timer compara:
TIMSK1 | = (1 << OCIE1A);
}
La rutina de interrupción del temporizador: no podemos cambiar su nombre, pero el contenido es totalmente personalizable.
ISR(TIMER1_COMPA_vect) Si (tempVal > maxTempSensor) {}
{
tempVal = analogRead(tempPin);
digitalWrite (ledPin, HIGH);
tempHigh = true;
}
Else {}
digitalWrite (ledPin, LOW);
tempHigh = false;
}
El valor de la temperatura - o, como se señaló anteriormente su 0-1023 representación de entero - se lee en el sensor y se compara con del valor umbral: cuando sobre el built-in LED se enciende y tempHigh se establece en verdadero, de lo contrario el LED se apaga andtempHigh se establece en false.
Si (segundos ++ > = maxSeconds) {}
statusReport = true;
segundos = 0;
}
}
Recordar que la interrupción se dispara cada segundo, pero queremos que informe el estado del sistema menos con frecuencia: la variable segundos se incrementa en cada iteración hasta alcanzar los valores cuando el informe es debido; Esto se hará más adelante en el bucle principal marcando statusReport bandera. Como regla general, nunca nunca realizar alguna cosa tan lento tales datos escritura serial desde dentro de una rutina de interrupción.
La función loop() interpreta y ejecuta los comandos cuando recibió, entonces informa estado si bandera es levantada por interrupción de temporizador. Para leer una cadena desde el búfer serial, loop() se basa en la función serialEvent() que se definirá al final: esta rutina se ejecuta entre cada vez loop(). No está ampliamente documentada y probablemente no se aplica a todos los modelos de Arduino; en cualquier caso, no es difícil por su contenido dentro de la cañería del lazo (ver final de paso thi).
void loop() {} Si (stringComplete) {}
intValue int = 0;
Serial.println(InputString);
Boolean stringOK = false;
Si (inputString.startsWith ("CMD")) {}
inputString = inputString.substring(4);
En primer lugar comprobamos si la cadena recibida comienza con "CMD": Si por lo que podemos descartar los cuatro primeros caracteres, de lo contrario te después levantamos un error.
int pos = inputString.indexOf('=');
Si (pos > -1) {}
comando = inputString.substring (0, pos);
valor = inputString.substring (pos + 1, inputString.length()-1); Extraiga el mando hasta \n excluida
Hay dos tipos de comandos: un valor, donde encontraremos "=" separar el par variable + valor y donde el mando es una única directiva (estado). Si "=" está presente en el pos, la cadena es se dividen en comandos (parte izquierda) y valor (parte derecha), cayendo ambos el "=" en el medio y el carácter de fin de línea al final.
Si (command.equals("RED")) {/ / rojo = ON|] DE
¿Value.Equals("ON")? digitalWrite (led3Pin, HIGH): digitalWrite (led3Pin, bajo);
stringOK = true;
}
else if (command.equals("GREEN")) {/ / verde = ON|] DE
¿Value.Equals("ON")? digitalWrite (led2Pin, HIGH): digitalWrite (led2Pin, bajo);
stringOK = true;
}
else if (command.equals("YELLOW")) {/ / amarillo = ON|] DE
¿Value.Equals("ON")? digitalWrite (led1Pin, HIGH): digitalWrite (led1Pin, bajo);
stringOK = true;
}
Examinamos y ejecutar los comandos de LED; Tenga en cuenta que el código sólo comprueba el valor ON: Si escribes verde = ASD se interpretará como verde = OFF. No es perfecto, pero mantiene las cosas mucho más simples. stringOK = true se establece cada vez que un comando es reconocido y ejecutado para que posteriormente se indicará con comandos mal.
else if (command.equals("TMAX")) {/ / TMAX = valor
intValue = value.toInt();
si (intValue > 0) {
maxTemp = (float) intValue;
maxTempSensor = (int) ((maxTemp/100 + 5) * 204.8);
stringOK = true;
}
}
else if (command.equals("SECONDS")) {/ / segundos = valor
intValue = value.toInt();
si (intValue > 0) {
maxSeconds = intValue;
stringOK = true;
}
}
Cuando el valor debe ser un número, tenemos que convertir y prueba es realmente un número. En el caso de MaxTemp, también se calcula el valor del sensor como se explica en la sección de definición de variables
} / / pos > -1
else if (inputString.startsWith("STATUS")) {
Serial.print ("estado rojo =");
Serial.println(digitalRead(led3Pin));
Serial.print ("estado verde =");
Serial.println(digitalRead(led2Pin));
Serial.print ("estado amarillo =");
Serial.println(digitalRead(led1Pin));
Serial.print ("estado TMAX =");
Serial.println(maxTemp);
Serial.print ("estado segundos =");
Serial.println(maxSeconds);
Serial.print ("estado TEMP =");
Serial.println(Temperature);
Serial.print ("estado muslo =");
Serial.println(tempHigh);
stringOK = true;
} / / inputString.startsWith("STATUS")
Si el comando es estado, el programa simplemente salidas de toda la información en serie.
} / / inputString.startsWith ("CMD")
¿stringok de ? Serial.println ("comando ejecutado"): Serial.println ("comando no válido");
Si un comando válido o no se ha recibido la señal.
claro la cadena para la siguiente iteración
inputString = "";
stringComplete = false;
} / / stringComplete
Servicio de limpieza variable para la siguiente iteración de comando.
Si (statusReport) {}
temperatura = (tempVal * 0.0048828125 -.5) * 100;
Serial.print ("estado TEMP =");
Serial.println(Temperature);
Serial.print ("estado muslo =");
Serial.println(tempHigh);
statusReport = false;
}
}
Si la rutina de interrupción ha levantado la bandera statusReport, cierta información se imprime en serie y se despeja la bandera.
Tenga en cuenta que el valor actual de la temperatura se calcula en este punto: por lo tanto, si emite un comando de estado entre el intervalo statusReport, obtendrás el valor de la temperatura anterior.
Como se ha señalado, serialEvent() ocurre cuando una nueva información viene en el hardware serie RX. Esta rutina se ejecuta entre cada loop() agote el tiempo, así que usando retraso dentro de bucle puede retrasar la respuesta. Varios bytes de datos pueden estar disponibles.
void serialEvent() {}
mientras (Serial.available()) {}
obtener el byte nuevo:
char a inChar = (char)Serial.read();
Añadir a la inputString:
inputString += inChar;
Si el carácter entrante es una nueva línea o un retorno de carro, establece un indicador
así que el bucle principal puede hacer algo al respecto:
Si (inChar == '\n' || inChar == '\r') {}
stringComplete = true;
}
}
}
Cada octeto es leído de la serie y añadido a la cadena de entrada hasta el "\n" o en "\r" es para indicar el final de la cadena: en este caso se encuentra la bandera de stringComplete, que es revisada por loop(),. Utilizando tanto retorno de carro \r y nueva línea, \n, asegura que el código es capaz de detectar el final de la cadena de una variedad de entradas como otros terminales seriales que el IDE de Arduino Serial Monitor.
Nota sobre Bluetooth y serie
En muchos ejemplos, incluyendo uno de JY-MCU vendedor, usted puede encontrar el módulo de Bluetooth conectado en diferentes pernos digitales de Arduino (ej. 10 y 11) y acceder a través de la librería SoftwareSerial. Basándose en los resultados de mis pruebas, SoftwareSerial funciona perfectamente cuando el módulo se utiliza para enviar información solamente, pero el Arduino Uno no es rápido bastante durante la recepción de comandos. No intentar reducir la velocidad de la conexión SoftwareSerial (en los ejemplos a menudo se establece en 2400bps) porque la aplicación AppInventor MIT no parece apoyar la opción de velocidad de conexión de Bluetooth.
Con SoftwareSerial, serialEvent() no funciona: hay que cambiarle el nombre (ej. mySerialEvent()) y llamar explícitamente al principio de loop().