Trushin A.N., Arutyunyan M.G. Etablera en anslutning och datautbyte via bluetooth mellan Arduino och iOS-applikation. Protokollparametrar för kommunikation mellan Arduino och ESP8266 arduino-kommunikation

Ladda ner standardexempel"Physical Pixel" via menyn File\Examples\4.Communication\PhysicalPixel. Detta program väntar på data från datorn. Vid mottagande av tecknet 'H' tänds testindikatorn, vid mottagande av tecknet 'L' slocknar den. Låt oss analysera dess källkod:

int outputPin = 13 ; // här lagrar vi kontaktnumret
int värde; // mottagna tecken kommer att lagras här

void setup()
{
Serial.begin(9600) ; //ställ in porten till 9600 bps
pinMode(outputPin, OUTPUT); // ställ stift 13 till utgångsläge
}

void loop()
{
if(Serial.available())( //om det finns en accepterad karaktär,
val = Serial.read(); // läs den sedan och lagra den i val
if (val == "H") ( // om tecknet "H" accepteras...
digitalWrite(outputPin, HIGH); // slå sedan på lysdioden
}
if (val == "L") ( // om tecknet "L" accepteras,
digitalWrite(outputPin, LOW); // stäng sedan av lysdioden
}
}
}

Lägg märke till de kapslade förhållandena och ordningen på de öppnings- och stängningskransar. För att underlätta läsningen av programkoden, flyttas varje nästa nivå av kapsling åt höger. Dessutom hjälper editorn att läsa koden - om du sätter markören till höger om parentesen kommer den att markera motsvarande par parentes.

Hur kontrollerar man funktionen för det här programmet efter att du laddat ner det till mikrokontrollern? Vi måste hitta ett sätt att skicka tecken till datorns COM-port så att mikrokontrollern tar emot och bearbetar dem. Det finns många alternativ för att lösa detta problem.

Vi använder den inbyggda COM-portmonitorn i Arduinos utvecklingsmiljö

Detta är den enklaste och mest förståeliga metoden för nybörjare.

COM-portmonitorn startas via menyn Tools\Serial Monitor eller via verktygsfältet. I äldre versioner av programvaran var monitorn endast tillgänglig via verktygsfältet: . När du anropar monitorn, se till att samma baudhastighet är vald som i mikrokontrollerprogrammet. Nu kan du ange vilka tecken som helst i inmatningsfältet till höger och trycka på "Skicka" -knappen - de inmatade tecknen kommer att skickas till porten, och ditt program kommer att acceptera dem där. Skriv in den latinska bokstaven "H" där, tryck på "Skicka" - testlampan tänds. Om du skickar "L" - kommer den att stängas av. Förresten, all data som ditt program kommer att skicka till COM-porten kommer att visas i fönstret nedan.

Använder terminalemuleringsprogrammet HyperTerminal

Detta är ett lite mer komplext utbytesalternativ att implementera.

Windows innehåller vanligtvis ett terminalemuleringsprogram som heter HyperTerminal. I Windows XP finns den under Start\Alla program\Program\Tillbehör\Kommunikationer\HyperTerminal. Vid start måste du vägra att skapa en anslutning, välj menyn Arkiv \ Egenskaper. I dialogrutan som visas, välj din COM-port, klicka på "Konfigurera" och konfigurera kommunikationsinställningarna enligt bilden:

Du kan använda en annan terminalemulator - de har alla vanligtvis liknande funktionalitet och liknande inställningar.

Klicka på "OK" i båda fönstren, och en gång i huvudprogramfönstret, valfri tangent på tangentbordet - HyperTerminal kommer att ansluta till COM-porten. Nu går alla tecken som skrivs på tangentbordet genom COM-porten till mikrokontrollern, och allt som mikrokontrollern skickar går till skärmen. Tryck på "H" och "L"-knapparna (beakta det valda språket och fallet) - testlampan ska tändas och slockna.

Låt oss skriva vårt eget PC-program!

Det här alternativet är för riktiga entusiaster som vill programmera inte bara Freeduino utan även PC. Varför inte? Vi behöver inte lära oss detaljerna i programmering serieport under Windows, eller andra komplicerade saker. Speciellt för att lösa sådana enkla uppgifter finns Processing-språket (http://processing.org), som i syntax och till och med utvecklingsmiljö är väldigt likt Arduino-mjukvaran.

Installera och kör Processing - Du kommer att se en Arduino-liknande utvecklingsmiljö.

Källkoden för bearbetningsspråket finns i kommentarerna under huvudtexten i Physical Pixel-exemplet. Här är den med minimala ändringar - vi fixade portöppningen så att du enkelt kan byta ut dess nummer:

import processing.serial.* ;
serieport;
void setup()
{
storlek(200, 200);
noStroke() ;
frameRate(10) ;
port = new Serial(detta , "COM5" , 9600 ); //!!! Ange din COM-port här!
}
boolean mouseOverRect() //Returnerar sant om markören är inuti en kvadrat
{
return ((mouseX >= 50 ) && (mouseX<= 150 ) && (mouseY >= 50 ) & (musY<= 150 ) ) ;
}
void draw()
{
bakgrund(#222222);
if (mouseOverRect() ) // Om markören är inuti en kvadrat...
{
fill(#BBBBB0) ; // ändra färg till ljusare
port.write("H"); // skicka "H" till mikrokontroller
) annat ( // om inte inuti...
fyll(#666660); // ändra färg till mörkare
port.write("L"); // skicka "L" till mikrokontrollern
}
rect(50 , 50 , 100 , 100 ); // rita en kvadrat
}

Kör programmet (via Sketch \ Run-menyn) - ett fönster med en fyrkant kommer upp, när du placerar muspekaren i den kommer lysdioden på Freeduino att tändas.

En beskrivning av bearbetningsspråket och dess möjligheter ligger utanför räckvidden för denna enkla berättelse, men många av Arduino-exemplen i kommentarerna under programmets brödtext visar bearbetning av PC-kod som interagerar med Freeduino.

Det är helt enkelt viktigt för honom att utbyta information med mikrokontrollern. Det finns situationer då du behöver manuellt, genom att styra från en PC eller bärbar dator, aktivera en eller annan funktion i mikrokontrollerprogrammet.

Men låt oss börja. Det är inte så svårt att utbyta data med Arduino, men haken är att data överförs tecken för tecken, vilket är väldigt dåligt. På jakt efter det här problemet var jag tvungen att spendera ganska lång tid, tills jag stötte på ett underbart bibliotek på Habrahabr. Författaren implementerade i den funktionen att acceptera siffror, dvs. du kan skicka mer än en siffra till styrenheten och det kommer att fungera korrekt. Ladda ner biblioteket (länk), packa upp det i hårdvarubibliotek och låt oss gå vidare till övningen.

Först och främst kommer vi att skriva en skiss och ladda upp den till Arduino (Freeduino)

#include void setup() (

Serial.begin(9600); // ställ in porthastighet

PinMode(9, OUTPUT); // ställ in stift 9 som högtalarutgång

) void loop()

Långt intNumber; Serial.print("Ange nummer: ");

Number = SerialInput.InputNumber(); // Ange ett nummer Serial.print("Resultat = ");

Serial.println(Number * Antal, DEC);

Pip (500);

} void pip (osignerade char fördröjningar)(

analogWrite(9, 20); //-värdet måste vara mellan 0 och 255

// experimentera för bra ton

analogWrite(9, 0); // 0 - stäng av piezo

Fördröjning(fördröjningar); // pausfördröjningar ms

Vad betyder allt detta. Jag försökte förse koden med detaljerade kommentarer, allt verkar vara klart. Den här skissen ber dig att ange valfritt tal, varefter den ger ut sin kvadrat, och spelar en ljudsignal genom en piezo-högtalare ansluten till stift 9.

Och nu, det mest intressanta - det är dags att prova. För att växla med styrenheten rekommenderar jag att du använder ett gratisprogram Spackel. I inställningarna för Anslutningstyp, välj Seriell och ange rätt portnummer istället för COM1 (du kan kika i Arduinos programmeringsmiljö i menyn Verktyg->Serial Port). Vi trycker på Öppna och vi ser inskriptionen Enter number i konsolen, vi anger valfritt nummer (inom rimliga skäl), vi trycker på Enter och vi ser resultatet.

Allt, du kan glädjas och hoppa av glädje. Naturligtvis kan allt detta förbättras, till exempel, visa först en meny för att skicka från styrenheten till konsolen, där man beskriver kommandona i detalj. Ange till exempel siffran 0 - tänds Led-lampor, tryck på 1 - den slocknar. Således kan du skjuta in minst 100500 kommandon, bara det finns tillräckligt med mikrokontrollerminne (som är så litet). Och vi ska prata om hur man utökar det tillgängliga minnet nästa gång.

UPD: en del av koden klipptes av motorparsern, så här är källan

Precis som många andra gör det själv använder jag regelbundet AVR-mikrokontroller för alla möjliga olika amatörhantverk. Och tack vare konceptet "Arduino" får dessa hantverk nu ett elegant utseende. Faktum är att för cirka 300-400 rubel får vi ett flerskiktskort i miniatyr med en mask, silkescreentryck och med kringutrustning för mikrokontrollern som är helt ansluten till den (och i SMD-version!). Jag pratar inte om alla typer av plug-ins av samma "Arduino"-serie: sensorer, kontroller, displayer och hela uppsättningar av extra kringutrustning som vi behöver så mycket. Och återigen, allt är också billigt och i utmärkt prestanda. Det finns praktiskt taget inget behov av att späda och löda något på "knäet".

Men alla dessa olika amatörhantverk kräver naturligtvis, förprogrammering. Och i framtiden, med olika förbättringar, måste dessa hantverk ständigt återflash. Det är tydligt att det är bekvämare att göra detta på distans än att ständigt dra dem till en konventionell programmerare. I allmänhet, tack vare samma Arduino-plattform, finns det många alternativ här: Bluetooth, ZigBee, en radiokanal med ditt personliga protokoll, IR och till och med Wi-Fi. Alla låter dig upprätta trådlös kontakt med din mikrokontroller. Men vi kommer att fokusera på det sista alternativet. Det finns fyra huvudorsaker här:

1: modern, internet of things!

2: trådlös router finns i varje lägenhet, anmäl dig på hemnätverk dina enheter och voila!

3: ditt hantverk gör ett revolutionerande steg i sin utveckling; inte bara kan de programmeras på avstånd, de kan nu också kommunicera med omvärlden: Digital klocka självständigt ta exakt tid från klock-NTP-servrar styrs verkställande enheter från andra sidan av staden eller landet, registrerande enheter sparar ackumulerad data till molnet, etc. etc.

4: det finns en underbar serie ESP8266-chips som det inte är särskilt lätt att implementera allt detta på.

Vidare, i denna artikel, med hjälp av exemplet med en mekanisk arm på servon, fjärrprogrammering och datautbyte från en PC (eller något) med enheter baserade på AVR mikrokontroller. Jag vill genast notera att alla program som anges nedan är rent demonstrationsmässiga och har inget kommersiellt värde. Därför accepteras inte påståenden, som varför programmeraren är så kastrerad och inte särskilt funktionell, eller varför det inte finns några ytterligare tjänster som finns tillgängliga överallt. Eftersom koderna är öppna kan vem som helst avsluta dem efter eget gottfinnande, men för mig finns det fortfarande tillräckligt många för jobbet.

Det antas att läsaren redan är bekant med "Arduino"-modulerna (sköldarna) och med anslutningen och den fasta programvaran för ESP8266. Faktum är att en enorm mängd material har lagts ut på webben som förklarar grunderna för att arbeta med dessa enheter, och jag skulle inte vilja upprepa mig själv här. För nybörjare finns en lista i slutet av artikeln. Användbara länkar om dessa frågor, där du kan hitta mycket information om varför allt inte fungerar för dig. Från min erfarenhet som före detta elektronikingenjör kan jag ansvarsfullt konstatera att 99% av problemen beror på följande:

1. Dåliga kontakter. Eftersom "Arduino"-sköldar betyder att man växlar med varandra genom ledningar av typen "far-mamma", och inte genom lödning, mycket ofta något, någonstans, men lämnar. Kolla upp. Och i allmänhet, som de säger, är elektronik vetenskapen om kontakter.

2. Näringsproblem. Applicera inte 5 volt ström där 3,3 krävs. Ibland kommer rök ut ur ESP8266. Även om den å andra sidan smälter logiska signaler från femvoltsenheter utan problem.

3. Problem med tillräcklig strömförsörjning. ESP8266 har en elak natur och kan ibland dra nästan trehundra milliampere, även om den innan dess kunde nöja sig med trettio. Följaktligen sjunker den bräckliga 3,3 volts stabilisatorn på Arduino-kortet, till vilken du kopplade den utan att tveka, omedelbart till mikroskopiska värden. Och du kan inte förstå varför det antingen fungerar eller inte.

4. Förvirring med slutsatser. Kontrollera alltid vilka signaler som går vart. RXD-mottagaren måste vara ansluten till TXD-sändaren, liksom TXD till RXD, men MOSI måste anslutas till MOSI, MISO till MISO, och så vidare.

5. Lita inte på ESP8266:s in-circuit pull-up motstånd, dra alltid stiften till noll eller effekt, genom 5-10 kilo ohm externa motstånd, inte bara en bygel. Annars kan du i bästa fall få en aldrig tidigare skådad strömförbrukning, och sedan känna den obehagliga lukten av bränd plast.

6. Ogräs programvara. Eftersom programvara för enskilda användare är skriven av samma entusiaster, dyker det upp fel i själva firmwaren och buggar med jämna mellanrum när versioner av samma firmware uppdateras. Det behandlas genom att söka igenom lämpliga forum, ibland till och med på engelska. Vissa kamrater hävdade till och med att ESP-chippet i sig är lika fuktigt som vädret i S:t Petersburg, men å andra sidan finns det också en uppfattning om att situationen sedan 2014 (året för den första releasen) har förbättrats dramatiskt (till skillnad från vädret).

7. Mystiska fel. Detta är en sällsynt men nervkrävande händelse. Till exempel hade jag inte en "Arduino" -enhet fjärrsydd. Snarare var den sydd, men med fel. Men den syddes utan fel om en kabel från programmeraren hängde på den (men utan själva programmeraren). "YAH," sa jag till mig själv och lödde en 15 pF kondensator mellan sändningsstiftet och klockstiftet. Allt fungerade. Men dödade dagen.

Så låt oss börja med det enklaste. Vi har en MechArm mekanisk lem (men inte den Howard Wolowits byggde) tillverkad i Kina och Personlig dator med Windows. Uppgiften är att fjärrflasha programmet och hantera det från en dator.


För kontrollkontrollen, ta en fin miniatyrhalsduk Arduino Nano med ATmega328P sten. Denna bräda passar perfekt inuti den mekaniska armen.


Låt oss nu bestämma hur vi ska programmera det. Det finns tre huvudsakliga metoder som är mest lämpade för firmware på distans: genom SPI-gränssnittet, genom den inbyggda bootloadern, genom JTAG-porten.

Det enklaste alternativet är förstås den inbyggda bootloader (bootloader). Detta är ett minne som är förskrivet i FLASH, ett program som tar emot en kod med ett visst protokoll (till exempel med den enklaste UART) och skriver den med speciella kommandon till platsen för det nedladdade programmet. Så här fungerar till exempel själva bootloadern ARDUINO IDE. Efter en återställning eller start väntar laddaren en tid på att data tas emot, och om den inte väntar börjar den köra programmet från adress noll. Om data kommer in, skriver den till programdelen. Efter nästa återställning börjar det laddade programmet att köras. I detaljer kanske jag har beskrivit felaktigt, men kärnan är precis det. Som ett resultat behöver vi bara tre stift för programmering: RTD-mottagare, RESET och GND. I allmänhet används också en TRD-sändare för att verifiera det inspelade programmet, men för enkla demonstrationsapplikationer (inte för ett kärnkraftverk) kan verifiering utelämnas.

Själva bootloadern är skriven på assemblerspråk, det finns exempel på enkla bootloaders i AVR-databladen. Du kan hitta en befintlig starthanterare om den finns i fri tillgång och använd det bara i sin färdiga form, om protokollet som det fungerar på är känt. Den enda varningen är att för detta måste du konfigurera AVR i ett speciellt läge genom att blinka speciella säkringsbitar, vilket görs av en vanlig programmerare, och sedan sy själva bootloadern i mikrokontrollerns minne (det vill säga, du kan fortfarande inte klara dig utan en programmerare en gång).

Det andra alternativet är programmering Seriellt gränssnitt SPI. Det finns ingen intern bootloader här, utan vi programmerar genom att skicka speciella kommandon och sedan data via ovan nämnda gränssnitt. Här har vi en extern bootloader, men vi behöver fortfarande skriva den. Vid överföring används förutom RESET och GND fyra extra utgångar MOSI, MISO - data, SLK-synkronisering, CS - kristallval. Men generellt sett kan du också ta bort MISO och CS. Uppgifterna kommer bara att tas emot (då blir det ingen verifiering av programmet), och vi har ändå bara en kristall.

Varje tillvägagångssätt har sina för- och nackdelar (och jag övervägde inte JTAG alls, eftersom mänskligt liv är kort). Men till slut lutade jag mig mot SPI eftersom jag var för lat för att skriva i assembler, och jag hittade inte öppna färdiga lastare (jag såg bara inte bra ut).

För att bygga trådlös kanal Jag, som redan nämnts, valde det för närvarande extremt välkända ESP8266-chippet - en mikrokontroller, eller snarare en hel SoC (System-on-Chip) från den kinesiska tillverkaren Espressif med ett Wi-Fi-gränssnitt. Förutom Wi-Fi kännetecknas det av möjligheten att köra program från externt flashminne. Och specifikt för mitt projekt tog jag ESP8266-07 med 512 KB minne ombord.


I allmänhet är vilken ESP8266 som helst lämplig, där det finns extra ben för att implementera SPI. Därför kommer den enklaste ESP8266-01 inte att passa oss, eftersom den har väldigt få ben för I/O-portar. Men å andra sidan är skillnaden i pris för dem mindre än hundra rubel, och de är lika tillgängliga. Tja, stora felsökningskort med ESP, där ett gäng kringutrustning är skilda för bekvämlighets skull, är inte heller lämpliga för oss, eftersom de inte passar där vi vill stoppa in dem i vår mekaniska hand.

Den globala essensen av idén i allmänhet var följande. Från datorn till ESP:n överförs programmets kropp som laddas in i mikrokontrollern trådlöst via WI-FI (inom ditt hemnätverk). Och ESP redan via tråd som använder SPI-gränssnittet skriver detta program direkt till FLASH-minnet på mikrokontrollern. Sedan återställs det naturligtvis och låter det laddade programmet köras. Dessutom måste ESP:n ha en oberoende enhet som också hanterar datautbytet med mikrokontrollern, eftersom vi inte bara vill programmera utan också utbyta data med den. Speciellt för MechArm-projektet, efter inspelning av programmet, skickar vi även servostyrsignaler för att sätta denna arm i rörelse. Därför, på ESP själv, är det önskvärt för oss att höja TCP-server för att överföra programmet och UDP-servern för att styra MechArm. Följaktligen går dessa servrar med i hemnätverket och lyssnar noga för att se om någon vill ladda upp ny kod till MechaArm eller vinka den till någon.

Så, jag hittade på webben, låter den fasta programvaran dig redan producera AVR programmering med flyg, men där är det största problemet att den här firmwaren inte längre kan användas till. Och vi skulle vilja kommunicera med AVR även på distans efter programmering.

Vilken programvara kommer vi att använda:

För PC skrev jag allt i JAVA, IntelliJ IDEA-miljön. Men i princip kan du använda vad som helst, det viktigaste för oss där är att skriva en klient som ska skicka ett program för AVR firmware på ESP8266.

Jag skriver programmen för AVR i ATMEL STUDIO, i C, sällan i assembler. Jag använder inte Arduino-skisser i princip, nästan alla nödvändiga bibliotek skrivs på ytterligare en timme, och med full förståelse för dess arbete. Jag provade skisser, men än så länge har du det inte på AVR operativ system, kommer skisser att fortsätta att ta kringutrustning från en vän och misslyckas regelbundet. Ja, själva Arduino IDE, jämfört med ATMEL STUDIO, är naturligtvis en väldigt primitiv sak. Men här är frågan förstås diskutabel, för humaniora och skolbarn blir det roligare och lättare, förmodligen, med sketcher.

För programmering av ESP8266 använde jag NodeMCU firmware och skrev programmen i Lua. Nej, jag skulle älska att skriva i Java och C, men det finns inga på ESP. Lua-språket i tillämpningen av vår uppgift är inte svårt, det är ett par småsaker att behärska det. Och faktiskt, för att ladda ner program och felsöka dem på ESP:n, tog jag IDE ESPlorer. Inhemsk gratis produkt(men du kan ge en donation till författaren), vilket naturligtvis inte går att jämföra med ovan nämnda miljöer, men som man säger till en presenthäst... Men för att kunna använda ESPlorer och skriva i LUA måste vi först ändra den grundläggande firmware (levereras från tillverkaren) i ESP8266-chippet till en ny. I det här företaget kommer NODE MCU PyFlasher-programmet att hjälpa oss. På sätt och vis hjälper det att återuppliva det. Och vi kommer att skapa själva firmwaren och få den i våra händer på skaparnas webbplats: NodeMCU. Och du kan läsa mer om denna process

Allt är väldigt lättillgängligt och begripligt. Vi lägger till SPI-stöd och bitoperationer till basbiblioteken (i LUA, i vårt fall, är bitoperationer överbelastade och de är till liten nytta). Du bör inte stoppa in en massa bibliotek i den fasta programvaran, för på grund av förekomsten av alla typer av programvara finns det väldigt lite minne kvar på ESP8266, några eländiga 20 kB.

Naturligtvis kan du bara ta färdig firmware, av vilken det redan finns en hel del dinglande på Internet, men jag rekommenderar det inte. Om så bara för att vissa inte stöder bitoperationer (och vi behöver dem) och det inte finns någon reglering av dataöverföringshastigheten via SPI.
Följaktligen sänds de som standard med en hastighet på 40 MHz dividerat med någon liten koefficient, och därför har AVR inte tid att smälta dem.

Om du är för lat för att skapa firmware kan du ladda ner min från molnet.

Nu har vi firmware och vi måste ladda in den i ESP8266 istället för basen. För att göra detta behöver vi en enkel USB-UART-adapter.


Vi ansluter benen TXD till RXD och RXD till TXD, vi gör en gemensam jord, men vi använder inte, som det verkade, en bekväm 3,3 V-strömutgång på adaptern. I de flesta fall kommer ESP8266 att slösa bort det helt. Därför frågar vi det separat. Sedan sätter vi ESP i programmeringsläge (GP0 till marken, om någon har glömt) och kör NODE MCU PyFlasher.

Viktigast av allt, glöm inte att radera flashminnet (ja, torkar all data), annars, beroende på firmwareversionen, kan det finnas kvar i minnet efter programmering onödigt skräp, som i sin tur kommer att hälla skräp i konsolen under fortsatt arbete. Innan dess använde jag mjukvara där det inte fanns någon möjlighet att radera minnet i förväg, jag led fruktansvärt, eftersom ingenting fungerade. Och kistan har precis öppnats, bara sanningen finns på det engelskspråkiga forumet för skaparna av NODE MCU.

Zaimev önskad firmware vi kan nu skriva och felsöka program i LUA-språket (det finns också MicroPython, men jag använde det inte) med mycket bekväma API:er från NODE MCU. Vi lanserar den tidigare nämnda ESPlorer.

Vi konfigurerar den också för att fungera med ESP8266, ställ in parametrarna seriell anslutning. Allt är ganska enkelt och upprepade gånger anges på Internet.

Nu skriver vi ett program i LUA, som vi sedan laddar upp till ESP8266:

Lua bootloader för AVR skriven till ESP8266

function InstrProgrammingEnable () -- instruktion för MC "aktivera programmering" p=0 medan p<31 do p=p+1 pin=8 gpio.write(pin, gpio.LOW) spi.send(1, 0xAC,0x53) read = spi.recv(1, 8) spi.send(1,0,0) gpio.write(pin, gpio.HIGH) if (string.byte(read)== 83) then print("connection established") p=33 if(p==31) then print("no connection") end end end end functionProgrammingDisable() pin=2--END OF ESET FÖR MK gpio.mode(pin, gpio.INPUT) pin=8 gpio.mode(pin, gpio.INPUT) pin=5--CLK MASTER för SPI gpio.mode(pin, gpio. INPUT) pin=6--MISO MASTER för SPI gpio.mode(pin, gpio.INPUT) pin=7--MOSI MASTER för SPI gpio.mode(pin, gpio.INPUT) end funktion ProgrammeringEnable() pin=2-- RESET FOR MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) pin=2--POZITIV FOR 4MSEC RESET FOR MK gpio.mode(pin, gpio.OUTPUT) gpio .write(pin, gpio.HIGH) tmr.delay(4) gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) tmr.delay(25000) end funktion InstrFlashErase() pin=8 gpio.write(pin, gpio.LOW) spi.send(1,0xAC,0x80,0,0) gpio.write(pin, gpio.HIGH) tmr.delay(15000) pin=2--RESET FOR MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) tmr.delay(20000) gpio.write(pin, gpio.LOW) print("FLASH är raderad") InstrProgrammingEnable () end funktion InstrStorePAGE(H, adress, data) pin=8 gpio.write(pin, gpio.LOW) spi.send(1,H,0,address,data) gpio.write(pin, gpio.HIGH) tmr.delay(500) end funktion InstrWriteFLASH(page_address_low, page_address_high) pin=8 gpio.write(pin, gpio.LOW) spi.send(1,0x4C,page_address_high,page_address_low,0) gpio.write(pin, gpio.HIGH) tmr.delay(5000)-- ibland skrivs inte flash när korta förseningar upphör funktion Programmering (nyttolast) pin=8--CS MASTER för SPI gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP) pin=4--LED LIGHTS ON LOW gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio. LOW) print(string.len(payload)) page_count = 7 -- skriv 1 kilobyte för k =0 ,page_count ,1 do--antal sidor för i=0 , 127, 2 do-- -1 adress = i/ 2 data=nyttolast:byte(i+1+128*k) om data == noll då data = 0xff slut InstrStorePAGE(0x40,adress,data) -- tmr.delay(100)-- annars inte i tid skriva data = nyttolast:byte(i+1+1+128*k) om data == noll då data = 0xff end InstrStorePAGE(0x48,adress,data) -- tmr.delay(100) end page_address_low=bit.band(k ,3 )*64 -- 3 är binär 11 page_address_high=k/4+frame1024*2 tmr.delay(1000) InstrWriteFLASH(page_address_low,page_address_high) tmr.wdclr() end pin=4--LED gpio.mode(pin, gpio.mode.(pin) OUTPUT) gpio.write(pin, gpio.HIGH) slut --HUVUDBLOCK wifi.setmode(wifi.STATION) --wifi.sta.config("nätverksnamn","lösenord") -- ställ in SSID och lösenord för din åtkomstpunkt station_cfg=() tmr.delay(30000) station_cfg.ssid=" nätverksnamn" tmr.delay(30000) station_cfg.pwd="lösenord" tmr.delay(30000) wifi.sta.config(station_cfg) tmr.delay(30000) wifi.sta.connect() tmr.delay(1000000) print (wifi.sta.status()) print(wifi.sta.getip()) while (wifi.sta.status()~=1) do if(wifi.sta.status()==5) then break end end sv=net.createServer(net.TCP,30) tmr.delay(100) print("SERVER READY") sv:listen(4000,function(c) c:on("receive", function(c, payload) print (nyttolast) if (nyttolast =="program\r\n") sedan c:send("ready\r\n") print("redo för program\r\n") spi.setup(1, spi.MASTER , spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8,320,spi.FULLDUPLEX) ProgrammingEnable () tmr.delay(100) InstrProgrammingEnable () tmr.delay(100) InstrFlashErase() tmr02)=frame(10004) -antal frames skickade st=net.createServer(net.TCP,30) st:listen(4001,function(c) c:on("receive" , function(c, payload) tmr.wdclr() Programmering (nyttolast) frame1024=frame1024+1 end) end) end if (nyttolast =="data\r\n") sedan c:send("ready\r\n ") print("redo för data\r\n") srv=net.createServer(net.UDP) tmr.delay(1000) pin=10 gpio.write(pin, gpio.HIGH) uart.setup(0.9600 ,8 ,0,1,0) srv:listen(5000) srv:on("receive", function(srv, pl) pl=pl*1 --print(pl) uart.write(0,pl) tmr. wdclr( ) end) end if (nyttolast =="stopp\r\n") sedan if(st~=nil) then st:close() frame1024=0 ProgrammeringDisable () print("stopp program") end if(srv ~= noll) sedan srv:close() print("stopp data") end end end) end) end)


Där motsvarande funktioner gör följande:

function InstrProgrammingEnable()- sätter mikrokontrollern i programmeringsläge med ett speciellt kommando skickat via SPI.

funktion ProgrammeringEnable()– återställ bara AVR i 25ms innan programmering

functionProgrammingDisable()- efter programmering överför vi SPI-stiften i ESP8266 till ett inaktivt tillstånd så att de inte stör oss när vi kör kod på mikrokontrollern (plötsligt används de där)

funktion InstrFlashErase()- skriv över flashminnet på mikrokontrollern innan du börjar programmera. Varför detta behöver förklaras är inte nödvändigt.

funktion InstrStorePAGE(H, adress, data)- med detta kommando skrivs en programbyte till den interna bufferten i mikrokontrollern. Men detta är inte själva flashrekordet, eftersom flashen skrivs här sidan med 128 byte.

funktion InstrWriteFLASH(page_address_low, page_address_high)- men det här är en blixtinspelning och det tar tid, var uppmärksam på tidsfördröjningen på 5 000 µs.

funktion Programmering (nyttolast)- den största och viktigaste funktionen med ovanstående funktioner. Den tar det överförda programmet i bitar om 1024 byte, delar upp dem i byte och bildar adresser för dem, och skickar dem sedan till mikrokontrollern i den interna bufferten och initierar flashskrivningen var 128:e byte. Sedan tar han nästa kilobyte kod och upprepar operationen, naturligtvis med en offset i adresserna, för att skriva vidare och inte skriva över det som skrevs. Först försökte jag skicka hela program, men om ESP8266 överstiger 6 kilobyte slutar det tillgängliga minnet helt enkelt och det kraschar. En kilobyte visade sig vara den mest bekväma enheten, eftersom den är snyggt uppdelad i delar och bekvämt överförd via TCP (vi behöver fortfarande få den från datorn). En större storlek behövs inte heller, TCP, ni vet, i den nuvarande versionen begränsar det överförda paketet, till 1500 byte eller något (men av någon anledning överförde jag 1440, typ).

Hur svårt det än är, men några fallgropar måste övervinnas.

Vi registrerar oss i ett trådlöst nätverk.

Vi skapar först en TCP-server som lyssnar efter tre kommandon:

1. "program" (vi kommer att programmera),

2. "data" (vi kommer att utbyta data),

3. "stoppa" (vi stoppar allt).

Om vi ​​programmerar, initialiserar vi först SPI och skapar en annan TCP-server som tar data (koden för programmet som blinkar) per kilobyte och anropar mikrokontrollerns programmeringsfunktioner för dem. Jag förstår att det ser dumt ut att skapa en andra server, men detta är en nödvändighet, eftersom det lokala API:et stöder skapandet av endast en socket, och vi måste separera kommandona "program" och "data" med själva överförda data, eftersom de inte skiljer sig från ögat, det finns byte och byte här.

Om vi ​​inte vill programmera, utan utbyta data, skicka dem i vårt fall till mikrokontrollern, skickar vi först strängen "data" via TCP. Som svar på detta kommer en UDP-server redan att skapas (jag påminner dig om att vi styr dynamiskt med en mekanisk hand och vi behöver inte förseningar i bildandet av TCP-paket, och skickar faktiskt en byte som en hel TCP-ram dåligt uppförande ). Och UDP-datagram kommer att vara små och kommer att bildas snabbt.

Därefter initieras UART, och varje byte som tas emot trådlöst skickas via TXD-tråden till mikrokontrollern, som är skyldig att acceptera den om motsvarande program blinkar där. Det är inte heller svårt att organisera datautbytet åt andra hållet, men jag har inte implementerat det ännu.

Tja, vid "stopp"-kommandot stänger de ovan nämnda servrarna (förutom den allra första) anslutningarna och den viktigaste servern går igen in i tillståndet att vänta på kommandona "program" och "data".

Eftersom SPI-gränssnittet är programmatiskt emulerat i ESP8266, kan du använda alla I/O-portar för CS, CLK, MISO, MOSI, RESET-signaler (för AVR) tillgängliga, och inte de som anges i min bootloader. Dessutom visade det sig att CS och MISO i princip också kan skäras av i det här fallet, det kommer att fungera utan dem. Tja, en utgång används på lysdioden som är inbyggd i ESP8266-kortet, så att den blinkar ibland och visar att programmet fortfarande lever.

Det finns inga kontroller för skrivfel (förutom den första begäran till AVR, men denna information visas helt enkelt på konsolen), EEPROM är inte programmerat, mer än 32 KB är inte sytt - kort sagt, det finns fortfarande något att fungera på. SPI-växelkursen är cirka 115 Kbps, allt blinkar på några sekunder, ungefär som en konventionell seriell programmerare som ISP500).

Ta koden, ange dina nätverk och lösenord, kompilera på ESplorer, kalla den "init" (för att köras vid omstart) och skicka den till ESP8266. Borde fungera. I bemärkelsen att arbeta som trådlös programmerare, åtminstone.

Nu ska vi ta itu med kontrollsidan - en persondator.

Faktum är att vi måste ta HEX-filen som dina program skrivna i ATMEL STUDIO-miljön förvandlas till och skicka den via WI-FI till den socketport vi känner till (i det här fallet 4000). Den lilla haken är att vi behöver en binär BIN-fil för att skicka, och ATMEL STUDIO behagar oss bara med HEX. Här finns två utgångar; eller konvertera det till BIN-format med ett speciellt omvandlingsprogram, som WinHex, eller gör det själv i ditt program. Jag har inte gjort det än, men det verkar inte vara svårt, du måste skära av titeln och göra något annat.

Som ett resultat skrev jag loader-programmet i JAVA (främst för att jag inte vet hur man gör något annat), och arbetade i den helt enkelt vackra och fria IntelliJ IDEA-miljön. Den skapar en TCP-klient som letar efter en server som körs på ESP8266. Om den hittar den kontaktar den den och skickar en fil som finns på en sådan och en sådan adress. Kod nedan.

JAVA-filuppladdningsprogrammet körs på PC-sidan

importera java.io.*; importera java.net.*; importera java.util.ArrayList; importera java.util.List; offentlig klass Net( public static void main(String args) (new Http_client(4000);)) class Http_client extends Thread ( int port; String s; String Greetings_from_S; Http_client(int port)( this.port = port; start(); ) public void run() ( //192.168.1.113 är ESP8266-adressen i mitt nätverk Men i allmänhet lär man sig från kommunikation med routern // det är bättre att göra det statiskt, routrar kan göra detta försök (Socket socket = new Socket("192.168.1.113", port)) ( PrintWriter pw = new PrintWriter( new OutputStreamWriter(socket.getOutputStream( )),true); pw.println("program");// Hälsningar med SERVER System.out.println("program"); ​​​​BufferedReader br = new BufferedReader(ny InputStreamReader(socket) .getInputStream())); Greetings_from_S = br.readLine(); System.out.println(Greetings_from_S); if(Greetings_from_S.equals("ready")) (försök ( File file = new File("d:BlinkOUT.bin ");// adress till filen att ladda upp BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fil)); byte data = new byte; bis.read(data); byte data_buffer = new byte; int frames = data.length/1024 ; Syste m.out.println(ramar); int residence = data.length%1024; för (int i = 0; i< frames;i++) { for (int k = 0; k< (1024); k++) { data_buffer[k] = data; } sendingChunk(data_buffer); } byte data_buffer2= new byte; for (int i = 0; i < residy;i++) { data_buffer2[i] = data; } sendingChunk(data_buffer2); pw.println("stop");// System.out.println("stop program"); } catch (Exception e) { System.out.println(e); } } } catch (Exception e) { System.out.println(e); } } public void sendingChunk (byte data_buffer){ try (Socket socket = new Socket("192.168.1.113", 4001)){ BufferedOutputStream bos = new BufferedOutputStream((socket.getOutputStream())); bos.write(data_buffer); bos.flush(); System.out.println(data_buffer.length); } catch (Exception e) { System.out.println(e); } } }


Här avvecklas naturligtvis överflödiga grejer, alla möjliga färdiga behövs i princip inte. Om en TCP-anslutning upprättas, så upprättas den. Det enda problemet var att filen inte ville skickas i jämna bitar av 1024 byte, som jag verkligen behövde, även om jag uttryckligen angav storleken. Tydligen finns det någon slutbuffert oåtkomlig från JAVA, och den skickar paket i den storlek den vill ha, vilket är helt oacceptabelt för den mottagande sidan. Först försökte jag göra en fördröjning så att bufferten tröttnade på att vänta på nästa bitar och skickade den som den är. Men fördröjningen började fungera när den nådde 10 sekunder, vilket på något sätt tycktes mig vara lite för mycket för en överförd kilobyte.

Men så märkte jag att det första stycket av någon anledning alltid går precis som beställt, och en oförutsägbar bacchanalia börjar från den andra. Därför gjorde jag det så att klienten öppnade en anslutning, skickade en del av koden i 1024 byte och stängde anslutningen. Och så vidare tills hela filen skickas. Allt fungerade framgångsrikt.

Det enda är att du behöver installera JAVA runtime-miljön på din dator för att köra den. Men jag brukar börja direkt från IntelliJ IDEA för där kan man alltid se vad som händer i konsolen (men här behövs även JAVA-miljön). Även om du naturligtvis på ett smart sätt behöver göra ett GUI. Det vill säga ett fönster där sökvägen till filen faller ut, möjligheten att ändra portnummer i samma fönster och, ja, och andra nödvändiga saker. Och samla allt detta i form av en körbar fil.

Och tapericha, som Koroviev brukade säga, låt oss faktiskt återvända medborgarna till den mekaniska delen av MechArm, som nämndes i början. Vi har nu möjlighet att fjärrprogrammera den och sedan styra den. Låt oss gå vidare till kontrollprogrammet på sidan av mikrokontrollern.

I det här fallet måste vi kontrollera fyra servon. Dessa är.


En sådan drivning styrs av rektangulära pulser, period 20 ms (50 Hz) med en arbetscykel på 2 till 4 procent. Det vill säga, 2 % är en hel varv åt ena hållet, 4 % åt den andra. Uppgiften är bara för den inbyggda PWM i AVR.

En servo används för höger-vänster rörelse; den andra på dig själv - från dig själv; tredje upp-ned; den fjärde är själva klon, som måste komprimeras och frigöras. Allt är skrivet i C och kompilerat till en HEX-fil i ATMEL STUDIO. Ett lite konstigt utseende av programmet beror på det faktum att handen från början styrdes från ett tangentbord som var bundet med sladdar till mikrokontrollern. Men trådarna är igår, vi måste utvecklas ytterligare.

Man kan givetvis använda skisser till servon från "ARDUINO", men jag gillade dem inte. Det är roligare att skriva på egen hand. Dessutom måste alla fyra servon arbeta samtidigt, och inte i multiplexerat läge, när PWM växlas till varje servo i tur och ordning. För ingen har avbrutit gravitationen och den upplyfta lemmet kommer omedelbart att falla om kontrollimpulser slutar ta emot kontrollimpulser till motsvarande servo. Jag är inte säker på om "ARDUINO"-skissen ger samtidig drift för fyra servon. Men vi kan själva skriva ett program som uppfyller de nödvändiga kraven. Och i allmänhet, i avsaknad av ett operativsystem som skiljer fåren från getterna, är användningen av skisser som tävlar om kringutrustning för mikrokontroller (och vi vet inte ens i förväg vilka) för buggproducerande.

Här är den faktiska koden som vi skriver till Arduino Nano med ESP8266-07.

MechArm styrprogram för AVRmega328P mikrokontroller

#define F_CPU 16000000 #inkludera #omfatta // standardheltal #inkludera #omfatta // matematik #inkludera //standard I/O #inkludera #omfatta #omfatta //standardfunktioner #define UART_BAUD_RATE 115200 // räknare T1 ställer in ett tidsintervall på 20ms #define COUNTER1_OFF TCCR1B=0b00000000 // CS02 CS01 CS00 - 000 - inaktiverad; 001 utan avdelare; 010 med divisor 8; 011-64; 100-256; 101 -1024 #define COUNTER1_ON TCCR1B=0b00000011 // räknare T0 ställer in styrpulsbredden för PB0 och PB1 servon #define COUNTER0_OFF TCCR0B=0b00000000 // CS02 CS01 0CS000 -d disable; 001 utan avdelare; 010 med divisor 8; 011-64; 100-256; 101 -1024 #define COUNTER0_ON TCCR0B=0b00000100 // räknare T2 ställer in bredden på styrpulsen för servon PB2(PD6) och PB3(PD7) #define COUNTER2_OFF TCCR2B=0b00000CS000 -0d00000CS000 -0dable 1CS000; 001 utan avdelare; 010 med divisor 8; 011-64; 100-256; 101 -1024 #define COUNTER2_ON TCCR2B=0b00000110 volatile uint16_t period_20ms; flyktigt uint8_t State_of_keyboard; flyktig uint8_t startposition ; flyktigt int8_t nummer_servo; ISR(USART_RX_vect)// avbrott för UART ( State_of_keyboard=UDR0; retur; ) ISR(TIMER0_COMPA_vect)// servo PB0 styrpulsbredd ( PORTB &=~(1<<0); TIMSK0&=~(1<
Kärnan i programmet framgår tydligt av texten och kommentarerna. Vi använder T1-räknaren för en referensperiod på 20 ms och T0, T2-räknarna för att skicka PWM-signaler till fyra I/O-portlinjer, eftersom var och en av dessa två räknare kan fungera för två enheter.
Programmet ställer in de initiala positionerna för servon genom att ladda räkneregistren OCR0A, OCR0B, OCR2A, OCR2B. Begränsningskonstanter introduceras också, eftersom vi inte alltid behöver ett spännvidd på 180 grader. Tja, vidare, genom avbrott från UART, fångar programmet numret som skickas av ESP8266 (från 1 till 8) och översätter det till ett kommando för motsvarande servo. Det finns fyra enheter som var och en arbetar i två riktningar, så heltal från ett till åtta räcker. När väl ett nummer har valts, inkrementeras eller minskas innehållet i de förutnämnda räknarregistren, varvid pulscykeln för styrpulsen och rotationsvinkeln för det valda servo ändras. De enheter som vi inte valde behåller det gamla värdet för rotationsvinkeln (eftersom innehållet i motsvarande register, även om det uppdaterades, inte ändrades) och fortsätter att hålla den mekaniska armen i samma position.

Nu ska vi bara skriva ett styrprogram, förlåt för tautologin, för att styra den mekaniska armen direkt från datorn via WI-FI.
Koden är också skriven i JAVA, men lite förädlad. Det fanns ett GUI och möjligheten att redigera portnummer och nätverksadress för ESP8266.

Vad som händer där framgår av fönstret. Jag tillhandahåller inte texten till programmet här (den finns tillgänglig på

Jag har en enhet byggd med Arduino uno:

    Arduino-programvara installerad på Arduino uno

    kan styras av seriella kommandon

    Kan styras med fysiska knappar och sensorer

    när någon knapp/sensor ändras, skriver den det aktuella tillståndet till serien

    Om inget meddelande har skickats inom 5 sekunder skickas ett seriellt meddelande oförändrat

Vad behöver du:

    Använd ESP8266 för att skapa en brygga mellan nuvarande Arduino-mjukvara och MQTT/web

    Jag kan programmera ESP8266 som en webbserver, MQTT-klient etc. med Arduino IDE eller Lua (men jag föredrar Arduino IDE då jag kan återanvända delar av koden för att generera/tolka kommunikationen).

    ESP8266 kommer att hantera allt som krävs för wifi/webb/MQTT; utan MQTT-modulen kommer Arduino-delen att fungera autonomt, bara fjärrkontrollen kommer att saknas.

    Jag skulle vilja göra minimala ändringar i Arduino-koden (eller inga om möjligt). Alla ändringar kommer att kräva omfattande omtestning, vilket jag försöker undvika.

    ESP8266 kanske inte är tillgänglig i vissa installationer.

Vilka alternativ hittade jag:

    <�Литий>Konsekvent

ESP8266 kan läsa seriell utdata och vara en brygga mellan nätverk/MQTT och seriell, kommer att lagra det aktuella tillståndet i minnet för att skickas på begäran för att undvika polling av enheten varje gång.

En av fördelarna är att inga kodändringar/testning krävs för Arduino-delen.

Gör Arduino till en I2C-master och ESP8266-slav (eller vice versa) och implementera dubbelriktad kommunikation. Fick denna idé genom att läsa denna tråd.

Annan information om seriella kommandon:

Ett datapaket (kommando eller tillståndsbeskrivning) består av 1-20 tecken med en möjlig topp på 20 paket på 5 sekunder och i genomsnitt ett paket var 3:e sekund. Om det behövs kan jag få detta att skicka 5 osignerade heltal istället för alfanumeriska tecken.

Om fler än I2C/seriella stift krävs kan jag uppgradera till en Arduino Mega (så antalet lediga stift är inget problem).

Finns det andra alternativ för detta? (protokoll, standardbibliotek för seriell kommunikation, etc.). Jag försöker att inte uppfinna hjulet på nytt.

Tack för din tid!

3

1 svar

De flesta I2C-tutorials gjorde varje Arduino till en slav och en master, men detta är bättre eftersom varje Arduino antingen är en master eller en slav (inte båda) och ingen växling krävs. Detta gör saker lättare.

I2C är bättre än seriell eftersom du kan lägga till fler Arduinos till samma buss.

Jag har implementerat I2C mellan två Arduinos och det är inte svårare än att läsa/skriva till en seriell port (vilket du redan gjort). Och jag är säker på att du kan generalisera din seriella portkod för att fungera med både seriell och I2C-kommunikation.

Detta är mitt exempel (bara ett proof of concept). Slave Arduino styr några stift, temp. sensor och watchdog timer på order av master Arduino. Om slaven inte tar emot en bit i tid återställer den Arduino-mastern.

Masterkod

#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; kolbuffert; void setup() ( Serial.begin(9600); Serial.println("Master"); Wire.begin(); pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); delay(1000); digitalWrite(LED, LÅG); Wire.beginTransmission(SLAVE_ADRESS); Serial.println("Skicka LED på"); Wire.write(CMD_PIN_ON); Wire.write(2); Wire.write(10); Wire.endTransmission(); int x = Wire.requestFrom(SLAVE_ADDRESS, 1); Serial.print("status="); Serial.println(x); ) //slutet på installationens void loop () ( Serial.println("."); Wire.beginTransmission (SLAVE_ADRESS); Wire.write(CMD_SENSOR); Wire.endTransmission(); int x = Wire.requestFrom(SLAVE_ADDRESS, 1); Serial.print("Disponibles = "); Serial.println(x); int temp = ( int) Wire.read(); Serial.println(temp); Wire.beginTransmission(SLAVE_ADDRESS); Wire.write(CMD_LUMEN); Wire.endTransmission(); Wire.requestFrom(SLAVE_ADDRESS, 2); int light = Wire.read ()<< 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

driven kod

/* Esclavo I2C Recibe los suientes 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 comando 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 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/tiempa ST_BAD_LEN_2AD/tiempa Pasado // ese tiempo, se aktivera el PIN_RESET. // En milisegundos. #define BEAT_INTERVAL 10000 osignerad long lastBeat; // Largo del reset en milisegundos. #define RESET_LENGTH 250 byte cmd = 0; byte status = 0; int thermoDO = 11; int thermoCS = 12; int thermoCLK = 13; MAX6675 termoelement (thermoCLK, thermoCS, thermoDO); void setup () ( Serial.begin(9600); pinMode(PIN_LUMEN, INPUT); analogRead(PIN_LUMEN); för (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. för (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); ha sönder; fall CMD_PIN_ON: fall CMD_PIN_OFF: fall CMD_BEAT: Wire.write(status); status = ST_OK; ha sönder; ) cmd = 0; ) // anropas av avbrottstjänstrutin när inkommande data anländer 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(); break; ) ) //end of receiveEvent void cmdPinOff() ( if (Wire.available() != 1) ( status = ST_BAD_LEN; ) else ( int pin = Wire.read(); int i = searchPin(pin); if (i< 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); Serial.print("pin="); Serial.print(pin); Serial.print(",index="); Serial.println(i); if (i< 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"); } } } }

En COM-port används oftast för att ansluta mikrokontrollern till en dator. I den här artikeln kommer vi att visa hur man skickar kontrollkommandon från en dator och skickar data från en kontroller.

Förberedelse för arbete

De flesta mikrokontroller har flera I/O-portar. UART-protokollet är det mest lämpliga för kommunikation med en PC. Det är ett seriellt asynkront dataöverföringsprotokoll. För att konvertera det till ett USB-gränssnitt har kortet en USB-RS232-omvandlare - FT232RL.
Du behöver bara ett Arduino-kompatibelt kort för att köra exemplen i den här artikeln. Vi använder . Se till att ditt kort har en lysdiod ansluten till stift 13 och en återställningsknapp.

Låt oss till exempel ladda upp en kod till kortet som visar en ASCII-tabell. ASCII är en kodning för att representera decimalsiffror, latinska och nationella alfabet, skiljetecken och kontrolltecken.

int symbol = 33 ; void setup() ( Serial. begin(9600 ) ; Serial. println(" ASCII Table ~ Character Map " ); ) void loop() ( Serial. write(symbol) ; Serial. print(" , dec: " ) ; Serial .print(symbol) ; Serial.print(" , hex: " ) ; Serial.print(symbol, HEX) ; Serial.print(" , okt: " ) ; Serial.print(symbol, OCT) ; Serial.print( " , bin: " ; Serial.println(symbol, BIN) ; if (symbol == 126 ) ( medan (sant) (fortsätt ; ) ) symbol+ + ; )

Symbolvariabeln lagrar symbolkoden. Bordet börjar vid 33 och slutar vid 126, så symbolen är initialt satt till 33.
För att starta driften av UART-porten, använd funktionen Serial.begin(). Dess enda parameter är hastighet. Hastigheten måste förhandlas på sändnings- och mottagningssidan i förväg, eftersom överföringsprotokollet är asynkront. I det här exemplet är hastigheten 9600 bps.
Tre funktioner används för att skriva ett värde till en port:

  1. Serial.write()– skriver data till porten i binär form.
  2. Serial.print() kan ha många värden, men alla tjänar till att visa information i en människovänlig form. Till exempel, om informationen som anges som en parameter som ska skickas är omgiven av citattecken, kommer terminalprogrammet att visa den oförändrad. Om du vill visa något värde i ett visst talsystem måste du lägga till ett serviceord: BIN-binär, OCT - oktal, DEC - decimal, HEX - hexadecimal. Till exempel, Serial.print(25,HEX).
  3. Serial.println() gör samma sak som Serial.print(), men översätter fortfarande strängen efter att ha visat informationen.

För att kontrollera programmets funktion är det nödvändigt att datorn har ett terminalprogram som tar emot data från COM-porten. Arduino IDE har redan en inbyggd. För att kalla det, välj Verktyg->Portövervakning från menyn. Fönstret för detta verktyg är mycket enkelt:

Klicka nu på omstartsknappen. MK kommer att starta om och visa ASCII-tabellen:

Var uppmärksam på den här delen av koden:

if (symbol = = 126 ) ( medan (sant) ( fortsätt ; ) )

Det stoppar körningen av programmet. Om du utesluter det kommer tabellen att visas på obestämd tid.
För att befästa kunskapen du fått, försök att skriva en oändlig loop som skickar ditt namn till serieporten en gång i sekunden. Lägg till stegnummer till utgången och glöm inte att översätta raden efter namnet.

Skicka kommandon från PC

Innan du gör detta måste du få en uppfattning om hur en COM-port fungerar.
Först och främst sker allt utbyte genom minnesbufferten. Det vill säga när du skickar något från en PC till en enhet placeras data i någon speciell del av minnet. Så snart enheten är klar läser den data från bufferten. Funktionen låter dig kontrollera buffertens tillstånd serial.avaliable(). Denna funktion returnerar antalet byte i bufferten. För att subtrahera dessa byte måste du använda funktionen Serial.read(). Låt oss se hur dessa funktioner fungerar med ett exempel:

int val = 0; void setup() ( Serial. begin(9600 ) ; ) void loop() ( if (Serial. available() > 0 ) ( val = Serial. read() ; Serial. print(" Jag fick: " ); Seriell. write(val); Serial.println() ; ) )

Öppna COM-portmonitorn efter att koden har laddats in i mikrokontrollerns minne. Skriv ett tecken och tryck på Enter. I det mottagna datafältet ser du: "Jag fick:X", var istället för X kommer att vara det tecken du skrev in.
Programmet snurrar oändligt i huvudslingan. I det ögonblick när en byte skrivs till porten tar funktionen Serial.available() värdet 1, det vill säga villkoret är uppfyllt Serial.available() > 0. Nästa funktion Serial.read() läser denna byte och rensar därigenom bufferten. Efter det, med de funktioner som redan är kända för dig, sker utmatningen.
Att använda Arduino IDE:s inbyggda COM-portmonitor har vissa begränsningar. När data skickas från kortet till COM-porten kan utdata organiseras i ett godtyckligt format. Och när du skickar från datorn till kortet sker överföringen av tecken i enlighet med ASCII-tabellen. Det betyder att när du till exempel anger tecknet "1", skickas det binära "00110001" (det vill säga "49" i decimal) genom COM-porten.
Låt oss ändra koden lite och kontrollera detta uttalande:

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

Efter nedladdning, i portmonitorn när du skickar "1", kommer du att se som svar: "Jag fick: 110001". Du kan ändra utdataformatet och se vad tavlan accepterar med andra tecken.

Enhetskontroll via COM-port

Uppenbarligen, med kommandon från en PC, kan du styra alla funktioner på mikrokontrollern. Ladda ner programmet som styr driften av lysdioden:

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

När "H"-tecknet skickas till COM-porten tänds lysdioden på den 13:e utgången och när "L" skickas slocknar lysdioden.
Om du, baserat på resultaten av att ta emot data från COM-porten, vill att programmet ska utföra olika åtgärder i huvudslingan, kan du kontrollera villkoren i huvudslingan. Till exempel.