Cuprins:

Trimiteți date numerice de la un Arduino la altul: 16 pași
Trimiteți date numerice de la un Arduino la altul: 16 pași

Video: Trimiteți date numerice de la un Arduino la altul: 16 pași

Video: Trimiteți date numerice de la un Arduino la altul: 16 pași
Video: Learn Arduino in 30 Minutes: Examples and projects 2024, Iulie
Anonim
Trimiteți date numerice de la un Arduino la altul
Trimiteți date numerice de la un Arduino la altul

Introducere

de David Palmer, CDIO Tech. la Universitatea Aston.

Ați avut vreodată nevoie să trimiteți câteva numere de la un Arduino la altul? Acest instructable arată cum.

Puteți testa cu ușurință funcționează prin simpla tastare a unui șir de numere pentru a fi trimise la terminalul Serial Monitor și puteți vedea numerele revenind la un al doilea monitor Serial conectat la al doilea Arduino. Puteți folosi chiar și un link Bluetooth.

Ce face

Două programe Arduino (schițe în vorbirea Arduino) trebuie dezvoltate, unul un program Master pentru conectarea la computerul gazdă care rulează Arduino Serial Monitor, unul pentru a acționa ca Slave pentru a primi mesajul serial de la Master, decodifica-l și trimite-l înapoi. Sclavul este opțional capabil să afișeze numerele cu care se ocupă pe un al doilea monitor serial IDE - doar în cazul în care doriți să utilizați acest lucru. Vă poate ajuta să faceți lucrurile să funcționeze în primul rând și vă poate ajuta dacă decideți să faceți modificări ale programelor pentru a vă potrivi propriilor cerințe.

Echipament

  • 2 Arduino's
  • 2 cabluri USB
  • fire de patch-uri (după cum este necesar)
  • 1 PC / laptop încărcat cu Arduino IDE (disponibil ca descărcare gratuită de pe site-ul Arduino.cc)

Pasul 1: Configurare - Configurați hardware-ul mai întâi

Configurare - Configurați hardware-ul mai întâi
Configurare - Configurați hardware-ul mai întâi
Configurare - Configurați hardware-ul mai întâi
Configurare - Configurați hardware-ul mai întâi

Conectați cele 2 Arduinos la 2 porturi USB de pe computer.

Sfat, este o idee bună să le etichetați ca M și S (stăpân și sclav), astfel încât să nu intrați mai târziu într-o confuzie (așa cum se arată în cele 2 fotografii de aici).

Pasul 2: Configurare - Setați ecranul

Configurare - Setați ecranul
Configurare - Setați ecranul

Cel mai bun lucru este să vă configurați ecranul astfel încât să aveți

  • IDE-ul încărcat cu programul Master din stânga și
  • asta cu Sclavul din dreapta.

Păstrați și monitoarele seriale pentru Maser și Slave în stânga și în dreapta, așa cum se arată în captura de ecran aici.

Pasul 3: Configurați capătul principal, apoi conectați-vă împreună - Partea 1

Configurați capătul principal, apoi conectați-vă împreună - Partea 1
Configurați capătul principal, apoi conectați-vă împreună - Partea 1

Când vă configurați Master End Serial Monitor pentru a trimite două numere, trebuie să utilizați întotdeauna caracterele de delimitare de început și sfârșit și caracterul separator de virgule așa cum vedeți aici.

Acum trebuie să conectați cele două Arduino împreună peste serial. Acest lucru se face cu două fire de patch-uri.

Am folosit verde și galben

  • Luați galbenul mai întâi, acesta trebuie să se conecteze la D6 într-un Arduino și D7 în cel de-al doilea
  • Apoi opusul pentru firul verde, D7 pe primul și D6 pe al doilea Arduino.

Alternativ, dacă aveți ceva disponibil, cum ar fi o pereche de module Bluetooth - cum ar fi HC-05, acestea vor funcționa și pentru a vă oferi exact același efect ca firele de mai sus.

Pasul 4: Configurați capătul principal, apoi conectați-vă împreună - partea 2

Configurați capătul principal, apoi conectați-vă împreună - partea 2
Configurați capătul principal, apoi conectați-vă împreună - partea 2
Configurați capătul principal, apoi conectați-vă împreună - partea 2
Configurați capătul principal, apoi conectați-vă împreună - partea 2

Folosim biblioteca software Serial. Informații suplimentare sunt disponibile cu acest link

Îl puteți vedea apelat la linia 7 a oricăruia dintre programe. Configurează pinii digitali 7 și 6 ca TX și RX (transmis și recepționat). Acesta este modul în care datele vor călători din Master Arduino prin firul verde în Slave și, când programul Slave din al doilea Arduino și-a terminat activitatea, înapoi prin firul galben. În partea de jos a aceleiași ilustrații (în fereastra Serial Monitor) puteți vedea datele pe care le-am transmis acum au trecut cu succes bucla descrisă aici și se pot întoarce în PC pe măsură ce perechea de numere întregi este bine separată.

Pasul 5: Prezentare generală a schițelor / programelor - Structura programului

Prezentare generală a schițelor / programelor - Structura programului
Prezentare generală a schițelor / programelor - Structura programului
Prezentare generală a schițelor / programelor - Structura programului
Prezentare generală a schițelor / programelor - Structura programului

Aspect Ca în toate schițele Arduino există 3 părți de bază:

  • Declarațiile
  • Pregatirea
  • Bucla principală

Așa cum se întâmplă adesea, am folosit aici o a 4-a secțiune care este adăugarea „Funcții”. Dacă nu sunteți familiarizați cu utilizarea funcțiilor, puteți utiliza Google pentru „funcțiile Arduino” și veți găsi site-uri de explicații precum exemplul din acest link: www.tutorialspoint.com/arduino/arduino_functions…..

De asemenea, am folosit tab-uri pentru a separa programul în blocuri mai ușor de gestionat.

Cele trei blocuri pe care le-am folosit pot fi văzute în partea de sus a fiecărei ilustrații a ferestrelor IDE de mai sus:

  • simpleRxTx0330Master
  • uzual
  • note

Acestea sunt de fapt fișiere separate în folderul programului, așa cum puteți vedea în această vizualizare Windows Explorer a fișierelor programului Slave.

Există un motiv foarte bun pentru care am făcut acest lucru.

  • În timp ce construiam programul, am ajuns să ne dăm seama că cea mai mare parte a programului pentru Maestru era aceeași ca și pentru Sclav.
  • Am ajuns să tragem toate părțile comune într-o filă, pe care, prin urmare, am denumit-o „comună” și apoi, de fiecare dată când am depanat o parte (am testat-o și am fost mulțumiți că a funcționat OK), am copiat și am lipit întreaga filă vizavi de Maestru la Sclav sau vice versa.
  • Filele de note sunt, de asemenea, identice, deoarece designul este generic.

Niciuna dintre funcții nu este apelată din setare, toate sunt apelate din buclă, așa că le-am creat după configurare, dar înainte de buclă.

Pasul 6: Design de sus în jos

Este o idee bună să vă proiectați schița începând cu o definiție a ceea ce doriți să faceți.

Odată ce ai acest lucru, poți începe să faci schița să facă acele lucruri. În general, dacă există un detaliu pe care încă nu știți să îl faceți, faceți-l doar o funcție și lăsați crearea funcției până mai târziu.

Aceasta urmează filozofia de proiectare bună, predată în multe universități, numită CDIO (Dacă nu o cunoașteți deja, o puteți face pe Google și găsiți site-uri care să o explice ca: https://www.cdio.org/s.) Acest lucru spune în esență: Nu începeți proiectarea înainte de a avea clar conceptul. Nu porniți implementarea până nu aveți designul clar. Nu vă așteptați să funcționeze înainte de a obține clar implementarea. C mai întâi, apoi D, I și O. La fiecare etapă ulterioară iterați (reveniți în jurul ciclului (buclelor), așa că, odată ce sunteți mulțumit (ă) de bucla inițială de proiectare înapoi și verificați dacă acesta încă îndeplinește Conceptul și actualizați C, dacă aveți nevoie. Și așa mai departe, așa că, chiar și atunci când ați ajuns la Operare, mergeți până în vârf și vedeți din nou cum arată C acum, apoi D și I, și faceți și verificați toate cu schițele de programare, acest lucru funcționează la fel dacă proiectați de sus în jos.

Pasul 7: Concept și proiectare - Partea 1

Concept și proiectare - Partea 1
Concept și proiectare - Partea 1
Concept și proiectare - Partea 1
Concept și proiectare - Partea 1

Conceptul de aici arată ca cerințele generale prezentate în fila „note”.”

Designul ar putea arăta ca o versiune timpurie a buclei, care se potrivește cu fila de note și ar putea arăta așa cum vedeți în această figură

Vedeți cum îmi place să încep prin a copia CTRL-C mai întâi comentariile în capul buclei și apoi începeți să completați spațiile libere cu comenzi care vor face aceste lucruri.

De fapt, acest lucru compilează OK așa cum puteți vedea în partea de jos a ecranului din figură. Aceasta ajunge de la etapa CDIO la I și, pe măsură ce dezvoltăm codul, este o idee bună să continuăm în jurul acestei bucle D-I.

Acum este timpul să coborâm la etapa următoare, există un comentariu acolo care spune că vom: // vom primi ceva de la hardware-ul USB, apoi vom transmite asta pe canalul serial al software-ului. Scriem acest cod pentru ca acest lucru să se întâmple - liniile 133 până la 138 afișate aici cu marcator galben

Pasul 8: Concept și proiectare - Partea 2

Concept și proiectare - Partea 2
Concept și proiectare - Partea 2
Concept și proiectare - Partea 2
Concept și proiectare - Partea 2

Primele două funcții pe care le introducem aici sunt (recv () și tran () pentru a efectua recepția de la portul hardware și transmiterea către portul software - prin urmare apelându-le cu parametrii „hw” sau „sw” afișați.

În plus față de acestea, am adăugat un test pe o variabilă globală numită newData. Acesta este un steag pe care îl vom seta în funcția "void recv ();". Când a fost primit un mesaj, această variabilă este marcată de la fals la adevărat. Facem acest lucru, astfel încât să transmitem un mesaj doar dacă unul a fost primit (flag == true) în linia 134. Și odată ce am transmis mesajul nostru, „s-a făcut treaba”, astfel încât să ștergem semnalul înapoi la fals în linia 137.

Din nou putem verifica compilarea (de la D la I) și de data aceasta avem un mesaj de eroare „nedeclarat” (afișat). Acest lucru ne spune că nu am declarat recv (); funcţie. Planificăm să facem acest lucru mai târziu, așa că, deocamdată, pentru a ne permite să obținem o compilare curată, trebuie să creăm o funcție fictivă sau substituent, așa cum se arată în continuare.

Din nou putem verifica compilarea (de la D la I) și de data aceasta avem un alt mesaj de eroare „nedeclarat” pentru tran (); funcţie. Acest lucru necesită o creație similară. Din nou putem verifica compilarea (de la D la I) și de data aceasta vom găsi că funcționează perfect; Până acum, bine.

Pasul 9: Finalizați bucla principală: A) Primirea de pe USB, B) Primirea de la Slave Arduino

Finalizați bucla principală: A) Primirea de pe USB, B) Primirea de la Slave Arduino
Finalizați bucla principală: A) Primirea de pe USB, B) Primirea de la Slave Arduino
Finalizați bucla principală: A) Primirea de pe USB, B) Primirea de la Slave Arduino
Finalizați bucla principală: A) Primirea de pe USB, B) Primirea de la Slave Arduino

Există o ultimă piesă pe care am adăugat-o pentru a finaliza această parte, care este să adăugăm un cod de depanare.

Există o altă schemă instructabilă privind schițele de depanare la care se poate face referire pentru a înțelege ce am făcut aici și de ce. Consultați Instrucțiunea „Cum să construiți și să testați schițele Arduino până când funcționează”

Deci, aceste linii de depanare [136-139 afișate] sunt adăugate în bucla principală și, lo-and-behold, le puteți testa în capătul Master făcând variabila de depanare adevărată și Compilarea (I), atunci dacă conectați un Arduino în sus, puteți încărca, deschide monitorul serial și a vedea dacă ceea ce revine în monitorul serial este așa cum se arată aici (vedeți că este adăugat mesajul „DEBUG MODE”?)

Pasul 10: Primirea și gestionarea datelor în Slave Arduino

Primirea și gestionarea datelor în Slave Arduino
Primirea și gestionarea datelor în Slave Arduino
Primirea și gestionarea datelor în Slave Arduino
Primirea și gestionarea datelor în Slave Arduino

Primirea de la Slave Arduino

Adăugați codul necesar pentru cel de-al doilea canal la bucla principală, receptorul serial al software-ului așa cum se arată - liniile 149 până la 155.

Puteți vedea că structura se bazează pe ceea ce am scris mai sus pentru cazul Master?

De asemenea, veți vedea că obținem o eroare de compilator, o altă funcție nedeclarată - de data aceasta parseData (); - deci, trebuie să facem și un stub pentru asta, înainte de a putea rula o compilare de test fără erori.

Manipularea datelor în Slave Arduino

Adăugați codul de buclă principal necesar pentru Arduino dacă este configurat ca dispozitiv Slave așa cum se arată - liniile 163 până la 174. Puteți vedea că structura acestuia este foarte similară cu cea a primului canal?

Și ar trebui să găsiți de data aceasta că se compilează absolut bine.

Pasul 11: Scrieți funcția de primire

Scrieți funcția de primire
Scrieți funcția de primire

Funcția Receive - void recv (char from) {} - are două lucrări principale.

1 pentru a primi un șir de caractere de pe canalul USB și

2 pentru a primi unul de la canalul Arduino la Arduino.

Pentru prima va trebui să o utilizăm, deoarece folosește hardware-ul încorporat al Arduino, iar pentru al doilea folosind biblioteca standard Arduino: software-ul UART.

Când începem să adăugăm cod la o funcție - pentru a crea o funcție care face ceva, în loc de doar un butuc - trebuie să ne amintim să eliminăm sau să comentăm butonul pe care îl înlocuiește. În caz contrar, vom obține o eroare de compilare: refefintion de 'void lrec (char)'.

Încercați să obțineți eroarea, apoi încercați oricare dintre modalitățile sugerate mai sus pentru a scăpa de ea.

Începeți cu o funcție care arată ca cea pe care o prezentăm aici de liniile 75 până la 88 în galben.

Acum știți că, având cod, va trebui să încercați operația Compilare. Vă apare o eroare, precum cele pe care le-am avut mai devreme, de tipul: numele funcției nedeclarate în acest domeniu. Vom avea nevoie inițial de un alt stub pentru a ne permite să compilăm după această eroare, așa că adăugați unul ca și înainte și asigurați-vă că puteți obține acum o compilare fără erori.

Acum, să aruncăm o privire asupra codului pe care l-am scris pentru funcția recv ().

Este destul de curat, puteți vedea utilizarea condiției „dacă” pentru a produce cele două părți ale funcției menționate mai sus.

Codul din partea „sw” și partea „hw” este de aceeași formă și îl voi descrie aici.

Prima din perechea de linii în fiecare caz este începutul unei bucle while. Dacă nu sunteți familiarizați cu timpul, îl puteți căuta în site-ul Arduino.cc/Reference pentru explicații și exemple. Aici așteptăm „în timp ce” funcția „Serial” încorporată nu a primit niciun caracter (i) și pentru că variabila newData a fost dezactivată (adică condiția falsă newData == este adevărată). De îndată ce un personaj - sau mai mult de un personaj - este primit, timpul va „trece” pe a doua linie din această pereche. Aceasta va apela apoi la recAstringChar (char); funcție pentru a gestiona caracterul curent. Această pereche de linii se va alterna în timp ce (sau atât timp cât) există caractere care încă trebuie primite. Odată ce toate sunt terminate, starea while se încheie, permițând nivelul sau dacă următorul nivel să se termine și, la rândul său, permițând înregistrarea (char); funcția să se termine. Astfel, acum a fost primit un mesaj complet.

Pasul 12: Scrieți subfuncția de primire - Partea 1

Scrieți subfuncția Primire - Partea 1
Scrieți subfuncția Primire - Partea 1
Scrieți subfuncția Primire - Partea 1
Scrieți subfuncția Primire - Partea 1

Acum trebuie să scriem funcția numită recAstringChar (char);. Vedeți din comentariul de la linia 50 aici, în partea de sus, că sarcina sa este de a actualiza două buffere cu copii ale mesajului serial primit. [S-a dovedit în timp ce încercam să pun totul în funcțiune că un singur lucru pe care l-am învățat a fost că am nevoie de două tampoane diferite - sau cel puțin acesta a fost cel mai simplu mod de a rezolva unele probleme, de aceea a cam evoluat spre a avea nevoie de 2 tampoane, așa că Tocmai le-am creat.] Am sunat la un buffer: ReceivedData, iar celălalt: ReceivedChars.

Tampoanele sunt variabile globale, deci sunt declarate la nivel de modul, a se vedea liniile 9 și 10 din fila comună. Există alte variabile declarate în interiorul acestei funcții care, prin urmare, au scop local - prezentate în liniile 51-54 aici. Acesta nu este locul pentru a explica diferențele dintre globali și localnici, dar există mai multe informații despre acest lucru în https://www.arduino.cc/glossary/en/ sub Local și Global.

De asemenea, puteți afla totul despre tipurile de date și modificatorii de tip: static, boolean, octet, const, char în https://www.arduino.cc/reference/en/#variables, afișat aici.

Fluxul principal al programului în această funcție este controlat de if la linia 56 de aici și celălalt corespunzător la linia 74. Aceasta tratează două scenarii

a) [de la linia 74 pe] când începe mesajul primit. Acest lucru se întâmplă atunci când startMarker este văzut - acest lucru a fost definit ca caracterul „<”, motiv pentru care ori de câte ori testăm schița, începem întotdeauna șirul cu acel caracter. Dacă nu o facem, atunci nimic nu va fi procesat ca fiind primit, totul va fi ignorat la fel ca și cum am tasta prostii la solicitarea tastaturii „Monitor serial”.

b) [rândurile 56 până la 73] care primește toate celelalte caractere, oricare ar fi acestea, dar se ocupă de caractere numai după ce a avut loc un început valid (a fost primit „>” ca la a) de mai sus.)

În aceste linii (de la 74 la 78) punem recepționarea <într-unul dintre buffere (data recepționată [0]), dar nu în cealaltă. Reglăm indicatorul tampon (variabilă: char ndx) pentru a indica următoarea poziție tampon de rezervă (data recepționată [1]) folosind comanda post-increment (++) din linia ndx ++; și setăm steagul în curs la adevărat.

Fluxul de programe din această parte a funcției este controlat de if la linia 57 de aici și celălalt corespunzător la linia 65. Aceasta tratează două scenarii

a) [de la linia 65 pe] când se termină mesajul primit. Acest lucru se întâmplă când endMarker este văzut - definit ca>, motiv pentru care ori de câte ori ne testăm schița, ne încheiem întotdeauna șirul cu acel caracter. Unul dintre lucrurile care se întâmplă atunci când este primit caracterul final este că steagul global (variabil din punct de vedere tehnic) newData este setat adevărat exact la sfârșitul funcției, astfel încât funcția care a numit sub-funcția noastră (funcția de apelare: recv (char);) poate „ști” că datele noi valide au fost primite complet.

b) [rândurile 57 până la 64] care primește toate celelalte personaje, indiferent care ar fi acestea. Îi parchează foarte ocupat în rânduri în ambele tampoane.

Pasul 13: Scrieți subfuncția Primire - Partea 2

Scrieți subfuncția de primire - partea 2
Scrieți subfuncția de primire - partea 2
Scrieți funcția de primire - partea 2
Scrieți funcția de primire - partea 2

S-ar putea ajuta să oferim un exemplu de cum arată cele 2 tampoane atunci când au fost populate. Dacă ar fi să introducem enter, bufferele ar avea caracterele afișate în ele:

Deci, acum puteți vedea că avem un tampon care este exact aceleași caractere pe care le-am introdus prima dată și un tampon care are doar cele două valori și o virgulă separatoare. Acum avem un cod care poate primi caracterele pe care le tastăm la tastatura Serial Monitor, putem trece de la faza I CDIO la O, tastând câteva șiruri și văzând ce se întâmplă. Încărcați codul pe Master Arduino, deschideți Serial Monitor și încercați să tastați ceva valid, cum ar fi enter. Primești un ecou pe ecranul Serial Monitor ca cel prezentat aici?

Pasul 14: Scrieți funcțiile de transmisie și analiză

Scrieți funcțiile de transmisie și analiză
Scrieți funcțiile de transmisie și analiză
Scrieți funcțiile de transmisie și analiză
Scrieți funcțiile de transmisie și analiză

Mai întâi pentru Transmit

Deci, acum am primit un șir, putem scrie funcția de transmisie: tran (char); pentru a-i înlocui butucul. Acest lucru ne va permite să trimitem un șir de la Master către Slave Arduino, deci asigurați-vă că ambele dispozitive sunt conectate și conectate împreună pentru a testa această nouă funcționalitate.

Introduceți această funcție așa cum se arată aici în liniile 117-133. După cum veți recunoaște, are două părți, una pentru a transmite canalului USB (hardware UART) și una pentru a transmite celuilalt Arduino (software UART.) Aceasta ar trebui să compileze erori -grat, și puteți încărca imediat schița și a vedea ce se întâmplă. De data asta voi trimite. Obțineți rezultatul afișat?

Captura de ecran este interesantă deoarece șirul primit … ar trebui să arate corect ca înainte, iar șirul transmis … ar trebui să arate acum corect. Cu toate acestea, rețineți că conversia întregului nu a funcționat. Există încă un pic mai mult cod de adăugat pentru ca acest lucru să funcționeze.

Pasul 15: Scrieți funcțiile de transmisie și analiză

Scrieți funcțiile de transmisie și analiză
Scrieți funcțiile de transmisie și analiză
Scrieți funcțiile de transmisie și analiză
Scrieți funcțiile de transmisie și analiză

Apoi pentru Parse

Aceasta este o bucată de cod care analizează șirul primit pentru a prelua șirurile parțiale numerice și le convertește în valori întregi. Este nul parseData (); funcția buclei principale

Înlocuiți butonul de analiză cu codul prezentat în liniile 98 - 113. Încărcați-l și să vedem dacă problema pe care o aveam cu cele 2 valori întregi este acum rezolvată. Sa incercam.

Da, funcționează, așa cum se arată, numerele întregi găsite sunt 49 și 98.

Pasul 16: Finala

Final!
Final!

Aceste date s-au învârtit în jurul buclei de la PC prin Master prin intermediul slave-ului și înapoi prin Master din nou către PC. Odată cu versiunea finalizată a aplicației comune încărcate atât în capetele Master, cât și în cele slave, și cu modul de depanare dezactivat acum, vom vedea datele primite corect la ambele capete, așa cum se arată aici.

Recomandat: