Inhoudsopgave:

Numerieke gegevens van de ene Arduino naar de andere verzenden: 16 stappen
Numerieke gegevens van de ene Arduino naar de andere verzenden: 16 stappen

Video: Numerieke gegevens van de ene Arduino naar de andere verzenden: 16 stappen

Video: Numerieke gegevens van de ene Arduino naar de andere verzenden: 16 stappen
Video: 🇳🇱 DIGITALE ARDUINO KLOK MET ANIMATIE - Arduino project 2024, November
Anonim
Numerieke gegevens van de ene Arduino naar de andere verzenden
Numerieke gegevens van de ene Arduino naar de andere verzenden

Invoering

door David Palmer, CDIO Tech. aan de Aston-universiteit.

Heb je ooit een aantal nummers van de ene Arduino naar de andere moeten sturen? Dit Instructable laat zien hoe.

U kunt eenvoudig testen of het werkt door simpelweg een reeks cijfers in te typen om te verzenden naar de seriële monitorterminal, en de cijfers terug te zien komen op een tweede seriële monitor die is aangesloten op de tweede Arduino. U kunt zelfs een Bluetooth-link gebruiken.

Wat het doet

Twee Arduino-programma's (schetsen in Arduino-spraak) moeten worden ontwikkeld, één een masterprogramma om verbinding te maken met de hostcomputer waarop de Arduino Serial Monitor draait, één om als slave te fungeren om het seriële bericht van de master te ontvangen, te decoderen en terug te sturen. De slave is optioneel in staat om de nummers waarmee hij te maken heeft weer te geven op de seriële monitor van een tweede IDE - voor het geval je dit wilt gebruiken. Het kan helpen om dingen in de eerste plaats werkend te krijgen en u helpen als u besluit wijzigingen aan te brengen in de programma's om aan uw eigen vereisten te voldoen.

Apparatuur

  • 2 Arduino's
  • 2 USB-kabels
  • patchdraden (indien nodig)
  • 1 pc/laptop geladen met Arduino IDE (beschikbaar als gratis download van de Arduino.cc-website)

Stap 1: Instellen - Stel eerst uw hardware in

Instellen - Stel eerst uw hardware in
Instellen - Stel eerst uw hardware in
Instellen - Stel eerst uw hardware in
Instellen - Stel eerst uw hardware in

Sluit de 2 Arduino's aan op 2 USB-poorten van je computer.

Tip, het is een goed idee om ze te labelen als M en S (master en slave) zodat je later niet in de war raakt (zoals te zien is op de 2 foto's hier.)

Stap 2: Instellen - Stel uw scherm in

Instellen - Stel uw scherm in
Instellen - Stel uw scherm in

Het beste is om uw scherm zo in te stellen dat u

  • de IDE geladen met het masterprogramma aan de linkerkant en
  • dat met de slaaf aan de rechterkant.

Houd de seriële monitoren voor Maser en Slave ook links en rechts zoals weergegeven in de schermafbeelding hier.

Stap 3: Stel het hoofdeinde in en maak vervolgens verbinding - deel 1

Stel het hoofdeinde in en maak vervolgens verbinding - deel 1
Stel het hoofdeinde in en maak vervolgens verbinding - deel 1

Wanneer u uw Master End Serial Monitor instelt om twee cijfers te verzenden, moet u altijd het begin- en eindscheidingsteken en het kommascheidingsteken gebruiken, zoals u hier ziet.

Je moet nu de 2 Arduino's via serieel met elkaar verbinden. Dit gebeurt met twee patchdraden.

Ik gebruikte groen en geel

  • Neem eerst de gele, deze moet worden aangesloten op D6 in één Arduino en D7 in de tweede
  • Dan het tegenovergestelde voor de groene draad, D7 op de eerste en D6 op de tweede Arduino.

Als alternatief, als je iets beschikbaar hebt zoals een paar Bluetooth-modules - zoals HC-05's - zullen deze ook werken om je precies hetzelfde effect te geven als de bovenstaande draden.

Stap 4: Stel het hoofdeinde in en maak vervolgens verbinding - deel 2

Stel het hoofdeinde in en maak vervolgens verbinding - deel 2
Stel het hoofdeinde in en maak vervolgens verbinding - deel 2
Stel het hoofdeinde in en maak vervolgens verbinding - deel 2
Stel het hoofdeinde in en maak vervolgens verbinding - deel 2

We maken gebruik van de Software Serial-bibliotheek. Meer informatie is beschikbaar via deze link

Je kunt het zien op regel 7 van een van de programma's. Het configureert pinnen digitaal 7 en 6 als TX en RX (zenden en ontvangen). Dit is hoe de gegevens van de Master Arduino via de groene draad naar de Slave gaan en, wanneer het Slave-programma in de tweede Arduino zijn werk heeft voltooid, terug door de gele draad. Onderaan dezelfde afbeelding (in het venster Seriële monitor) kunt u zien dat de gegevens die we hebben verzonden nu met succes de hier beschreven lus hebben doorlopen en terugkomen in de pc als het paar gehele getallen netjes gescheiden.

Stap 5: Overzicht van de schetsen / programma's - Structuur van het programma

Overzicht van de schetsen / programma's - structuur van het programma
Overzicht van de schetsen / programma's - structuur van het programma
Overzicht van de schetsen / programma's - structuur van het programma
Overzicht van de schetsen / programma's - structuur van het programma

Lay-out Zoals in alle Arduino-schetsen zijn er 3 basisonderdelen:

  • de verklaringen
  • De opzet
  • De hoofdlus

Zoals vaak gebeurt, hebben we hier gebruik gemaakt van een 4e sectie die de toevoeging is van 'Functies'. Als u niet bekend bent met het gebruik van Functions, kunt u Googlen voor "Arduino-functies" en vindt u uitlegsites zoals het voorbeeld in deze link: www.tutorialspoint.com/arduino/arduino_functions…..

We hebben ook gebruik gemaakt van tabbladen om het programma op te delen in beter hanteerbare blokken.

De drie blokken die we hebben gebruikt, staan bovenaan elke afbeelding van de IDE-vensters hierboven:

  • simpleRxTx0330Master
  • gemeenschappelijk
  • notities

Dit zijn eigenlijk afzonderlijke bestanden in de map van het programma, zoals u kunt zien in deze Windows Verkenner-weergave van de bestanden van het Slave-programma.

Er is een heel goede reden waarom we dit hebben gedaan.

  • Terwijl we het programma aan het opbouwen waren, kwamen we tot het besef dat het grootste deel van het programma voor de meester hetzelfde was als voor de slaaf.
  • Uiteindelijk trokken we alle gemeenschappelijke delen naar een tabblad, dat we daarom "algemeen" noemden, en elke keer dat we een onderdeel hadden debuggen (het getest en waren we ervan overtuigd dat het goed werkte), kopieerden en plakten we dat hele tabblad van meester naar slaaf, of omgekeerd.
  • De notitietabs zijn toevallig ook identiek, omdat het ontwerp generiek is.

Geen van de functies wordt aangeroepen vanuit de setup, ze worden allemaal aangeroepen vanuit de lus, dus we hebben ze gemaakt na de setup maar vóór de lus.

Stap 6: Top-down ontwerp

Het is een goed idee om uw schets te ontwerpen, te beginnen met een definitie van wat u wilt doen.

Als je dit eenmaal hebt, kun je beginnen met het maken van de schets om die dingen te doen. Over het algemeen, als er een detail is dat u nog niet weet, maakt u er gewoon een functie van en laat u het maken van de functie over tot later.

Dit volgt de goede ontwerpfilosofie, onderwezen in veel universiteiten, genaamd CDIO (als je deze nog niet kent, kun je het googlen en sites vinden om het uit te leggen zoals: https://www.cdio.org/s.) Dit zegt eigenlijk: begin niet met het ontwerp voordat je het concept helder hebt. Begin pas met de implementatie als je het ontwerp helder hebt. Verwacht niet dat het werkt voordat u de implementatie duidelijk hebt. C eerst, dan D, I en O. In elke volgende fase itereer je (ga terug rond de lus(sen), dus als je eenmaal tevreden bent met je eerste Design-loop terug en controleer of deze nog steeds voldoet aan het Concept, en update de C als dat nodig is enz. En ga zo maar door, dus zelfs als je moet werken, ga dan helemaal terug naar de top en kijk opnieuw hoe de C er nu uitziet, dan de D en I, en maak en controleer alle verandert waar nodig. Bij programmeerschetsen werkt dit net hetzelfde als je Top-Down ontwerpt.

Stap 7: concept en ontwerp - deel 1

Concept en ontwerp - Deel 1
Concept en ontwerp - Deel 1
Concept en ontwerp - Deel 1
Concept en ontwerp - Deel 1

Het Concept ziet er hier uit als de eisen op hoofdlijnen zoals vermeld in het tabblad 'opmerkingen'.'

Het ontwerp zou eruit kunnen zien als een vroege versie van de lus, die overeenkomt met het tabblad Notities en er ongeveer zo uit kan zien als u in deze afbeelding ziet

Kijk hoe ik het leuk vind om te beginnen met CTRL-C door de opmerkingen eerst naar de kop van de lus te kopiëren, en dan de lege plekken in te vullen met opdrachten die die dingen zullen doen.

Dit compileert eigenlijk OK, zoals je onderaan het scherm in de afbeelding kunt zien. Dat reikt van CDIO-fase D tot I, en terwijl we de code ontwikkelen, is het een goed idee om door deze D-I-lus te blijven gaan.

Nu is het tijd om naar de volgende fase te gaan, daar staat een opmerking die zegt dat we: // iets gaan ontvangen van de hardware-USB, dan gaan we dat naar het seriële softwarekanaal verzenden. We schrijven deze code om dat mogelijk te maken - regels 133 tot 138 hier weergegeven in gele markeerstift

Stap 8: concept en ontwerp - deel 2

Concept en ontwerp - Deel 2
Concept en ontwerp - Deel 2
Concept en ontwerp - Deel 2
Concept en ontwerp - Deel 2

De twee eerste twee functies die we hier introduceren zijn (recv() en tran() om het ontvangen van de hardwarepoort en het verzenden naar de softwarepoort te doen - vandaar dat ze worden aangeroepen met de weergegeven 'hw' of 'sw' parameters.

Daarnaast hebben we een test toegevoegd op een globale variabele met de naam newData. Dit is een vlag die we binnen de functie " void recv(); " zullen plaatsen. Wanneer een bericht is ontvangen, wordt deze variabele gemarkeerd van false naar true. We doen dit zodat we alleen een bericht verzenden als er een is ontvangen (vlag ==true) in regel 134. En zodra we ons bericht hebben verzonden, is dat 'job done', dus we wissen de vlag weer naar false in regel 137.

Opnieuw kunnen we compileren controleren (D naar I), en deze keer hebben we een 'niet gedeclareerd' foutbericht (weergegeven). Dit vertelt ons dat we de recv(); functie. We zijn van plan dit later te doen, dus voor nu, om ons in staat te stellen een schone compilatie te krijgen, moeten we een dummy- of tijdelijke aanduiding-functie maken, zoals hierna wordt getoond.

Opnieuw kunnen we compileren controleren (D naar I), en deze keer hebben we nog een 'niet gedeclareerd' foutbericht voor de tran(); functie. Dit vereist een vergelijkbare stub-creatie. We kunnen opnieuw compileren (D tot I), en deze keer zullen we ontdekken dat dit perfect werkt; tot nu toe zo goed.

Stap 9: Voltooi de hoofdlus: A) Ontvangen van USB, B) Ontvangen van Slave Arduino

Voltooi de hoofdlus: A) Ontvangen van USB, B) Ontvangen van slave Arduino
Voltooi de hoofdlus: A) Ontvangen van USB, B) Ontvangen van slave Arduino
Voltooi de hoofdlus: A) Ontvangen van USB, B) Ontvangen van slave Arduino
Voltooi de hoofdlus: A) Ontvangen van USB, B) Ontvangen van slave Arduino

Er is nog een laatste stuk dat we hebben toegevoegd om dit deel af te maken, namelijk het toevoegen van een foutopsporingscode.

Er is nog een Instructable over het debuggen van schetsen waarnaar kan worden verwezen om te begrijpen wat we hier hebben gedaan en waarom. Raadpleeg de Instructable "Hoe Arduino-schetsen te bouwen en te testen totdat ze werken"

Dus deze debug-regels [136-139 getoond] worden vervolgens toegevoegd in de hoofdlus en, zie je maar, je kunt ze testen in het Master-einde door de debug-variabele true te maken en Compiling (I), dan als je sluit een Arduino aan, je kunt uploaden, de seriële monitor openen en kijken of wat terugkomt in de seriële monitor is zoals hier wordt weergegeven (zie je het bericht "DEBUG-MODUS" is toegevoegd?)

Stap 10: Ontvangen en verwerken van de gegevens in de Slave Arduino

De gegevens ontvangen en verwerken in de slave-arduino
De gegevens ontvangen en verwerken in de slave-arduino
De gegevens ontvangen en verwerken in de slave-arduino
De gegevens ontvangen en verwerken in de slave-arduino

Ontvangen van Slave Arduino

Voeg de benodigde code voor het tweede kanaal toe aan de hoofdlus, de software seriële ontvanger zoals weergegeven - regels 149 tot 155.

Kun je zien dat de structuur losjes is gebaseerd op wat we hierboven schreven voor de Master-case?

Je zult ook zien dat we een compilerfout krijgen, een andere niet-gedeclareerde functie - deze keer parseData(); - dus we moeten hier ook een stub voor maken, voordat we een foutloze testcompilatie kunnen uitvoeren.

Omgaan met de gegevens in de Slave Arduino

Voeg de hoofdluscode toe die nodig is voor de Arduino als deze is geconfigureerd als een slave-apparaat zoals weergegeven - regels 163 tot 174. Kun je zien dat de structuur ervan erg lijkt op die van het eerste kanaal?

En je zou deze keer moeten ontdekken dat het absoluut prima compileert.

Stap 11: Schrijf de ontvangstfunctie

Schrijf de ontvangstfunctie
Schrijf de ontvangstfunctie

De functie Ontvangen - void recv(char from){} - heeft twee hoofdtaken.

1 om een reeks tekens van het USB-kanaal te ontvangen, en

2 om er een te ontvangen van het Arduino-naar-Arduino-kanaal.

Voor de eerste zullen we moeten gebruiken omdat het de ingebouwde hardware-UART van de Arduino gebruikt, en voor de tweede met de standaard Arduino-bibliotheek: software UART.

Wanneer we beginnen met het toevoegen van code aan een functie - om een functie te maken die iets doet, in plaats van alleen een stub - moeten we eraan denken om de stub die hij vervangt te verwijderen of uit te commentaaren. Anders krijgen we een compileerfout: refefintion van 'void lrec(char)'.

Probeer de fout te krijgen en probeer vervolgens een van de hierboven voorgestelde manieren om er vanaf te komen.

Begin met een functie die lijkt op de functie die we hier laten zien van regels 75 tot en met 88 in het geel.

Inmiddels weet je dat je met code de Compile-bewerking moet proberen. Je krijgt een foutmelding, zoals die we eerder hadden, van het type: functienaam niet gedeclareerd in dit bereik. We hebben in eerste instantie een andere stub nodig om ons voorbij deze fout te laten compileren, dus voeg er een toe zoals eerder, en zorg ervoor dat je nu een compilatie zonder fouten kunt krijgen.

Laten we nu eens kijken naar de code die we hebben geschreven voor de functie recv().

Het is vrij schoon, je kunt het gebruik van de 'als'-voorwaarde zien om de twee delen van de hierboven genoemde functie te produceren.

De code in het 'sw'-gedeelte en het 'hw'-gedeelte heeft dezelfde vorm en ik zal het hier beschrijven.

De eerste van het paar regels is in elk geval het begin van een while-lus. Als je niet bekend bent met while's, kun je het opzoeken op de Arduino.cc/Reference-site voor uitleg en voorbeelden. Hier wachten we 'terwijl' de ingebouwde 'Serial'-functie geen teken(s) heeft ontvangen en omdat de variabele newData is uitgeschakeld (d.w.z. de newData == false voorwaarde is waar). Zodra een karakter - of meer dan één karakter - wordt ontvangen, zal de while 'doorvallen' naar de tweede regel in dit paar. Dat zal dan een beroep doen op de recAstringChar(char); functie om het huidige teken te verwerken. Dit paar regels zal dan wisselen zolang (of zolang) er nog tekens moeten worden ontvangen. Als ze allemaal klaar zijn, eindigt de while-status, waardoor het if of else volgende niveau kan eindigen, en op zijn beurt de rec(char); functie te beëindigen. Zo is er nu een volledig bericht ontvangen.

Stap 12: Schrijf de subfunctie Ontvangen - Deel 1

Schrijf de subfunctie Ontvangen - Deel 1
Schrijf de subfunctie Ontvangen - Deel 1
Schrijf de subfunctie Ontvangen - Deel 1
Schrijf de subfunctie Ontvangen - Deel 1

We moeten nu de functie schrijven recAstringChar(char);. Je ziet aan de opmerking bij regel 50 hier bovenaan dat het zijn taak is om twee buffers bij te werken met kopieën van het binnenkomende seriële bericht. [Het bleek dat terwijl ik probeerde dit allemaal werkend te krijgen, ik leerde dat ik twee verschillende buffers nodig had - of dat was tenminste de gemakkelijkste manier om wat problemen te omzeilen, vandaar dat het een beetje evolueerde naar het nodig hebben van 2 buffers, dus Ik heb ze zojuist gemaakt.] Ik heb de ene buffer aangeroepen: ReceiveData, en de andere: ReceiveChars.

De buffers zijn globale variabelen, dus ze worden gedeclareerd op moduleniveau, zie regels 9 en 10 van het gemeenschappelijke tabblad. Er zijn andere variabelen gedeclareerd binnen deze functie die daarom een lokaal bereik hebben - weergegeven in regels 51-54 hier. Dit is niet de plaats om de verschillen tussen globals en locals uit te leggen, maar er is meer info hierover in https://www.arduino.cc/glossary/en/ onder Local and Global.

U kunt ook alles te weten komen over de gegevenstypen en type-modifiers: static, boolean, byte, const, char in https://www.arduino.cc/reference/en/#variables, hier weergegeven.

De hoofdprogrammastroom in deze functie wordt bestuurd door de if op regel 56 hier, en de corresponderende else op regel 74. Dit behandelt twee scenario's

a) [vanaf lijn 74] wanneer het ontvangen bericht begint. Dit gebeurt wanneer de startMarker wordt opgemerkt - dit is gedefinieerd als het ' < '-teken, daarom beginnen we onze tekenreeks altijd met dat teken wanneer we de schets testen. Als we dat niet doen, wordt niets verwerkt als ontvangen, het wordt allemaal genegeerd, net alsof we onzin aan het typen zijn bij de ' Serial Monitor '-toetsenbordprompt.

b) [regels 56 tot 73] die alle andere tekens ontvangt, wat ze ook zijn, maar ze behandelen alleen tekens nadat een geldige start heeft plaatsgevonden (een '>' is ontvangen zoals in a) hierboven.)

In deze regels (van 74 tot 78) plaatsen we die ontvangen < in een van de buffers (receivedData[0]) maar niet in de andere. We passen de bufferaanwijzer (variabele: char ndx) aan om naar de volgende reservebufferpositie (receivedData[1]) te wijzen met behulp van het post-increment-commando (++) in de regel ndx++;, en we zetten de vlag in uitvoering op true.

Het programmaverloop in dit deel van de functie wordt bestuurd door de if op regel 57 hier, en de corresponderende else op regel 65. Dit behandelt twee scenario's

a) [vanaf lijn 65] wanneer het ontvangen bericht is beëindigd. Dit gebeurt wanneer de endMarker wordt opgemerkt - gedefinieerd als >, daarom eindigen we onze tekenreeks altijd met dat teken wanneer we onze schets testen. Een van de dingen die gebeuren wanneer het eindteken wordt ontvangen, is dat de globale vlag (technisch variabel) newData wordt ingesteld op true net als de functie eindigt, zodat de functie die onze subfunctie heeft aangeroepen (de aanroepende functie: recv(char);) kan 'weten' dat geldige nieuwe gegevens compleet zijn ontvangen.

b) [regels 57 tot 64] die alle andere tekens ontvangt, wat ze ook zijn. Hij parkeert ze gewoon netjes in rijen in beide buffers.

Stap 13: Schrijf de subfunctie Ontvangen - Deel 2

Schrijf de subfunctie Ontvangen - Deel 2
Schrijf de subfunctie Ontvangen - Deel 2
Schrijf de subfunctie Ontvangen - Deel 2
Schrijf de subfunctie Ontvangen - Deel 2

Het kan helpen om een voorbeeld te geven van hoe de 2 buffers eruit zien als ze gevuld zijn. Als we enter zouden invoeren, zouden de buffers de volgende tekens bevatten:

Dus nu kun je zien dat we één buffer hebben die precies dezelfde karakters heeft als we eerst hebben ingetypt, en één buffer die alleen de twee waarden en een scheidingskomma heeft. Nu hebben we wat code die de karakters kan ontvangen die we typen op het Serial Monitor-toetsenbord, we kunnen van CDIO-fase I naar O gaan, wat strings intypen en kijken wat er gebeurt. Upload de code naar de Master Arduino, open de seriële monitor en probeer iets geldigs in te voeren, zoals enter. Ontvangt u een echo op het scherm van de seriële monitor zoals hier wordt weergegeven?

Stap 14: Schrijf de verzend- en ontledingsfuncties

Schrijf de verzend- en ontledingsfuncties
Schrijf de verzend- en ontledingsfuncties
Schrijf de verzend- en ontledingsfuncties
Schrijf de verzend- en ontledingsfuncties

Eerst voor de Transmit

Dus nu we een string hebben ontvangen, kunnen we de verzendfunctie schrijven: tran(char); om zijn stomp te vervangen. Hierdoor kunnen we een string van de Master naar de Slave Arduino sturen, dus zorg ervoor dat beide apparaten zijn aangesloten en op elkaar zijn aangesloten om deze nieuwe functionaliteit te testen.

Voer deze functie in zoals hier getoond in regels 117 tot 133. Zoals u zult herkennen, heeft het twee delen, één om naar het USB-kanaal te verzenden (hardware UART) en één om naar de andere Arduino te verzenden (software UART.) Dit zou een compileerfout moeten maken -gratis, en je kunt de schets meteen uploaden en kijken wat er gebeurt. Deze keer stuur ik. Krijg je het resultaat getoond?

De schermafbeelding is interessant omdat de ontvangen reeks… er correct uit zou moeten zien zoals voorheen, en de verzonden reeks… er nu correct uit zou moeten zien. Merk echter op dat de gehele conversie niet heeft gewerkt. Er is nog een beetje meer code om toe te voegen om dat te laten werken.

Stap 15: Schrijf de verzend- en ontledingsfuncties

Schrijf de verzend- en ontledingsfuncties
Schrijf de verzend- en ontledingsfuncties
Schrijf de verzend- en ontledingsfuncties
Schrijf de verzend- en ontledingsfuncties

Dan voor de Parse

Dit is een stukje code dat de ontvangen tekenreeks ontleedt om de numerieke gedeeltelijke tekenreeksen op te halen en ze omzet in gehele getallen. Het is de void parseData(); functie van de hoofdlus

Vervang de parse-stub door de code die wordt weergegeven in regels 98 - 113. Upload het, en laten we kijken of het probleem dat we hadden met de 2 integer-waarden nu is opgelost. Laten we proberen.

Ja, het werkt, zoals getoond, de gevonden gehele getallen zijn 49 en 98.

Stap 16: Finale

Finale!
Finale!

Deze gegevens zijn helemaal rondgegaan van de pc via de master via de slave en weer terug via de master naar de pc. Met de voltooide versie van common geüpload naar zowel Master- als slave-uiteinden, en met debug-modus nu uitgeschakeld, krijgen we de gegevens correct ontvangen aan beide uiteinden te zien, zoals hier wordt weergegeven.

Aanbevolen: