MATLAB Language
Använda seriella portar
Sök…
Introduktion
Seriella portar är ett vanligt gränssnitt för kommunikation med externa sensorer eller inbäddade system som Arduinos. Modern seriell kommunikation implementeras ofta via USB-anslutningar med hjälp av USB-seriella adaptrar. MATLAB tillhandahåller inbyggda funktioner för seriell kommunikation, inklusive RS-232 och RS-485-protokoll. Dessa funktioner kan användas för seriella portar för hårdvara eller "virtuella" USB-seriella anslutningar. Exemplen här illustrerar seriell kommunikation i MATLAB.
parametrar
Seriell portparameter | vad den gör |
---|---|
BaudRate | Ställer in baudraten. Det vanligaste idag är 57600, men 4800, 9600 och 115200 ses ofta också |
InputBufferSize | Antalet byte som finns i minnet. Matlab har en FIFO, vilket innebär att nya byte kommer att kasseras. Standardvärdet är 512 byte, men det kan enkelt ställas in på 20 MB utan problem. Det finns bara några få fall där användaren vill att det ska vara litet |
BytesAvailable | Antalet byte som väntar på att läsas |
ValuesSent | Antalet byte som skickats sedan porten öppnades |
ValuesReceived | Antalet byte som lästes sedan porten öppnades |
BytesAvailableFcn | Ange återuppringningsfunktionen som ska köras när ett specificerat antal byte är tillgängligt i ingångsbufferten eller en terminator läses |
BytesAvailableFcnCount | Ange antalet byte som måste finnas tillgängligt i inmatningsbufferten för att generera en bytes-available händelse |
BytesAvailableFcnMode | Ange om den bytes-available händelsen genereras efter att ett specificerat antal byte är tillgängligt i ingångsbufferten eller efter att en terminator har lästs |
Skapa en seriell port på Mac / Linux / Windows
% Define serial port with a baud rate of 115200
rate = 115200;
if ispc
s = serial('COM1', 'BaudRate',rate);
elseif ismac
% Note that on OSX the serial device is uniquely enumerated. You will
% have to look at /dev/tty.* to discover the exact signature of your
% serial device
s = serial('/dev/tty.usbserial-A104VFT7', 'BaudRate',rate);
elseif isunix
s = serial('/dev/ttyusb0', 'BaudRate',rate);
end
% Set the input buffer size to 1,000,000 bytes (default: 512 bytes).
s.InputBufferSize = 1000000;
% Open serial port
fopen(s);
Läser från serieporten
Förutsatt att du skapade den seriella porten objektet s
som i detta exempel, då
% Read one byte
data = fread(s, 1);
% Read all the bytes, version 1
data = fread(s);
% Read all the bytes, version 2
data = fread(s, s.BytesAvailable);
% Close the serial port
fclose(s);
Stänga en serieport även om den går förlorad, raderad eller överskriven
Förutsatt att du skapade den seriella porten objektet s
som i detta exempel, för att sedan stänga den
fclose(s)
Men ibland kan du av misstag förlora porten (t.ex. rensa, skriva över, ändra omfattning osv ...), och fclose(s)
fungerar inte längre. Lösningen är enkel
fclose(instrfindall)
Mer info på instrfindall()
.
Skriva till serieporten
Förutsatt att du skapade den seriella porten objektet s
som i detta exempel, då
% Write one byte
fwrite(s, 255);
% Write one 16-bit signed integer
fwrite(s, 32767, 'int16');
% Write an array of unsigned 8-bit integers
fwrite(s,[48 49 50],'uchar');
% Close the serial port
fclose(s);
Välja ditt kommunikationsläge
Matlab stöder synkron och asynkron kommunikation med en seriell port. Det är viktigt att välja rätt kommunikationsläge. Valet beror på:
- hur instrumentet du kommunicerar med uppför sig.
- vilka andra funktioner ditt huvudprogram (eller GUI) kommer att göra förutom att hantera serieporten.
Jag ska definiera tre olika fall att illustrera, från de enklaste till de mest krävande. För de tre exemplen är instrumentet jag ansluter till ett kretskort med en lutningsmätare, som kan fungera i de tre lägena som jag kommer att beskriva nedan.
Läge 1: Synkron (Master / Slave)
Det här läget är det enklaste. Det motsvarar fallet där datorn är mästaren och instrumentet är slaven . Instrumentet skickar inte något till den seriella porten på egen hand, det svarar bara ett svar efter att ha ställt en fråga / kommando av Master (datorn, ditt program). Till exempel:
- PC: n skickar ett kommando: "Ge mig en mätning nu"
- Instrumentet tar emot kommandot, tar mätningen och skickar sedan tillbaka mätvärdet till den seriella linjen: "Lutningsvärdet är XXX".
ELLER
- PC: n skickar ett kommando: "Ändra från läge X till läge Y"
- Instrumentet tar emot kommandot, kör det och skickar sedan ett bekräftelsemeddelande tillbaka till serielinjen: " Kommando utförd " (eller " Kommando INTE utförd "). Detta kallas vanligtvis ett ACK / NACK-svar (för "Acknowledge (d)" / "NOT Acknowledged").
Sammanfattning: i detta läge skickar instrumentet ( slaven ) bara data till serielinjen omedelbart efter att ha blivit frågad av PC ( Master )
Läge 2: Asynkron
Anta nu att jag startade mitt instrument, men det är mer än bara en dum sensor. Den övervakar ständigt sin egen lutning och så länge den är vertikal (inom en tolerans, låt oss säga +/- 15 grader), förblir den tyst. Om enheten lutas mer än 15 grader och kommer nära horisontellt skickar den ett larmmeddelande till serielinjen, omedelbart följt av en avläsning av lutningen. Så länge lutningen är över tröskeln fortsätter den att skicka en lutning varje 5: e.
Om ditt huvudprogram (eller GUI) ständigt "väntar" på meddelanden som kommer på serielinjen, kan det göra det bra ... men det kan inte göra något annat under tiden. Om huvudprogrammet är ett GUI, är det mycket frustrerande att ha ett GUI som till synes "fryst" eftersom det inte accepterar någon input från användaren. I huvudsak blev det slaven och instrumentet är mästaren . Såvida du inte har ett fint sätt att kontrollera din GUI från instrumentet, är detta något att undvika. Lyckligtvis låter det asynkrona kommunikationsläget dig:
- definiera en separat funktion som berättar ditt program vad du ska göra när ett meddelande tas emot
- hålla den här funktionen i ett hörn, den kommer bara att ringas och köras när ett meddelande kommer på serielinjen. Resten av tiden kan GUI köra alla andra koder som den måste köra.
Sammanfattning: I detta läge kan instrumentet skicka meddelande till serielinjen när som helst (men inte nödvändigtvis hela tiden). Datorn väntar inte permanent på att ett meddelande ska behandlas. Det är tillåtet att köra annan kod. Först när ett meddelande anländer aktiveras det en funktion som sedan kommer att läsa och behandla detta meddelande.
Läge 3: Streaming ( realtid )
Låt oss nu släppa loss hela kraften i mitt instrument. Jag sätter det i ett läge där det ständigt skickar mätningar till serielinjen. Mitt program vill ta emot dessa paket och visa det på en kurva eller en digital skärm. Om det bara skickar ett värde var femte sekund som ovan, inget problem, behåll ovanstående läge. Men mitt instrument vid fullständigt skick skickar en datapunkt till serielinjen på 1000Hz, dvs det skickar ett nytt värde varje millisekund. Om jag stannar i det asynkrona läget som beskrivs ovan finns det en hög risk (faktiskt en garanterad säkerhet) att den speciella funktionen vi definierade för att bearbeta varje nytt paket tar mer än 1 ms att utföra (om du vill plotta eller visa värdet, grafiska funktioner är ganska långsamma, inte ens med tanke på filtrering eller FFT-signal). Det betyder att funktionen kommer att börja köra, men innan den är klar kommer ett nytt paket att anlända och utlösa funktionen igen. Den andra funktionen placeras i en kö för exekvering och startar först när den första är klar ... men vid denna tid ankom några nya paket och var och en placerade en funktion för att köra i kön. Du kan snabbt förutse resultatet: När jag planerar de femte poängen har jag redan hundratals som väntar på att bli planerad också ... Gujan bromsar ner, så småningom fryser, stacken växer, buffertarna fylls upp tills något ger. Så småningom sitter du kvar med ett helt fruset program eller helt enkelt ett kraschat.
För att övervinna detta kommer vi att ytterligare koppla bort synkroniseringslänken mellan PC och instrument. Vi låter instrumentet skicka data i sin egen takt, utan att omedelbart utlösa en funktion vid varje paket ankomst. Seriell portbuffert samlar bara de mottagna paketen. PC: n samlar bara in data i bufferten i en takt som den kan hantera (ett regelbundet intervall, inställt på PC-sidan), gör något med det (medan bufferten fylls på igen av instrumentet) och samlar sedan en ny sats med data från bufferten ... och så vidare.
Sammanfattning: I detta läge skickar instrumentet data kontinuerligt, som samlas in av den seriella portbufferten. Med regelbundet intervall samlar datorn in data från bufferten och gör något med den. Det finns ingen hård synkroniseringslänk mellan datorn och instrumentet. Båda utför sina uppgifter på egen tidpunkt.
Bearbeta data som mottas från en serieport automatiskt
Vissa enheter anslutna via en seriell port skickar data till ditt program i en konstant hastighet (strömningsdata) eller skickar data med oförutsägbara intervaller. Du kan konfigurera den seriella porten så att den kör automatiskt för att hantera data när den anländer. Detta kallas "återuppringningsfunktionen" för det seriella portobjektet.
Det finns två egenskaper för den seriella porten som måste ställas in för att använda den här funktionen: namnet på den funktion du vill ha för återuppringning ( BytesAvailableFcn
) och villkoret som bör utlösa exekvering av återuppringningsfunktionen ( BytesAvailableFcnMode
).
Det finns två sätt att utlösa en återuppringningsfunktion:
- När ett visst antal byte har tagits emot i serieporten (vanligtvis används för binär data)
- När ett visst tecken tas emot i serieporten (vanligtvis används för text- eller ASCII-data)
Återuppringningsfunktioner har två obligatoriska inmatningsargument, kallad obj
och event
. obj
är den seriella porten. Om du till exempel vill skriva ut de data som mottagits från den seriella porten, definierar du en funktion för att skriva ut de data som heter newdata
:
function newdata(obj,event)
[d,c] = fread(obj); % get the data from the serial port
% Note: for ASCII data, use fscanf(obj) to return characters instead of binary values
fprintf(1,'Received %d bytes\n',c);
disp(d)
end
Konfigurera den seriella porten så här om du newdata
utföra newdata
funktionen när 64 byte newdata
emot:
s = serial(port_name);
s.BytesAvailableFcnMode = 'byte';
s.BytesAvailableFcnCount = 64;
s.BytesAvailableFcn = @newdata;
Med text- eller ASCII-data delas uppgifterna vanligtvis upp i rader med ett "terminatortecken", precis som text på en sida. För att utföra newdata
funktionen när vagnens newdata
emot konfigurerar du seriellporten så här:
s = serial(port_name);
s.BytesAvailableFcnMode = 'terminator';
s.Terminator = 'CR'; % the carriage return, ASCII code 13
s.BytesAvailableFcn = @newdata;