გადაიტანეთ მონაცემები ორ არდუინოს შორის. ტრუშინი A.N., Harutyunyan M.G.

10.09.2021

მოდით ჩატვირთოთ სტანდარტული მაგალითი „ფიზიკური პიქსელი“ მენიუდან File\Examples\4.Communication\PhysicalPixel. ეს პროგრამა ელოდება მონაცემებს კომპიუტერიდან. როდესაც "H" სიმბოლო მიიღება, ტესტის ინდიკატორი ანათებს "L" სიმბოლოს მიღებისას, ის ქრება. მოდით შევხედოთ მის საწყის კოდს:

int outputPin = 13; //აქ შეინახეთ საკონტაქტო ნომერი
ინტ ვალ; //მიღებული სიმბოლო აქ შეინახება

void setup()
{
Serial.begin(9600); //დააყენეთ პორტი 9600 bps
pinMode (outputPin, OUTPUT); //დააყენეთ პინი 13 გამომავალი რეჟიმში
}

void loop ()
{
if (Serial.available()) ( //თუ არის მიღებული სიმბოლო,
val = Serial.read(); // შემდეგ წაიკითხეთ და შეინახეთ ვალში
თუ (val == "H") ( // თუ მიიღება სიმბოლო "H"...
digitalWrite (outputPin, HIGH); // შემდეგ ჩართეთ LED
}
თუ (val == "L") ( // თუ სიმბოლო "L" მიღებულია,
digitalWrite (outputPin, LOW); // შემდეგ გამორთეთ LED
}
}
}

ყურადღება მიაქციეთ ბუდებულ პირობებს და ხვეული ბრეკეტების გახსნისა და დახურვის თანმიმდევრობას. პროგრამის კოდის წაკითხვის სიმარტივის მიზნით, ყოველი შემდგომი წყობის დონე გადაინაცვლებს მარჯვნივ. გარდა ამისა, რედაქტორი გეხმარებათ კოდის წაკითხვაში - თუ კურსორს მოათავსებთ ფრჩხილის მარჯვნივ, ის გამოყოფს შესაბამის დაწყვილებულ ფრჩხილს.

როგორ შევამოწმოთ ამ პროგრამის მუშაობა მიკროკონტროლერზე ჩამოტვირთვის შემდეგ? ჩვენ უნდა ვიპოვოთ სიმბოლოების გაგზავნის გზა კომპიუტერის COM პორტში, რათა მიკროკონტროლერმა მიიღოს და დაამუშაოს ისინი. ამ პრობლემის მოგვარების მრავალი ვარიანტი არსებობს.

ჩვენ ვიყენებთ COM პორტის მონიტორს, რომელიც ჩაშენებულია Arduino-ს განვითარების გარემოში

ეს არის ყველაზე მარტივი და გასაგები მეთოდი დამწყებთათვის.

COM პორტის მონიტორის გაშვება ხდება Tools\Serial Monitor მენიუდან ან ხელსაწყოთა ზოლის მეშვეობით. პროგრამული უზრუნველყოფის ძველ ვერსიებში მონიტორზე წვდომა მხოლოდ ხელსაწყოთა ზოლის საშუალებით იყო: . მონიტორის დარეკვით, დარწმუნდით, რომ არჩეულია იგივე ბაუდის სიხშირე, როგორც მიკროკონტროლერის პროგრამაში. ახლა თქვენ შეგიძლიათ შეიყვანოთ ნებისმიერი სიმბოლო შეყვანის ველში მარჯვნივ და დააჭირეთ ღილაკს "გაგზავნა" - შეყვანილი სიმბოლოები გაიგზავნება პორტში და თქვენი პროგრამა მიიღებს მათ იქ. შეიყვანეთ იქ ლათინური ასო "H", დააჭირეთ "გაგზავნას" - სატესტო LED აინთება. თუ "L"-ს გაგზავნით, ის გაქრება. სხვათა შორის, ყველა მონაცემი, რომელსაც თქვენი პროგრამა გაუგზავნის COM პორტს, გამოჩნდება ქვემოთ მოცემულ ფანჯარაში.

ჩვენ ვიყენებთ ტერმინალის ემულაციის პროგრამას HyperTerminal

ეს არის ოდნავ უფრო რთული გაცვლის ვარიანტი განსახორციელებლად.

Windows ჩვეულებრივ მოიცავს ტერმინალის ემულაციის პროგრამას, სახელწოდებით HyperTerminal. Windows XP-ში მისი ნახვა შეგიძლიათ Start მენიუში\All Programs\Programs\Accessories\Communications\HyperTerminal. დაწყებისას უარი უნდა თქვათ კავშირის შექმნაზე, აირჩიეთ მენიუ File\Properties. დიალოგში, რომელიც გამოჩნდება, აირჩიეთ თქვენი COM პორტი, დააწკაპუნეთ "კონფიგურაცია" და დააკონფიგურირეთ კომუნიკაციის პარამეტრები ფიგურის შესაბამისად:

თქვენ შეგიძლიათ გამოიყენოთ სხვა ტერმინალის ემულატორი - მათ ჩვეულებრივ აქვთ მსგავსი ფუნქციონირება და მსგავსი პარამეტრები.

დააწკაპუნეთ „OK“-ზე ორივე ფანჯარაში და ერთხელ პროგრამის მთავარ ფანჯარაში, კლავიატურაზე ნებისმიერი ღილაკი – HyperTerminal დაუკავშირდება COM პორტს. ახლა კლავიატურაზე აკრეფილი ყველა სიმბოლო გადის COM პორტით მიკროკონტროლერამდე და ყველაფერი, რასაც მიკროკონტროლერი აგზავნის, მთავრდება ეკრანზე. დააჭირეთ "H" და "L" ღილაკებს (უყურეთ არჩეულ ენას და ასოს) - სატესტო LED უნდა აანთოს და გამოვიდეს.

მოდით დავწეროთ ჩვენი საკუთარი პროგრამა კომპიუტერისთვის!

ეს ვარიანტი განკუთვნილია ნამდვილი ენთუზიასტებისთვის, რომლებსაც სურთ დაპროგრამონ არა მხოლოდ Freeduino, არამედ კომპიუტერებიც. რატომაც არა? ჩვენ არ გვჭირდება ვისწავლოთ სერიული პორტის პროგრამირების დეტალები Windows-ის ან სხვა რთული პერსონალის ქვეშ. განსაკუთრებით ასეთი მარტივი პრობლემების გადასაჭრელად, არსებობს Processing ენა (http://processing.org), რომელიც სინტაქსით და განვითარების გარემოშიც ძალიან ჰგავს Arduino პროგრამულ უზრუნველყოფას.

დააინსტალირეთ და გაუშვით Processing - თქვენ ნახავთ Arduino-ს მსგავსი განვითარების გარემოს.

დამუშავების ენის პროგრამის საწყისი კოდი მოცემულია Physical Pixel-ის მაგალითის ძირითადი ტექსტის ქვემოთ მოცემულ კომენტარებში. აქ ნაჩვენებია მინიმალური ცვლილებებით - ჩვენ შევასწორეთ პორტის გახსნა, რათა მარტივად შეცვალოთ მისი ნომერი:

იმპორტის დამუშავება.სერიული.* ;
სერიული პორტი;
void setup()
{
ზომა (200, 200);
noStroke() ;
კადრების სიხშირე (10);
პორტი = ახალი სერია (ეს, "COM5", 9600); //!!! დაარეგისტრირე შენი COM პორტი აქ!!!
}
ლოგიკური მაუსი OverRect() //აბრუნებს true თუ კურსორი არის კვადრატის შიგნით
{
დაბრუნება ((mouseX >= 50 ) && (mouseX<= 150 ) && (mouseY >= 50 ) & (მაუსიY<= 150 ) ) ;
}
void draw ()
{
ფონი(#222222);
if (mouseOverRect()) // თუ კურსორი არის კვადრატის შიგნით...
{
შევსება (#BBBBB0) ; // შეცვალეთ ფერი უფრო ნათელზე
port.write("H"); // გაგზავნეთ "H" მიკროკონტროლერთან
) სხვა ( // თუ შიგნით არა...
შევსება (#666660); // შეცვალეთ ფერი უფრო მუქზე
port.write("L"); // გაგზავნეთ "L" მიკროკონტროლერთან
}
rect(50, 50, 100, 100); // კვადრატის დახატვა
}

გაუშვით პროგრამა (Sketch\Run მენიუს მეშვეობით) - გამოჩნდება კვადრატული ფანჯარა, როცა მასში მაუსის კურსორს მოათავსებთ Freeduino-ზე LED შუქი აინთება.

დამუშავების ენისა და მისი შესაძლებლობების აღწერა სცილდება ამ მარტივი ნარატივის ფარგლებს, მაგრამ Arduino-ს მრავალი მაგალითი იძლევა კომპიუტერის დამუშავების კოდის ინტერაქციას Freeduino-სთან კომენტარებში ძირითადი პროგრამის ტექსტის ქვემოთ.

მე მაქვს Arduino uno-ით აშენებული მოწყობილობა:

    Arduino პროგრამული უზრუნველყოფა დაინსტალირებულია Arduino uno-ზე

    კონტროლდება სერიული ბრძანებების გამოყენებით

    მისი კონტროლი შესაძლებელია ფიზიკური ღილაკებისა და სენსორების გამოყენებით

    როდესაც ნებისმიერი ღილაკი/სენსორი იცვლება, ის წერს მიმდინარე მდგომარეობას სერიაში

    თუ შეტყობინება არ გაიგზავნა 5 წამის განმავლობაში, ის აგზავნის სერიულ შეტყობინებას უცვლელად

რაც გჭირდებათ:

    გამოიყენეთ ESP8266, რათა უზრუნველყოთ ხიდი მიმდინარე Arduino პროგრამულ უზრუნველყოფასა და MQTT/ვებს შორის

    მე შემიძლია ESP8266-ის დაპროგრამება, როგორც ვებ სერვერი, MQTT კლიენტი და ა.შ. Arduino IDE-ს ან Lua-ს გამოყენებით (მაგრამ მე მირჩევნია Arduino IDE, რადგან შემიძლია ხელახლა გამოვიყენო კოდის ნაწილები კომუნიკაციის გენერირებისთვის/ინტერპრეტაციისთვის).

    ESP8266 გაუმკლავდება ყველაფერს, რაც საჭიროა wifi/web/MQTT-ისთვის; MQTT მოდულის გარეშე Arduino-ს ნაწილი ავტონომიურად იმუშავებს, მხოლოდ დისტანციური მართვის პულტი აკლია.

    მსურს მინიმალური ცვლილებების შეტანა Arduino კოდში (ან არცერთ მათგანს, თუ ეს შესაძლებელია). ნებისმიერი ცვლილება მოითხოვს ვრცელ ხელახალი ტესტირებას, რასაც მე ვცდილობ თავიდან ავიცილო.

    ESP8266 შეიძლება არ იყოს ხელმისაწვდომი ზოგიერთ ინსტალაციაში.

რა ვარიანტები ვიპოვე:

    <�Литий>თანმიმდევრული

ESP8266-ს შეუძლია წაიკითხოს სერიული გამომავალი და იყოს ხიდი ქსელს/MQTT-სა და სერიებს შორის, შეინახავს მიმდინარე მდგომარეობას მეხსიერებაში, რომელიც გაიგზავნება მოთხოვნით, რათა თავიდან აიცილოს მოწყობილობის გამოკითხვა ყოველ ჯერზე.

ერთი უპირატესობა ის არის, რომ არ არის საჭირო კოდის ცვლილებები/ტესტები Arduino ნაწილისთვის.

გააკეთეთ Arduino I2C Master და ESP8266 Slave (ან პირიქით) და განახორციელეთ ორმხრივი კომუნიკაცია. ეს იდეა მივიღე ამ თემის წაკითხვით.

სხვა ინფორმაცია სერიული ბრძანებების შესახებ:

მონაცემთა პაკეტი (ბრძანების ან მდგომარეობის აღწერა) შედგება 1-20 სიმბოლოსგან, შესაძლო პიკი 20 პაკეტი 5 წამში და საშუალოდ ერთი პაკეტი ყოველ 3 წამში. საჭიროების შემთხვევაში, შემიძლია გავაგზავნო 5 ხელმოუწერელი მთელი რიცხვი ალფანუმერული სიმბოლოების ნაცვლად.

თუ საჭიროა მეტი I2C/სერიული ქინძისთავები, შემიძლია გავაუმჯობესო Arduino Mega-ზე (ასე რომ უფასო ქინძისთავები არ არის პრობლემა).

არის ამისთვის სხვა ვარიანტები? (პროტოკოლები, მზა ბიბლიოთეკები სერიული კომუნიკაციისთვის და ა.შ.). ვცდილობ ბორბალი ხელახლა არ გამოვიგონო.

გმადლობთ დროისთვის!

3

1 პასუხი

I2C გაკვეთილების უმეტესობამ თითოეული Arduino სლავად და ოსტატად აქცია, მაგრამ ეს უკეთესია, რადგან თითოეული Arduino არის ან master ან slave (ორივე არა) და გადართვა არ არის საჭირო. ეს აადვილებს საქმეს.

I2C უკეთესია ვიდრე სერიული, რადგან თქვენ შეგიძლიათ დაამატოთ მეტი Arduinos იმავე ავტობუსში.

მე დავაყენე I2C ორ არდუინოს შორის და ეს არ არის უფრო რთული ვიდრე სერიულ პორტში წაკითხვა/ჩაწერა (რაც თქვენ უკვე გააკეთეთ). და დარწმუნებული ვარ, რომ შეგიძლიათ თქვენი სერიული პორტის კოდის განზოგადება, რომ იმუშაოთ როგორც სერიულ, ასევე I2C კომუნიკაციებთან.

ეს არის ჩემი მაგალითი (მხოლოდ კონცეფციის დასტური). Arduino slave აკონტროლებს ზოგიერთ ქინძისთავებს, ტემპერატურას. სენსორი და მცველი ტაიმერი Arduino ოსტატის ბრძანებით. თუ slave არ მიიღებს ბიტს დროულად, ის აღადგენს Arduino Master-ს.

სამაგისტრო კოდი

#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 ბუფერი; void setup () ( Serial.begin (9600); Serial.println ("Master"); Wire.begin (); pinMode (LED, OUTPUT); digitalWrite (LED, HIGH); delay (1000); digitalWrite (LED, LOW.beginTransmission(SLAVE_ADDRESS)Wire.endTransmission(=SLAVE_ADDRESS) /დაყენების 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

მონის კოდი

/* Esclavo I2C Recibe los siguientes comandos<- 1° byte -> <- 2° byte -> <- 3° byte ->CMD_SENSOR CMD_PIN_ON n° de pin duration and segundos CMD_PIN_OFF n° de pin CMD_LUMEN CMD_BEAT Cada commando recibe una 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 მეშვეობით 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_TIMEe_0 2Bdefine მაქსიმალური დრო და CMD_BEAT . Pasado // ese tiempo, se activa el PIN_RESET. // En milisegundos. #define BEAT_INTERVAL 10000 ხელმოუწერელი long lastBeat; // Largo del reset en milisegundos. #define RESET_LENGTH 250 ბაიტი სმდ = 0; ბაიტის სტატუსი = 0; int thermoDO = 11; int thermoCS = 12; int thermoCLK = 13; MAX6675 თერმოწყვილი (thermoCLK, thermoCS, thermoDO); void setup () ( Serial.begin (9600); pinMode (PIN_LUMEN, INPUT); analogRead (PIN_LUMEN); for (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.< pgmaSize; i++) { if (pgma[i].off >for (int i = 0; i<= 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 >0 && pgma[i].გამორთულია< 0) { status = ST_BAD_PIN; } else { pgma[i].off = 0; digitalWrite(pin, LOW); } } } int searchPin(int pin) { int i = pgmaSize - 1; while (i >> 8);< 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"); } } } }

Wire.write(lightReading % 0xFF); შესვენება; ჭკვიანურად მოიხსენიება, როგორც უნივერსალური ასინქრონული მიღება/გადაცემა (UART), ის ჩვეულებრივ გამოიყენება Arduino-ს პროგრამირებისა და გამართვისთვის. USB პორტი. არსებობს სხვადასხვა სენსორები და მოწყობილობები, რომლებიც იყენებენ UART-ს, როგორც კომუნიკაციის მთავარ მეთოდს და ზოგჯერ ჩვენ გვჭირდება ორი ან მეტი Arduinos ერთმანეთთან დაკავშირება ინფორმაციის გასაცვლისთვის.

თუმცა, Arduinos-ის უმეტესობას აქვს მხოლოდ ერთი სერიული პორტი, რომელიც გამოიყენება USB კომუნიკაციისთვის. მაგრამ როგორ დააკავშიროთ ასეთი კონტროლერი სხვასთან? რა თქმა უნდა Arduino-ს გამოყენებითმეგას მსგავსი რამ აგვარებს ამ პრობლემას, რადგან მას აქვს ოთხამდე სერიული პორტი, მაგრამ თუ გჭირდებათ კომუნიკაცია Arduino ხაზის მარტივ დაფებთან, თქვენ უნდა მოძებნოთ სხვა გამოსავალი. არსებობს სპეციალური პროგრამული ბიბლიოთეკა, რომელიც ახდენს UART პორტის სიმულაციას სხვა ციფრულ ქინძისთავებზე. მას აქვს რამდენიმე ნაკლი, მაგრამ მთლიანობაში მუშაობს.

ასე რომ, ჩვენ გვჭირდება ასეთი კომუნიკაციის დემონსტრირება არის:

2 Arduino კონტროლერი

დამაკავშირებელი მავთულები

მიჰყევით ამ ნაბიჯებს ორის დასაკავშირებლად Arduino UNOპროგრამული უზრუნველყოფის სერიული პორტის გამოყენებით:

1. მაგალითად, გამოიყენეთ 8 და 9 ქინძისთავები RX-სთვის და TX-ისთვის ორივე Arduinos-ზე, დააკავშირეთ pin 8 ერთ Arduino-ზე მე-9 პინზე მეორეზე და პინი 9 პირველზე. მე-8 ქინძისთავზე მეორეზე.

2. დაკავშირება საერთო მავთულიორივე არდუინოს GND ერთად.

3. დააკავშირეთ ერთი Arduino კომპიუტერი USBდა შეაერთეთ ამ კონტროლერის 5 ვ პინი მეორის იმავე პინთან ან მიაწოდეთ მეორეს ცალკე დენით.

აქ არის დანერგვა 8 და 9 პინების გამოყენებით RX და TX-ისთვის:



შემდეგი კოდი დაყოფილია ორ ნაწილად. Arduino Master მიიღებს ბრძანებებს კომპიუტერიდან და გადასცემს მათ პროგრამული უზრუნველყოფის სერიული პორტის მეშვეობით. აქ არის კოდის პირველი ნაწილი:

// ჩართეთ პროგრამული სერიული ბიბლიოთეკა

#შეიცავს

// გამოაცხადეთ ჩართული დისკრეტული კონტროლერის არხები კომუნიკაციისთვის

Serial.begin(9600); // ნორმალური ბაუდის სიხშირე

softSerial.begin(9600); // პროგრამული უზრუნველყოფის სერიული პორტის ინიციალიზაცია

// შეამოწმეთ კომპიუტერიდან ბრძანებების მიღება

if (Serial.available())(

// მიღებული კომპიუტერის ბრძანება გაუგზავნეთ პროგრამულ UART-ს

და აქ არის slave კოდი, რომელიც განმარტავს ოსტატისგან გამოგზავნილ სიმბოლოებს. თუ სიმბოლო "a" მიიღება, ის ჩართავს ჩაშენებულ LED-ს. თუ სიმბოლო "x" მიიღება, LED ჩაქრება:

// პროგრამული უზრუნველყოფის სერიული ბიბლიოთეკის დაკავშირება

#შეიცავს

// ჩართული დისკრეტული არხების მინიჭება

SoftwareSerial softSerial(8, 9); // RX, TX

// დისკრეტული არხი, რომელზედაც ჩაშენებული LED კიდია

softSerial.begin(9600); // პროგრამული უზრუნველყოფის სერიული პორტის ინიცირება

pinMode (LED, OUTPUT); // განსაზღვრეთ LED პინი, როგორც გამოსავალი

// შეამოწმეთ არის თუ არა რაიმე პროგრამული უზრუნველყოფის სერიული პორტის ბუფერში

if (softSerial.available())(

// წაიკითხეთ ერთი სიმბოლო პროგრამული უზრუნველყოფის სერიული პორტის ბუფერიდან და შეინახეთ იგი com ცვლადში

int com = softSerial.read();

// იმოქმედეთ მიღებული სიმბოლოს მიხედვით

თუ (com == "x")(

// გამორთეთ LED

digitalWrite (LED, LOW);

სხვა შემთხვევაში, თუ (com == "a") (

// ჩართეთ LED

digitalWrite (LED, HIGH);

როგორ მუშაობს ეს

პროგრამული უზრუნველყოფის სერიული პორტი ახდენს სტანდარტული სერიული პორტის სიმულაციას სხვადასხვაზე ციფრული გამომავალიარდუინო. ეს ზოგადად საკმაოდ მოსახერხებელია, მაგრამ თქვენ უნდა გესმოდეთ, რომ ეს არის პროგრამული სიმულაცია და არ არის მხარდაჭერილი აპარატურის მიერ. ეს ნიშნავს, რომ ის ხარჯავს ზოგადი კონტროლერის რესურსებს, კერძოდ, პროგრამის ციკლის დროს და მეხსიერებას. ზოგადად, ის მუშაობს ისევე, როგორც ჩვეულებრივი სერიული პორტი. ნორმალურ სერიულ პორტში არსებული ყველა ფუნქცია ასევე წარმოდგენილია პროგრამულ პორტში.

კოდის გარჩევა

პირველ რიგში, მოდით შევხედოთ სამაგისტრო პროგრამას, რომელიც იღებს ბრძანებებს კომპიუტერიდან ჩვეულებრივი სერიული პორტის მეშვეობით და აგზავნის მათ სლავ კონტროლერთან. კოდის დასაწყისში ჩვენ ჩავრთავთ ბიბლიოთეკას SoftwareSerial.h

SoftwareSerial softSerial(8, 9); // RX, TX

ეს გამოიწვევს პარალელურ კომუნიკაციას, ამ შემთხვევაში პროგრამულ უზრუნველყოფას. ის გამოიყენებს pin 8-ს წაკითხვისთვის (RX) და pin 9-ს გადაცემისთვის (TX). შემდეგი, ჩვენ უფრო დეტალურად ვისაუბრებთ იმაზე, თუ რომელი დასკვნები უნდა შეირჩეს.

დეკლარირებული ბიბლიოთეკის ობიექტის გამოყენებით, ჩვენ შეგვიძლია გამოვიყენოთ ყველა ფუნქცია, რომელიც საერთოა ჩვეულებრივი ტექნიკის პარალელური პორტისთვის, როგორიცაა softSerial.read(), softSerial.write() და ა.შ. კოდის შემდეგ ნაწილში ჩვენ ვამოწმებთ, არის თუ არა რაიმე ტექნიკის პორტიდან. და თუ რამე მოდის, ჩვენ ვკითხულობთ მას და ვუგზავნით პროგრამული უზრუნველყოფის პორტს:

if (Serial.available())(

softSerial.write(Serial.read());

Slave კონტროლერის კოდი იყენებს LED-ის კონტროლის უმარტივეს განხორციელებას სერიული პორტის საშუალებით ბრძანებებით, ერთადერთი განსხვავება ისაა, რომ აქ გამოიყენება პროგრამული პორტის ბრძანებები. იცვლება მხოლოდ სინტაქსი და ჩვეულებრივი ფუნქციების Serial.read(), Serial.available() და ასე შემდეგ, თქვენ უნდა დაწეროთ softSerial.read() და softSerial.available().

პროგრამულ UART-ს აქვს რამდენიმე მნიშვნელოვანი შეზღუდვა და უარყოფითი მხარე. აქ არის რამდენიმე მათგანი.

ქინძისთავების გამოყენება

ჩვენ არ შეგვიძლია გამოვიყენოთ რაიმე დისკრეტული ქინძისთავები Arduino დაფებიდან პროგრამული პორტის შესაქმნელად. Tx-ისთვის ჩვენ შეგვიძლია გამოვიყენოთ ნებისმიერი, მაგრამ Rx-ისთვის შეგვიძლია გამოვიყენოთ მხოლოდ ის, ვინც მხარს უჭერს გარე შეფერხებებს. Arduino Leonardo და Micro დაფებს შეუძლიათ გამოიყენონ მხოლოდ ქინძისთავები 8, 9, 10, 11, 14, 15 და 16, ხოლო Mega ან Mega 2560 შეიძლება გამოიყენონ მხოლოდ ქინძისთავები 10. 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68 და 69.

სხვა პროგრამული პარალელური კომუნიკაციები

შესაძლებელია ერთზე მეტი პროგრამული სერიული კავშირის ორგანიზება, მაგრამ მხოლოდ ერთ კავშირს შეუძლია ერთდროულად მიიღოს მონაცემები. ამან შეიძლება გამოიწვიოს მონაცემთა დაკარგვა. მაგრამ არსებობს ალტერნატიული პროგრამული პარალელური პორტის ბიბლიოთეკა, დაწერილი პოლ სტოფრეგენის მიერ, რომელიც შექმნილია მხოლოდ გადასაჭრელად ამ პრობლემას. http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html

დროა გავაერთიანოთ ეს ორი ტექნიკა Android-სა და Arduino-ს შორის სრული ორმხრივი კომუნიკაციის მისაღებად.

ამისათვის ჩვენ შევაგროვებთ მარტივ პროექტს ულტრაბგერითი დიაპაზონის მაძიებელისა და პიეზო ზუმერის გამოყენებით.

მუშაობის ალგორითმი

აქტივობა "Measure" ღილაკით გამოჩნდება Android მოწყობილობის ეკრანზე, როდესაც მასზე დააჭერთ, შესაბამისი ბრძანება იგზავნება Arduino დაფაზე. არდუინოს დაფაამუშავებს ბრძანებას და იწყებს გაზომვის ციკლს, რის შემდეგაც გამოითვლება საშუალო მანძილი დაბრკოლებამდე სანტიმეტრებში. ეს მანძილიობიექტზე, გადაეცემა უკან Android მოწყობილობაში, სადაც ნაჩვენებია ტექსტის სახით, ასევე სლაიდერზე (ProgressBar).
Android-ში ასევე ხდება მონაცემთა დამუშავება: თუ მანძილი ობიექტამდე 20 სმ-ზე ნაკლებია, მაშინ საკონტროლო სიგნალი გადაეცემა Arduino-ს ზუმერის ჩართვისთვის. ბუნებრივია, ეს შეიძლება გაკეთდეს Arduino კოდით, მაგრამ სიცხადისთვის, მე ეს დავალება Android მოწყობილობას დავავალე. ზოგადად, ეს იყო პატარა პარკირების სენსორი.

ასე რომ, ჯერ უნდა გადაწყვიტოთ მენეჯმენტის გუნდები. ისინი იდენტურად უნდა განისაზღვროს როგორც Arduino-ში, ასევე Android მოწყობილობა. მე ავირჩიე შემდეგი ნომრები:
1 - გადაცემის ჩართვის ბრძანება
2 - გადაცემის აკრძალვის ბრძანება
3 - ბრძანება ზუმერის ჩართვისთვის

პირველი ორი ბრძანებით ცოტა დამაბნეველი აღმოჩნდა, რადგან... მე ვერ მივიღე ანდროიდი, რომ სწორად მიმეღო ერთი შეტყობინება მონაცემებით (ვცადე მისი გაგზავნა ციკლში და დროთა განმავლობაში, მაგრამ ანდროიდს ჯიუტად არ სურს მონაცემების მიღება, მეეჭვება, რომ ეს დაკავშირებულია ADB-თან და არ უნდა იყოს ასეთი პრობლემები აქსესუარების რეჟიმის გამოყენებისას). ამიტომ, როდესაც Arduino იღებს ბრძანებას 1 (გადაცემის ჩართვა), ის ზომავს მანძილს და უზრუნველყოფს მონაცემთა უწყვეტ გადაცემას მარყუჟში. მას შემდეგ, რაც Android მიიღებს მონაცემებს, ის გასცემს ბრძანებას 2 Arduino-ს მონაცემთა გადაცემის შესაჩერებლად.

პროგრამა Arduino-სთვის

ესკიზი Arduino-სთვის:

#include #include // Adb კავშირი. კავშირი * კავშირი; // Adb კავშირი. #define COMMAND_SEND_TRUE 1 // ბრძანება გადაცემის გასააქტიურებლად #define COMMAND_SEND_FALSE 2 // ბრძანება გადაცემის აკრძალვისთვის #define COMMAND_PLAY_BEEP 3 // ბრძანება ზუმერის გასააქტიურებლად const int numOfReadings = 10; // გაზომვების რაოდენობა (მასივის ელემენტები) int კითხვები; // გაზომვის მნიშვნელობები მასივში int arrayIndex = 0; // ელემენტის ინდექსი მასივში int total = 0; // საერთო მნიშვნელობები საშუალო მანძილი = 0; // საშუალო მანძილი // ქინძისთავების და ცვლადების დაყენება ულტრაბგერითი სენსორისთვის int echoPin = 2; // DYP_ME007 ECHO pin int initPin = 3; // DYP_ME007 TRIG pin int BeeperPin = 8; // buzzer pin unsigned long pulseTime = 0; // პულსის ხანგრძლივობა მიკროწამებში unsigned long distance = 0; // მანძილი (სმ) ლოგიკურში SendToAndroid = false; void setup() ( pinMode (initPin, OUTPUT); pinMode (echoPin, INPUT); pinMode (BeeperPin, OUTPUT); // Buzzer // შექმნას მასივი (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(დისტანცია, DEC);< 10; j++) { analogWrite(BeeperPin, 20); delay(50); analogWrite(BeeperPin, 0); delay(150); } }

) საშუალო მანძილი = სულ / numOfReadings; //საშუალო მანძილის გამოთვლა //Serial.println(averageDistance, DEC);

Connection->Write(2,(uint8_t*)&AverageDistance); // 2 ბაიტის დაგვიანებით გაგზავნა(10); ) void playBeep() ( for (int j = 0; j თავიდანვე განვსაზღვრავთ 3 მუდმივას - ეს არის ბრძანებები მოწყობილობებს შორის შეტყობინებების გასაგზავნად: COMMAND_SEND_TRUE = 1, COMMAND_SEND_FALSE = 2, COMMAND_PLAY_BEEP = 3დამმუშავებელი

adbEventHandler() გამოიძახება ყოველი მონაცემების მიღებისას და როდესაც სხვა მოვლენები ხდება ADB-დან (კავშირის გახსნა და დახურვა).ფუნქცია makeDimension()აკეთებს 10 მანძილის გაზომვას და შემდეგ ითვლის მათგან საშუალო მნიშვნელობას, რომელიც ბრძანების მეშვეობით

კავშირი->დაწერა>() იგზავნება 2 ბაიტით Android მოწყობილობაზე.ფუნქციით playBeep ()ყველაფერი მარტივია - ის შექმნილია 10-ის სათამაშოდ

პროგრამა ანდროიდისთვის

ჩვენი აქტივობის ფანჯარა შედგება შემდეგი ძირითადი ელემენტებისაგან:
ღილაკი (ღილაკი) - მანძილის გაზომვის ბრძანების გასაგზავნად
ტექსტური ველი (TextView) - მიღებული მანძილის ჩვენება
პროგრესის ზოლი (ProgressBar) - მანძილის ვიზუალური ჩვენებისთვის (მაქსიმუმ - 500 სმ)
კავშირის ხატულა (ImageView) - ნაჩვენებია Android მოწყობილობასთან აქტიური კავშირის დროს.

ამ აქტივობის XML ფაილი, იხილეთ მიმაგრებული ფაილები

ძირითადი აქტივობის ფაილი შეიცავს შემდეგ კოდს:

პაკეტი com.example.arduino54; იმპორტი java.io.IOException; იმპორტი org.microbridge.server.Server; იმპორტი org.microbridge.server.AbstractServerListener; იმპორტი com.example.arduino54.R; იმპორტი android.os.AsyncTask; იმპორტი android.os.Bundle; იმპორტი android.app.Activity; იმპორტი android.util.Log; იმპორტი android.view.View; იმპორტი android.widget.ImageView; იმპორტი android.widget.ProgressBar; android.widget.TextView იმპორტი; იმპორტი android.widget.Button; საჯარო კლასი MainActivity აფართოებს აქტივობას ( კერძო int მანძილი = 0; საჯარო საბოლოო სტრიქონი APP_NAME = "arduino54"; საჯარო საბოლოო ბაიტი COMMAND_SEND_TRUE = 1; // ბრძანების ჩართვა საჯარო საბოლოო ბაიტი COMMAND_SEND_FALSE = 2; // გამორთვა ბრძანების გაგზავნა საჯარო საბოლოო ბაიტი COMMAND_BEP_PL 3 // ბრძანება საჯარო საბოლოო int SYS_COMMAND_DATA-ს გასააქტიურებლად // შიდა ბრძანება: საჯარო საბოლოო int SYS_COMMAND_CONNECTED = 1: სერვერის სერვერი= null;<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>ImageView დაკავშირებულიImage;< 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); } } }

@Override public void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // TCP სერვერის შექმნა (MicroBridge LightWeight სერვერზე დაყრდნობით) სცადე ( სერვერი = ახალი სერვერი (4568); // იგივე პორტი უნდა იყოს გამოყენებული ADK board server.start( ) catch (IOException e) ( Log.e(APP_NAME, "Unable to start TCP server", e); System.exit(-1); ) connectImage = (ImageView) findViewById(R.id.imageConnected)connectedImage.setAlpha(20)Button Button1 = (Button)findViewById(R.id.button1 Button1.setOnClickListener(ClickOn); onClick( View v) ( ცდილობენ ( server.send (ახალი ბაიტი ((ბაიტი) COMMAND_SEND_TRUE)); //მონაცემების გაგზავნა //Log.d(APP_NAME, "data_send:"+bSend); ) catch (IOException e) ( ჟურნალი .e (APP_NAME, "პრობლემა TCP შეტყობინების გაგზავნისას", e server.addListener(new AbstractServerListener() ( @Override public void onReceive(org.microbridge.server.Client Client, byte data) ( Log.d( APP_NAME, "); data0:"+მონაცემები+"; data1:"+data); თუ (data.length ( // გამოძახებულია ფონური აქტივობის დასაწყებად @Override დაცულია Integer doInBackground(Integer... ArdState) ( if((ArdStateაქ ვართ გაკვეთილზე სერვერიმეთოდის განსაზღვრა server.addListener(new AbstractServerListener() ())და ასევე: onReceive(), onClientConnect()და

onClientDisconnect() რომელიც იძახება MicroBridge სერვერიდან მონაცემების მიღებისას, დაკავშირებისა და გათიშვისას.ჩვენ ვამაგრებთ დაწკაპუნების მოვლენის დამმუშავებელს Button1-ზე

setOnClickListener() . ღილაკზე დაჭერისას გამოიძახება ეს მეთოდი და აგზავნის COMMAND_SEND_TRUE ბრძანებას Arduino დაფაზე, რომლის მეშვეობითაც Arduino ზომავს მანძილს და გადასცემს მანძილის მნიშვნელობას.მეთოდში

onReceive ()

, როგორც კი მივიღებთ მონაცემებს, მაშინვე ვუბრუნებთ COMMAND_SEND_FALSE ბრძანებას, რათა Arduino-მ გამორთოს პაკეტის გადაცემა. ამ ალგორითმის შესახებ ზემოთ დავწერე. გთხოვთ, გაითვალისწინოთ, რომ მონაცემების ცალკე თემაში გადასატანად, ჩვენ ვიყენებთ შიდა სისტემის ბრძანებებს SYS_COMMAND_DATA, SYS_COMMAND_CONNECTED და SYS_COMMAND_DISCONNECTED. ბრძანებები გადაიცემა მასივის მე-2 ელემენტით, ხოლო პირველი ელემენტი შეიცავს Arduino-დან მიღებულ გაზომილ მანძილს.როდესაც ხდება მოვლენა onClientConnect ()ალფა მნიშვნელობის მაქსიმუმ 255-ზე დაყენებით, გამოჩნდება კავშირის ხატი. როდესაც SYS_COMMAND_DISCONNECTED ბრძანება მიიღება, Alpha დაყენებულია 20-ზე, ხატულა გაცვეთილია და თითქმის უხილავია, ეს ნიშნავს, რომ კავშირი არ დამყარდა. ალფა გამჭვირვალობა დაყენებულია გამოყენებით setAlpha (int).

როდესაც თემა იღებს მონაცემებს onReceive მეთოდიდან, შემდეგ მეთოდში doInBackground()მდგომარეობა შედარებულია და თუ მანძილი არ არის ადრეული ნული და 20 სმ-ზე ნაკლები, მაშინ მეთოდი server.send() COMMAND_PLAY_BEEP ბრძანება იგზავნება Arduino-ს დაფაზე ზუმერის გასააქტიურებლად.

setOnClickListener() onClientConnect () UI ელემენტები გამოდის პროგრესის ზოლზე მანძილისა და ზოლების რიცხვითი მნიშვნელობის საჩვენებლად.

თანდართულ ფაილში შეგიძლიათ ჩამოტვირთოთ პროექტები Arduino-სთვის და Android-ისთვის, ასევე ყველა საჭირო ბიბლიოთეკისთვის

მისთვის უბრალოდ სასიცოცხლოდ მნიშვნელოვანია მიკროკონტროლერთან ინფორმაციის გაცვლა. სიტუაციები წარმოიქმნება, როდესაც საჭიროა ხელით გააქტიუროთ კონკრეტული ფუნქცია მიკროკონტროლერის პროგრამაში, კომპიუტერიდან ან ლეპტოპიდან მისი კონტროლით.

მაგრამ გადავიდეთ საქმეზე. Arduino-სთან მონაცემების გაცვლა არც ისე რთულია, მაგრამ საქმე იმაშია, რომ მონაცემები გადაიცემა ხასიათის მიხედვით, რაც ძალიან ცუდია. საკმაოდ დიდი დრო მომიწია ამ პრობლემის მოსაძებნად, სანამ არ წავაწყდი ერთ მშვენიერ ბიბლიოთეკას ჰაბრაჰაბრზე. ავტორმა მასში განახორციელა რიცხვების მიღების ფუნქცია, ე.ი. შეგიძლიათ კონტროლერს გაუგზავნოთ ერთზე მეტი ციფრისგან შემდგარი ნომრები და ის სწორად იმუშავებს. ჩამოტვირთეთ ბიბლიოთეკა (ბმული), გახსენით იგი აპარატურულ ბიბლიოთეკებში და მოდით გადავიდეთ პრაქტიკაზე.

პირველ რიგში დავწეროთ ესკიზი და ავტვირთოთ Arduino-ზე (Freeduino)

#include void setup() (

Serial.begin(9600); // დააყენეთ პორტის სიჩქარე

PinMode (9, OUTPUT); // დააყენეთ მე-9 ფეხი, როგორც გამომავალი სპიკერისთვის

) void loop ()

Long int ნომერი; Serial.print ("შეიყვანეთ ნომერი: ");

ნომერი = SerialInput.InputNumber(); // შეიყვანეთ ნომერი Serial.print ("შედეგი = ");

Serial.println(Number * Number, DEC);

სიგნალი (500);

} ბათილად სიგნალი (ხელმოუწერელი სიმბოლოების დაგვიანება)

AnalogWrite(9, 20); // მნიშვნელობა უნდა იყოს 0-დან 255-მდე

// ექსპერიმენტი კარგი ტონის მისაღებად

AnalogWrite(9, 0); // 0 - გამორთეთ პიეზო

დაგვიანება (დაყოვნება); // პაუზა დაგვიანებით ms

რას ნიშნავს ეს ყველაფერი? შევეცადე კოდი დეტალური კომენტარებით მიმეწოდებინა, ასე რომ ყველაფერი გასაგები უნდა იყოს. ეს ჩანახატი გთხოვს შეიყვანოთ ნებისმიერი ნომერი, რის შემდეგაც ის აჩვენებს მის კვადრატს და უკრავს ხმოვან სიგნალს პიეზო დინამიკის მეშვეობით, რომელიც დაკავშირებულია პინ 9-თან.

და ახლა, ყველაზე საინტერესო ის არის, რომ დროა სცადოთ. კონტროლერთან დასაკავშირებლად გირჩევთ გამოიყენოთ უფასო პროგრამა წასახემსებელი. კავშირის ტიპის პარამეტრებში აირჩიეთ Serial და COM1-ის ნაცვლად შეიყვანეთ სწორი პორტის ნომერი (შეგიძლიათ იხილოთ მენიუში Tools->Serial Port Arduino პროგრამირების გარემოში). ვაჭერთ Open-ს და ვნახავთ შეტყობინებას Enter number კონსოლში, შეიყვანეთ ნებისმიერი ნომერი (მიზეზის ფარგლებში), დააჭირეთ Enter-ს და ვნახავთ შედეგს.

ესე იგი, შეგიძლია გაიხარო და სიხარულისგან ხტუნვა. ბუნებრივია, ეს ყველაფერი შეიძლება გაუმჯობესდეს, მაგალითად, ჯერ მენიუს ჩვენება, კონტროლერიდან კონსოლში გაგზავნა, რომელშიც შეგიძლიათ დეტალურად აღწეროთ ბრძანებები. მაგალითად, შეიყვანეთ ნომერი 0 - ირთვება LED განათება, დააჭირეთ 1 - ის გადის. ამრიგად, თქვენ შეგიძლიათ შეიყვანოთ მინიმუმ 100,500 ბრძანება, თუ საკმარისია მიკროკონტროლერის მეხსიერება (რაც ძალიან მცირეა). ჩვენ ვისაუბრებთ იმაზე, თუ როგორ გავაფართოვოთ ხელმისაწვდომი მეხსიერება შემდეგ ჯერზე.

UPD: კოდის ნაწილი ამოჭრა ძრავის პარსერის მიერ, ასე რომ, აქ არის წყარო