Pagpapalitan ng data sa pagitan ng dalawang arduino. Android at Arduino. Palitan ng data. Lua bootloader para sa AVR na isinulat sa ESP8266

Mahalaga lamang para sa kanya na makipagpalitan ng impormasyon sa microcontroller. Lumilitaw ang mga sitwasyon kapag kailangan mong manu-manong i-activate ang isang partikular na function sa microcontroller program sa pamamagitan ng pagkontrol nito mula sa isang PC o laptop.

Ngunit dumating tayo sa punto. Ang pakikipagpalitan ng data sa Arduino ay hindi ganoon kahirap, ngunit ang catch ay ang data ay inilipat ng character sa pamamagitan ng character, na napakasama. Kinailangan kong gumugol ng mahabang panahon sa paghahanap para sa problemang ito hanggang sa nakatagpo ako ng isang napakagandang aklatan sa Habrahabr. Ipinatupad ng may-akda sa loob nito ang pag-andar ng pagtanggap ng mga numero, i.e. maaari kang magpadala ng mga numero na binubuo ng higit sa isang digit sa controller, at ito ay gagana nang tama. I-download ang library (link), i-unpack ito sa mga hardware library, at magpatuloy tayo sa pagsasanay.

Una sa lahat, magsulat tayo ng sketch at i-upload ito sa Arduino (Freeduino)

#include void setup() (

Serial.begin(9600); // itakda ang bilis ng port

PinMode(9, OUTPUT); // itakda ang 9th leg bilang output para sa speaker

) void loop()

Mahabang int na Numero; Serial.print("Ipasok ang numero: ");

Numero = SerialInput.InputNumber(); // Maglagay ng numero Serial.print("Resulta = ");

Serial.println(Number * Number, DEC);

Beep(500);

} void beep(unsigned char delayms)(

AnalogWrite(9, 20); // ang value ay dapat nasa pagitan ng 0 at 255

// eksperimento upang makakuha ng magandang tono

AnalogWrite(9, 0); // 0 — patayin ang piezo

Pagkaantala(mga pagkaantala); // pause delayms ms

Ano ang ibig sabihin ng lahat ng ito. Sinubukan kong ibigay ang code na may mga detalyadong komento, kaya dapat na malinaw ang lahat. Hinihiling sa iyo ng sketch na ito na maglagay ng anumang numero, pagkatapos nito ay ipapakita ang parisukat nito at magpapatugtog ng sound signal sa pamamagitan ng piezo speaker na konektado sa pin 9.

At ngayon, ang pinaka-kagiliw-giliw na bagay ay oras na upang subukan. Upang kumonekta sa controller, inirerekumenda ko ang paggamit ng isang libreng programa masilya. Sa mga setting ng uri ng Koneksyon, piliin ang Serial at sa halip na COM1, ilagay ang tamang numero ng port (maaari kang tumingin sa Tools->Serial Port menu sa Arduino programming environment). Pinindot namin ang Buksan, at nakita namin ang mensaheng Ipasok ang numero sa console, ipasok ang anumang numero (sa loob ng dahilan), pindutin ang Enter, at nakita namin ang resulta.

Iyon lang, maaari kang magsaya at tumalon sa tuwa. Naturally, ang lahat ng ito ay maaaring mapabuti, halimbawa, unang magpakita ng isang menu, ipadala ito mula sa controller sa console, kung saan maaari mong ilarawan ang mga utos nang detalyado. Halimbawa, ipasok ang numero 0 - ang LED backlight ay naka-on, pindutin ang 1 - ito ay lumabas. Kaya, maaari kang maglagay ng hindi bababa sa 100,500 na mga utos, hangga't mayroong sapat na memorya ng microcontroller (na napakaliit). Pag-uusapan natin kung paano palawakin ang magagamit na memorya sa susunod.

UPD: bahagi ng code ay pinutol ng engine parser, kaya narito ang source code

Ang isang COM port ay kadalasang ginagamit upang makipag-usap sa pagitan ng isang microcontroller at isang computer. Sa artikulong ito, ipapakita namin sa iyo kung paano magpadala ng mga control command mula sa computer at magpadala ng data mula sa controller.

Paghahanda para sa trabaho

Karamihan sa mga microcontroller ay may maraming I/O port. Ang UART protocol ay ang pinaka-angkop para sa komunikasyon sa isang PC. Ito ay isang serial asynchronous na data transfer protocol. Para i-convert ito sa USB interface, mayroong USB-RS232 – FT232RL converter sa board.
Upang makumpleto ang mga halimbawa sa artikulong ito, kakailanganin mo lamang ng Arduino-compatible board. Ginagamit namin ang . Tiyaking ang iyong board ay may LED na nakakonekta sa pin 13 at isang reset button.

Halimbawa, i-load natin ang code sa board na nagpapakita ng ASCII table. Ang ASCII ay isang encoding para sa kumakatawan sa mga decimal na digit, Latin at pambansang alpabeto, mga bantas, at control character.

int simbolo = 33 ; void setup() ( Serial. begin(9600); Serial. println(" ASCII Table ~ Character Map " ); ) void loop() ( Serial. write(symbol) ; Serial. print(" , dec: " ); Serial . print(simbolo) ; Serial. print( " ; " ; ipagpatuloy ; ) ) simbolo + + ;

Iniimbak ng variable ng simbolo ang code ng simbolo. Ang talahanayan ay nagsisimula sa 33 at nagtatapos sa 126, kaya ang simbolo ng variable ay unang nakatakda sa 33.
Upang simulan ang pagpapatakbo ng UART port, gamitin ang function Serial.begin(). Ang tanging parameter nito ay bilis. Ang bilis ay dapat na napagkasunduan sa pagpapadala at pagtanggap ng mga panig nang maaga, dahil ang transmission protocol ay asynchronous. Sa halimbawang isinasaalang-alang, ang bilis ay 9600bps.
Tatlong function ang ginagamit para magsulat ng value sa isang port:

  1. Serial.write()– nagsusulat ng data sa port sa binary form.
  2. Serial.print() maaaring magkaroon ng maraming kahulugan, ngunit lahat sila ay nagsisilbing magpakita ng impormasyon sa isang form na nababasa ng tao. Halimbawa, kung ang impormasyon na tinukoy bilang isang parameter na ililipat ay naka-highlight sa mga quote, ang terminal program ay maglalabas nito nang hindi nagbabago. Kung gusto mong magpakita ng value sa isang partikular na sistema ng numero, kailangan mong magdagdag ng service word: BIN - binary, OCT - octal, DEC - decimal, HEX - hexadecimal. Halimbawa, Serial.print(25,HEX).
  3. Serial.println() ginagawa ang parehong bagay bilang Serial.print(), ngunit sinisira din ang linya pagkatapos i-output ang impormasyon.

Upang suriin ang pagpapatakbo ng programa, kinakailangan na ang computer ay may terminal program na tumatanggap ng data mula sa COM port. Ang Arduino IDE ay mayroon na nitong built in. Para tawagan ito, piliin ang Tools->Port Monitor mula sa menu. Ang window ng utility na ito ay napaka-simple:

Ngayon i-click ang reboot button. Magre-reboot ang MK at ipapakita ang talahanayan ng ASCII:

Bigyang-pansin ang bahaging ito ng code:

kung (simbolo = = 126 ) ( habang (totoo) ( ituloy ; ) )

Ito ay huminto sa pagpapatupad ng programa. Kung ibubukod mo ito, ang talahanayan ay ipapakita nang walang katapusang.
Upang pagsamahin ang iyong kaalaman, subukang magsulat ng isang walang katapusang loop na magpapadala ng iyong pangalan sa serial port nang isang beses sa isang segundo. Magdagdag ng mga numero ng hakbang sa output at huwag kalimutang putulin ang linya pagkatapos ng pangalan.

Nagpapadala ng mga utos mula sa PC

Bago gawin ito, kinakailangan na magkaroon ng pag-unawa sa kung paano gumagana ang isang COM port.
Una sa lahat, ang lahat ng palitan ay nangyayari sa pamamagitan ng memory buffer. Iyon ay, kapag nagpadala ka ng isang bagay mula sa isang PC patungo sa isang aparato, ang data ay inilalagay sa ilang espesyal na seksyon ng memorya. Sa sandaling handa na ang device, babasahin nito ang data mula sa buffer. Binibigyang-daan ka ng function na suriin ang katayuan ng buffer Serial.avaliable(). Ibinabalik ng function na ito ang bilang ng mga byte sa buffer. Upang ibawas ang mga byte na ito kailangan mong gamitin ang function Serial.read(). Tingnan natin kung paano gumagana ang mga function na ito gamit ang isang halimbawa:

int val = 0 ; void setup() ( Serial. begin(9600); ) void loop() ( if (Serial. available() > 0 ) ( val = Serial. read() ; Serial. print("Natanggap ko: " ); Serial. write(val);

Kapag na-load na ang code sa memorya ng microcontroller, buksan ang monitor ng COM port. Mag-type ng isang character at pindutin ang Enter. Sa natanggap na patlang ng data makikita mo ang: "Natanggap ko: X", saan sa halip X magiging karakter na iyong ipinasok.
Ang programa ay umiikot nang walang katapusang sa pangunahing loop. Sa sandaling ang isang byte ay nakasulat sa port, ang Serial.available() function ay tumatagal ng halaga 1, iyon ay, ang kundisyon ay natutugunan Serial.available() > 0. Susunod na function Serial.read() binabasa ang byte na ito, sa gayon ay na-clear ang buffer. Pagkatapos nito, gamit ang mga function na alam mo na, ang output ay nangyayari.
Ang paggamit ng built-in na COM port monitor ng Arduino IDE ay may ilang mga limitasyon. Kapag nagpapadala ng data mula sa board patungo sa COM port, ang output ay maaaring ayusin sa anumang format. At kapag ipinadala mula sa PC hanggang sa board, ang mga character ay ipinadala alinsunod sa talahanayan ng ASCII. Nangangahulugan ito na kapag ipinasok mo, halimbawa, ang character na "1", "00110001" ay ipinadala sa pamamagitan ng COM port sa binary (iyon ay, "49" sa decimal).
Baguhin natin ng kaunti ang code at suriin ang pahayag na ito:

int val = 0 ; void setup() ( Serial. begin(9600); ) void loop() ( if (Serial. available() > 0 ) ( val = Serial. read() ; Serial. print("Natanggap ko: "); Serial. println(val, BIN);

Pagkatapos mag-download, sa port monitor kapag nagpapadala ng "1" makikita mo ang tugon: "Natanggap ko: 110001". Maaari mong baguhin ang format ng output at tingnan kung ano ang tinatanggap ng board kasama ng iba pang mga character.

Kontrol ng device sa pamamagitan ng COM port

Malinaw, gamit ang mga utos mula sa isang PC, maaari mong kontrolin ang anumang mga function ng microcontroller. I-download ang program na kumokontrol sa pagpapatakbo ng LED:

int val = 0 ; void setup() ( Serial. begin(9600); ) void loop() ( if (Serial. available() > 0 ) ( val = Serial. read() ; if (val= = "H") digitalWrite(13 , HIGH) ; kung (val= = "L") digitalWrite(13 , LOW) )

Kapag ang character na "H" ay ipinadala sa COM port, ang LED sa pin 13 ay iilaw, at kapag ang "L" ay ipinadala, ang LED ay mamamatay.
Kung, batay sa mga resulta ng pagtanggap ng data mula sa COM port, nais mong ang programa ay magsagawa ng iba't ibang mga aksyon sa pangunahing loop, maaari mong suriin ang mga kondisyon sa pangunahing loop. Halimbawa.

Mayroon akong device na binuo gamit ang Arduino uno:

    Arduino software na naka-install sa Arduino uno

    maaaring kontrolin gamit ang mga serial command

    maaaring kontrolin gamit ang mga pisikal na button at sensor

    kapag nagbago ang anumang button/sensor, isinusulat nito ang kasalukuyang estado sa serial

    Kung walang mensaheng naipadala sa loob ng 5 segundo, ipapadala nito ang serial message na hindi nagbabago

Ano'ng kailangan mo:

    Gamitin ang ESP8266 para magbigay ng tulay sa pagitan ng kasalukuyang Arduino software at MQTT/web

    Maaari kong i-program ang ESP8266 bilang isang web server, MQTT client, atbp. gamit ang Arduino IDE o Lua (ngunit mas gusto ko ang Arduino IDE dahil maaari kong gamitin muli ang mga bahagi ng code upang makabuo/mag-interpret ng komunikasyon).

    Hahawakan ng ESP8266 ang lahat ng kailangan para sa wifi/web/MQTT; Kung wala ang MQTT module, ang bahagi ng Arduino ay gagana nang awtonomiya, tanging ang remote control ang mawawala.

    Gusto kong gumawa ng kaunting mga pagbabago sa Arduino code (o wala sa mga ito kung maaari). Ang anumang mga pagbabago ay mangangailangan ng malawak na muling pagsubok, na sinusubukan kong iwasan.

    Maaaring hindi available ang ESP8266 sa ilang mga pag-install.

Anong mga opsyon ang nakita ko:

    <�Литий>Consistent

Mababasa ng ESP8266 ang serial output at maging tulay sa pagitan ng network/MQTT at serial, mag-iimbak ng kasalukuyang estado sa memorya na ipapadala kapag hiniling upang maiwasan ang pagboto sa device sa bawat oras.

Ang isang bentahe ay walang mga pagbabago/pagsusulit ng code na kinakailangan para sa bahagi ng Arduino.

Gawin ang Arduino I2C master at ESP8266 slave (o vice versa) at ipatupad ang bidirectional na komunikasyon. Nakuha ang ideyang ito sa pamamagitan ng pagbabasa ng thread na ito.

Iba pang impormasyon tungkol sa mga serial command:

Ang isang data packet (command o state description) ay binubuo ng 1-20 character na may posibleng peak na 20 packet bawat 5 segundo at isang average ng isang packet bawat 3 segundo. Kung kinakailangan, maaari kong ipadala ito ng 5 unsigned integer sa halip na mga alphanumeric na character.

Kung higit sa I2C/serial pin ang kailangan, maaari akong mag-upgrade sa Arduino Mega (kaya hindi isyu ang bilang ng mga libreng pin).

Mayroon bang iba pang mga pagpipilian para dito? (mga protocol, handa na mga aklatan para sa serial communication, atbp.). Sinusubukan kong huwag muling likhain ang gulong.

Salamat sa iyong oras!

3

1 sagot

Karamihan sa mga tutorial sa I2C ay ginawa ang bawat Arduino na isang alipin at isang master, ngunit ang isang ito ay mas mahusay dahil ang bawat Arduino ay alinman sa isang master o isang alipin (hindi pareho) at hindi kinakailangan ang paglipat. Ginagawa nitong mas madali ang mga bagay.

Ang I2C ay mas mahusay kaysa sa serial dahil maaari kang magdagdag ng higit pang mga Arduino sa parehong bus.

Ipinatupad ko ang I2C sa pagitan ng dalawang Arduino at hindi na ito mas mahirap kaysa sa pagbabasa/pagsusulat sa serial port (na nagawa mo na). At sigurado ako na maaari mong gawing pangkalahatan ang iyong serial port code upang gumana sa parehong serial at I2C na komunikasyon.

Ito ang aking halimbawa (isang patunay lamang ng konsepto). Kinokontrol ng Arduino slave ang ilang mga pin, temp. sensor at watchdog timer ayon sa pagkakasunud-sunod ng Arduino master. Kung ang alipin ay hindi nakatanggap ng kaunti sa oras, nire-reset nito ang Arduino master.

Master code

#include #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 const byte SLAVE_ADDRESS = 42; const byte LED = 13; char buffer; void setup() ( Serial.begin(9600); Serial.println("Master"); Wire.begin(); pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); delay(1000); digitalWrite(LED, LOW); Wire.beginTransmission(SLAVE_ADDRESS); Wire.write(CMD_PIN_ON); /end of setup void loop () ( Serial.println("."); Wire.beginTransmission (SLAVE_ADDRESS); Wire.write(CMD_SENSOR); int x = Wire.requestFrom(SLAVE_ADDRESS, 1); int) Wire.read( ); Wire.beginTransmission(SLAVE_ADDRESS);<< 8 | Wire.read(); Serial.print("Light="); Serial.println(light); Wire.beginTransmission (SLAVE_ADDRESS); Wire.write (CMD_BEAT); Wire.endTransmission(); Wire.requestFrom(SLAVE_ADDRESS, 1); delay (5000); } //end of loop

Alipin code

/* Esclavo I2C Recibe los siguientes comandos<- 1° byte -> <- 2° byte -> <- 3° byte ->CMD_SENSOR CMD_PIN_ON n° de pin duracion en segundos CMD_PIN_OFF n° de pin CMD_LUMEN CMD_BEAT Cada commando recibe un respuesta, ya sea el valor pedido o un status. */ #include #include typedef struct ( int pin; unsigned long off; ) PIN_PGMA; /* Lista de pines que se pueden activar via CMD_PIN_ON. */ #define PIN_LUMEN A0 #define PIN_LED 2 #define PIN_RESET 3 PIN_PGMA pgma = ( (PIN_LED, 0), (PIN_RESET, 0) ); const int pgmaSize = sizeof(pgma)/sizeof(PIN_PGMA); #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 #define ST_OK 0 #define ST_BAD_PIN 1 #define ST_TIME_0 2 #define ST_BAD_LEN_3 #define MY_3 #define MD_BEAT . Pasado // ito ay tiempo, se activa el PIN_RESET. // En milisegundos. #define BEAT_INTERVAL 10000 unsigned long lastBeat; // Largo del reset en milisegundos. #define RESET_LENGTH 250 byte cmd = 0; katayuan ng byte = 0; int thermoDO = 11; int thermoCS = 12; int thermoCLK = 13; MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); void setup () ( Serial.begin(9600); pinMode(PIN_LUMEN, INPUT); analogRead(PIN_LUMEN); para sa (int i = 0; i< pgmaSize; i++) { pinMode(pgma[i].pin, OUTPUT); digitalWrite(pgma[i].pin, LOW); } lastBeat = millis(); Wire.begin (MY_ADDRESS); Wire.onReceive (receiveCommand); Wire.onRequest (sendAnswer); } void loop() { unsigned long now = millis(); // Baja la linea de RESET si no ha recibido un beat ultimamente. unsigned long diff = now - lastBeat; if (diff >BEAT_INTERVAL) ( resetPin(); ) // Recorre la lista de pines y apaga aquellos cuyo tiempo termino. para sa (int i = 0; i< pgmaSize; i++) { if (pgma[i].off >0 && pgma[i].off<= now) { Serial.print("off pin="); Serial.println(pgma[i].pin); pgma[i].off = 0; digitalWrite(pgma[i].pin, LOW); } } } // called by interrupt service routine when outgoing data is requested void sendAnswer() { byte temp; int lightReading; switch (cmd) { case CMD_SENSOR: temp = thermocouple.readCelsius(); Wire.write(temp); break; case CMD_LUMEN: lightReading = analogRead(PIN_LUMEN); Wire.write(lightReading >> 8); Wire.write(lightReading % 0xFF); pahinga; case CMD_PIN_ON: case CMD_PIN_OFF: case CMD_BEAT: Wire.write(status); katayuan = ST_OK; pahinga; ) cmd = 0; ) // tinatawag ng interrupt service routine kapag dumating ang incoming data void receiveCommand (int howMany) ( cmd = Wire.read (); status = ST_OK; switch (cmd) ( case CMD_PIN_ON: cmdPinOn();; break; case CMD_PIN_OFF: cmdPinOff (); break; case CMD_BEAT: lastBeat = millis() ) //end of receiveEvent void cmdPinOff() ( if (Wire.available() != 1) ( status = ST_BAD_LEN; ) else ( int pin = Wire.read( ); int i = searchPin(pin);< 0) { status = ST_BAD_PIN; } else { pgma[i].off = 0; digitalWrite(pin, LOW); } } } int searchPin(int pin) { int i = pgmaSize - 1; while (i >= 0 && pgma[i].pin != pin) ( i--; ) return i; ) /* * Programa el encendido y duracion del RESET. */ void resetPin() ( if (digitalRead(PIN_RESET) == LOW) ( unsigned long now = millis(); int i = searchPin(PIN_RESET); pgma[i].off = now + RESET_LENGTH; lastBeat = now; digitalWrite (PIN_RESET, HIGH); ) ) void cmdPinOn() ( if (Wire.available() != 2) ( status = ST_BAD_LEN; ) else ( int pin = Wire.read(); int len ​​= Wire.read( ); int i = searchPin(pin);< 0) { status = ST_BAD_PIN; Serial.println("bad pin"); } else { if (len == 0) { status = ST_TIME_0; Serial.println("ban len"); } else { pgma[i].off = millis() + len * 1000; digitalWrite(pin, HIGH); Serial.println("ok"); } } } }

I-load natin ang karaniwang halimbawang “Physical Pixel” sa pamamagitan ng menu na File\Examples\4.Communication\PhysicalPixel. Ang program na ito ay naghihintay para sa data mula sa computer. Kapag ang simbolo ng 'H' ay natanggap, ang test indicator ay umiilaw kapag ang 'L' na simbolo ay natanggap, ito ay mawawala. Tingnan natin ang source code nito:

int outputPin = 13 ; //imbak ang contact number dito
int val; //ang natanggap na simbolo ay maiimbak dito

void setup()
{
Serial.begin(9600); //itakda ang port sa 9600 bps
pinMode(outputPin, OUTPUT) ; //itakda ang pin 13 sa output mode
}

void loop()
{
kung (Serial.available()) ( //kung may tinatanggap na karakter,
val = Serial.read(); // pagkatapos ay basahin ito at i-save ito sa val
kung (val == "H") ( // kung tinanggap ang karakter na "H"...
digitalWrite(outputPin, HIGH) ; // pagkatapos ay i-on ang LED
}
kung (val == "L") ( // kung tinanggap ang karakter na "L",
digitalWrite(outputPin, LOW) ; // pagkatapos ay patayin ang LED
}
}
}

Bigyang-pansin ang mga nested na kondisyon at ang pagkakasunud-sunod ng pagbubukas at pagsasara ng mga kulot na braces. Para sa kadalian ng pagbabasa ng code ng programa, ang bawat kasunod na antas ng nesting ay inililipat sa kanan. Bilang karagdagan, tinutulungan ka ng editor na basahin ang code - kung ilalagay mo ang cursor sa kanan ng isang bracket, iha-highlight nito ang katumbas na ipinares na bracket.

Paano suriin ang pagpapatakbo ng program na ito pagkatapos mong i-download ito sa microcontroller? Kailangan nating maghanap ng paraan upang magpadala ng mga character sa COM port ng computer upang matanggap at maproseso ng microcontroller ang mga ito. Mayroong maraming mga pagpipilian para sa paglutas ng problemang ito.

Ginagamit namin ang COM port monitor na nakapaloob sa Arduino development environment

Ito ang pinakasimpleng at pinaka-naiintindihan na paraan para sa mga nagsisimula.

Ang COM port monitor ay inilunsad sa pamamagitan ng Tools\Serial Monitor menu, o sa pamamagitan ng toolbar. Sa mas lumang mga bersyon ng software, ang monitor ay naa-access lamang sa pamamagitan ng toolbar: . Sa pamamagitan ng pagtawag sa monitor, siguraduhin na ang parehong baud rate ay pinili tulad ng sa microcontroller program. Ngayon ay maaari kang magpasok ng anumang mga character sa input field sa kanan, at pindutin ang "Ipadala" na pindutan - ang ipinasok na mga character ay ipapadala sa port, at tatanggapin sila ng iyong programa doon. Ipasok ang Latin na titik na "H" doon, i-click ang "Ipadala" - ang test LED ay sisindi. Kung magpapadala ka ng "L" ay lalabas ito. Sa pamamagitan ng paraan, ang lahat ng data na ipapadala ng iyong programa sa COM port ay ipapakita sa window sa ibaba.

Ginagamit namin ang terminal emulation program na HyperTerminal

Ito ay isang bahagyang mas mahirap na opsyon sa palitan na ipatupad.

Karaniwang may kasamang terminal emulation program ang Windows na tinatawag na HyperTerminal. Sa Windows XP, makikita ito sa Start menu\All Programs\Programs\Accessories\Communications\HyperTerminal. Kapag nagsisimula, kailangan mong tumanggi na lumikha ng isang koneksyon, piliin ang menu ng File\Properties. Sa dialog na lalabas, piliin ang iyong COM port, i-click ang "I-configure", at i-configure ang mga parameter ng komunikasyon alinsunod sa figure:

Maaari kang gumamit ng isa pang terminal emulator - lahat sila ay karaniwang may katulad na pag-andar at katulad na mga setting.

I-click ang "OK" sa parehong mga window, at sa sandaling nasa pangunahing window ng programa, anumang key sa keyboard - ang HyperTerminal ay kumonekta sa COM port. Ngayon ang lahat ng mga character na nai-type sa keyboard ay dumaan sa COM port sa microcontroller, at lahat ng ipinapadala ng microcontroller ay napupunta sa screen. Pindutin ang "H" at "L" na mga key (panoorin ang napiling wika at kaso) - ang test LED ay dapat umilaw at lumabas.

Sumulat tayo ng sarili nating programa para sa PC!

Ang pagpipiliang ito ay para sa mga tunay na mahilig mag-program hindi lamang sa Freeduino, kundi pati na rin sa mga PC. Bakit hindi? Hindi namin kailangang matutunan ang mga detalye ng serial port programming sa ilalim ng Windows o anumang iba pang kumplikadong bagay. Lalo na para sa paglutas ng mga simpleng problema, mayroong isang Processing language (http://processing.org), na halos kapareho sa syntax at maging sa development environment sa Arduino software.

I-install at ilunsad ang Processing - Makakakita ka ng development environment na katulad ng Arduino.

Ang source code para sa Processing language program ay nasa mga komento sa ibaba ng pangunahing teksto ng halimbawa ng Physical Pixel. Narito ito ay ipinapakita na may kaunting mga pagbabago - naitama namin ang pagbubukas ng port upang madali mong palitan ang numero nito:

import processing.serial.* ;
Serial port;
void setup()
{
laki(200 , 200 );
noStroke();
frameRate(10);
port = bagong Serial(ito, "COM5", 9600); //!!! Irehistro ang iyong COM port dito!!!
}
boolean mouseOverRect() //Nagbabalik ng true kung ang cursor ay nasa loob ng parisukat
{
return ((mouseX >= 50 ) && (mouseX<= 150 ) && (mouseY >= 50 ) at (mouseY<= 150 ) ) ;
}
void draw()
{
background(#222222 ) ;
kung (mouseOverRect()) // Kung ang cursor ay nasa loob ng isang parisukat...
{
punan(#BBBBB0) ; // baguhin ang kulay sa mas maliwanag
port.write("H"); // ipadala ang "H" sa microcontroller
) iba ( // kung hindi sa loob...
punan(#666660 ) ​​​​; // baguhin ang kulay sa mas madilim
port.write("L"); // ipadala ang "L" sa microcontroller
}
rect(50 , 50 , 100 , 100 ); // gumuhit ng parisukat
}

Patakbuhin ang programa (sa pamamagitan ng menu ng Sketch\Run) - lilitaw ang isang window na may isang parisukat, kapag inilagay mo ang cursor ng mouse dito, ang LED sa Freeduino ay sisindi.

Ang isang paglalarawan ng Processing language at ang mga kakayahan nito ay lampas sa saklaw ng simpleng salaysay na ito, ngunit marami sa mga halimbawa ng Arduino ang nagbibigay ng Processing PC code na nakikipag-ugnayan sa Freeduino sa mga komento sa ibaba ng pangunahing teksto ng programa.

Oras na para pagsamahin ang dalawang diskarteng ito para magkaroon ng ganap na two-way na komunikasyon sa pagitan ng Android at Arduino.

Upang gawin ito, bubuo kami ng isang simpleng proyekto gamit ang isang ultrasonic range finder at isang piezo buzzer.

Algoritmo ng trabaho

Ang isang aktibidad na may pindutang "Sukatan" ay ipinapakita sa screen ng Android device kapag nag-click ka dito, ang kaukulang command ay ipinapadala sa Arduino board. Pinoproseso ng Arduino board ang command at sinimulan ang isang cycle ng pagsukat, pagkatapos ay kalkulahin ang average na distansya sa balakid sa sentimetro. Ang distansya na ito sa bagay ay ipinadala pabalik sa Android device, kung saan ito ay ipinapakita bilang teksto, pati na rin sa slider (ProgressBar).
Sa Android, nangyayari rin ang pagpoproseso ng data: kung ang distansya sa bagay ay mas mababa sa 20 cm, pagkatapos ay isang control signal ang ipinadala sa Arduino upang i-on ang buzzer. Naturally, ito ay maaaring gawin sa Arduino code, ngunit para sa kalinawan, itinalaga ko ang gawaing ito sa Android device. Sa pangkalahatan, ito ay naging isang maliit na sensor ng paradahan.

Kaya, kailangan mo munang magpasya sa mga pangkat ng pamamahala. Dapat silang tukuyin nang magkapareho sa Arduino at sa Android device. Pinili ko ang mga sumusunod na numero:
1 - transmission enable command
2 - utos ng pagbabawal sa paghahatid
3 - utos na i-on ang buzzer

Ito ay naging medyo nakakalito sa unang dalawang utos, dahil... Hindi ko makuha ang Android na makatanggap nang tama ng isang mensahe na may data (sinubukan kong ipadala ito sa isang cycle at sa paglipas ng panahon, ngunit ang Android ay matigas ang ulo na ayaw tumanggap ng data, pinaghihinalaan ko na ito ay nauugnay sa ADB at hindi dapat mga ganitong problema kapag gumagamit ng Accessory Mode). Samakatuwid, kapag ang Arduino ay nakatanggap ng command 1 (transmission enable), sinusukat nito ang distansya at pinapagana ang tuluy-tuloy na paghahatid ng data sa isang loop. Kapag natanggap na ng Android ang data, naglalabas ito ng command 2 sa Arduino upang ihinto ang paglilipat ng data.

Programa para sa Arduino

Sketch para sa Arduino:

#include #include // Koneksyon sa Adb. Koneksyon * koneksyon; // Koneksyon ng adb. #define COMMAND_SEND_TRUE 1 // command to enable transmission #define COMMAND_SEND_FALSE 2 // command to prohibit transmission #define COMMAND_PLAY_BEEP 3 // command to enable the buzzer const int numOfReadings = 10; // bilang ng mga sukat (mga elemento ng array) int readings; // mga halaga ng pagsukat sa array int arrayIndex = 0; // element index sa array int total = 0; // kabuuang halaga int averageDistance = 0; // average na distansya // pagse-set up ng mga pin at variable para sa ultrasonic sensor int echoPin = 2; // DYP_ME007 ECHO pin int initPin = 3; // DYP_ME007 TRIG pin int BeeperPin = 8; // buzzer pin unsigned long pulseTime = 0; // tagal ng pulso sa microseconds unsigned long distance = 0; // distansya sa (cm) boolean SendToAndroid = false; void setup() ( pinMode(initPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(BeeperPin, OUTPUT); // Buzzer // bumuo ng array para sa (int thisReading = 0; thisReading< numOfReadings; thisReading++) { readings = 0; } Serial.begin(115200); // Инициализация подсистемы ADB. ADB::init(); // Open an ADB stream to the phone"s shell. Auto-reconnect. Use any unused port number eg:4568 connection = ADB::addConnection("tcp:4568", true, adbEventHandler); } void loop() { if(SendToAndroid == true) makeDimension(); ADB::poll(); // Poll the ADB subsystem. } void adbEventHandler(Connection * connection, adb_eventType event, uint16_t length, uint8_t * data) { if (event == ADB_CONNECTION_RECEIVE) // Если приняли данные { Serial.print("data:"); // Вывод в Serial Monitor для отладки Serial.println(data,DEC); if((data) == COMMAND_SEND_TRUE) SendToAndroid = true; // Флаг, что надо вкл. передачу данных else if ((data) == COMMAND_SEND_FALSE) SendToAndroid = false; //Флаг, что данные приняты и откл. передачу данных else if ((data) == COMMAND_PLAY_BEEP) playBeep(); } else if (event == ADB_CONNECTION_OPEN) Serial.println("ADB connection open"); else if (event == ADB_CONNECTION_CLOSE) Serial.println("ADB connection close"); else { Serial.println(event); } } void makeDimension() { for (int i = 0; i < numOfReadings; i++) { digitalWrite(initPin, HIGH); // посылаем импульс длительностью 10мс delayMicroseconds(10); digitalWrite(initPin, LOW); pulseTime = pulseIn(echoPin, HIGH); // Считываем длительность пришедшего импульса distance = pulseTime/58; // Дистанция = (длит. импульса / 58) см total= total - readings; readings = distance; total= total + readings; arrayIndex = arrayIndex + 1; // После того, как достигли последнего элемента, начинаем сначала if (arrayIndex >= numOfReadings) ( arrayIndex = 0; ) //Serial.println(distansya, DEC); ) averageDistance = kabuuang / numOfReadings; //calculate the average distance //Serial.println(averageDistance, DEC); connection->write(2,(uint8_t*)&averageDistance); // Send 2 bytes delay(10); ) void playBeep() ( para sa (int j = 0; j< 10; j++) { analogWrite(BeeperPin, 20); delay(50); analogWrite(BeeperPin, 0); delay(150); } }

Sa simula pa lang, tinukoy namin ang 3 constant - ito ang mga command para sa pagpapadala ng mga mensahe sa pagitan ng mga device: COMMAND_SEND_TRUE = 1, COMMAND_SEND_FALSE = 2, COMMAND_PLAY_BEEP = 3

Handler adbEventHandler() tinatawagan tuwing natatanggap ang data at kapag naganap ang iba pang mga kaganapan mula sa ADB (pagbubukas at pagsasara ng koneksyon).

Function makeDimension() gumagawa ng 10 mga sukat ng distansya, at pagkatapos ay kinakalkula ang average na halaga mula sa kanila, na, sa pamamagitan ng utos koneksyon->sumulat>() Ipinadala sa 2 byte sa Android device.

May function playBeep() lahat ay simple - ito ay idinisenyo upang i-play ang 10 maikling tunog sa pamamagitan ng isang buzzer.

Programa para sa Android

Ang aming window ng aktibidad ay binubuo ng mga sumusunod na pangunahing elemento:
button (Button) - upang magpadala ng command sa pagsukat ng distansya
text field (TextView) - upang ipakita ang nakuhang distansya
progress bar (ProgressBar) - para sa visual na pagpapakita ng distansya (maximum - 500 cm)
icon ng koneksyon (ImageView) - ipinapakita kapag mayroong aktibong koneksyon sa isang Android device.

XML file ng aktibidad na ito, tingnan ang mga naka-attach na file

Ang file para sa pangunahing Aktibidad ay naglalaman ng sumusunod na code:

Package com.example.arduino54; import java.io.IOException; import org.microbridge.server.Server; import org.microbridge.server.AbstractServerListener; import com.example.arduino54.R; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; mag-import ng android.widget.TextView; import android.widget.Button; pinalawak ng pampublikong klase ang MainActivity ng Aktibidad ( private int Distance = 0; public final String APP_NAME = "arduino54"; public final byte COMMAND_SEND_TRUE = 1; // Send enable command public final byte COMMAND_SEND_FALSE = 2; // Send disable command public final byte COMMAND_PLAY_BEEP = 3; // Command upang paganahin ang buzzer public final int SYS_COMMAND_DATA = 0; ; @Override public void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Gumawa ng TCP server (batay sa MicroBridge LightWeight server) subukan ( server = bagong Server(4568) ; //Ang parehong port ay dapat gamitin sa ADK board server.start(); System.exit(-1); ) connectedImage = (ImageView) findViewById(R.id.imageConnected); connectedImage.setAlpha(20); Button Button1 = (Button)findViewById(R.id.button1); Button1.setOnClickListener(new View.OnClickListener() ( public void onClick(View v) ( try ( server.send(new byte ((byte) COMMAND_SEND_TRUE)); //Send data //Log.d(APP_NAME, "data_send: "+bSend); ) catch (IOException e) ( Log.e(APP_NAME, "Problema sa pagpapadala ng TCP message", e); ) ) )); server.addListener(new AbstractServerListener() ( @Override public void onReceive(org.microbridge.server.Client client, byte data) ( Log.d(APP_NAME, "data0:"+data+"; data1:"+data); kung (data.haba<2) Log.e(APP_NAME, "Размер данных менее 2-х байт:"+data.length); else { try { server.send(new byte {(byte) COMMAND_SEND_FALSE}); //Посылаем данные } catch (IOException e) { Log.e(APP_NAME, "Problem sending TCP message", e); } } Distance = ((data << 8) | (data & 0xFF)); // Формируем слово из 2-х байт //Any update to UI can not be carried out in a non UI thread like the one used //for Server. Hence runOnUIThread is used. runOnUiThread(new Runnable() { //@Override public void run() { new UpdateData().execute(Distance,SYS_COMMAND_DATA); } }); } //@Override public void onClientConnect(org.microbridge.server.Server server, org.microbridge.server.Client client){ Log.d(APP_NAME, "ClientConnected"); runOnUiThread(new Runnable() { public void run() { new UpdateData().execute(0,SYS_COMMAND_CONNECTED); } }); } public void onClientDisconnect(org.microbridge.server.Server server, org.microbridge.server.Client client){ Log.d(APP_NAME, "ClientDisconnected"); runOnUiThread(new Runnable() { public void run() { new UpdateData().execute(0,SYS_COMMAND_DISCONNECTED); } }); } }); } @Override protected void onDestroy (){ super.onDestroy(); server.stop(); } class UpdateData extends AsyncTask< Integer, Integer, Integer>( // Tinawag upang simulan ang background na aktibidad @Override protected Integer doInBackground(Integer... ArdState) ( if((ArdState)< 20) && (ArdState != 0)){ //Если расстояние меньше 20см try { server.send(new byte {(byte) COMMAND_PLAY_BEEP}); } catch (IOException e) { Log.e(APP_NAME, "Problem sending TCP message", e); } } return (ArdState); //Возвращаем в onPostExecute() } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); // Not used in this case } @Override protected void onPostExecute(Integer... result) { Log.d(APP_NAME, "onPostExecute:"+result); Log.d(APP_NAME, "onPostExecute:"+result); if(result == 1){ connectedImage.setAlpha(255); } else if(result == 2){ connectedImage.setAlpha(20); } TextView txt_Distance_Arduino = (TextView) findViewById(R.id.textDistance); txt_Distance_Arduino.setText(String.valueOf(result+" см")); // Выводим на activity дистанцию ProgressBar mProgressBar = (ProgressBar)findViewById(R.id.progressBar1); mProgressBar.setProgress(result); } } }

Dito na kami para sa klase server tukuyin ang pamamaraan server.addListener(bagong AbstractServerListener() ()), at: onReceive(), onClientConnect() At onClientDisconnect() na tinatawag kapag tumatanggap ng data mula sa server ng MicroBridge, kapag kumokonekta at dinidiskonekta.

Nag-attach kami ng isang click event handler sa Button1 setOnClickListener(). Kapag pinindot mo ang pindutan, ang pamamaraang ito ay tinatawag at ipinapadala ang command na COMMAND_SEND_TRUE sa Arduino board, kung saan sinusukat ng Arduino ang distansya at ipinapadala ang halaga ng distansya.

Sa pamamaraan onReceive(), sa sandaling matanggap namin ang data, agad naming ibinabalik ang command na COMMAND_SEND_FALSE upang i-off ng Arduino ang packet transmission. Sumulat ako tungkol sa algorithm na ito sa itaas.

Pakitandaan na para maglipat ng data sa isang hiwalay na thread, ginagamit namin ang mga panloob na command ng system na SYS_COMMAND_DATA, SYS_COMMAND_CONNECTED at SYS_COMMAND_DISCONNECTED. Ang mga utos ay ipinapadala ng ika-2 elemento ng array, at ang unang elemento ay naglalaman ng sinusukat na distansya na natanggap mula sa Arduino.

Kapag na-trigger ang isang kaganapan onClientConnect(), isang bagong thread ay nilikha kung saan ang isang array na may SYS_COMMAND_CONNECTED na utos (sa aming kaso 0) ay inilipat, at sa pamamaraan onPostExecute() Sa pamamagitan ng pagtatakda ng Alpha value sa maximum na 255, ang icon ng koneksyon ay ipinapakita. Kapag ang SYS_COMMAND_DISCONNECTED na utos ay natanggap, ang Alpha ay nakatakda sa 20, ang icon ay nagiging kupas at halos hindi nakikita, nangangahulugan ito na ang koneksyon ay hindi naitatag. Itinatakda ang alpha transparency gamit ang pamamaraan setAlpha(int).

Kapag ang isang thread ay nakatanggap ng data mula sa onReceive na paraan, pagkatapos ay sa pamamaraan doInBackground() ang kondisyon ay inihambing, at kung ang distansya ay hindi maagang zero at mas mababa sa 20 cm, pagkatapos ay ang paraan server.send() Ang command na COMMAND_PLAY_BEEP ay ipinadala upang paganahin ang buzzer sa Arduino board.

Sa pamamaraan onPostExecute() Ang mga elemento ng UI ay output upang ipakita ang numerical na halaga ng distansya at mga guhit sa progress bar.

Sa naka-attach na file maaari mong i-download mga proyekto para sa Arduino at Android, pati na rin ang lahat ng kinakailangang aklatan