Ansluta Arduino Uno till Android via Bluetooth (3 / 6 steg)
Steg 3: Arduino kod - Detaljer
Kommandot och meddelande struktur som beskrivs i föregående steg
Seriella parametrar: COM11 9600 8 N 1
\r eller \n att avsluta kommandoraden
Bluetooth är på stift 0 & 1 @ 9600 hastighet
Kommandot struktur / / CMD RED| GREEN| GUL = ON| UTANFÖR
CMD TMAX| SEKUNDER = värde
CMD sekunder = värde
CMD STATUS
Status meddelandestruktur
STATUS RED| GREEN| YELLOW| TMIN| TMAX| SECONDS| TEMP| LÅR = värde
Initiering av variabler som behövs för temperaturkontroll
flyta maxTemp = 30,0; slå på ledde när temp > maxTemp
int maxTempSensor (int) = ((maxTemp/100 +.5) * 204,8);
flyta temperatur = 0,0;
maxTemp kan senare ändras, men programmet behöver ett standardvärde till att börja med. maxTempSensor är omvandlingen av maxTemp till 0-1023 utbud som tillhandahålls av Arduino ADC omvandlare; temperaturen jämförelse kommer att utföras av ett avbrott rutin som vi vill så fort som möjligt: det är effektivare att direkt jämföra heltalet Pin produktionen värde i stället för float temperaturen. Vi vill fortfarande att rapportera temperaturen och programmet lagrar det i variabeln med samma namn.
Om du inte är bekant med konverteringsformeln temperatur, kan du ta en titt här.
maxSeconds kan också ändras med ett kommando men behöver vi en standard
int maxSeconds = 10; Skicka statusmeddelande varje maxSeconds
Förklaringar av Pin konstanter
CONST int ledPin = 13. temperatur som ledde
CONST int tempPin = A0; T36 temperatur sensor analoga ingångsstift
CONST int led1Pin = 3; Gul
CONST int led2Pin = 4; Grön
CONST int led3Pin = 5; Röd
Variabler används i rutinen avbrott och tillgängliga från utsidan av det
flyktiga int tempVal;
flyktiga int sekunder = 0;
flyktiga boolean tempHigh = false;
flyktiga boolean statusReport = false;
Volatile är ett speciella nyckelord som hindrar att kompilatorn utför vissa optimeringar: alla variabler som ändras inom ett avbrott rutin och är också nås utanför det måste deklareras som volatile att signalera att deras värde kan ändra när som helst och för att se Senast, korrekt, värdet avläses minne när det behövs.
Kommandot strängvariabler (de kommer att förklaras senare)
String inputString = "";
String kommando = "";
String value = "";
booleska stringComplete = false;
Funktionen setup()
void setup() {
Starta seriell anslutning
Serial.BEGIN(9600);
Serial.Print (Max T:");
Serial.Print(maxTemp);
Serial.Print ("Sensor:");
Serial.println(maxTempSensor);
inputString.reserve(50); pinMode (ledPin, produktionen); pinMode (led1Pin, produktionen);
Command.Reserve(50);
Value.Reserve(50);
digitalWrite (ledPin, låg);
pinMode (led2Pin, produktionen);
pinMode (led3Pin, produktionen);
digitalWrite (led1Pin, låg);
digitalWrite (led2Pin, låg);
digitalWrite (led3Pin, låg);
Metoden reserv i en sträng allokerar antalet byte som anges som argument.
Följande kod behövs för att initiera på timer avbryta och ställa in den att skjuta varje sekund, den långsammaste den Arduinoen kan göra; för detaljerad information se här.
CLI(); Inaktivera globala avbryter initiera Timer1 för avbrott @ 1000 MSEK Set jämför match register till önskad timer räkning: SEI(); Aktivera global avbryter
TCCR1A = 0; satt hela TCCR1A register till 0
TCCR1B = 0; samma för TCCR1B
OCR1A = 15624; slå på CTC-läge:
TCCR1B | = (1 << WGM12);
Anger CS10 och CS12 bitar för 1024 prescaler:
TCCR1B | = (1 << CS10);
TCCR1B | = (1 << CS12);
Aktivera timern jämför avbrott:
TIMSK1 | = (1 << OCIE1A);
}
Timer-avbrott rutin: vi kan inte byta namn, men innehållet är helt anpassningsbara.
ISR(TIMER1_COMPA_vect) om (tempVal > maxTempSensor) {
{
tempVal = analogRead(tempPin);
digitalWrite (ledPin, hög);
tempHigh = sant;
}
annat {
digitalWrite (ledPin, låg);
tempHigh = false;
}
Temperaturvärde - eller, som diskuterats ovan sin 0-1023 heltal representation - läses från sensorn och jämförs med den tröskelvärdet: när ovanför inbyggd LED lyser och tempHigh är inställt på true, annars LED är avstängd andtempHigh sätts till false.
om (sekunder ++ > = maxSeconds) {
statusReport = sant;
sekunder = 0;
}
}
Kom ihåg att avbrottet avfyras varje sekund, men vi vill rapportera systemets status mindre ofta: sekunder variabeln ökas efter varje iteration tills den når värden när rapporten är oberättigat. Detta kommer att ske senare i de viktigaste loopen genom att kontrollera statusReport flagga. Som regel aldrig aldrig utföra något så sakta skriva uppgifterna vidare till följetong från inom en avbrott rutin.
Funktionen loop() tolkar och kör kommandon när emot, det rapporterar sedan status om flaggan tas upp av timer-avbrott. För att läsa en sträng från seriella bufferten, loop() förlitar sig på den serialEvent() funktion som kommer att definieras i slutet: denna rutin körs mellan varje gång loop() körs. Det är inte väldokumenterat och det förmodligen gäller inte för alla Arduino modeller; i vilket fall är det inte svårt att kapsla dess innehåll inom viktigaste kretsar (se slutet av thi steg).
void loop() { om (stringComplete) {
int intValue = 0;
Serial.println(inputString);
booleska stringOK = false;
om (inputString.startsWith ("CMD")) {
inputString = inputString.substring(4);
Vi kontrollera först om den mottagna strängen börjar med "CMD": om så vi kan ignorera de första fyra tecknen, annars vi ska senare höja ett fel.
int pos = inputString.indexOf('=');
om (pos > -1) {
kommandot = inputString.substring (0, pos);
värde = inputString.substring (pos + 1, inputString.length()-1); extrahera kommandot upp till \n studerandena
Det finns två typer av kommandon: ställa in ett värde, där hittar vi "=" separera variabel + värdeparet, och de där kommandot är ett enda direktiv (STATUS). Om "=" vid pos, är strängen uppdelade i kommandot (vänstra delen) och värde (högra delen), släppa både den "=" i mellan och end-of-line karaktär i slutet.
om (command.equals("RED")) {/ / röd = ON| UTANFÖR
Value.equals("on")? digitalWrite (led3Pin, hög): digitalWrite (led3Pin, låg);
stringOK = sant;
}
annat if (command.equals("GREEN")) {/ / grön = ON| UTANFÖR
Value.equals("on")? digitalWrite (led2Pin, hög): digitalWrite (led2Pin, låg);
stringOK = sant;
}
annat if (command.equals("YELLOW")) {/ / gul = ON| UTANFÖR
Value.equals("on")? digitalWrite (led1Pin, hög): digitalWrite (led1Pin, låg);
stringOK = sant;
}
Vi undersöker och LED kommandon; Observera att koden endast kontrollerar att värdet på: om du skriver grön = ASD det kommer att tolkas som grön = OFF. Det är inte perfekt, men den håller saker mycket enklare. stringOK = true anges varje gång ett kommando är erkänt och utförs så att fel kommandon kommer att flaggas senare.
annat if (command.equals("TMAX")) {/ / TMAX = värde
intValue = value.toInt();
om (intValue > 0) {
maxTemp = (float) intValue;
maxTempSensor = (int) ((maxTemp/100 +.5) * 204,8);
stringOK = true;
}
}
annat if (command.equals("SECONDS")) {/ / sekunder = värde
intValue = value.toInt();
om (intValue > 0) {
maxSeconds = intValue;
stringOK = true;
}
}
När värdet bör vara ett nummer, måste vi konvertera samt test det är verkligen ett nummer. När det gäller MaxTemp beräkna vi också värdet sensor som förklaras i avsnittet variabel definition
} / / pos > -1
annat if (inputString.startsWith("STATUS")) {
Serial.print ("STATUS röd =");
Serial.println(digitalRead(led3Pin));
Serial.print ("STATUS grön =");
Serial.println(digitalRead(led2Pin));
Serial.print ("STATUS gul =");
Serial.println(digitalRead(led1Pin));
Serial.print ("STATUS TMAX =");
Serial.println(maxTemp);
Serial.print ("STATUS sekunder =");
Serial.println(maxSeconds);
Serial.print ("STATUS TEMP =");
Serial.println(temperature);
Serial.print ("STATUS lår =");
Serial.println(tempHigh);
stringOK = true;
} / / inputString.startsWith("STATUS")
Om kommandot är STATUS, utgångar programmet helt enkelt all information till följetong.
} / / inputString.startsWith ("CMD")
stringOK? Serial.println ("kommandot körs"): Serial.println ("Ogiltigt kommando"),
Signal om ett giltigt eller ogiltigt kommando har mottagits.
Rensa strängen för nästa iteration
inputString = "";
stringComplete = false;
} / / stringComplete
Variabel hushållning för nästa kommando iteration.
om (statusReport) {
temperatur = (tempVal * 0.0048828125 -.5) * 100;
Serial.print ("STATUS TEMP =");
Serial.println(temperature);
Serial.print ("STATUS lår =");
Serial.println(tempHigh);
statusReport = false;
}
}
Om rutinen avbrott har höjt flaggan statusReport, viss information skrivs ut på följetong och flaggan är avmarkerad.
Observera att nuvarande temperatur värdet beräknas på denna punkt: därför, om du utfärda en STATUS mellan statusReport intervallet, får du det gamla temperatur värdet.
Som redan nämnts, serialEvent() inträffar när en nya data kommer i hårdvara seriell RX. Denna rutin är köra mellan varje gång loop() körs, så använder dröjsmål inuti loop kan fördröja svar. Finns kanske flera byte data.
void serialEvent() {
samtidigt (Serial.available()) {
få den nya byten:
char inChar = (char)Serial.read();
Lägg till det inputString:
inputString += inChar;
om den inkommande karaktären är en ny rad eller en vagnretur, ange en flagga
så den viktigaste loopen kan göra något åt det:
om (inChar == '\n' || inChar == '\r') {
stringComplete = sant;
}
}
}
Varje byte läses från serial och lagt till ingång strängen tills "\n" eller "\r" påträffas för att beteckna sträng slutet: i detta fall den stringComplete flaggan, som kontrolleras av loop(), ligger. Använder både vagnretur \r och newline, \n, garanterar koden kan upptäcka sträng utgången från en mängd olika ingångar inbegripet andra seriella terminaler än Arduino IDE Serial Monitor.
Anteckning om Bluetooth och följetong
I många exempel, inklusive en från JY-MCU säljare, kan du hitta Bluetooth-modulen ansluten på olika Arduino digital stift (t.ex. 10 och 11) och nås via SoftwareSerial biblioteket. Baserat på resultaten av mina tester, fungerar SoftwareSerial perfekt när modulen används för att skicka information bara, men den Arduino Uno är inte fort nog när tar emot kommandon. Jag inte försökte att minska hastigheten på SoftwareSerial-anslutning (i exemplen det anges ofta till 2400bps) eftersom MIT AppInventor app inte verkar stödja Bluetooth anslutningshastigheten.
Med SoftwareSerial, serialEvent() fungerar inte: man måste byta namn på den (t.ex. mySerialEvent()) och kallar det uttryckligen i början av loop().