87
UNIVERZITET U SARAJEVU ELEKTORTEHNIČKI FAKULTET SARAJEVO Akvizicija podataka pomoću modula Arduino UNO u okviru Matlab okruženja - Završni rad - Mentor: Student: Doc. dr Samim Konjicija Marko Lalić

Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Embed Size (px)

DESCRIPTION

The thesis describes a system which allows an Arduino board to be used as a low-cost data acquisition device, complete with integration with the MATLAB DAQ toolkit. The thesis is written in Bosnian.

Citation preview

Page 1: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

UNIVERZITET U SARAJEVUELEKTORTEHNIČKI FAKULTET SARAJEVO

Akvizicija podataka pomoću modula Arduino UNO u okviru

Matlab okruženja- Završni rad -

Mentor: Student:Doc. dr Samim Konjicija Marko Lalić

Page 2: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Sažetak

Data Acquisition Toolbox je dio MATLAB-a koji omogućava korištenje uređaja za akviziciju podataka. Pomoću posebnih DLL-ova, korisnici mogu proširiti mogućnosti toolboxa tako da omoguće uređaje koji nisu podržani. Arduino uređaji imaju programabilan mikroprocesor sa mogućnosti analognog i digitalnog ulaza i izlaza. U ovom radu je predstavljen sistem koji pretvara Arduino uređaj u uređaj za akviziciju podataka i omogućava MATLAB-u njegovo korištenje pomoću Data Acquisition Toolboxa. Sistem se sastoji od četiri komponente: program za Arduino, servis za pristup funkcijama Arduino uređaja, već pomenuti DLL za toolbox i GUI aplikacija za upravljanje uređajima. Demonstracija akvizicije analognog signala i analognog izlaza koristeći ovaj sistem je također predstavljena u radu.

Abstract

Data Acquisition Toolbox is a part of MATLAB which enables the use of data acquisition hardware devices. Through custom DLLs, users can extend the toolbox to enable devices not supported by default. Arduino devices feature a programmable microprocessor with analog and digital input/output capabilities. A system which turns the Arduino board into a data acquisition device, complete with MATLAB Data Acquisition Toolbox integration, is presented in this paper. The system is made of four components: a program for the Arduino, a service for accessing an Arduino board's functions, the aforementioned DLL for the toolbox and a GUI application for device management. A demonstration of analog data acquisition and analog data output which uses this system is also presented.

2

Page 3: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

SadržajPostavka završnog rada..............................................................................................................................6Uvod...........................................................................................................................................................71. Data Acquisition Toolbox.......................................................................................................................8

1.1. Uvod...............................................................................................................................................81.2. Generalno o Data Acquisition Toolboxu........................................................................................81.3. Arhitektura Data Acquisition Toolboxa..........................................................................................8

1.3.1. M-fileovi...............................................................................................................................101.3.2. Data Acquisition Engine.......................................................................................................101.3.3. Adaptor DLL.........................................................................................................................10

1.4. Analog Input.................................................................................................................................121.5. Analog Output..............................................................................................................................161.6. Digital I/O.....................................................................................................................................181.7. Dodatne funkcije Data Acquisition Toolboxa..............................................................................19

1.7.1. daqhwinfo.............................................................................................................................191.8. Zaključak......................................................................................................................................20

2. Arduino.................................................................................................................................................212.1. Uvod.............................................................................................................................................212.2. Arduino Platforma........................................................................................................................212.3. Arduino Uno.................................................................................................................................21

2.3.1. Atmel ATmega328 procesor.................................................................................................212.3.2. Analogno-digitalni konvertor................................................................................................222.3.3. Analogni izlaz.......................................................................................................................232.3.4. Timeri....................................................................................................................................232.3.5. Serijska komunikacija...........................................................................................................24

2.4. Zaključak......................................................................................................................................263. Implementacija.....................................................................................................................................27

3.1. Uvod.............................................................................................................................................273.2. Generalni opis...............................................................................................................................273.3. Problem sinhronizacije niti...........................................................................................................29

3.3.1. Win32 API: uzajamno isključivanje.....................................................................................293.3.2. CriticalSection klasa.............................................................................................................303.3.3. Lock klasa.............................................................................................................................30

3.4. Međuprocesna komunikacija........................................................................................................313.4.1. Named pipe...........................................................................................................................31

3.4.1.1. Win32 API za komunikacjiu preko named pipeova......................................................313.4.1.2. PipeCommunicator klasa..............................................................................................33

3.4.2. Window Messages................................................................................................................343.4.2.1. Win32 API: Window i WindowMessage......................................................................343.4.2.2. MessageWindow klasa..................................................................................................363.4.2.3. MessageWindowSender klasa.......................................................................................40

3.5. EtfArduinoService proces............................................................................................................413.5.1. EtfArduinoService klasa.......................................................................................................423.5.2. Komunikacija sa Arduinom..................................................................................................44

3.5.2.1. Win32 API: Serijska komunikacija...............................................................................44

3

Page 4: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.5.2.2. SerialCommunicator klasa............................................................................................463.5.2.3. ArduinoDevice klasa.....................................................................................................47

3.5.3. DeviceMap klasa..................................................................................................................533.5.4. Obrada zahtjeva....................................................................................................................55

3.5.4.1. RequestHandler.............................................................................................................553.5.4.2. RequestHandlerFactory.................................................................................................553.5.4.3. RequestHandlerFactoryImpl klasa................................................................................563.5.4.4. Konkretne RequestHandler klase..................................................................................56

3.5.5. Glavni program EtfArduinoService servisa..........................................................................583.6. Adaptor implementacija...............................................................................................................60

3.6.1. COM interfejs.......................................................................................................................603.6.2. Adaptor klasa........................................................................................................................613.6.3. CetfarduinoAin klasa............................................................................................................633.6.4. CetfarduinoAout klasa..........................................................................................................683.6.5. CetfarduinoDio klasa............................................................................................................69

3.7. Arduino Firmware........................................................................................................................713.7.1. Analogni ulaz........................................................................................................................713.7.2. Analogni izlaz.......................................................................................................................733.7.3. Digitalni izlaz........................................................................................................................733.7.4. Glavna petlja.........................................................................................................................74

3.8. EtfArduinoConfig - GUI aplikacija..............................................................................................753.9. Zaključak......................................................................................................................................77

4. Demonstracija......................................................................................................................................784.1. Uvod.............................................................................................................................................784.2. Setup.............................................................................................................................................784.3. Akvizicija sinusnog signala..........................................................................................................794.4. Akvizicija trouglastog signala......................................................................................................804.5. Akvizicija signala oblika četvrtke................................................................................................814.6. Akvizicija promjene napona na NTC otporniku...........................................................................824.7. Analogni izlaz...............................................................................................................................834.8. Zaključak......................................................................................................................................85

Zaključak..................................................................................................................................................86Literatura..................................................................................................................................................87

4

Page 5: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Sadržaj slikaSlika 1: Data Acquisition Toolbox arhitektura...........................................................................................9Slika 2: Komunikacija Data Acquisition Enginea i adaptor DLL-a.........................................................11Slika 3: Aliasing pri korištenju Data Acquisition Toolbox objekata........................................................13Slika 4: Dijagram sekvence - proces akvizicije analognog signala.........................................................15Slika 5: Dijagram sekvence - proces analognog izlaza............................................................................17Slika 6: Rezultat izvršavanja daqhwinfo funkcije bez parametara..........................................................19Slika 7: Grafik koji pokazuje vrijeme (μs) potrebno za izvršavanje iteracije petlje koja šalje 2 bajta na serijski izlaz u odnosu na redni broj petlje...............................................................................................25Slika 8: Komunikacija komponenti sistema.............................................................................................28Slika 9: Dijagram klasa EtfArduinoService komponente........................................................................41Slika 10: Poruka greške ukoliko nije registrovan uređaj s traženim ID-em............................................64Slika 11: EtfArduinoConfig aplikacija: otkriven port, uređaj neregistrovan...........................................76Slika 12: EtfArduinoConfig aplikacija: poruka o uspješnoj registraciji uređaja.....................................76Slika 13: EtfArduinoConfig aplikacija: poruka o neuspješnoj registraciji uređaja..................................76Slika 14: EtfArduinoConfig aplikacija: uređaj registrovan.....................................................................77Slika 15: Grafik koji prikazuje podatke dobivene akvizicijom sinusoidnog signala frekvencije 100 Hz..................................................................................................................................................................79Slika 16: Očitanje osciloskopa za sinusoidni signal frekvencije 100 Hz.................................................79Slika 17: Grafik koji prikazuje podatke dobivene akvizicijom signala oblika trougla frekvencije 100 Hz..................................................................................................................................................................80Slika 18: Očitanje osciloskopa za signal oblika trougla frekvencije 100 Hz...........................................80Slika 19: Grafik koji prikazuje podatke dobivene akvizicijom signala oblika četvrtke frekvencije 100 Hz.............................................................................................................................................................81Slika 20: Očitanje osciloskopa za signal oblika četvrtke frekvencije 100 Hz.........................................81Slika 21: Grafik podataka dobivenih akvizicijom naponskog signala na krajevima NTC otpornika......82Slika 22: Laboratorija za vrijeme izvršavanja akvizicije vrijednosti napona sa NTC otpornika.............82Slika 23: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 0 V.......................83Slika 24: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 1.25 V..................83Slika 25: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 2.5 V....................84Slika 26: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 3.75 V..................84Slika 27: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 5 V.......................85

5

Page 6: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Univerzitet u Sarajevu

Elektrotehnički fakultet Sarajevo

Odsjek za računarstvo i informatiku

Postavka završnog radaTema

Akvizicija podataka pomoću modula Arduino UNO u okviru Matlab okruženja

Cilj

Razviti driver za Data Acquistion Toolbox koji omogućava korištenje modula Arduino UNO kao akvizicijskog uređaja.

O pis

Analizirati i opisati Matlab Data Acquisition Toolbox i kreiranje drivera za hardverske uređaje za akviziciju podataka. Razviti driver za Arduino UNO, koji omogućava da se u okviru Data Acquisition Toolbox-a koristi analogni ulaz, PWM izlaz i digitalni izlaz modula Arduino UNO.

Očekivani rezultati:

Razvije driver za Arduino UNO i demonstrirane mogućnosti Arduino modula kao uređaja za akviziciju podataka.

Polazna literatura:

1. S. Konjicija: "Predavanja sa kursa Praktikum automatike"2. Matlab Data Acquisition Toolbox User's Guide, The Mathworks Inc., 20113. Getting Started with Arduino, http://arduino.cc/en/Guide/HomePage

Mentor

Doc. dr Samim Konjicija, dipl. ing. el.

6

Page 7: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

UvodData Acquisition Toolbox je dio MATLAB-a koji omogućava korištenje uređaja za akviziciju podataka. Arduino uređaji su bazirani na mikroprocesorima koji imaju mogućnosti analognog i digitalnog ulaza i izlaza. U ovom radu su razmatrane mogućnosti Arduino uređaja da rade kao jeftini akvizicioni moduli te je razvijen sistem pomoću kojeg je moguća integracija sa MATLAB-ovim Data Acquisition Toolboxom kako bi način upotrebe bio identičan kao i način na koji se koristi hardver prvenstveno namijenjen za akviziciju.

U prvom poglavlju izvršena je analiza Data Acquisition Toolboxa. Predstavljene su njegove mogućnosti, način upotrebe i arhitektura. Od arhitekture zavisi i razvoj adaptera za Arduino uređaje koji bi služili kao akvizicioni moduli. Obrađena je i komunikacija komponenti toolboxa, kako bi se steklo razumijevanje procesa koji se odvijaju pri upotrebi tog alata.

U drugom poglavlju je predstavljena Arduino platforma pri čemu je posebna pažnja data Arduino Uno uređaju koji je korišten pri implementaciji sistema. Dat je opis svih osobina uređaja bitnih za implementaciju akvizicije i komunikaciju sa računarom. Na osnovu toga, određena su i ograničenja koja moraju biti zadovoljena.

Treće poglavlje je posvećeno implementaciji sistema. Objašnjen je dizajn komponenti sistema zajedno sa njihovom interakcijom i kooperacijom. Zatim je svaka od komponenti razmatrana samostalno. Predstavljena je implementacija komponente s osvrtom na namjenu svake klase, korištene bibliotečne funkcije i algoritme.

Četvrto poglavlje sadrži demonstraciju korištenja razvijenog sistema. Dobiveni rezultati su prikazani i upoređeni sa očekivanim. Ovo predstavlja način provjere konačne upotrebne vrijednosti sistema.

7

Page 8: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

1. Data Acquisition Toolbox1.1. Uvod

U ovom poglavlju je predstavljen MATLAB-ov Data Acquisition Toolbox. To obuhvata način na koji se koristi te njegovu arhitekturu obzirom da od te dvije stvari zavisi i implementacija adaptora, što je zadatak rada.

1.2. Generalno o Data Acquisition Toolboxu

Data Acquisition Toolbox MATLAB-u omogućava povezivanje sa uređajima za akviziciju podataka. Između ostalog, ono što je moguće postići koristeći toolbox je konfiguracija akvizicionog hardvera i preuzimanje podataka sa uređaja. Preuzete podatke je zatim moguće koristiti u standardnom MATLAB okruženju za analizu, pohranjivanje ili bilo koju drugu namjenu. Također je moguće vršiti i slanje podataka preko analognih ili digitalnih izlaznih kanala koji postoje na akvizicionim karticama.

Korisnik ovim mogućnostima pristupa koristeći funkcije toolboxa koje su podijeljene u sljedeće kategorije:

• funkcije za upravljanje analognim ulazom (analog input);• funkcije za upravljanje analognim izlazom (analog output);• funkcije za upravljanje digitalnim ulazom/izlazom (digital I/O).

Data Acquisition Toolbox podržava uređaje mnogih proizvođača opreme za akviziciju podataka, kao što su National Instruments, Measurement Computing, Advantech i sl. Ipak, ukoliko uređaj nije podržan, moguće je razviti poseban driver koji se integriše u toolbox čime se postiže podrška za dodatne uređaje.

1.3. Arhitektura Data Acquisition Toolboxa

MATLAB-ov Data Acquisition Toolbox se sastoji iz tri dijela:

• M-fileovi – MATLAB funkcije za pristup funkcionalnostima akvizicionih uređaja;

• Data Acquisition Engine – MEX-file koji upravlja MATLAB objektima za pristup akvizicionim uređajima: njihovim kreiranjem, postavljanjem svojstava, podacima vezanih uz njih;

• Adaptori – DLL-ovi koji omogućavaju engineu komunikaciju sa različitim hardverskim uređajima za akviziciju.

8

Page 9: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Saradnja dijelova je organizovana tako da svaki nivo pristupa uslugama nivoa ispod njega, pri čemu postoji jasna podjela odgovornosti među njima. Na dijagramu ispod je prikazana komunikacija ovih komponenti.

9

Slika 1: Data Acquisition Toolbox arhitektura

Page 10: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

1.3.1. M-fileovi

M-fileovi su MATLAB funkcije koje korisniku omogućavaju spajanje i komunikaciju sa hardverskim uređajima za akviziciju. Za obavljanje bilo kojeg akvizicionog zadatka, potrebno je koristiti ove funkcije.

Sve funkcije koje Data Acquisition Toolbox definiše se mogu pronaći korsteći naredbu help('daq') u MATLAB okruženju. Neke od najznačajnijih su:

• Funkcije za kreiranje MATLAB objekata za kontrolu podsistema uređaja za akviziciju: analoginput, analogoutput, digitalio;

• Funkcije za preuzimanje prikupljenih ili slanje izračunatih podataka: getdata, putdata;

• Funkcije za postavljanje ili preuzimanje konfiguracijskih vrijednosti objekata: get, set.

Implementacija M-fileova se zasniva na komunikaciji sa Data Acquisition Engineom, tj. pozivanju njegovih funkcija.

1.3.2. Data Acquisition Engine

MEX-fileovi (MATLAB executable) su dijeljene biblioteke koje se mogu učitati i izvršavati unutar MATLAB funkcija, bez obzira što su implementirane u drugim programskim jezicima.

Engine je MEX-file koji sadrži funkcije koje upravljaju objektima za akviziciju, njihovim svojstvima i podacima. Data Acquisition Toolbox M-fileovi zatim koriste funkcije definisane u engineu u svojoj implementaciji.

Osim toga, engine prima i brine se za ispravno obrađivanje svih događaja koji se signaliziraju pri komunikaciji sa uređajem za akviziciju. Neki od njih su potreba za spašavanjem primljenih podataka ili podataka koje treba proslijediti prema uređaju. Bitno je naglasiti da se ove radnje odvijaju u pozadini, tj. u isto vrijeme je moguće koristiti MATLAB okruženje za izvršavanje drugih funkcija.

Kako bi Data Acquisition Engine komunicirao sa uređajem za akviziciju, koristi Adaptor DLL koji odgovara tom uređaju.

1.3.3. Adaptor DLL

Adaptor DLL služi za komunikaciju sa uređajem za akviziciju kome prenosi podatke i konfiguracijske vrijednosti te od kojeg prima podatke koji su rezultat akvizicije. Adaptor je, dakle, interfejs preko kojeg Data Acquisition Engine komunicira sa uređajem.

10

Page 11: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Sam adaptor i engine komuniciraju preko COM (Component Object Model) interfejsa. Za svaki uređaj, koristeći COM interfejs, engine kreira odgovarajući adaptor objekat. Adaptor objekat, na engineov zahtjev za pristup određenom podsistemu, kreira objekat specifičan za taj podsistem. Engine za potrebe upravljanja tim podsistemom komunicira direktno sa objektom podsistema. Komunikaciju s uređajem mora implementirati svaki od objekata podsistema.

11

Slika 2: Komunikacija Data Acquisition Enginea i adaptor DLL-a

Page 12: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

1.4. Analog Input

Način na koji se koristi analog input podsistem uređaja za akviziciju koristeći Data Acquisition Toolbox je prikazan u sljedećem dijelu koda:

ai = analoginput('mcc', 0);addchannel(ai, 1);ai.SampleRate = 1000;ai.SamplesPerTrigger = 5000;start(ai)wait(ai, 10);[data, t] = getdata(ai, ai.SamplesAcquired);plot(t, data)delete(ai)

U ovom primjeru, korisnik vrši akviziciju signala u trajanju od 5 sekundi, sa frekvencijom uzorkovanja od 1000 Hz. Zatim crta grafik tog signala.

Pozivom analoginput funkcije, M-file zahtijeva od enginea da kreira MATLAB objekat pomoću kojeg će korisniku biti omogućeno korištenje analog input podsistema mcc uređaja sa ID-om 0. Pri kreiranju tog objekta, engine, koristeći adaptor definisan za taj uređaj (čiji je naziv prvi parametar funkcije), kreira specijalni adaptor objekat za analog input podsistem pomoću kojeg će moći vršiti komunikaciju sa samim hardverom i pridružuje ga novokreiranom MATLAB objektu.

Korisnik nije svjestan ovog detalja, ali ipak utiče na njegovo korištenje toolboxa. Naime, ukoliko se izvrši jednostavno kopiranje MATLAB analoginput objekta, npr. sa

ai1 = ai

Rezultat će biti taj da su oba ta objekta povezana sa istim adaptor objektom za komunikaciju sa uređajem za akviziciju. Drugim riječima, dolazi do pojave koja se u programiranju naziva aliasing kada ai1 i ai predstavljaju samo referencu na isti interni objekat te bilo koja promjena pomoću jednog od njih se odražava i na drugi. Slika ispod pobliže ilustrira ovu pojavu:

12

Page 13: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Funkcija addchannel dodaje novi ulazni kanal na MATLAB objekat za analognu akviziciju. Engine, kada dobije naredbu od M-filea, pomoću adapter objekta za analog input signalizira uređaju da je potrebno da vrši akviziciju sa navedenih kanala.

Naredne dvije komande postavljaju osobine SampleRate i SamplesPerTrigger MATLAB analoginput objekta. Ove osobine određuju koja će biti frekvencija uzimanja uzoraka ulaznog signala prilikom akvizicije, te koji je ukupan broj samplova koji se trebaju prikupiti za vrijeme jednog izvršavanja akvizicije. Osobina SamplesPerTrigger može biti postavljena na vrijednost Inf, što znači da vrijeme prikupljanja podataka nije ograničeno, već korisnik mora zaustaviti korištenjem funkcije stop. Za postavljanje ovih vrijednosti, opet je zadužen engine.

Prilikom postavljanja osobina, engine nije obavezan komunicirati sa uređajem ukoliko je u pitanju neka osobina koja ne utiče na izvršavanje akvizicije. Adaptor objekti za podsisteme imaju poseban način da signaliziraju engineu koje su te osobine za čije promjene žele biti obaviješteni. O ovome će biti više riječi u poglavlju Implementacija.

Komanda start signalizira engineu da je potrebno započeti sa akvizicijom. Nakon što se pozove ova funkcija, MATLAB program nastavlja sa izvršavanjem, obzirom da je od tog trenutka engine zadužen za komunikaciju sa uređajem. Kaže se da je start poziv asinhron. Engine je taj koji prima i spašava podatke koje uređaj vraća računaru.

Dok je aktivna akvizicija, osobina Started analoginput objekta je postavljena na vrijednost true.

Ipak, iako funkcija start započinje akviziciju, spašavanje očitanih vrijednosti od strane enginea ne počinje u tom trenutku. U zavisnosti od postavke osobine TriggerType objekta analoginput, spašavanje može početi u istom trenutku kada i akvizicija (Immediate postavka), kada sam korisnik, pozivajući funkciju trigger, to zatraži (Manual postavka) ili kada se detektuje neki događaj koji indicira da spašavanje podataka treba započeti (Software postavka).

13

Slika 3: Aliasing pri korištenju Data Acquisition Toolbox objekata

Page 14: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Događaji koji mogu izazvati početak spašavanja podataka mogu biti prelazak očitane vrijednosti na nekom ulaznom kanalu preko ili ispod postavljene granice, ulazak očitane vrijednosti unutar postavljenog intervala ili rastuća, tj. opadajuća, ivica signala. U ovom slučaju, sam Data Acquisition Engine je taj koji se brine da će korisnik dobiti ispravne podatke, adaptor nije svjestan da se neki podaci koje vraća odbacuju. Događaj koji će započeti spašavanje podataka se bira postavljanjem svojstva TriggerCondition MATLAB analoginput objekta.

Treba napomenuti da neki uređaji osim navedene tri opcije za TriggerType omogućavaju i Hardware opciju. U tom slučaju, spašavanje podataka treba da počne kada sam uređaj primi i obradi određen signal od drugog hardverskog uređaja; engine više nije taj koji se za to brine. Na taj način, reakcija može biti brža, ali je potrebno da to hardver akvizicionog modula podržava.

Funkcija wait služi kada korisnik želi da program zaustavi svoje izvršavanje sve dok određeni analoginput objekat ne završi sa svojim izvršavanjem ili dok ne protekne vrijeme navedeno kao parametar (u sekundama).

Pomoću getdata funkcije, korisnik zahtijeva od enginea da vrati podatke prikupljene za vrijeme akvizicije. Drugi parametar funkcije je broj samplova koji se žele preuzeti. Funkciju je moguće pozivati i dok je MATLAB analoginput objekat u aktivnom stanju. Svaki poziv funkcije uklanja vraćene podatke iz enginea. Osim samih podataka, za svaki od samplova, funkcija vraća i apsolutno vrijeme od početka akvizicije u kojem je taj sample uzet.

Preuzeti podaci se nalaze u klasičnim MATLAB matricama te to znači da ih je moguće dalje koristiti u bilo kojim MATLAB funkcijama za obradu podataka. Primjer u ovom slučaju je funkcija plot koja će nacrtati grafik preuzetog signala.

Poziv funkcije delete oslobađa sve resurse koje je analoginput objekat zauzeo. Engine je zadužen za oslobađanje tih resursa. Nakon poziva ove funkcije, više nije moguće koristiti ovaj objekat te za korištenje istog uređaja je potrebno ponovo pozvati konstruktorsku funkciju analoginput.

Ispod se nalazi dijagram sekvence koji prikazuje kako se odvija komunikacija svih dijelova Data Acquisition Toolboxa u ovom primjeru.

14

Page 15: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

15

Slika 4: Dijagram sekvence - proces akvizicije analognog signala

Page 16: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

1.5. Analog Output

Način na koji se koristi analog output podsistem uređaja za akviziciju koristeći Data Acquisition Toolbox je prikazan u sljedećem dijelu koda:

ao = analogoutput('mcc', 1);addchannel(ao, 1);ai.SampleRate = 500;data = sawtooth(linspace(0, 4 * pi, 500));putdata(ao, data)start(ao)delete(ao)

U ovom primjeru, na analogni izlaz uređaja se šalje signal u trajanju od 1 sekunde, oblika “pile”, amplitude 1 volta i perioda 0.5 s.

Funkcija analogoutput, na isti način kao i već opisana analoginput, funkcija kreira MATLAB objekat analogoutput koji služi da korisnik pristupi podsistemu za analogni izlaz mcc uređaja s ID-om 1.

Naredne dvije naredbe također rade na isti način kao i već opisane funkcije kod analognog ulaza.

Funkcija putdata šalje engineu podatake koje će biti potrebno da uređaj pošalje na svoje izlazne kanale. Podaci su predstavljeni standardnom MATLAB matricom realnih brojeva, koja je u ovom slučaju generisana naredbom prije.

Pozivom start funkcije za MATLAB analogoutput objekte, engine osigurava da se podaci koji su prethodno dodani šalju na uređaj. Poziv ove funkcije je asinhron, pa korisnik može nastaviti sa radom dok će uređaj dobivati ispravne podatke za svoj izlaz od Data Acquisition Enginea.

Delete funkcija radi isto što i u slučaju analoginput objekta.

Ispod se može vidjeti dijagram sekvence koji prikazuje način komunikacije komponenti Data Acquisition Toolboxa za prethodno dati primjer.

16

Page 17: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

17Slika 5: Dijagram sekvence - proces analognog izlaza

Page 18: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

1.6. Digital I/O

Slijedi primjer korištenja podsistema za digitalni ulaz i izlaz:

dio = digitalio('mcc');addline(dio, 0, 'Out');v = 0;for i = 1 : 1000 pause(0.1) putvalue(dio, v) v = ~v;enddelete(dio)

Ovaj primjer svakih 100 ms mijenja stanje nekog digitalnog izlaznog porta uređaja.

Funkcija digitalio je konstruktorska funkcija za MATLAB digitalio objekat koji služi za pristup tom podsistemu i radi na isti način kao i već opisane konstruktorske funkcije.

Funkcija addline mijenja funkciju addchannel za podsistem za digitalni ulaz i izlaz, tj. signalizira uređaju da doda dodatnu liniju koja će biti korištena za ulaz ili izlaz, u zavisnosti od parametra. Svaka linija je povezana sa portom, ali je moguće adresirati svaku individualnu liniju pomoću cijelog broja koji predstavlja njen ID. Svaki port može više od jedne linije, a najčešće je to 1, 8 ili 16 linija. Ipak, ponašanje prilikom slanja izlaza na neku liniju zavisi od uređaja do uređaja, tj. neki uređaji kada se postavi neka vrijednost na jednu od linija porta, postave tu vrijednost za sve ostale linije porta, a drugi omogućavaju individualno mijenjanje vrijednsoti na svakoj liniji.

Funkcija putvalue služi da na određeni uređaj pošalje digitalne vrijednosti. Ukoliko postoji više linija, binarna reprezentacija proslijeđenog parametra vrijednosti određuje koje linije će biti u logičkom HIGH stanju, a koje u logičkom LOW.

Postoji i funkcija getvalue koja očitava vrijednosti svih linija i vraća cijeli broj čija binarna reprezentacija predstavlja stanje svake od linija.

Funkcija delete, kao i za sve ostale podsisteme, vrši oslobađanje zauzetih resursa.

Ono što je bitno za sistem za digitalni ulaz i izlaz Data Acquisition Toolboxa je da objekte tipa digitalio nije moguće pokrenuti. Drugim riječima, čitanje vrijednosti i slanje vrijednosti je uvijek pod kontrolom korisnika te nikad ne prelazi pod kontrolu enginea, kao što je to slučaj kod analoginput i analogoutput objekata toolboxa.

18

Page 19: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

1.7. Dodatne funkcije Data Acquisition Toolboxa

1.7.1. daqhwinfo

Funkcija daqhwinfo ima više namijena.

Prva je kada se pozove bez parametara i tada daje generalne informacije o Data Acquisition Toolboxu: njegovu verziju, naziv, verziju MATLAB-a i listu svih instaliranih adaptora što predstavlja listu dozvoljenih parametara za konstruktorske funkcije toolboxa.

Drugi slučaj je kada se proslijedi string parametar koji predstavlja naziv nekog od adaptora. Taj poziv daje informacije o samom adaptoru: lokacija DLL-a pomoću kojeg je implementiran, verziju, njegov naziv, a najbitnije, listu svih instaliranih uređaja s kojim adaptor može komunicirati zajedno sa njihovim ID-ovima. To su jedini ID-ovi koji su dozvoljeni za koristiti prilikom poziva konstruktorskih funkcija za dati adaptor.

Na kraju, funkciji daqhwinfo je moguće proslijediti i neki od MATLAB objekata Data Acquisition Toolboxa, tj. analoginput, analogoutput ili digitalio objekat. U tom slučaju, funkcija vraća informacije specifične samo za podsistem na koji se odnosi dati objekat.

19

Slika 6: Rezultat izvršavanja daqhwinfo funkcije bez parametara

Page 20: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Neke od najbitnijih informacija koje se dobiju u tom slučaju su lista svih kanala koji su dostupni tom podsistemu na samom uređaju zajedno sa ID-evima koji se mogu proslijediti addchannel funkciji kako bi im se pristupilo.

1.8. Zaključak

U ovom poglavlju je predstavljen Data Acquisition Toolbox, njegov način korištenja i arhitektura, što podrazumijeva komponente i način njihove komunikacije. Iz analize arhitekture se vidi da je potrebno implementirati DLL koji sadrži COM komponente s kojima će komunicirati Data Acquisition Engine kako bi se podržali Arduino uređaji za akviziciju direktno kroz toolbox. Također, može se primijetiti da podsistem za digitalni ulaz i izlaz ima značajno manji broj podržanih funkcionalnosti.

20

Page 21: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

2. Arduino2.1. Uvod

U ovom poglavlju je predstavljena Arduino platforma – njen hardverski i softverski dio. Posebno je razmatran Arduino Uno, uređaj na kojem je izvršena implementacija zadatka. Prikazane su mogućnosti i ograničenja od kojih zavisi planirana implementacija sistema za akviziciju.

2.2. Arduino Platforma

Arduino je open source platforma za prototipiranje elektroničkih sistema zasnovana na fleksibilnom i jednostavnom za korištenje hardveru i softveru. Arduino uređaji se sastoje od Arduino štampane pločice, čiji dizajn je open source, mikroprocesora iz Atmel AVR porodice i podrške za ulaz ili izlaz.

Softver se sastoji od kompajlera i razvojnog okruženja za Arduino jezik koji je pojednostavljenje C++ jezika prilagođeno za jednostavnije korištenje funkcionalnosti AVR procesora. Uz to, Arduino uređaji imaju preinstaliran boot loader koji omogućava jednostavan prenos novih programa na uređaj sa računara na kojem su kompajlirani, po cijenu nešto smanjenog ukupno raspoloživog memorijskog prostora za program.

2.3. Arduino Uno

Za svrhe ovog projekta, korišten je Arduino Uno uređaj iz Arduino porodice. Uno je baziran na Atmel ATmega328 procesoru i ima 14 digitalnih pinova koji se mogu koristiti za ulaz ili izlaz, 6 analognih ulaza, oscilator frekvencije 16 MHz i USB konektor. Uređaj je moguće napajati eksternim naponom od 7-12V (baterija ili adapter) ili direktno preko USB porta računara na koji je spojen.

2.3.1. Atmel ATmega328 procesor

ATmega328 procesor čini srce Arduino Uno uređaja što znači da svaki aspekt funkcionalnosti zavisi od mogućnosti ovog procesora.

ATmega328 je 8-bitni RISC procesor sa maksimalnom frekvencijom 20 MHz. Sadrži 32 registra opšte namjene, podršku za interne i eksterne prekide (interrupte), 10-bitni analogno-digitalni konvertor i 23 linije namijenjene za ulaz ili izlaz.

Na raspolaganju ima tri tipa memorije, svaka različite namjene i kapaciteta:

• Flash memorija – 32KB od čega 0.5KB zauzima boot loader. U flash memoriji se spašava izvršni kod programa koji procesor treba da izvršava.

21

Page 22: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

• EEPROM – persistentna memorija, tj. prostor u kojem programi mogu spasiti vrijednosti koje se trebaju sačuvati i kada se uređaj ugasi. Pristup ovoj memoriji je veoma spor te je namijenjen za minimalnu količinu podataka. Kapacitet je 1 KB.

• SRAM – RAM memorija, kapaciteta 2KB, gdje program spašava vrijednosti varijabli za vrijeme svog izvršavanja.

2.3.2. Analogno-digitalni konvertor

Analogno-digitalni konvertor (ADC) ima rezoluciju 10-bita, što znači da je moguće detektovati 1024 diskretna nivoa ulaznog naponskog signala. ADC koristi algoritam uzastopnih aproksimacija. Ovaj algoritam je zasnovan na binarnom pretraživanju gdje se u svakom koraku određuje jedan bit digitalne vrijednosti.

U prvom koraku, najznačajniji bit digitalne vrijednosti se postavlja na 1, a ulazna vrijednost se, pomoću ugrađenog komparatora, poredi sa polovinom referentnog napona koji predstavlja maksimalnu vrijednost koju uređaj može prepoznati. Ukoliko komparator indicira da je ulazna vrijednost manja, najznačajniji bit postaje 0, a proces se nastavlja na isti način postavljanjem sljedećeg bita na 1 i dijeljenjem referentnog napona sa 4.

Ovaj proces nakon 10 koraka daje digitalnu aproksimaciju ulaznog naponskog signala. Najmanja promjena napona koju ADC može detektovati, uzimajući 5V kao referentni napon, se može dobiti kao:

Za ovaj proces, konvertoru je potreban sinhronizacijski signal (clock). Za jednu analogno-digitalnu konverziju je potrebno 13 ciklusa sinhronizacijskog sata, pa od frekvencije sata zavisi i brzina izvršavanja konverzije. Ipak, maksimalna frekvencija pri kojoj ne dolazi do gubitka preciznosti konverzije je 1 MHz, što znači da je vrijeme potrebno za konverziju ograničeno na minimalno 13 μs.

ATmega328 procesor omogućava korištenje signala sata samog procesora za ovu namjenu. Pomoću specijalnog sklopa unutar konvertora, frekvencija signala sata se može podijeliti određenom vrijednosti, koja se naziva faktor skaliranja (prescaler), kako bi se za signal sinhronizacije analogno-digitalne konverzije dobila niža frekvencija. Uzimajući u obzir da je frekvencija sata 16 MHz za korišteni Arduino Uno uređaj, faktor skaliranja je potrebno postaviti na vrijednost 16 kako bi se postigla frekvencija od 1 MHz.

Odabir faktora skaliranja se vrši upisom odgovarajuće vrijednosti u za to predviđene bite ADPS[2:0] registra ADCSRA. Iz data sheeta procesora se može vidjeti da za faktor skaliranja 16, treba postaviti navedene bite na vrijednosti:

ADPS2 = 1ADPS1 = 0ADPS0 = 0

22

Page 23: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

ADC sadrži i multiplekser pomoću kojeg se može odabrati koji od 6 raspoloživih ulaznih portova će se konvertovati u digitalnu vrijednost. Odabir porta se vrši upisom odgovarajuće vrijednosti u bite MUX[3:0] registra ADMUX.

2.3.3. Analogni izlaz

Arduino Uno nema sklop za digitalno-analognu konverziju pa za postizanje analognog izlaza koristi pulse width modulation (PWM) tehniku.

PWM radi tako što se prosječna vrijednost napona koja dolazi do potrošača kontroliše slanjem digitalnih impulsa (maksimalna naponska vrijednost ili minimalna naponska vrijednost) velikom frekvencijom. Što je duže vrijeme u kojem je na izlazu maksimalna vrijednost, to je srednja vrijednost napona veća. Na taj način, odabirom odgovarajućeg broja impulsa vrijednosti 1, postižu se različite srednje vrijednosti napona, tj. analogne vrijednosti.

Ipak, da bi se mogao prepoznati oblik signala, potrebno je izvršiti njegovo filtriranje, u što se ovdje neće ulaziti jer je izvan teme ovog rada.

Na Arduino platformi za korištenje analognog izlaza je obezbijeđena globalna funkcija analogWrite koja prima vrijednost od 0 do 255 koju treba pretvoriti u analognu vrijednost na izlaznom portu koji je također zadat kao parametar. Vrijednost 255 odgovara maksimalnoj vrijednosti izlaza – 5V.

2.3.4. Timeri

Timeri ili brojači su specijalni registri čija se vrijednost automatski inkrementuje određenom frekvencijom koja zavisi od frekvencije sata i faktora skaliranja koji je primijenjen na tu frekvenciju. Kada dođe do overflowa vrijednosti u registru, ATmega328 procesoru se signalizira hardverski prekid (interrupt). Postavljanjem odgovarajuće vrijednosti faktora skaliranja, početne vrijednosti u registru te u zavisnosti od veličine registra, ovaj mehanizam može biti korišten za sinhrono generisanje događaja, obzirom da je procesor obavezan preći u rutinu za obradu prekida kada se on javi.

ATmega328 sadrži 3 timera. Od toga, Timer0 i Timer2 imaju registre veličine 8 bita, a Timer1 registar veličine 16 bita.

Na Arduino platformi, svi ovi timeri su korišteni za implementaciju PWM izlaza, obzirom da je za tu svrhu potrebna sinhrona generacija signala. Uz to, Timer0 je korišten za imlementaciju funkcija koje mjere vrijeme: milis, micros, delay, delayMicroseconds. Ukoliko korisnik želi koristiti neki od timera, izgubit će neku od funkcionalnosti Arduino uređaja.

Faktor skaliranja za Timer0 je postavljen na 64, što znači da je frekvencija inkrementovanja vrijednosti tog brojača 250 kHz, što odgovara periodu od 4μs. Iz tog razloga, funkcija micros, koja vraća broj mikrosekundi od početka rada uređaja, ima rezoluciju od 4μs, tj. vraćena vrijednost je uvijek djeljiva s 4.

23

Page 24: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

2.3.5. Serijska komunikacija

ATmega328 omogućava serijsku komunikaciju s drugim uređajima preko pinova 0 (RX) i 1 (TX). Kako Arduino Uno za spajanje sa računarom koristi USB, sadrži dodatni mikroprocesor, Atmega8U2 koji je programiran da radi kao USB-serijski konvertor. Pinovi 0 i 1 ATmega328 procesora su spojeni na ovaj procesor koji je zatim zadužen da generiše odgovarajući signal za USB. Na računaru, Arduino Uno se registruje kao virtualni COM port te se komunikacija može postići potpuno transparentno koristeći API za serijsku komunikaciju.

Sam Atmega328 podržava baud vrijednosti (broj prenesenih bita u jedinici vremena) do 2 Mbaud s procentom greške od 0%. Ipak, nakon testova sprovedenih tokom izrade ovog rada, utvrđeno je da zbog dodatnog procesiranja koje zahtijeva konverzija USB u serijski signal, nakon vrijednosti od 256 kbaud, dolazi do pojave grešaka u prenosu podataka, pa je najveća efektivna brzina prenosa koju je moguće postići koristeći Arduino Uno 256 kbaud.

Za programiranje serijske komunikacije je ostavljena mogućnost korištenja manipulacije registara procesora, ali Arduino platforma implementira specijalanu klasu HardwareSerial i instancu klase Serial kojoj svaki Arduino program ima pristup. Pomoću metoda objekta Serial, moguće je izvršiti slanje i očitavanje vrijednosti.

Najbitnije metode su:

• begin – služi za inicijalizaciju komunikacije te kao parametar prima baud koji treba koristiti;

• write – metoda za slanje proslijeđenog bajta na izlaz. Ono što je bitno za ovu metodu je da je njeno izvršavanje asinhrono – ne čeka da se vrijednost zaista pošalje na izlaz, već se ona upisuje u interni FIFO buffer iz kojeg se, kada je podsistem za serijski izlaz procesora spreman, proslijeđuje sljedeća vrijednost na izlaz. Ukoliko je buffer pun, metoda blokira izvršavanje sve dok se ne oslobodi mjesto, tj. dok se bajt iz buffera ne pošalje na izlaz;

• read – čita sljedeći bajt iz buffera vrijednosti primljenih preko serijskog porta. Vraćenu vrijednost uklanja iz buffera. Ukoliko nema nepročitanih vrijednosti, vraća -1;

• available – vraća broj nepročitanih bajta primljenih preko serijskog porta;

• peek – vraća sljedeći bajt iz buffera vrijednosti primljenih preko serijskog porta, bez uklanjanja vrijednosti iz buffera. Ukoliko nema nepročitanih vrijednosti, vraća -1.

Iako je write funkcija po svojoj prirodi asinhrona, najmanji period kreiranja podataka koji će se slati preko serijskog porta je jednak vremenu za prenos tih podataka iz buffera preko serijskog interfejsa. Razlog za to je što bi se u slučaju proizvodnje podataka brže od vremena potrebnog za prenos tih podataka, buffer punio brže nego što bi se praznio, što znači da nakon nekog vremena dolazi do situacije da je buffer pun te da funkcija write mora da čeka da se dovoljan broj podataka pošalje kako bi se novi podaci mogli dodati u njega. Vrijeme potrebno da se čeka je upravo jednako vremenu za slanje podataka, pa se iz toga može zaključiti da proizvodnja podataka ne može biti brža od vremena

24

Page 25: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

potrebnog za njihovu transmisiju.

Za prenos 1 bajta podataka je potrebno izvršiti prenos 10 bita, obzirom da serijski protokol zahtijeva upotrebu jednog start bita i (barem) jednog stop bita. Tako, pri baud vrijednosti od 256000, za prenos 2 bajta podataka, očekivano vrijeme prenosa je:

Ispod se može vidjeti grafik koji pokazuje vrijeme potrebno za izvršavanje petlje na Arduino Uno uređaju koja, koristeći write funkciju, šalje 2 bajta. Funkcija micros je korištena za određivanje razlike između vremena u kojem je izvršena svaka iteracija petlje. Može se uočiti trenutak kada se buffer napuni te od kada vrijeme potrebno za dolazak u sljedeću iteraciju postaje jednako vremenu za prenos 2 bajta.

Iz ovoga se može zaključiti da je najmanji mogući period sampliranja, ukoliko se ti podaci žele slati na računar, jednak 80μs što je ekvivalentno maksimalnoj frekvenciji sampliranja od 12.5 kHz.

25

Slika 7: Grafik koji pokazuje vrijeme (μs) potrebno za izvršavanje iteracije petlje koja šalje 2 bajta na serijski izlaz u odnosu na redni

broj petlje

Page 26: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

2.4. Zaključak

U ovom poglavlju je predstavljena Arduino platforma. Na osnovu analize dostupne memorije i brzine prenosa podataka s uređaja na računar, može se zaključiti da je maksimalna frekvencija uzorkovanja prilikom procesa akvizicije analognog signala 12.5 kHz. Znajući da je rezolucija analogno-digitalnog konvertora 10 bita, dolazi se do zaključka da je maksimalan broj diskretnih naponskih nivoa koje Arduino može prepoznati 1024.

Obzirom da je analogni izlaz implementiran pomoću PWM tehnike, analogni izlaz Arduino “akvizicione kartice” bez dodatnog filtera neće imati valni oblik koji se očekuje.

26

Page 27: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3. Implementacija

3.1. Uvod

U ovom poglavlju su predstavljene sve komponente sistema koje su potrebne kako bi se postigla tražena funkcionalnost Arduino uređaja kao akvizicionog modula. Najprije je dat opis svrhe svake komponente i načina njihove saradnje. Iza toga slijedi opis metoda komunikacije tih komponenti.

Po tom, svaka od komponenti je detaljno opisana, njen dizajn i implementacija. Sve bitne klase su predstavljene i krucijalni dijelovi implementacije metoda objašnjeni.

3.2. Generalni opis

Da bi se postigao cilj implementiranja adaptora za Data Acquisition Toolbox, osim samog DLL-a kojeg će koristiti Data Acquisition Engine, razvijene su još tri komponente koje kroz međusobnu kooperaciju sistemu omogućavaju ispravan rad. Svaki od dijelova ima odgovornost koja se ne preklapa ni sa jednim drugim dijelom.

Sve četiri komponente su:

• EtfArduinoFirmware – program za Arduino uređaj koji mu omogućava izvršavanje funkcionalnosti akvizicione kartice i komunikacije s računarom.

• EtfArduinoService proces – predstavlja servis koji klijentima omogućava pristup funkcionalnostima Arduino uređaja za akviziciju (Arduino sa EtfArduino firmwareom).

Zadužen je za svu komunikaciju s uređajem – korištenje usluga ovog procesa je jedini način da se pristupi mogućnostima uređaja. Ovaj proces je jedini koji brine o direktnoj komunikaciji s uređajem, tj. protokolima koje je potrebno koristiti kako bi se komunikacija obavila.

Klasa EtfArduinoService je implementirana da bi se korištenje servisa olakšalo svim procesima koji imaju potrebu za njegovim uslugama.

• EtfArduinoConfig GUI aplikacija – služi da se Arduino uređaji koji imaju instaliran odgovarajući firmware registruju za korištenje, tj. da se servisu signalizira da treba da omogući komunikaciju sa tim uređajem.

• etfarduino.dll – DLL koji implementira adaptor za MATLAB-ov Data Acquisition Toolbox koji omogućava Data Acquisition Engineu da koristi Arduino uređaje. Koristi usluge EtfArduinoService procesa kako bi komunicirao s uređajem i proslijeđivao mu komande.

27

Page 28: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Iz ovog opisa se može vidjeti da svaka od komponenti ima potrebu da komunicira sa makar jednom drugom komponentom.

Obzirom da su u pitanju odvojeni procesi, za postizanje komunikacije EtfArduinoService servisa sa etfarduino.dll objektima i EtfArduinoConfig aplikacijom, potrebno je upotrijebiti neki mehanizam međuprocesne komunikacije. U ovom projektu to su named pipes i window messages.

Za komunikaciju samog uređaja sa računarom, tj. EtfArduinoService servisom, je potrebno koristiti neki vid komunikacije među različitim uređajima. U ovom projektu, korištena je komunikacija preko (virtualnog) serijskog porta.

DLL sa engineom komunicira tako što implementira COM interfejs koji engine zahtijeva.

28

Slika 8: Komunikacija komponenti sistema

Page 29: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.3. Problem sinhronizacije niti

Prije prelaska na opis implementacije pojedinih komponenti sistema, bit će dat opis određenih klasa koje će biti korištene kao pomoćne (utility) klase pri implementaciji nekih većih i kompleksnijih dijelova.

Jedan od najbitnijih problema koji se javlja pri razvoju kompleksnih sistema je postizanje ispravnog funkcionisanja više niti unutar jednog procesa. Koristeći višenitnost može se puno dobiti na efikasnosti, ali, ukoliko se ne preduzmu potrebne mjere, može doći do problema koje je izuzetno teško otkriti.

Jedna od tih mjera je sinhronizacija ili serijalizacija niti. To podrazumijeva korištenje odgovarajućih mehanizama kako bi se osiguralo da više niti ne izvršava neki dio programa u isto vrijeme. Ukoliko jedna nit uđe u taj dio programa (koji se naziva kritična sekcija), sve ostale moraju čekati dok ta nit ne izađe iz kritičnog dijela. Najčešće je tako nešto potrebno postići kada se pristupa dijeljenom resursu kao što su hardverski uređaji, objekti dijeljeni među nitima i sl. Ovo se još naziva uzajamno isključivanje (mutual exclusion).

3.3.1. Win32 API: uzajamno isključivanje

Za postizanje uzajamnog isključivanja Win32 API nudi više različitih opcija. U implementaciji ovog projekta je odabrano korištenje critical section objekata. To su objekti koji obezbjeđuju sinhronizaciju niti unutar istog procesa, tj. objekat nije moguće dijeliti između različitih procesa kao što je to slučaj sa mutex objektima.

Funkcije za korištenje critical section objekta su:

• InitializeCriticalSection – inicijalizira critical section objekat čiji je pokazivač proslijeđen kao parametar funkcije.

• EnterCriticalSection – niti koriste ovu funkciju kako bi zahtijevali isključivo vlasništvo nad critical section objektom čiji je pokazivač proslijeđen kao parametar. Ukoliko neka druga nit posjeduje objekat u trenutku poziva funkcije, poziv blokira izvršavanje niti sve dok objekat ne postane slobodan i pređe u vlasništvo trenutne niti.

• LeaveCriticalSection – funkcija korištena kako bi nit napustila vlasništvo critical section objekta i time omogućila drugim nitima da nastave svoje izvršavanje, tj. preuzmu vlasništvo nad tim objektom. Ukoliko nit završi svoje izvršavanje bez poziva ove funkcije, critical section objekat ostaje permanentno u zaključanom stanju, tj. sve ostale niti koje žele preuzeti vlasništvo će osatati permanentno blokirane.

• DeleteCriticalSection – funkcija oslobađa sve resurse koje critical section objekat zauzima. Nakon poziva ove funkcije više nije moguće koristiti objekat za sinhronizaciju.

29

Page 30: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Kako bi korištenje ovog sinhronizacijskog mehanizma bilo olakšano te kako bi se spriječile moguće greške i problemi nastali zbog neoslobađanja vlasništva nad critical section objektima uslijed bačenih izuzetaka, implementirane su dvije pomoćne klase.

3.3.2. CriticalSection klasa

class CriticalSection{public:

CriticalSection();~CriticalSection();

void enter();void leave();

private:CRITICAL_SECTION cs;

};

Wrapper klasa oko CRITICAL_SECTION objekta koja pomoću svojih metoda Enter i Leave nudi funkcionalnost preuzimanja i oslobađanja vlasništva nad critical section objektom. Te metode su implementirane preko poziva EnterCriticalSection i LeaveCriticalSection funkcija.

Konstruktor i destruktor se brinu o ispravnom inicijaliziranju i oslobađanju resursa asociranih sa critical section objektom tako što pozivaju funkcije InitializeCriticalSection i DeleteCriticalSection.

3.3.3. Lock klasa

class Lock{public:

Lock(CriticalSection& criticalSection);~Lock();

private:void acquire();void release();CriticalSection& criticalSection;

};

Klasa definiše objekte koji u svom konstruktoru primaju CriticalSection objekat i pokušavaju preuzeti vlasništvo nad njim pozivajući metodu enter tog objekta. Vlasništvo nad objektom se oslobađa u desktruktoru objekta pozivom leave metode CriticalSection objekta.

Na ovaj način je obezbijeđeno da nit oslobodi vlasništvo u trenutku izlaska iz bloka u kojem je deklarisan Lock objekat, bez obzira da li je u pitanju normalno izvršavanje ili je bačen neočekivani izuzetak.

30

Page 31: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.4. Međuprocesna komunikacija

Kao što je pomenuto na početku poglavlja, za komunikaciju među procesima su korišteni mehanizmi named pipe i poruka prozorima (window messages). Slijedi opis svake od tih metoda, načina na koji su podržani kroz WinAPI te načina na koji su korišteni u ovom projektu.

3.4.1. Named pipe

Named pipe predstavlja jednosmjerni ili duplex komunikacioni kanal između pipe servera i jednog ili više pipe klijenata. Sve instance named pipe objekta dijele isto ime, ali svaka od njih ima zasebne buffere što znači da svim klijentima omogućava zasebnu metodu komunikacije sa serverom.

Named pipe omogućava procesima da razmjenjuju velike količine podataka pa je iz tog razloga odabran kao jedan od mehanizama međuprocesne komunikacije u ovom projektu.

3.4.1.1. Win32 API za komunikacjiu preko named pipeova

Win32 API definiše nekoliko funkcija pomoću kojih se implementira komunikacija koristeći named pipe. Najbitnije, tj. one korištene u implementaciji ovog projekta su:

• CreateNamedPipe – kreira novu instancu named pipea datog imena. Vraća handle na novokreiranu instancu pomoću kojeg je moguće pristupiti ostalim funkcionalnostima te instance.

Ime pipea mora biti dato u formatu \\.\pipe\IME_PIPEA.

Ovom funkcijom se također postavljaju atributi instance named pipea koja se kreira. Postavljanjem atributa moda otvaranja instance (open mode) na PIPE_ACCESS_DUPLEX dozvoljava se dvosmjerna komunikacija između klijenta i servera.

Mod komunikacije preko instance pipea se može postaviti na tzv. bajt mod i message mod. Razlika je u tome što se u message modu različite operacije pisanja na named pipe mogu raspoznati i u njihovoj cijelosti čitati, što dovodi do lakšeg razdvajanja nevezanih poruka, bez potrebe za slanjem specijalnih znakova koji bi odvajali različite poruke. Ovaj mod se postavlja zadavanjem PIPE_TYPE_MESSAGE i PIPE_READMODE_MESSAGE flagova parametra pipe mode.

• ConnectNamedPipe – omogućava serverskom procesu named pipe komunikacije da čeka da se na instancu kreiranu pozivom funkcije CreateNamedPipe spoji klijent. Poziv ove funkcije blokira nit koja je izvršila poziv sve dok se klijent ne spoji kada funkcija vraća BOOL vrijednost kojom govori da li je konekcija uspješno izvršena.

31

Page 32: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

• CreateFile – funkcija omogućava klijentskom procesu da se poveže na neku instancu named pipea datog imena koja je već kreirana i otvorena za klijentske konekcije (prethodne dvije funkcije).

Funkcija prepoznaje da je u pitanju otvaranje konekcije sa named pipe instancom na osnovu formata imena filea koji se proslijedi.

Funkcija vraća handle pomoću kojeg se može pristupiti klijentskoj strani pipea.

• SetNamedPipeHandleState – funkcija koja se koristi za izmjenu moda komunikacije pipea. Nakon što se klijent spoji na instancu named pipea, handle koji vraća CreateFile funkcija omogućava bajt mod čitanja. Postavljanjem PIPE_READMODE_MESSAGE flaga za parametar mode ove funkcije, mod se prebacuje na message.

• WriteFile – pomoću ove funkcije klijent i server vrše upis podataka koje druga strana može čitati. Funkciji kao parametre prime handle na pipe instancu, pokazivač na buffer iz kojeg treba slati podatke i broj bajta koje je potrebno poslati.

Kada je handle koji je proslijeđen funkciji u message modu, primalac je u stanju automatski razdvojiti podatke poslane različitim pozivima ove funkcije.

Funkcija blokira izvršavanje niti iz koje je pozvana sve dok se svi podaci ne pošalju nakon čega vraća BOOL vrijednost koja je indikator uspješnosti slanja podataka.

• ReadFile – pomoću ove funkcije klijent i server čitaju podatke koje je druga strana poslala preko instance named pipea čiji je handle dat kao parametar.

Kada je mod komunikacije named pipea postavljen na tip message, funkcija bez obzira na proslijeđeni broj bajta koje treba pročitati, vraća samo onoliko podataka koliko je pošiljalac poslao pri pozivu WriteFile funkcije.

Ukoliko ne postoje nepročitane poruke na strani pipea s koje je pozvana funkcija, blokira se izvršavanje niti sve dok druga strana ne izvrši slanje poruke.

• TransactNamedPipe – kada je mod komunikacije na instanci named pipea postavljen na message, moguće je koristiti ovu funkciju kako bi se u jednoj operaciji poslali podaci na drugu stranu pipea, a zatim sačekao i pročitao odgovor na tu poruku.

Izvršavanje operacije se na završava prije nego što se pročita odgovor i smjesti u odgovarajući buffer čiji pokazivač je proslijeđen.

• DisconnectNamedPipe – funkcija diskonektuje serversku stranu named pipea od klijentskog procesa. Ukoliko je u trenutku poziva funkcije klijentska strana otvorena, funkcija uzrokuje njeno zatvaranje. Nakon toga, svaki pokušaj klijenta da pristupi named pipeu vraća grešku.

32

Page 33: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Instanca named pipea nad kojom je pozvana funkcija se može otvoriti za konekciju drugog klijenta koristeći ConnectNamedPipe funkciju nad istim handleom.

• CloseHandle – pozivanjem ove funkcije nad handleom povezanim sa klijentskom ili serverskom stranom pipea, zatvara se komunikacioni kanal.

3.4.1.2. PipeCommunicator klasa

Ova klasa služi da sakrije detalje kreiranja named pipe instanci, primanja klijentskih konekcija, kao i primanja i slanja poruka preko kreirane veze. Javni interfejs klase otkriva koje funkcije klasa podržava:

public:typedef int message_t;

static DWORD const bufferSize = 512;

PipeCommunicator(LPCWSTR pipeName);~PipeCommunicator();

bool Connect();bool SendMessage(LPCVOID buffer, DWORD bufferSize);bool RetrieveMessage(LPVOID buffer, DWORD bufferSize, LPDWORD bytesRead);

Konstruktor objekta kreira novu instancu named pipea pod imenom koje mu je proslijeđeno kao parametar. Ovo je postignuto pozivom WinAPI funkcije CreateNamedPipe.

Vrijednosti parametara poziva funkcije su takvi da se kreira named pipe koji radi u message modu prenosa podataka.

hPipe = CreateNamedPipe( pipeName, // pipe name PIPE_ACCESS_DUPLEX, // read/write access PIPE_TYPE_MESSAGE | // message type pipe

PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode

PIPE_UNLIMITED_INSTANCES, // max. instances bufferSize, // output buffer size bufferSize, // input buffer size 0, // client time-out NULL); // default security attribute

Destruktor objekta zatvara serversku stranu named pipe konekcije.

Metoda Connect čeka da se klijent spoji na named pipe instancu koja je kreirana. To je postignuto pozivom ConnectNamedPipe WinAPI funkcije.Metoda blokira izvršavanje threada u kojoj je pozvana sve dok se neki klijent ne konektuje. Povratna vrijednost je tipa bool i označava da li je konekcija uspješno izvršena ili ne.

Metoda SendMessage prima pokazivač na buffer i broj bajta koje je potrebno poslati. Metoda pozivom WriteFile funkcije vrši prenos podataka od servera prema klijentu.

33

Page 34: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Izvršavanje niti koja poziva ovu metodu se blokira sve dok se cijela poruka ne pošalje. Povratna vrijednost je tipa bool i označava da li je poruka uspješno poslana.

Metoda RetrieveMessage prima pokazivač na buffer u koji se trebaju smjestiti pročitani podaci, broj bajta koje treba pročitati i pokazivač na DWORD u koji se može smjestiti broj bajta koji su zaista pročitani.Izvršavanje niti koja poziva ova funkciju se blokira sve dok se poruka ne pročita. Povratna vrijednost je tipa bool i označava da li je poruka uspješno pročitana.

3.4.2. Window Messages

Windows operativni sistem implementira sistem proslijeđivanja poruka aplikacijama kako bi Windows aplikacije bile event-driven, tj. kako bi mogle da odgovaraju na različite događaje u sistemu. Događaji na koje aplikacija može odgovarati uključuju korisnički ulaz, promjenu veličine prozora aplikacije i sl.

Ovaj sistem radi tako što operativni sistem šalje poruku (Message) nekom prozoru (Window) aplikacije. Svaki prozor registruje callback funkciju koja će se pozvati kada aplikacija primi poruku koja je namijenjena za taj prozor. Callback funkcija je zadužena da na osnovu primljene poruke preduzme odgovarajuću akciju. Svaka poruka sadrži dvije vrijednosti koje mogu nositi dodatne informacije o poruci i koje mogu uticati na to šta callback funkcija radi.

Poruke za aplikaciju se smiještaju u message queue iz kojeg se mogu preuzeti na FIFO način koristeći WinAPI funkcije. Uobičajeni način za preuzimanje poruka je da se u nekoj niti aplikacije izvršava petlja koja konstantno provjerava ima li novih poruka u message queueu te ako ima pokreće odgovarajuće callback funkcije. Ova petlja se naziva message loop.

Ono što je značajno je da poruke prozoru aplikacije ne mora slati samo operativni sistem. Svi programi, s dovoljnim nivoom privilegije, mogu poslati poruku u message queue bilo kojeg prozora. Ova činjenica, kao i to da je moguće kreirati prozore bez grafičkog prikaza, je iskorištena kako bi se implementirala međuprocesna komunikacija i u ovom projektu.

3.4.2.1. Win32 API: Window i WindowMessage

• RegisterClass – funkcija registruje window klasu koja će u budućnosti biti korištena u pozivima CreateWindow funkcije.

Funkcija kao parametar prima pokazivač na WNDCLASS strukturu koja definiše sve parametre prozora te klase, od kojih su najbitniji callback funkcija koja će se izvršiti kada prozor primi poruku i tekstualno ime prozora.

Funkcija vraća identifikator registrovanog prozora koji se može koristiti pri pozivu funkcije CreateWindow.

34

Page 35: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

• CreateWindow – funkcija kreira novi prozor tipa proslijeđene Window klase. Također postavlja parametre prikaza kreiranog prozora.

Kao identifikator Window klase koja treba biti korištena za kreiranje prozora, može se proslijediti ili tekstualno ime klase ili vrijednost koju je vratila RegisterClass funkcija.

Funkcija vraća handle tipa HWND pomoću kojeg se može identifikovati novokreirani prozor.

• FindWindow – funkcija pronalazi prozor čija klasa ima tekstualno ime ili identifikator koji je proslijeđen kao parametar i vraća handle (HWND) pomoću kojeg se može referencirati.

• GetMessage – funkcija preuzima sljedeću neobrađenu poruku iz message queuea aplikacije i stavlja je u MSG strukturu čiji pokazivač je proslijeđen kao parametar.

• DispatchMessage – funkcija, na osnovu podataka iz MSG strukture čiji pokazivač joj je proslijeđen kao parametar, poziva odgovarajuću callback funkciju povezanu s prozorom za koji je poruka namijenjena.

Povratna vrijednost funkcije je vrijednost koju vrati callback.

• DestroyWindow – funkcija uništava prozor čiji handle prima kao parametar. Šalje prozoru Windows predefinisanu poruku WM_DESTROY koja signalizira callback proceduri prozora da izvrši oslobađanje svih resursa koje je prozor zauzeo. Ovu funkciju može pozvati samo thread koji je i kreirao prozor pozivom funkcije CreateWindow.

• UnregisterClass – funkcija deregistruje klasu prozora čime se oslobađa memorija koju definicija tog prozora zauzima. Parametar funkcije je tekstualno ime prozora ili identifikator koji je vratila RegisterClass funkcija.

• RegisterWindowMessage – registruje novu poruku koja se može slati prozorima (window message) na nivou sistema čiji je identifikator jedinstven. Identifikator je povratna vrijednost funkcije i može se koristiti pri slanju poruka prozorima.

Ukoliko dvije različite aplikacije pozovu funkciju sa istom vrijednosti imena poruke, obje aplikacije dobivaju istu vrijednost čime se postiže mogućnost komunikacije tih aplikacija pomoću registrovane poruke.

• PostMessage – funkcija stavlja message, čiji identifikator i parametri su proslijeđeni funkciji, na kraj message queuea koji je povezan sa prozorom čiji handle je proslijeđen. Funkcija ne čeka da poruka bude obrađena.

35

Page 36: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.4.2.2. MessageWindow klasa

Pomoću objekta klase MessageWindow, adaptor prima i obrađuje poruke od procesa koji je zadužen za komunikaciju sa Arduino uređajima – EtfArduinoService servis. Ove poruke služe da obavijeste adaptor o stanju servisa.

Jedina poruka koja je trenutno implementirana u projektu je signal da je servis prikupio cijeli buffer podataka od uređaja pri analognoj akviziciji te da je spreman za novi zahtjev za preuzimanje buffera podataka.

Klasa implementira singleton design pattern, obzirom da je moguće kreirati samo jedan prozor koji bi obrađivao poruke od servisa, bez obzira na broj akvizicionih podsistema koje MATLAB-ov Data Acquisition Engine kreira.

Ovaj prozor prilikom obrade primljene poruke određuje za koji podsistem je poruka namijenjena i poziva metodu objekta povezanog s tim podsistemom predviđenu za obradu tog događaja. Kako bi pronašao odgovarajući objekat za dati podsistem, MessageWindow objekat ima std::map objekat koji čuva mapiranja para (ID uređaja, podsistem uređaja) na pokazivač na odgovarajući objekat podsistema. Kada podsistem započne aktivnost koja će zahtijevati poruke od servisa, registruje se pri MessageWindow klasi pozivom odgovarajuće metode kojoj proslijedi pokazivač na sebe. Po završetku aktivnosti, kada prestane potreba za primanjem signala od servisa, podsistem se deregistruje iz skupa podsistema koje MessageWindow treba obavještavati.

Javni interfejs sa privatnim članovima i pomoćnim funkcijama je:

class MessageWindow {public:

// Destructorvirtual ~MessageWindow();// Public member functionsbool AddDevice(UINT deviceId, UINT subsystem, LPVOID device);bool RemoveDevice(UINT deviceId, UINT subsystem);// Public static member functionsstatic MessageWindow& getInstance();

private:typedef LPVOID DevicePtr;struct DeviceIdentificator {

UINT deviceId;UINT subsystem;DeviceIdentificator(UINT deviceId, UINT subsystem) :

deviceId(deviceId), subsystem(subsystem) { }bool operator< (DeviceIdentificator const& rhs) const {

return deviceId < rhs.deviceId;}

};typedef std::map<DeviceIdentificator, DevicePtr> map_t;// ConstructorsMessageWindow();// Private membersHWND mHandle;

36

Page 37: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

HANDLE hThread;map_t devices;CriticalSection cs;// Private member functionsbool StartMessageLoopThread();bool CreateMessageWindow();DevicePtr GetDevice(UINT deviceId, UINT subsystem);// Private static membersstatic TCHAR const* mClassName;// A Window Message registered with the OSstatic UINT WM_ETFARDUINO;// Subsystem identifier constantsstatic UINT const AI_SUBSYSTEM = 1;static UINT const AO_SUBSYSTEM = 2;// Private static member functionsstatic TCHAR const* className();static LRESULT CALLBACK WindowProc(HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp);static DWORD WINAPI ThreadProc(LPVOID param);

};

Kao što se može vidjeti, konstruktor klase se nalazi u privatnom dijelu kako bi se zabranilo kreiranje objekata tipa MessageWindow vanjskim korisnicima klase.

Statička javna metoda getInstance vraća referencu na jedinu instancu objekta koja postoji za vrijeme izvršavanja procesa.

MessageWindow& MessageWindow::getInstance() {// Singleton patternstatic MessageWindow mInstance;return mInstance;

}

Statički privatni atribut className čuva tekstualno ime klase prozora.

Statički privatni atribut WM_ETFARDUINO predstavlja identifikator poruke koja se registruje pri operativnom sistemu za komunikaciju adaptora i servisa.

UINT MessageWindow::WM_ETFARDUINO = RegisterWindowMessage(TEXT("WM_ETFARDUINO"));

Konstruktor registruje klasu prozora i pozivom pomoćne privatne metode StartMessageLoop, započinje thread u kojem se izvršava message loop.

Poziv WinAPI funkcije RegisterClass u konstruktoru:

WNDCLASS classStruct = {0, // style&MessageWindow::WindowProc, // WndProc0, // cbClsExtra0, // cbWndExtra0, // hInstance0, // hIcon0, // hCursor0, // hbrBackground0, // lpszMenuName

37

Page 38: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

className // lpszClassName};if (!RegisterClass(&classStruct)) {

throw TEXT("Fatal error! Unable to register the MessageWindow class.");}

Nit u kojoj se izvršava message loop je i nit koja kreira prozor pozivajući CreateMessageWindow metodu klase MessageWindow nad objektom čiji je pokazivač proslijeđen kao parametar. Ovo je iz razloga što samo nit koja kreira prozor može zvati funkciju DestroyWindow. Snippet koda ispod prikazuje statičku funkciju ThreadProc koja predstavlja opisanu nit.

DWORD WINAPI MessageWindow::ThreadProc(LPVOID param) {// Thread treba najprije da registruje prozor kojem ce se// proslijedjivati porukeMessageWindow& msgWin = *((MessageWindow*)param);msgWin.CreateMessageWindow();// Sada zapoceti message loopMSG msg;while (GetMessage(&msg, NULL, 0, 0)) {

DispatchMessage(&msg);}return 0;

}

Metoda CreateMessageWindow, kao što je već rečeno, kreira prozor:

bool MessageWindow::CreateMessageWindow() {mHandle = CreateWindow(

className, // className0, // titleWS_CAPTION, // style0, 0, 0, 0, // x, y, cx, cy0, // parent0, // menu0, // instance0); // create struct

return true;}

Iz snippeta koda konstruktora, koji je dat iznad, vidi se da je callback procedura koja se izvršava za obradu poruka koje stignu prozoru statička metoda WindowProc klase MessageWindow.

Ukoliko prozor primi poruku koju je poslao servis može je prepoznati po jedinstvenom identifikatoru WM_ETFARDUINO, zbog svojstva RegisterWindowMessage funkcije koja je već objašnjena. Za obradu te poruke, pronalazi se odgovarajući objekat podsistema kojem je namijenjena poruka i poziva metoda predviđena za obradu događaja. Vrijednosti koje su potrebne za pronalazak podsistema su ID uređaja i ID podsistema koji su poslani u prvom (wParam) i drugom (lParam) parametru messagea.

if (msg == WM_ETFARDUINO) {// Preuzimanje parametaraUINT deviceId = (UINT)wp;UINT subsystem = (UINT)lp;// Pronalazak podsistema

38

Page 39: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

if (subsystem == AI_SUBSYSTEM) {MessageWindow& msgWin = MessageWindow::getInstance();CetfarduinoAin* ain =

(CetfarduinoAin*) msgWin.GetDevice(deviceId, subsystem);if (ain != 0) {

ain->ReceivedMessage(wp, lp);}

}}

Ostale poruke koje je potrebno obraditi su riješene na sljedeći način:

switch (msg){case WM_CLOSE:

DestroyWindow(msgWindow);return 0;

case WM_DESTROY:PostQuitMessage(0);break;

default:return DefWindowProc(msgWindow, msg, wp, lp);

}

Vidi se da poruka WM_CLOSE izaziva poziv WinAPI funkcije DestroyWindow, a da WM_DESTROY poruka dovodi do zaustavljanja message loopa.

Privatna ugniježdena klasa DeviceIdentificator služi kao pomoćna klasa čiji su objekti ključevi pomoću kojih se identifikuju i pronalaze pokazivači na objekte podsistema.

Metode AddDevice, RemoveDevice i GetDevice, služe za manipulaciju std::map objektom devices, koji čuva sve pokazivače na objekte podsistema. Metode su međusobno sinhronizovane koristeći CriticalSection i Lock objekte kako bi se pristup objektu devices zaštitio od istovremenog pristupa iz različitih niti procesa.

bool MessageWindow::RemoveDevice(UINT deviceId, UINT subsystem) {Lock lock(cs);devices.erase(DeviceIdentificator(deviceId, subsystem));return true;

}

39

Page 40: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.4.2.3. MessageWindowSender klasa

MessageWindowSender je klasa koju koristi EtfArduinoService proces kako bi poslao odgovarajuće notifikacije adaptoru.

class MessageWindowSender {public:

// ConstructorsMessageWindowSender(UINT deviceId, int subsystem);// Destructorvirtual ~MessageWindowSender();// Public member functionsbool NotifyBufferFull();// Public static membersstatic int const SUBSYSTEM_AI = 1;static int const SUBSYSTEM_AO = 2;

private:// Private membersHWND mHandle;UINT const deviceId;int const subsystem;// Private static membersstatic TCHAR const* className;static UINT WM_ETFARDUINO;

};

Obzirom da su notifikacije predviđene da se šalju kao poruke prozoru, klasa sadrži privatne statičke atribute className i WM_ETFARDUINO koji definišu tekstualno ime klase prozora i identifikator poruke koju šalje servis, respektivno.

TCHAR const* MessageWindowSender::className = TEXT("EtfArduinoMessageWindow");UINT MessageWindowSender::WM_ETFARDUINO = RegisterWindowMessage(TEXT("WM_ETFARDUINO"));

Bitno je primijetiti da je ime klase postavljeno na istu vrijednost kao što je to i u klase MessageWindow koja registruje prozor.

Konstruktor MessageWindowSender objekta pomoću WinAPI funkcije FindWindow pronalazi kreirani prozor koji očekuje da primi poruke. Kao parametre konstruktor prima ID uređaja i podsistema za kojeg će sve njegove poruke biti namijenjene.

Metoda NotifyBufferFull pomoću PostMessage funkcije u message queue prozora stavlja poruku koja označava da je servis popunio cijeli buffer podataka koje je primio od Arduino uređaja.

if (!PostMessage(mHandle, WM_ETFARDUINO, (WPARAM) deviceId, (LPARAM) subsystem)) {return false;

}

Iz snippeta se vidi da je identifikator poruke WM_ETFARDUINO, prvi parametar poruke ID uređaja, a drugi parametar identifikator podsistema.

40

Page 41: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.5. EtfArduinoService proces

Ovo je proces koji služi za direktnu komunikaciju sa Arduino uređajima. Ostali procesi koji žele pristup funkcionalnostima Arduino uređaja za akviziciju im mogu pristupiti samo preko usluga ovog procesa.

Za komunikaciju sa klijentima koristi mehanizam međuprocesne komunikacije named pipe. Klijenti, znajući ime pipea se spajaju na servis, a zatim, slanjem poruka kroz instancu pipea na koju su spojeni, zahtijevaju usluga od ovog servisa. Za olakšano korištenje usluga servisa, implementirana je klasa EtfArduinoService koja detalje komunikacije sakriva iza svog interfejsa.

Servis koristi i drugu metodu međuprocesne komunikacije koja je ranije predstavljena, poruke prozorima. Ta metoda je korištena kada sam proces ima potrebu da obavijesti klijente o događajima koji su se desili. Potreba za ovim dolazi iz činjenice da neke operacije moraju biti asinhrone, pa je onda jedini način da se pozivalac obavijesti o njihovom završetku ili statusu, neki vid međuprocesne komunikacije. Tu su poruke prozorima izuzetno pogodne jer nije potrebno brinuti o implementaciji sinhronizacije reda poruka, već se Windows operativni sistem za to brine.

Ispod se može vidjeti dijagram klasa korištenih u implementaciji komponente.

41

Slika 9: Dijagram klasa EtfArduinoService komponente

Page 42: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Može se uočiti da je korišten abstract factory dizajn pattern za implementaciju klasa za procesiranje zahtijeva klijenata. Razlog za to je veća modularnost i time lakša proširivost servisa dodatnim funkcionalnostima, ukoliko za tim bude postojala potreba.

3.5.1. EtfArduinoService klasa

Ova klasa služi da od svog korisnika sakrije detalje komunikacije klijentskog procesa sa EtfArduinoService server procesom. Ono što klasa otkriva su metode koje predstavljaju funkcionalnosti koje server nudi. Pozivom odgovarajuće metode, klijent pristupa tim funkcionalnostima.

Javni interfejs klase je:

public:// ConstructorsEtfArduinoService();// Destructorvirtual ~EtfArduinoService();// Public member functionsbool setResponseBufferSize(DWORD responseBufferSize);bool GetBufferedData(

UINT deviceId,LPVOID ptrBuffer,DWORD bufferSize);

bool StartAcquisition(UINT deviceId);bool StopAcquisition(UINT deviceId);bool SetAcquisitionBufferSize(UINT deviceId, DWORD bufferSize);bool SetSampleRate(UINT deviceId, DWORD sampleRate);bool CheckDeviceRegistered(UINT deviceId, LPTSTR serialPortName);bool RegisterDevice(UINT& deviceId, LPCWSTR serialPortName);bool GetRegisteredDeviceIds(std::vector<UINT>& deviceIds);unsigned short GetSingleValue(UINT deviceId);bool SendDigitalValue(UINT deviceId, int line, int value);bool PutSingleValue(UINT deviceId, int channel, int value);

Konstruktor klase poziva OpenPipeConnection privatnu metodu koja se pokušava spojiti na postojeću named pipe instancu na kojoj je server predvidio komunikaciju sa klijentima. Ukoliko je konekcija neuspješna, pri budućim pozivima metoda kojima je potrebna mogućnost komunikacije sa serverom, ponovo se pokušava uspostaviti konekcija kako bi se za sigurno utvrdilo da komunikacija nije moguća prije vraćanja poruke greške.

U snippetu koda koji se nalazi ispod se vidi način na koji se klijent pokušava spojiti na server.

hPipe = CreateFile( PIPENAME, // pipe name GENERIC_READ | // read and write access

GENERIC_WRITE, 0, // no sharing NULL, // default security attributesOPEN_EXISTING, // opens existing pipe 0, // default attributes NULL); // no template file

42

Page 43: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

if (hPipe != INVALID_HANDLE_VALUE)break;

if (GetLastError() != ERROR_PIPE_BUSY) {hPipe = 0;return false;

}if (!WaitNamedPipe(PIPENAME, 20000)) {

hPipe = 0;return false;

}

Ukoliko je konekcija uspješna, mod komunikacije se postavlja na message.

DWORD dwMode = PIPE_READMODE_MESSAGE; BOOL fSuccess = SetNamedPipeHandleState(

hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL); // don't set maximum time

Privatna metoda SendMessage vrši slanje podataka iz buffera koji joj je proslijeđen kao parametar prema serveru.

BOOL fSuccess = WriteFile( hPipe, // pipe handle lpvMessage, // message cbToWrite, // message length &cbWritten, // bytes written NULL); // not overlapped

// Make sure the message got through the pipe before returning.FlushFileBuffers(hPipe);

Privatna metoda ClosePipeConnection najprije serveru šalje specijalnu poruku kojom signalizira kraj komunikacije, a zatim zatvara klijentsku stranu NamedPipe instance.

Sve javne metode, koje klijentskom procesu otkrivaju neku od funkcionalnosti servera, prolaze kroz istu sekvencu koraka pri implementaciji, obzirom da je zadatak svake od njih jednostavno poslati odgovarajuću poruku serveru i, eventualno, preuzeti odgovor.

Najprije, formira se buffer u kojem će se naći podaci koji se trebaju poslati prema serveru. Buffer je niz alociran na stacku čiji su elementi tipa message_t. Tip message_t je definisan kako bi svaki niz koji je predviđen da sadrži podatke koji se šalju serveru bio lako prepoznatljiv, ali i kako bi se taj tip mogao u budućnosti lako izmijeniti, ukoliko za tim bude postojala potreba. Trenutno je ovaj tip alias za tip int.

Buffer se puni podacima tako što se na prvo mjesto u nizu stavlja kod operacije koja se zahtijeva od servera. Klasa kao privatne statičke članove sadrži vrijednosti svih kodova koji odgovaraju operacijama čije izvršavanje podržava:

43

Page 44: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

static message_t const GET_BUFFERED_DATA = 1;static message_t const START_ACQUISITION = 2;static message_t const STOP_ACQUISITION = 3;static message_t const GET_SINGLE_VALUE = 4;static message_t const CHECK_DEVICE_REGISTERED = 5;static message_t const REGISTER_DEVICE = 6;static message_t const GET_REGISTERED_DEVICE_IDS = 7;

static message_t const SET_ACQUISITION_BUFFER_SIZE = 10;static message_t const SET_SAMPLE_RATE = 11;

static message_t const SEND_DIGITAL_VALUE = 20;

static message_t const PUT_SINGLE_VALUE = 30;

static message_t const DISCONNECT_CLIENT = 255;

Nakon toga, u bufferu slijede svi parametri koje server zahtijeva od klijenta za uspješno izvršavanje tražene komande.

Nakon toga, poruka se šalje preko otvorene instance NamedPipe-a koja je pridružena objektu. Ukoliko je u pitanju operacija koja zahtijeva odgovor od servera, koristi se TransactNamedPipe funkcija koja automatski nakon slanja podataka čeka i odgovor. S druge strane, ako se izvršava operacija kojoj nije potreban odgovor od servera, podaci se jednostavno šalju pomoću funkcije WriteFile.

Na kraju, preuzeti odgovor se postavlja u za to predviđene strukture koje su proslijeđene metodi.

Metode vraćaju bool koji uvijek predstavlja da li je izvršavanje uspješno okončano.

3.5.2. Komunikacija sa Arduinom

3.5.2.1. Win32 API: Serijska komunikacija

Komunikacija sa serijskim portovima je u Win32 API-u podržana pomoću standardnih funkcija za upravljanje fileovima. Pri tome, serijski portovi imaju specijalna imena pomoću kojih sistem prepoznaje koji serijski port je u pitanju.

Prije početka komunikacije sa otvorenim serijskim portom, potrebno je izvršiti i određenu konfiguraciju svojstava porta.

• CreateFile – otvara serijski port čije ime je proslijeđeno kao parametar funkcije. Imena serijskih portova moraju biti u formatu COMx, gdje je x jednocifren broj.

Moguće je odrediti da li je će port biti korišten za pisanje (GENERIC_WRITE), čitanje (GENERIC_READ) ili obje funkcije.

Pri pozivu funkcije obavezno je proslijediti parametar OPEN_EXISTING obzirom da serijski portovi već postoje, tj. njihovo kreiranje nije dozvoljeno.

44

Page 45: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Postavljanjem flaga FILE_FLAG_OVERLAPPED u odgovarajućem parametru, port se otvara u overlapped modu, čime se definiše mogućnost istovremenog izvršavanja operacija čitanja i pisanja na istom portu.

Funkcija vraća handle na otvoreni serijski port. Ukoliko poziv nije uspješan, vraćena vrijednost će biti INVALID_HANDLE_VALUE.

• SetCommState – postavlja parametre serijskog porta bitne za uspostavljanje uspješne komunikacije. Kao parametar prima handle na serijski port koji je potrebno konfigurisati i pokazivač na DCB strukturu koja definiše sve potrebne parametre koje je potrebno postaviti.

Polja DCB strukture koja treba postaviti su:

◦ BaudRate – brzina prenosa podataka;

◦ ByteSize – broj bita u bajtima koji se šalju i primaju;

◦ StopBits – broj stop bitova koje treba koristiti;

◦ Parity – korištena šema pariteta za detekciju grešaka.

• SetCommTimeouts – postavlja parametre serijske komunikacije koji se tiču timeouta, tj. vremena koje je dozvoljeno čekati da se pojedina operacija na serijskom portu izvrši. Funkcija kao parametar prima handle na serijski port koji se konfiguriše i pokazivač na COMMTIMEOUTS strukturu koja definiše sve potrebne vrijednosti.

Polja strukture COMMTIMEOUTS koja je potrebno definisati su:

◦ ReadIntervalTimeout – vrijeme u milisekundama koje je dozvoljeno čekati između prijema bajtova prije nego što se operacija čitanja završi;

◦ ReadTimeoutMultiplier – vrijeme u milisekundama koje predstavlja vrijeme čekanja za svaki bajt koji je zahtijevan u operaciji čitanja.

◦ ReadTotalTimeoutConstant – vrijeme u milisekundama koje je ukupno dozvoljeno provesti čitajući poruku sa serijskog porta. Suma ove vrijednosti i prethodne definiše ukupno vrijeme koje je dozvoljeno iskoristiti za čitanje;

◦ WriteTimeoutMultiplier i WriteTimeoutConstant – predstavljaju isto što i prethodne dvije vrijednosti samo za operacije pisanja na serijski port.

• WriteFile – funkcija šalje vrijednosti iz proslijeđenog buffera na serijski port. Prima broj bajtova koje je potrebno ispisati.

Povratna vrijednost funkcije je BOOL koji označava da li je operacija uspješno izvršena.

45

Page 46: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Također, funkcija zapisuje broj uspješno ispisanih bajtova na poziciju određenu proslijeđenim pokazivačem.

Ukoliko je postavljen overlapped mod za port na koji se pokušavaju poslati podaci, funkcija ne čeka na kraj izvršavanja prenosa svih podataka, već se izvršavanje nastavlja odmah nakon njenog poziva. Tako, moguće je da povratna vrijednost bude FALSE, ali da je prenos podataka još uvijek u toku. Ta situacija se otkriva tako što WinAPI funkcija GetLastError vrati kod koji odgovara grešci ERROR_IO_PENDING.

Iz tog razloga, funkcija kao parametar prima pokazivač na OVERLAPPED strukturu koja sadrži Event objekat koji će biti signaliziran kada se operacija uspješno završi.

• ReadFile – funkcija vrši čitanje vrijednosti sa serijskog porta i upisuje ih u buffer koji je proslijeđen kao parametar. Prima broj bajtova koje je potrebno učitati.

Broj uspješno učitanih bajtova se zapisuje na poziciju određenu proslijeđenim pokazivačem. Funkcija vraća BOOL vrijednost koja označava da li je čitanje datog broja bajtova uspješno izvršeno.

• CloseHandle – zatvara handle na serijski port čime se oslobađaju resursi i prestaje komunikacija sa portom. Omogućava se drugim aplikacijama da započnu komunikaciju sa istim portom.

3.5.2.2. SerialCommunicator klasa

SerialComunicator klasa služi da detalje komunikacije sa određenim serijskim portom sakrije iza svog javnog interfejsa:

public:SerialCommunicator(LPCWSTR serialPortName);virtual ~SerialCommunicator();

bool SendMessage(LPCVOID buffer, DWORD bufferSize);bool RetrieveMessage(LPVOID buffer, DWORD bufferSize, LPDWORD bytesRead);

Konstruktor objekta se brine da se uspostavi komunikacija sa serijskim portom, čije je ime proslijeđeno kao parametar. To radi pozivom privatne metode InitializeSerial koja otvara port i postavlja odgovarajuće parametre komunikacije.

Pri otvaranju porta, specificiran je FILE_FLAG_OVERLAPPED kako bi se omogućilo istovremeno čitanje i pisanje podataka na serijskom portu.

46

Page 47: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

hSerial =CreateFile(serialPortName,

GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

Brzina prenosa podataka, baud rate, je postavljena na 256000, istu vrijednost koju postavlja i Arduino firmware, kako bi komunikacija između računara i uređaja bila sinhronizirana.

dcbSerialParams.BaudRate = CBR_256000;

Destruktor vrši zatvaranje otvorenog serijskog porta kako bi se pri uništavanju objekta oslobodili svi resursi koji su zauzeti.

Metoda SendMessage kao parametre prima pokazivač na buffer i veličinu buffera u bajtima.

WinAPI funkciji WriteFile se proslijeđuju odgovarajući parametri, uključujući i pokazivač na OVERLAPPED strukturu u kojoj se nalazi Event koji će primiti signal okončanja prenosa podataka. Funkcija čeka na kraj prenosa podataka pozivajući GetOverlappedResult funkciju čime se postiže da se izvršavanje neće nastaviti sve dok se slanje podataka ne završi.

Povratna vrijednost SendMessage metode je bool vrijednost koja označava da li je prenos uspješno završen ili ne.

Metoda RetrieveMessage prima pokazivač na buffer, broj bajta koje je potrebno pročitati i pokazivač na DWORD u koji se može upisati ukupni broj bajta koji su pročitani.

Slično kao što je i slučaj kod metode SendMessage kreira se i OVERLAPPED struktura kojoj će biti signaliziran kraj procesa čitanja podataka sa serijskog porta.

Metoda vraća bool vrijednost koja označava da li je čitanje uspješno izvršeno.

3.5.2.3. ArduinoDevice klasa

Pomoću ArduinoDevice klase, moguće je pristupati funkcionalnostima Arduino kartice bez potrebe za poznavanjem načina komunikacije između računara i same kartice. Sama ArduinoDevice klasa je abstraktna bazna klasa, pa je za implementaciju metoda koje ona specificira potrebno definisati konkretnu klasu izvedenu iz nje. Time je postignuto da su svi detalji u vezi s formatom poruka koje se razmjenjuju sadržani samo u implementaciji metoda konkretnih ArduinoDevice klasa. Zahvaljujući ovom dizajnu, sasvim je jednostavno podržati drugi metod komunikacije sa Arduino uređajima.

47

Page 48: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Javni interfejs klase ArduinoDevice otkriva koje funkcije su sve podržane:

public:typedef unsigned short response_t;

ArduinoDevice(UINT deviceId);ArduinoDevice(UINT deviceId, DWORD bufferSize);virtual ~ArduinoDevice();

virtual bool StartAcquisition() = 0;virtual bool StopAcquisition() = 0;virtual response_t GetSingleValue() = 0;virtual bool SetSampleRate(int sampleRate) = 0;virtual bool SetBufferSize(int bufferSize) = 0;virtual bool SendDigitalValue(int line, int value) = 0;virtual bool PutSingleValue(int channel, int value) = 0;virtual response_t* GetNextBuffer() = 0;

DWORD GetBufferSize() const;UINT GetDeviceId() const;virtual LPCTSTR GetPortName() const = 0;

Protected članovi su predviđeni da budu korišteni od strane izvedenih klasa.

protected:UINT deviceId;DWORD bufferSize;BufferQueue bufferQueue;static DWORD const DEFAULT_BUFFER_SIZE = 64;

ArduinoDeviceSerial klasa je izvedena iz ArduinoDevice abstraktne bazne klase i implementira čiste virtualne metode tako što za komunikaciju s uređajem koristi serijski port uz pomoć SerialCommunicator klase.

Privatni dio klase ArduinoDeviceSerial je:

private:TCHAR serialPortName[10];int const tickFrequency;volatile LONG acquisitionActive;SerialCommunicator serial;CriticalSection cs;ArduinoDeviceSerial(ArduinoDeviceSerial const&);ArduinoDeviceSerial& operator=(ArduinoDeviceSerial const&);

Konstruktor inicijalizira privatni SerialCommunicator objekat proslijeđujući mu ime serijskog porta koje je asocirano s ArduinoDevice objektom. Time se otvara i zauzima serijski port za komunikaciju sve dok se ne pozove destruktor samog ArduinoDevice objekta nakon kojeg će biti uništen i SerialCommunicator.

U desktruktoru nema potrebe poduzimati nikakvu aktivnost za oslobađanje resursa, obzirom da tako nešto nije potrebno ni za jedan član klase.

48

Page 49: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Privatni član acquisitionActive je LONG vrijednost koja se može naći u tri stanja. Kada ima vrijednost 0, označava da proces analogne akvizicije za dati Arduino uređaj nije aktivan. Vrijednost 1 znači da je proces započeo i trenutno aktivan, a vrijednost 2 predstavlja stanje u kojem je poslan zahtjev za prestankom akvizicije, ali se još uvijek čeka prestanak preuzimanja novih podataka od uređaja.

Obzirom da više različitih threadova programa može pozivati metode objekta koje imaju potrebu da provjere ili promijene stanje varijable, potrebno je osigurati sinhronizovan pristup njenoj vrijednosti. S tim ciljem, prvo što se treba osigurati je da čitanje i pisanje bude završeno kao jedan jedinstven nedjeljiv korak bez mogućnosti da se vrijednost u memoriji nađe u nevalidnom stanju (atomic operacija). Ovo je zagarantovano činjenicom da se čitanje i pisanje riječi (word) uvijek izvršava u jednom nedjeljivom koraku.

Druga stvar koja je potrebna je biti siguran da se čitanje vrijednosti varijable izvršava prije svih memorijskih operacija koje dolaze nakon nje u programu (read-acquire operacija), kao i da se pisanje vrijednosti varijable izvršava nakon svih memorijskih operacija koje dolaze ispred u programu (write-release). Ovo je potrebno jer, bez posebno preduzetih mjera, moderni procesori, uslijed pokušaja optimizacije izvršavanja programa, vrše izmjenu redoslijeda pristupa memoriji što, u slučaju pristupa istoj vrijednosti iz različitih niti programa, može dovesti do čitanja ili pisanja neispravnih vrijednosti. Iako standard C++ jezika to ne spominje, Microsoft Visual C++ kompajler od verzije 2005 garantuje da sve operacije čitanja i pisanja volatile kvalificiranih varijabli imaju već navedene osobine read-acquire, tj. write-release operacija. To je razlog iz kojeg je acquisitionActive potrebno označiti i kao volatile.

Metoda StartAcquisition služi da započne proces akvizicije analognog signala. Najprije je potrebno postaviti vrijednost acquisitionActive na 1 kako bi od tog trenutka sve ostale operacije objekta bile u stanju prepoznati da je akvizicija aktivna.

Ipak, mogućnost postoji da je sama metoda StartAcquisition pozvana u trenutku u kojem je aktivan proces akvizicije, pa je njeno izvršavanje onemogućeno. Ovo znači da prije postavljanja nove vrijednosti treba uraditi provjeru trenutne i samo u slučaju da je ta vrijednost 0, postaviti novu. Očito, ova operacija mora biti nedjeljiva (atomic) kako mogući context switch nakon čitanja vrijednosti varijable, a prije upisa nove, ne bi doveo do neispravnih rezultata u nastavku izvršavanja. Ovakva operacija se naziva compare-and-swap (CAS).

Za tu svrhu, WinAPI obezbjeđuje funkciju InterlockedCompareExchange koja za novu vrijednost objekta čiji je pokazivač proslijeđen, postavlja vrijednost drugog parametra, samo u slučaju da je stara vrijednost jednaka trećem parametru. Funkcija vraća vrijednost koju je zatekla, pa se tako može odrediti da li je operacija izvršena ili ne – u slučaju da je povratna vrijednost različita od zadnjeg parametra operacija nije izvršena.

if (InterlockedCompareExchange(&acquisitionActive, 1, 0) != 0) {// Another thread already holds the acquisition active!return false;

}

Iz snippeta koda s početka metode StartAcquisition se vidi upotreba ove funkcije.

49

Page 50: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Nakon što je metoda uspješno postavila indikator da je akvizicija aktivna, potrebno je poslati poruku Arduino uređaju s komandom da započne s vraćanjem očitanih vrijednosti analognog signala. To je postignuto slanjem jednog bajta koji sadrži vrijednost ASCII znaka '1'. Ukoliko poruka nije uspješno poslana, izvršavanje se prekida i signalizira se da proces akvizicije nije aktivan.

if (!serial.SendMessage(buffer, sizeof buffer)) {acquisitionActive = 0;return false;

}

Iza toga, program ulazi u petlju čije se izvršavanje nastavlja sve dok se status indikatora acquisitionActive ne izmijeni pozivom odgovarajuće metode za zaustavljanje akvizicije. Petlja čita vrijednosti koje Arduino uređaj vraća, stavlja ih u red preuzetih buffera te šalje signal adaptoru da su novi podaci spremni za preuzimanje.

while (acquisitionActive == 1) {DWORD bytesRead = 0;response_t* values = new response_t[bufferSize];if (serial.RetrieveMessage(

values,bufferSize * sizeof(response_t), &bytesRead)) {

bufferQueue.Push(values);} else {

delete[] values;}// Send notification that this device has filled another buffer.msgWinSender.NotifyBufferFull();

}

Po izlasku iz petlje, šalje se poruka Arduino uređaju koja označava da treba prestati vršiti analognu akviziciju, pa time i slanje podataka računaru. Tek poslije toga se indikator acquisitionActive vraća na vrijednost 0 koja označava da je novi proces akvizicije moguće započeti.

buffer[0] = '2';bool status = serial.SendMessage(buffer, sizeof buffer);acquisitionActive = 0;return status;

Poziv metode StartAcquisition blokira thread iz kojeg je poziv izvršen, za sve vrijeme trajanja akvizicije, što je potencijalno veliki vremenski period. Iz tog razloga, potrebno je osigurati da se poziv izvrši iz niti koja je namijenjena isključivo za izvršavanje ove metode kako ne bi došlo do velikog kašnjenja u obradi drugih podataka.

StopAcquisition metoda služi da se proces akvizicije zaustavi. Ona postavlja indikator acquisitionActive na vrijednost 2 – što će izazvati da petlja koja vrši preuzimanje vrijednosti u sljedećoj iteraciji prestane s radom. Izmjena se vrši samo ako trenutna vrijednost pokazuje da je akvizicija aktivna. Slična kao i pri početku akvizicije, za ovu svrhu je potrebno koristiti compare-and-swap operaciju.

50

Page 51: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

bool ArduinoDeviceSerial::StopAcquisition() {// Sets the flag to indicate the acquisition should stopif (InterlockedCompareExchange(&acquisitionActive, 2, 1) != 1)

return false;return true;

}

GetSingleValue metoda služi za preuzimanje jedne vrijednosti analognog signala (jedan sample) sa Arduino uređaja. Uz potrebne provjere validnosti i sinhronizacije izvršavanja operacije, uređaju se šalje poruka od jednog bajta s ASCII vrijednosti koja odgovara karakteru '4'. Odmah nakon toga se traži odgovor – jedna unsigned short vrijednost (2 bajta) koja predstavlja traženi uzorak. Preuzeta vrijednost se vraća kao povratna vrijednost funkcije.

U slučaju bilo koje greške pri izvršavanju metode, vraćena vrijednost je jednaka 0xFFFFFFFF što je znak da ispravna vrijednost nije preuzeta, obzirom da je Arduino ADC ograničen na 10 bita, tj. najveću vrijednost 1023.

SetSampleRate metoda vrši izračun potrebne vrijednosti perioda koju je potrebno poslati Arduino uređaju kako bi brzina sampliranja odgovarala traženom sample rateu. Uređaju se, nakon koda operacije, šalju bajti od kojih se sastoji izračunata vrijednost, počevši od najmanje značajnog bajta (LSB) do najbitnijeg bajta.

char buffer[1 + 4];buffer[0] = '3';buffer[1] = period; // Truncated to least significant bytebuffer[2] = period >> 8;buffer[3] = period >> 16;buffer[4] = period >> 24;

Redoslijed slanja bajta je izuzetno bitan kako bi uređaj mogao ispravno rekonstruisati poslanu vrijednost.

SetBufferSize metoda nema potrebu za komuniciranjem s Arduino uređajem, već samo mijenja internu vrijednost veličine buffera koji će puniti vrijednostima koje dolaze s Arduina. Ovu operaciju nije moguće izvršiti za vrijeme trajanja procesa akvizicije te se u tom slučaju vraća false.

SendDigitalValue metoda služi za izvršavanje funkcije digitalnog izlaza Arduino uređaja. Njeno izvršavanje prati istu sekvencu koraka kao SetSampleRate obzirom da je u pitanju samo slanje poruke uređaju bez potrebe za čekanjem odgovora. Poruka je veličine 3 bajta: kod poruke, identifikator digitalnog izlaza, vrijednosti 0 ili 1 koja označava da li treba postaviti izlaz na low ili high vrijednost.

PutSingleValue metoda izvršava funkcionalnost slanja jedne analogne vrijednosti na izlaz Arduina. Jedina razlika u odnosu na prethodnu metodu je da je drugi bajt poruke identifikator analognog izlaza, a treći bajt može primiti sve vrijednosti od 0 do 255, obzirom da je rezolucija Arduino analognog izlaza 8 bita.

GetNextBuffer metoda služi da pozivaocu vrati pokazivač na prvi sljedeći nepreuzeti buffer podataka koji su preuzeti s Arduino uređaja. U suštini, vraća se najstariji buffer obzirom da je struktura podataka koja ih čuva red (queue). Bitno je napomenuti da je predviđeno da pozivalac nakon preuzimanja ovog

51

Page 52: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

pokazivača preuzima i potpunu odgovornost za eventualno oslobađanje resursa koje buffer zauzima pozivom delete[] operatora.

ArduinoDevice::response_t* ArduinoDeviceSerial::GetNextBuffer() {// No need to copy the data to another array since after this call// the ownership of the buffer will be transferred to the caller// anyway. (The caller will have to free some memory in any case.)response_t* buffer = bufferQueue.Pop();return buffer;

}

BufferQueue klasa

Logičan izbor strukture podataka za čuvanje buffera koji se trebaju vratiti adaptoru je red (queue), obzirom da se bufferi obavezno moraju vratiti onim redoslijedom kojim su i stigli uređaju. Ipak, std::queue definisan u standardnoj biblioteci jezika C++ ima ozbiljan problem koji ga čini nedovoljno dobrim izborom implementacije reda. U pitanju je činjenica da pristupi redu (pisanje i čitanje) nisu sinhronizovani između različitih threadova, obzirom da C++ standard ni ne poznaje pojam threada. Ukoliko bi došlo do istovremenog izvršavanja više metoda std::queue klase, ponašanje programa je nedefinisano (undefined behavior) i može voditi do korupcije podataka.

Rješenje problema je implementacija wrapper klase oko std::queue objekta koja sinhronizuje sve pristupe redu koristeći uzajamno isključive kritične sekcije. Već predstavljene klase CriticalSection i Lock su korištene u tu svrhu.

Javni interfejs klase pokazuje koje metode su podržane, a u privatnom dijelu se mogu vidjeti std::queue i CriticalSection objekti koji su korišteni za implementaciju:

class BufferQueue{public:

typedef unsigned short* buffer_t;

BufferQueue();~BufferQueue();

void Push(buffer_t value);buffer_t Pop();void Clear();

private:std::queue<buffer_t> queue;CriticalSection cs;

};

Push, Pop i Clear imaju poznatu semantiku dodavanja elementa na kraj reda, brisanja elementa s početka reda i brisanja svih elemenata u redu. Implementacija svake od metoda na početku inicijalizira Lock objekat nad CrticalSection objektom koji je član instance klase. Time je postignuta serijalizacija metoda tog objekta, tj. nemoguće je da se u istom trenutku izvršava više od jedne metode objekta bez obzira na to iz kojeg threada je pozvana.

52

Page 53: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

void BufferQueue::Push(unsigned short* value) {Lock lock(cs);queue.push(value);

}

Snippet koda za prikaz korištenja Lock objekta s svrhom postizanja uzajamnog isključivanja metoda BufferQueue objekta.Dodatno je predviđeno da je objekat vlasnik svih buffera koji se dodaju sve do trenutka kada se izbriše iz reda pozivom metode Pop. Nakon toga, pozivalac koji je preuzeo vrijednost je obavezan osloboditi memoriju. Ovo znači da metoda Clear, kao i destruktor objekta, mora osloboditi memoriju koju bufferi zauzimaju pozivom delete[] operatora.

void BufferQueue::Clear() {Lock lock(cs);while (!queue.empty()) {

unsigned short* buffer = queue.front();delete[] buffer;queue.pop();

}}

3.5.3. DeviceMap klasa

Kako bi bilo moguće pronaći sve ArduinoDevice objekte koji su povezani sa Arduino uređajima za rad sa sistemom akvizicije opisanim u ovom radu, za njihovo čuvanje je potrebna struktura podataka koja na osnovu ID-a uređaja vraća traženi objekat.

std::map je C++ opcija za čuvanje key, value parova kakvi su iznad opisani. Ipak, std::map je dio standardne biblioteke, pa, slično kao što je i slučaj sa std::queue pri implementaciji BufferQueue klase, poziv njegovih metoda je bez mehanizma sinhronizacije i može dovesti do neočekihvanih rezultata i pada programa ukoliko se metode pozivaju konkurentno iz različitih threadova. To je situacija koja se može razumno očekivati u opisanom slučaju čuvanja ArduinoDevice objekata. Iz tog razloga, DeviceMap klasa implementira metode koje sinhronizuju pozive std::map metoda.

Javni interfejs zajedno sa privatnim strukturama korištenim za implementaciju:

class DeviceMap{public:

DeviceMap();~DeviceMap();// Inserts a device into the map and returns its IDUINT Insert(LPCWSTR serialPortName);void Remove(UINT deviceId);ArduinoDevice* Find(UINT deviceId);void GetAllRegisteredDevices(std::vector<UINT>& devices);

private:std::map<UINT, ArduinoDevice*> devices;UINT nextId;CriticalSection cs;

};

53

Page 54: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

DeviceMap klasa ipak nije samo wrapper oko std::map objekta koji dozvoljava thread-safe pristup. Metoda Insert, prije umetanja novog key, value para u std::map objekat, pronalazi koji je sljedeći ID uređaja koji je moguće koristiti te na kraju vraća tu vrijednost kao rezultat izvršavanja. Time je postignuto da je DeviceMap objekat taj koji se brine o dodjeljivanju ID-eva novim uređajima koji se registruju. Također, ta metoda kreira sam ArduinoDevice objekat na osnovu proslijeđenih i izračunatih parametara.

UINT DeviceMap::Insert(LPCWSTR serialPortName) {Lock lock(cs);std::pair<std::map<UINT, ArduinoDevice*>::iterator, bool> ret =

devices.insert(std::pair<UINT, ArduinoDevice*>(nextId, new ArduinoDeviceSerial(nextId, serialPortName)));

++nextId;return nextId - 1;

}

Kao što se može vidjeti, postizanje međusobnog isključivanja metoda DeviceMap objekta je postignuto korištenjem Lock i CriticalSection klasa na već opisani način.

Find metoda objekta vraća pokazivač na ArduinoDevice objekat koji odgovara proslijeđenom ID-u. Ukoliko se ne pronađe registrovan uređaj s datim ID-om, vraća se null pointer.

GetAllRegisteredDevices metoda u std::vector čija je referenca proslijeđena kao parametar stavlja ID-eve svih registrovanih uređaja.

DeviceMap objekat je vlasnik svih ArduinoDevice objekata koje interno kreira i čuva pa je njen zadatak da izvrši oslobađanje resursa koji ti objekti zadržavaju. Destruktor DeviceMap objekta poziva delete operator nad svim postojećim objektima. Ovo ponašanje se vidi iz snippeta koda iz destruktora klase koji se nalazi ispod.

for (std::map<UINT, ArduinoDevice*>::iterator it = devices.begin();it != devices.end();++it) {

delete it->second;}

Metoda Remove također eksplicitno oslobađa resurse koje zauzima objekat koji je potrebno deregistrovati.

void DeviceMap::Remove(UINT deviceId) {Lock lock(cs);std::map<UINT, ArduinoDevice*>::const_iterator it = devices.find(deviceId);if (it != devices.end())

delete it->second;devices.erase(it);

}

54

Page 55: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.5.4. Obrada zahtjeva

3.5.4.1. RequestHandler

RequestHandler je abstraktna bazna klasa koja definiše metodu koju svaki konkretni objekat, koji će vršiti obradu zahtijeva pristiglih EtfArduinoService servisu, mora implementirati.

class RequestHandler{public:

RequestHandler(std::tr1::shared_ptr<PipeCommunicator> pipe);virtual ~RequestHandler();enum Status { OK, FAIL, EXIT };// Pure virtual functionvirtual Status run() = 0;

protected:std::tr1::shared_ptr<PipeCommunicator> pipe;

};

Metoda run je čista virtualna metoda, što i čini klasu abstraktnom.

Definisane su i tri vrijednosti koje ta metoda može vratiti: OK, FAIL i EXIT, koje, redom, signaliziraju da je operacija uspješno izvršena, operacija neuspješno izvršena te da klijent od kojeg je zahtjev došao zatvorio komunikaciju.

Konstruktor definiše da RequestHandler objekti trebaju primiti pokazivač na PipeCommunicator objekat pomoću kojeg mogu vratiti odgovor klijentu, ukoliko je to potrebno.

Destruktor abstraktne bazne klase je obavezno virtualan.

3.5.4.2. RequestHandlerFactory

RequestHandlerFactory je abstraktna bazna klasa koja definiše metode koje svaka konkretna RequestHandlerFactory klasa mora implementirati.

class RequestHandlerFactory {public:

typedef int request_t;RequestHandlerFactory(DeviceMap& devices);virtual ~RequestHandlerFactory();// Pure virtual member functionvirtual std::auto_ptr<RequestHandler> GetRequestHandler(request_t const* const

buffer) = 0;protected:

// Request codes. All concrete Factories will use them!static request_t const GET_BUFFERED_DATA = 1;static request_t const START_ACQUISITION = 2;static request_t const STOP_ACQUISITION = 3;static request_t const GET_SINGLE_VALUE = 4;static request_t const CHECK_DEVICE_REGISTERED = 5;

55

Page 56: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

static request_t const REGISTER_DEVICE = 6;static request_t const GET_REGISTERED_DEVICE_IDS = 7;

static request_t const SET_ACQUISITION_BUFFER_SIZE = 10;static request_t const SET_SAMPLE_RATE = 11;

static request_t const SEND_DIGITAL_VALUE = 20;

static request_t const PUT_SINGLE_VALUE = 30;

static request_t const DISCONNECT_CLIENT = 255;DeviceMap& devices;

};

U javnom dijelu interfejsa klase je deklarisana čista virtualna metoda GetRequestHandler koja vraća pokazivač na RequestHandler objekat. Korišten je std::auto_ptr pametni pokazivač kako bi se automatski oslobodili resursi koje zauzima objekat. Time su izbjegnuti potencijalni leakovi resursa uslijed bačenog izuzetka obzirom da će RequestHandler objekat biti uništen pri izlasku std::auto_ptr objekta iz scopea.

Kao parametar metoda prima pokazivač na buffer koji sadrži pristigli zahtjev na osnovu kojeg je potrebno odlučiti koji konkretni RequestHandler objekat treba kreirati.

Protected dio klase sadrži kodove svih zahtijeva za koje je moguće kreirati konkretni RequestHandler objekat.

3.5.4.3. RequestHandlerFactoryImpl klasa

Ova klasa je derivirana iz abstraktne bazne klase RequestHandlerFactory i implementira metodu GetRequestHandler.

Obzirom da prvi element buffera zahtjeva (ulazni parametar metode) uvijek sadrži kod zahtjeva, metoda u switch-case bloku dekodira zahtjev i kreira odgovarajući konkretni objekat kojem se proslijeđuju svi potrebni parametri.

3.5.4.4. Konkretne RequestHandler klase

Za svaki od zahtijeva čiji kod je definisan u RequestHandlerFactory klasi kreiran je jedan konkretni RequestHandler:

• GetBufferedDataRequestHandler – zahtjev za preuzimanjem zadnjeg buffera podataka prikupljenih od Arduino uređaja u procesu analogne akvizicije;

• StartAcquisitionRequestHandler – zahtjev za početkom akvizicije analognog signala nekog uređaja;

56

Page 57: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

• StopAcquisitionRequestHandler – zahtjev za obustavljanjem analogne akvizicije;

• GetSingleValueRequestHandler – zahtjev za preuzimanjem jedne vrijednosti analognog signala Arduino uređaja (jedan sample);

• CheckDeviceRegisteredRequestHandler – zahtjev za provjeru da li postoji registrovan uređaj s ID-om koji je dat u zahtjevu;

• RegisterDeviceRequestHandler – zahtjev za registracijom novog uređaja na serijskom portu čije ime je dato u zahtjevu;

• GetRegisteredDevicesRequestHandler – zahtjev kojim klijent traži listu ID-eva svih registrovanih uređaja;

• SetAcquisitionBufferSizeRequestHandler – zahtjev kojim se postavlja veličina buffera kojeg servis treba da vraća klijentu za vrijeme procesa akvizicije analognog signala;

• SetSampleRateRequestHandler – zahtjev za postavljanjem nove frekvencije sampliranja signala;

• SendDigitalValueRequestHandler – zahtjev za slanjem digitalne vrijednosti na izlaz Arduino uređaja;

• PutSingleValueRequestHandler – zahtjev za slanjem analogne vrijednosti na izlaz nekog Arduino uređaja;

• DisconnectRequestHandler – zahtjev kojim klijent označava servisu da od tog momenta neće biti više zahtjeva, tj. da prekida konekciju.

Implementacija run metode svake od klasa poziva potrebne metode objekata ArduinoDevice, DeviceMap i PipeCommunicator kako bi uspješno odgovorila na sve zahtjeve.

Za klasu StartAcquisitionRequestHandler treba naglasiti da pri pozivu run metode kreira novu nit u kojoj će se izvršavati akvizicija analognog signala s uređaja koja se pokreće pozivom metode StartAcquisition ArduinoDevice objekta. Inače, nit koja obrađuje zahtjeve tog podsistema bi bila blokirana i ne bi bilo moguće obraditi zahtjev za prestankom akvizicije (StopAcquisitionRequestHandler). Funkcija koju nit izvršava kao parametar prima pokazivač na ArduinoDevice objekat čija akvizicija treba da započne.

DWORD WINAPI StartAcquisitionRequestHandler::AnalogAcquisitionProc(LPVOID lpvParam) {ArduinoDevice& device = *(ArduinoDevice*)lpvParam;device.StartAcquisition();return 0;

}

57

Page 58: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.5.5. Glavni program EtfArduinoService servisa

Entry point, tj. main funkcija EtfArduinoService procesa u beskonačnoj petlji kreira instance named pipea preko kojeg se klijenti mogu spojiti na servis. Kada se neki klijent uspješno konektuje, kreira se nova nit koja će služiti za rješavanje svih zahtijeva koji budu pristizali od tog klijenta. Ime named pipea sadrži GUID generisan iz Visual Studio okruženja kako bi se osiguralo jedinstveno ime na sistemu.

for (;;){

PipeCommunicator* pipe = new PipeCommunicator(_T( "\\\\.\\pipe\\etfarduino-{522590F9-C51E-4711-B6E2-9CECC7C3FD91}"));

// Wait for the client to connectif (pipe->Connect()){

// Create a thread for this client. HANDLE hThread = CreateThread(

NULL, // no security attribute 0, // default stack size InstanceThread, // thread proc(LPVOID) pipe, // thread parameter 0, // not suspended NULL); // no thread ID

if (hThread == NULL) {// Thread creation failed, pipe ownership still in this thread!delete pipe;

} else {CloseHandle(hThread);

}} else {

// The client could not connect, so close the pipe. delete pipe;

}}

Funkciji novokreirane niti se proslijeđuje pokazivač na PipeCommunicator objekat koji, kako je već objašnjeno, služi za komunikaciju preko instance named pipe objekta. Vlasništvo nad objektom prelazi toj funkciji, a time i odgovornost da se oslobode resursi koje on zauzima.

Ukoliko kreiranje threada ne uspije ili se klijent neuspješno konektuje, resursi se oslobađaju prije sljedeće iteracije petlje.

Nit koja uslužuje klijenta čeka poruke koje pristižu na instancu named pipe objekta, koristeći PipeCommunicator čiji pokazivač je proslijeđen pri kreiranju niti. Svaki zahtjev se obrađuje tako što se proslijedi GetRequestHandler metodi RequestHandlerFactory objekta. Povratna vrijednost, pokazivač na RequestHandler objekat, se preuzima i poziva se njegova run metoda.

58

Page 59: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Opisani postupak se može vidjeti i kroz snippet koda koji se nalazi ispod:

std::tr1::shared_ptr<PipeCommunicator> pipe((PipeCommunicator*) lpvParam);std::vector<PipeCommunicator::message_t> request(PipeCommunicator::bufferSize);PipeCommunicator::message_t* pchRequest = &request[0];std::auto_ptr<RequestHandlerFactory> factory(

new RequestHandlerFactoryImpl(registeredDevices,pipe));

for (;;) {

DWORD cbBytesRead = 0;bool success = pipe->RetrieveMessage(

pchRequest,PipeCommunicator::bufferSize * sizeof(PipeCommunicator::message_t), &cbBytesRead);

if (!success || cbBytesRead == 0) {if (GetLastError() == ERROR_BROKEN_PIPE) {

break;}continue;

}

std::auto_ptr<RequestHandler> handler(factory->GetRequestHandler(pchRequest));

if (handler.get() != 0) {RequestHandler::Status const status =

handler->run();if (status == RequestHandler::Status::EXIT) break;

}}

Iz ovoga se vidi moć korištenog factory design patterna – za implementaciju novog zahtjeva potrebno je samo implementirati novu konkretnu klasu deriviranu iz RequestHandler abstraktne bazne klase te dodati odgovarajući dio koda u konkretnoj RequestHandlerFactoryImpl klasi kojim se kreiraju ti objekti. U kodu niti koja uslužuje klijenta ništa nije potrebno modifikovati.

59

Page 60: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.6. Adaptor implementacija

3.6.1. COM interfejs

Kao što je spomenuto u poglavlju Data Acquisition Toolbox, svaki adaptor mora biti implementiran tako da se komunikacija sa Data Acquisition Engineom odvija preko COM (Component Object Model) interfejsa.

COM je Microsoftova tehnologija koja omogućava kreiranje softverskih komponenti koje je moguće koristiti neovisno od platforme na kojoj je urađena implementacije te komponente. COM definiše standard koji komponentama omogućava da komuniciraju sa drugim objektima. Jedino ograničenje programskog jezika koji može biti korišten za implementaciju COM komponenti je da je jezik u stanju pristupati memorijskim lokacijama na osnovu pokazivača te da može vršiti pozive funkcija na osnovu pokazivača na funkcije.

COM je zasnovan na principima objektno-orijentisanog programiranja. Svaki COM objekat (komponenta) implementira određene interfejse. Interfejsi definišu koje operacije moraju biti podržane od strane objekata koji ih implementiraju. Operacije nekog interfejsa sa nazivaju metodama interfejsa. Jedini način da se pristupi operacijama nekog COM objekta je preko pokazivača na neki od njegovih interfejsa. COM objekti se definišu pomoću COM klasa.

Pokazivač na COM interfejs nekog objekta predstavlja pokazivač na niz koji sadrži pokazivače na funkcije. Pozivom tih funkcija se vrši izvršavanje metode objekta. Kompajleri za jezike C i C++ omogućavaju pozivanje tih funkcija po imenu, bez potrebe da se vrši eksplicitno indeksiranje pomenutog niza pokazivača, pa tako nije potrebno poznavanje tačnog redoslijeda metoda u nizu.

COM interfejsi i COM klase se identifikuju pomoću 128-bitnih jedinstvenih globalnih identifikatora (GUID) koji se nazivaju IID i CLSID. COM sistem na određenom računaru je obavezan čuvati informacije o tome koje DLL ili EXE datoteke sadrže kod sa implementacijom neke COM klase te koje sve interfejse implementira određena klasa. Također, za svaku komponentu treba čuvati i njeno tekstualno ime, tj. identifikaciju, pored GUID-a. Na Windows operativnom sistemu ove informacije se čuvaju u registryu.

Pri prvom učitavanju DLL-a ili pokretanju EXE-a koji implementira neke COM komponente, potrebno je izvršiti registraciju te komponente na sistemu koristeći odgovarajuće API funkcije.

Svaki objekat je obavezan da implementira interfejs IUnknown. Bitna metoda koju taj interfejs zahtijeva je QueryInterface preko koje je moguće dobiti pokazivač na drugi interfejs istog objekta.

Kako bi otkrivanje svih COM objekata koji podržavaju neku funkcionalnost bilo olakšano, postoje COM kategorije. COM kategorije su identifikovane GUID-om koji se naziva CATID. Svaki COM objekat može pripadati jednoj ili više kategorija.

60

Page 61: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Klijenti COM objekata, koristeći predefinisane WinAPI funkcije, od sistema mogu zahtijevati pokazivač na neki interfejs određenog objekta, poznavajući odgovarajuće CLSID i IID vrijednosti. Moguće je i dobiti listu svih objekata (njihovih CLSID-eva i tekstualnih imena) na sistemu koji pripadaju nekoj kategoriji, ukoliko je poznat njen CATID, te je na taj način klijent u stanju odabrati koju implementaciju želi koristiti.

COM sadrži još mnoge definicije i standarde, ali za svrhu ovog rada, nije potrebno ulaziti u dodatne detalje.

Kako bi se definisanje COM interfejsa i klasa, zajedno s interfejsima koje će podržavati, olakšalo, Microsoft je kreirao Microsoft Interface Description Language (MIDL). Opise COM komponenti iz MIDL jezika poseban kompajler prevodi u C kod koji se zatim može prevesti u binarni izvršni kod.

Visual C++ također olakšava kreiranje DLL-a koji sadrži COM komponentu, što podrazumijeva olakšanu izmjenu vrijednosti u registryu koristeći za to predviđene klase i predefinisane funkcije koje sistem može pozvati kako bi pristupio pokazivačima na interfejse objekata definisanih u DLL-u.

3.6.2. Adaptor klasa

Kao što je rečeno u objašnjenju konstruktorsih funkcija Data Acquisition Toolboxa, prilikom kreiranja nekog MATLAB Data Acquisition Toolbox objekta (analoginput, analogoutput, digitalio) Data Acquisition Engine prima ime adaptora kojeg treba koristiti za komunikaciju sa odgovarajućim hardverom. Tada, engine od sistema zahtijeva listu svih komponenti koji pripadaju kategoriji s CATID-em: {6FE55F7B-AF1A-11D3-A536-00902757EA8D}.

Na osnovu tekstualnih imena vraćenih komponenti, pronalazi onu koja odgovara imenu datom u pozivu konstruktorske funkcije. Na osnovu CLSID-a pridruženog tom imenu, pomoću odgovarajućih funkcija kreira COM objekat i pristupa mu preko pokazivača na ImwAdaptor interfejs.

ImwAdaptor je interfejs koji je definisao i registrovao sam Data Acquisition Engine prilikom svoje instalacije. Ovaj interfejs specificira koje sve metode adaptori moraju implementirati.

U ovom projektu, klasa Cetfarduinoadapt je ta koja implementira potrebne metode.

MIDL definicija klase je:

[uuid(013D390C-EA84-4d05-907F-15B5903A2952),helpstring("etfarduinoadapt Class")

]coclass etfarduinoadapt{

[default] interface ImwAdaptor;};

61

Page 62: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Kako bi implementacija adaptora u C ili C++-u bila olakšana, MathWorks uz Data Acquisition Toolbox obezbjeđuje i daqmex.h header datoteku koja sadrži definicije svih COM interfejsa vezanih za tooblox kao C struktura ili C++ abstraktnih baznih klasa. Ova datoteka je dobivena kompajliranjem definicije datih interfejsa pomoću MIDL jezika.

Tako pri implementaciji Cetfarduinoadapt klase treba navesti da je izvedena iz ImwAdaptor klase koja je definisana upravo u daqmex.h.

Tri metode koje definiše ovaj interfejs su: OpenDevice, AdaptorInfo i TranslateError.

Metoda AdaptorInfo vraća informacije vezane za adaptor i uređaje s kojima može komunicirati koje MATLAB preuzima pri pozivu funkcije daqhwinfo za taj adaptor. Dakle, potrebno je vratiti ime adaptora, ime DLL-a adaptora, niz registrovanih uređaja s kojima može komunicirati, tj. koji mogu biti korišteni u procesu akvizicije te podsisteme kojima je moguće pristupiti na tim uređajima.

Metoda prima pokazivač na interfejs IPropContainer te pozivanjem njegove metode put_MemberValue definiše pomenute vrijednosti. Primjer koda se vidi ispod gdje se definiše naziv adaptora.

HRESULT Cetfarduinoadapt::AdaptorInfo(IPropContainer * Container){ HRESULT hRes = Container->put_MemberValue(L"adaptorname", variant_t(ConstructorName)); if (!(SUCCEEDED(hRes))) return hRes; // ... nastavak metode za ostale informacije ...}

OpenDevice metoda kreira objekat vezan uz određeni podsistem uređaja: analogni ulaz, analogni izlaz ili digitalni ulaz/izlaz i vraća pokazivač na taj objekat. Podsistem koji treba kreirati se identifikuje na osnovu parametra koji prima funkcija koji je IID jednog od interfejsa ImwInput, ImwOutput, ImwDIO koji redom odgovaraju navedenim podsistemima. Ove interfejse također definiše Data Acquisition Toolbox, a adaptor DLL klase CetfarduinoAin, CetfarduinoAout, CetfarduinoDio implementiraju ove interfejse.

Dio koda koji kreira podsistem za analogni ulaz i vraća pokazivač na njega je:

bool Success = false;CComPtr<ImwDevice> pDevice;

if (InlineIsEqualGUID(__uuidof(ImwInput),riid)){ CComObject<CetfarduinoAin>* Ain; CComObject<CetfarduinoAin>::CreateInstance(&Ain); RETURN_HRESULT(Ain->Open((IDaqEngine*)pIEngine, id)); pDevice = Ain; Success = true;}

62

Page 63: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.6.3. CetfarduinoAin klasa

Već pomenuta klasa CetfarduinoAin implementira metode interfejsa ImwInput koje su potrebne kako bi engine pristupao podsistemu za analogni ulaz uređaja za koje je adaptor DLL namijenjen.

Kako je i ova klasa COM komponenta, njena MIDL definicija je:

[uuid(DF13DDD3-AB25-4470-A5CA-0CFCE6A4E1C5),helpstring("etfarduinoAin Class")

]coclass etfarduinoAin{

[default] interface IetfarduinoAin;interface ImwDevice;interface ImwInput;

};

Može se vidjeti da klasa implementira još jedan interfejs, ImwDevice. To je Data Acquisition Toolbox interfejs koji moraju implementirati svi podsistemi, a definiše metode koje nisu specifične ni za jedan od podsistema.

Slijedi opis svih metoda implementiranih u klasi.

Open – metode ImwDevice interfejsa. Ovu metodu poziva metoda OpenDevice, adaptor objekta kada je potrebno kreirati vezu sa analognim podsistemom nekog uređaja.

Ova metoda je zadužena da izvrši provjeru postojanja uređaja koji se pokušava koristiti, a zatim i inicijalizaciju komunikacije. Još je bitno da postavi vrijednosti svojstava podsistema, kao što su podrazumijevane vrijednosti za SampleRate, SamplesPerTrigger i sl.

Metoda prima dva parametra; prvi je pokazivač na IDaqEngine interfejs pomoću čijih metoda ovaj objekat može komunicirati sa Data Acquisition Engineom. Drugi parametar je ID uređaja s kojim se želi započeti komunikacija.

Za provjeru postojanja uređaja, implementacija Open metode koristi metodu CheckDeviceRegistered klase EtfArduinoService koja je već opisana. CetfarduinoAin objekti imaju, kao privatni član, objekat ovog tipa koji je korišten za vrijeme cijelog života objekta.

bool registered = service.CheckDeviceRegistered(DeviceId, portName);

if (!registered) {char tempMessage[255];sprintf(tempMessage, "etfarduino: Device %d not found.", DeviceId);return CComCoClass<ImwDevice>::Error(CComBSTR(tempMessage));

}

63

Page 64: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Statička funkcija Error interfejsa ImwDevice omogućava podsistemima adaptora da vrate određene poruke greške koje se pojavljuju u MATLAB okruženju.

Osobine koje se zatim postavljaju u funkciji su:

• ID uređaja;• Minimalna i maksimalna vrijednost za SampleRate – pokušaj postavljanja vrijednosti izvan

ovih granica automatski korisniku javlja grešku;• Ime uređaja – uvijek u formatu “etfarduino (Device x)”, gdje je x ID uređaja;• Granice u kojima se nalazi ulaz – postavlja se na 0 do 5V, obzirom da je to ograničenje Arduino

uređaja;• Tip podataka koji će biti korišten za vrijednosti koje uređaj vraća – u ovom slučaju unsigned

short – 2 bajtna nepredznačena vrijednost koja odgovara Arduino tipu unsigned int;• Broj bita rezolucije – engine na osnovu ovog podatka i granica ulaza, automatski vrši

konverziju primljenih digitalnih vrijednosti od uređaja u analogne;• Postavljaju se podrazumijevane vrijednosti za SampleRate i SamplesPerTrigger – ove

vrijednosti, prema uputama Data Acquisition Enginea, se trebaju postaviti tako da bi podrazumijevano vrijeme akvizicije dobiveno na osnovu ove dvije osobine bilo 1 sekunda. Podrazumijevane vrijednosti se postavljaju na 1000.

Na kraju, metoda signalizira engineu da objekat želi prima obavijesti kada se vrijednost neke od osobina promijene. Ovo je potrebno kako bi se uređaj mogao obavijestiti o nekim izmjenama koje utiču na način njegovog rada ili kako bi sam adaptor objekat izvršio izmjene nekih privatnih svojstava na osnovu novih vrijednosti.

Metoda ovu signalizaciju obavlja koristeći predefinisani ATTACH_PROP makro:

ATTACH_PROP(SamplesPerTrigger);

Ovaj makro zahtijeva da je moguć pristup objektu tipa TRemoteProp s istim nazivom kao proslijeđeni naziv osobine uz prefiks slova 'p'. Pomoću ovog objekta bit će pristupano vrijednostima osobine. Objekat je definisan kao privatni atribut CetfarduinoAin objekata kako bi pristup bio moguć iz bilo koje metode:

TRemoteProp<double> pSamplesPerTrigger;

SetDaqHwInfo je pomoćna metoda za definisanje vrijednosti osobina podsistema. Poziva je samo Open metoda.

64

Slika 10: Poruka greške ukoliko nije registrovan uređaj s traženim ID-em

Page 65: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

ChildChange metoda se poziva kada

SetProperty je metoda koju engine poziva kada se promijeni neka od osobina za koju je zahtijevano da se primaju obavijesti o izmjeni pri pozivu Open metode.

Prima dva parametra od kojih je prvi long tipa i služi da se identifikuje koja osobina je izmijenjena, a drugi predstavlja pokazivač na novu vrijednosti.

Pomoću makroa USER_VAL moguće je dobiti long identifikator TRemoteProp objekata i na osnovu toga utvrditi za koju osobinu je pozvana metoda.

U implementaciji, samo dvije osobine se razmatraju: SampleRate i ClockSource.

Pri izmjeni SampleRatea potrebno je izvršiti provjeru da li je nova vrijednost validna. Obzirom da period uzorkovanja na Arduino uređaju mora biti djeljiv s 4 mikrosekunde, onda postoje i ograničenja na validne SampleRateove. Standardno ponašanje adaptora za akvizicione uređaje je da umjesto tražene vrijednosti, postave SampleRate na najbližu moguću. Izmjena vrijednosti od strane SetProperty metode izaziva automatsku poruku upozorenja korisnicima u MATLAB okruženju.

if (User == USER_VAL(pSampleRate)) {double newSampleRate = *val;if (pClockSource == CLOCKSOURCE_SOFTWARE) {

return CswClockedDevice::SetProperty(User, NewValue);}// Calculate a sample rate which is compatible with the boardint const factor = (static_cast<double>(tickFrequency) / newSampleRate) +

0.5;int const period = 4 * factor;newSampleRate = (1. / period) * 1000 * 1000; // us -> Hzif (newSampleRate > 12500) {

// Issue warning of max sample rate_engine->WarningMessage(CComBSTR("etfarduino: Sample rates higher than

12,500 are not supported by etfarduino."));newSampleRate = 12500;

}pSampleRate = newSampleRate;*val = pSampleRate;

}

ClockSource osobina specificira da li će se koristiti interni sat uređaja za uzorkovanje (Hardware) ili će biti korišten tzv. softverski sat (Software). Softverski sat radi tako što Data Acquisition Engine, nakon što protekne odgovarajući period, automatski poziva metodu GetSingleValue ovog objekta. Na ovaj način korisnik je ograničen na maksimalnu frekvenciju uzorkovanja 500 Hz.

Pri izmjeni ClockSource osobine potrebno je izvršiti izmjenu granica za SampleRate, obzirom na upravo pomenuto ograničenje. Također, potrebno je promijeniti podrazumijevane vrijednosti za SampleRate i SamplesPerTrigger i trenutne vrijednosti – ne smije se dozvoliti da se objekat nađe u nekonsistentnom stanju nakon izmjene ClockSourcea.

65

Page 66: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

if (User == USER_VAL(pClockSource)) {if ((long)(*val) == CLOCKSOURCE_SOFTWARE) {

// Software clocking chosen// First, change the SampleRate to SW clocked defaultsdouble softwareClockedDefault = 100;pSampleRate.SetDefaultValue(CComVariant(softwareClockedDefault));pSampleRate = softwareClockedDefault;pSampleRate.SetRange(

CComVariant((double)MIN_SW_SAMPLERATE),CComVariant((double)MAX_SW_SAMPLERATE));

EnableSwClocking();pSamplesPerTrigger->put_DefaultValue(

CComVariant(softwareClockedDefault));pSamplesPerTrigger = softwareClockedDefault;

} else {// Na isti način se postavljaju vrijednosti za Hardware Clocking

}}

ChildChange je metoda koju engine poziva pri dodavanju, izmjeni ili brisanju kanala na analoginput objektu.

Prima dva parametra; prvi je bitmaska koja daje tip promjene koja se vrši, a drugi pokazivač na strukturu NESTABLEPROP koja opisuje kanal koji se mijenja.

Trenutno je podržan samo jedan kanal, pa ukoliko se pokušava dodati dodatni kanal nakon prvog, vraća se greška.

if ((typeofchange & CHILDCHANGE_REASON_MASK) == ADD_CHILD) {if (_nChannels == 1) {

return Error(CComBSTR("etfarduino: Nije podrzano vise od jednog kanala po AnalogInput objektu"));

}}

SetChannelProperty je metoda koja se poziva kada engine želi izmijeniti neku vrijednost osobine kanala objekta. Osobina koja je bitna za implementaciju CetfarduinoAin klase je opseg ulaznih vrijednosti. Ukoliko se pokuša izmijeniti, u ovoj metodi se pokuša naći podržani opseg koji najbolje odgovara traženom. Obzirom da je jedini moguć opseg 0-5V, to će uvijek biti rezultat pokušaja izmjene opsega.

GetSingleValue metoda, kao što je već pomenuto, služi da engineu vrati trenutnu vrijednost s analognog ulaza i koristi se samo kada je ClockSource postavljen na Software.

Prima dva parametra; prvi je redni broj kanala s kojeg se želi preuzeti vrijednost, a drugi pokazivač na mjesto u memoriji na koje treba staviti očitanu vrijednost.

Implementacija se zasniva na pozivanju metode GetSingleValue nad EtfArduinoService objektom koji je privatni član ove klase.

66

Page 67: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

HRESULT CetfarduinoAin::GetSingleValue(int chan, RawDataType *value){

*value = (RawDataType) service.GetSingleValue(DeviceId);return S_OK;

}

Start se poziva kada korisnik, koristeći MATLAB funkciju start, engineu pošalje signal da želi započeti s akvizicijom. Spašavanje vrijednosti u engineu počinje tek kada se pozove trigger funkcija u zavisnosti od postavke osobine TriggerType, pa zbog toga je jedini zadatak ove metode da izvrši inicijalizaciju svih potrebnih pretpostavki za obavljanje zadatka akvizicije.

Implementacija najprije provjerava da li je ClockSource postavljen na Software. U tom slučaju, posao se prepušta već implementiranoj klasi koja dolazi uz Data Acquisition Engine.

Inače, koristeći metode EtfArduinoService objekta, servisu za komunikaciju s uređajem se signaliziraju vrijednosti SampleRate i veličine buffera koja će biti korištena za vrijeme akvizicije.

Adaptor je dužan engineu vraćati podatke u bufferima koje može dobiti od njega i čija veličina je fiksna za vrijeme jednog zadatka akvizicije. Kada se prikupi podaci za jedan cijeli buffer, potrebno je poslati signal engineu da je buffer napunjen. Iz tog razloga je potrebno servisu dati do znanja koja je veličina buffera, tj. koliko podataka je potrebno vraćati adaptoru.

Trigger metoda započinje prikupljanje podataka s uređaja i njihovo slanje engineu. Ova metoda obavezno mora biti asinhrona jer engine mora nastaviti sa radom nakon njenog poziva. Iz tog razloga, ono što metoda radi je to da šalje signal servisu za komunikaciju s uređajem da treba početi te se registruje kao sistem zainteresovan za primanje obavještenja servisa preko već objašenjenog mehanizma međuprocesne komunikacije korištenjem Window poruka.

Metoda se registruje pozivom metode AddDevice nad singleton objektom tipa MessageWindow kojoj proslijedi ID uređaja s kojim želi komunicirati, tip podsistema (analogni ulaz) i pokazivač na sebe. Zatim, pomoću EtfArduinoService objekta započinje prikupljanje podataka na samom uređaju.

msgWindow.AddDevice(DeviceId, subsystemId, this);

if (!service.StartAcquisition(DeviceId)) {return CComCoClass<ImwDevice>::Error(_T("etfarduino: Problem starting

acquisition."));}

ReceivedMessage je metoda koja će biti pozvana kada MessageWindow primi poruku od servisa za komunikaciju s uređajem koja je namijenjena podsistemu s kojim je objekat povezan.

Zadatak metode je preuzeti podatke koji su spremni u servisu i poslati ih engineu u odgovarajućoj buffer strukturi. Buffer strukturu se preuzima metodom GetBuffer IDaqEngine interfejsa, a, nakon što je napunjen odgovarajućim podacima, vraća engineu pozivom metode PutBuffer.

Preuzimanje podataka od servisa za komunikaciju s uređajem je postignuto jednostavnim pozivom metode GetBufferedData nad EtfArduinoService objektom.

67

Page 68: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Buffer struktura postavljanjem bita BUFFER_IS_LAST u Flags polju daje adaptoru do znanja da proces akvizicije treba biti završen. StartPoint polje predstavlja ukupni redni broj prvog uzorka u bufferu od početka akvizicije.

BUFFER_ST* pBuffer = 0;_engine->GetBuffer(0, &pBuffer);service.GetBufferedData(DeviceId, pBuffer->ptr, pointsPerBuffer);

pBuffer->StartPoint = m_samplesThisRun * _nChannels;pBuffer->ValidPoints = samplesToFetch * _nChannels;m_samplesThisRun += pBuffer->ValidPoints / _nChannels;if ((pBuffer->Flags & BUFFER_IS_LAST) || pBuffer->ValidPoints < pointsPerBuffer) {

mustStop = true;}// Konacno vratiti buffer engineu_engine->PutBuffer(pBuffer);

3.6.4. CetfarduinoAout klasa

Klasa CetfarduinoAout implementira metode interfejsa ImwOutput koje su potrebne kako bi engine pristupao podsistemu za analogni izlaz uređaja za koje je adaptor DLL namijenjen. Implementira i ImwDevice interfejs koji je obavezan za sve podsisteme.

Kako je i ova klasa COM komponenta, njena MIDL definicija je:

[uuid(F5D02ED5-BAA4-49f1-AE9B-F63F0E82A1C5),helpstring("etfarduinoAout Class")

]coclass etfarduinoAout{

[default] interface IetfarduinoAout;interface ImwDevice;interface ImwOutput;

};

Metode Open, SetDaqHwInfo, SetChannelProperty i ChildChange imaju isto značenje kao i u slučaju analoginput objekta, pa ovdje neće biti ponovo objašnjavani.

Obzirom na ograničenja Arduino uređaja u vezi sa analognim izlazom, ova komponenta podržava samo softverski sat za upravljanje periodom slanja vrijednosti na izlaz (ClockSource osobina može biti samo Software).

Metoda PutSingleValue služi da omogući engineu da na izlaz uređaja pošalje jednu analognu vrijednost. Engine je koristi pri implementaciji izlaz koristeći softverski sat.

Prima dva parametra; prvi je kanal na koji treba poslati vrijednost, a drugi upravo vrijednost koju treba postaviti. Bitno je da je primljena vrijednost već pretvorena iz analogne u digitalnu vrijednost na osnovu poznatih podataka o opsegu izlaznog kanala i broju bita rezolucije digitalno-analognog konvertora uređaja.

68

Page 69: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Implementacija jednostavnim pozivom PutSingleValue metode EtfArduinoService objekta izvršava potrebnu operaciju.

HRESULT CetfarduinoAout::PutSingleValue(int chan, RawDataType value){ if (!service.PutSingleValue(DeviceId, chan, value)) { return CcomCoClass<ImwDevice>::Error(CComBSTR("etfarduino: Analog output failed.")); } return S_OK;}

3.6.5. CetfarduinoDio klasa

Klasa CetfArduinoDio implementira metode interfejsa ImwDio koje su potrebne kako bi engine pristupao podsistemu za digitalni ulaz/izlaz uređaja za koje je adaptor DLL namijenjen. Implementira i ImwDevice interfejs koji je obavezan za sve podsisteme.

Kako je i ova klasa COM komponenta, njena MIDL definicija je:

[uuid(5EF1299B-0EA2-4039-AB34-012FD8F978F2),helpstring("etfarduinoDio Class")

]coclass etfarduinoDio{

[default] interface IetfarduinoDio;interface ImwDevice;interface ImwDIO;

};

Metode Open i SetDaqHwInfo opet imaju istu svrhu kao i u prethodna dva slučaja.

Metode specifične za ImwDio interfejs su ReadValues, WriteValues, SetPortDirection.

Engine koristi WriteValues da na digitalni izlaz uređaja s kojim je povezan objekat pošalje potrebne vrijednosti. Implementacija se svodi na poziv metode SendDigitalValue EtfArduinoService objekta.

for (int i = 0; i < NumberOfPorts; ++i) { if (!service.SendDigitalValue(DeviceId, PortList[i], Data[i])) { return CComCoClass<ImwDevice>::Error(CComBSTR("etfarduino: Digital write failed.")); }}

Pomoću SetPortDirection se implementira mogućnost izmjene smjera određenog porta, tj. da li će biti korišten za ulaz ili izlaz. U ovom projektu nije predviđena mogućnost izmjene smjera porta, pa metoda samo vraća grešku.

69

Page 70: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

HRESULT CetfarduinoDio::SetPortDirection(LONG Port, ULONG DirectionValues){ // For now, there is no possiblity to change any port direction return CcomCoClass<ImwDevice>::Error(

CComBSTR("etfarduino: Port direction change is not supported."));}

70

Page 71: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.7. Arduino Firmware

Arduino firmware program, koji omogućava korištenje Arduino uređaja kao akvizicionog modula u saradnji sa ostalim komponentama sistema razvijenog kroz ovaj projekat, ima zadatak da na osnovu primljenih komandi preko serijskog komunikacionog porta izvršava određene zahtjeve.

3.7.1. Analogni ulaz

Za podršku analognog ulaza, Arduino implementira podršku za sljedeće komande:

• Početak akvizicije – komanda čiji je kod bajt 49 koji odgovara ASCII vrijednosti znaka '1'. Započinje prikupljanje podataka s analogno-digitalnog konvertora, frekvencijom koja je zadata, i njihovo slanje računaru.

• Kraj akvizicije – komanda s kodom čija vrijednost odgovara ASCII vrijednosti znaka '2'. Zaustavlja proces akvizicije podataka i njihovog slanja računaru.

• Postavljanje perioda akvizicije – komanda s kodom čija vrijednost odogovara ASCII vrijednosti znaka '3'. Osim koda, čita još 4 bajta s serijskog ulaza koji predstavljaju vrijednost perioda akvizicije u mikrosekundama. Period treba da bude broj djeljiv sa 4 inače će se očekivani period razlikovati od onog kojeg će Arduino koristiti.

• Preuzimanje jedne analogne vrijednosti – komanda s kodom čija vrijednost odogovara ASCII vrijednosti znaka '4'. Komanda vrši očitavanje trenutne vrijednosti s analognog kanala i tu vrijednost odmah šalje nazad preko serijskog porta.

Kako bi se implementirao proces akvizicije analognog signala s tačno specificiranim periodom, korišten je Timer1 ATmega328 procesora. Faktor skaliranja je postavljen na 64 što znači da je period s kojim se inkrementuje brojač 4μs. To znači da Arduino podržava samo one postavke perioda koje su djeljive sa 4. Dio koda koji vrši inicijalizaciju timera se može vidjeti u sljedećem isječku.

cli(); TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = (period >> 2) - 1; TCCR1B |= (1 << WGM12); // CTC mode TCCR1B |= (1 << CS11) | (1 << CS10); // 64 prescaler (str. 135) TIMSK1 &= ~(1 << OCIE1A); // disable timer interrupt sei();

71

Page 72: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Kada je potrebno izmijeniti period akvizicije, Arduino postavlja vrijednost registra OCR1A na vrijednost nakon koje treba da se izvrši rutina za obradu prekida tog timera. Ova vrijednost se računa po sljedećoj formuli.

Gdje je T period akvizicije u mikrosekundama, a Ttimer period inkrementovanja timera u mikrosekundama. Od količnika te dvije vrijednosti je potrebno oduzeti 1, obzirom da se prekid javlja kada brojač pređe postavljenu vrijednost.

Dio koda koji to radi je:

OCR1A = (period >> 2) - 1;

Obrada komandi za početak i kraj akvizicije jednostavno aktiviraju, tj. deaktiviraju pokretanje rutine za obradu ovog prekida.

case '1': { TCNT1 = 0; // reset the counter TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt return; } case '2': { TIMSK1 &= ~(1 << OCIE1A); // disable timer compare interrupt return; }

U samoj rutini, Arduino vrši sampliranje ADC-a, nakon čega se postavlja vrijednost boolean indikatora da postoji vrijednost koja se treba proslijediti računaru. Rutina ne vrši slanje te vrijednosti obzirom da svaka rutina za obradu prekida mora biti što kraća kako ne bi onemogućila ispravno rješavanje drugih prekida koji se jave za to vrijeme.

Potreba za što kraćim vremenom izvršavanja ove rutine je razlog korištenja direktne manipulacije registrima za akviziciju vrijednosti signala, umjesto Arduino funkcije analogRead koja ima puno veći overhead.

Kod za inicijalizaciju analogno-digitalnog konvertora gdje se specificira da treba vršiti očitavanje analognog ulaza A0, Arduino uređaja, koristiti referentni napon od 5V te faktor skaliranja 16 se vidi ispod:

72

Page 73: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

ADMUX = 0; ADMUX |= (1 << REFS0); // Enable the ADC ADCSRA |= (1 << ADEN); // Set the prescale factor to 16 (100 == ADPS bits) ADCSRA |= (1 << ADPS2); ADCSRA &= ~(1 << ADPS1); ADCSRA &= ~(1 << ADPS0);

Ispod se može vidjeti snippet koda sa rutinom za obradu prekida Timera1.

ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine{ // Do a conversion ADCSRA |= (1 << ADSC); // Start conversion // This blocks for 13us 208 cycles wasted while (bit_is_set(ADCSRA, ADSC)) ; analogSample.buffer[0] = ADCL; analogSample.buffer[1] = ADCH; toSend = true;}

Zadnja komanda koju je potrebno podržati je vraćanje jedne analogne vrijednosti čija implementacija koristi isti način preuzimanja analogne vrijednosti kao što je slučaj u upravo navedenoj rutini za obradu prekida te tu vrijednost šalje na serijski izlaz.

3.7.2. Analogni izlaz

Za funkcionalnost analognog izlaza, potrebno je implementirati samo jednu komandu, s kodom koji odgovara vrijednosti ASCII znaka '6', koja dobiveni bajt, pomoću funkcije analogWrite proslijeđuje na analogni izlaz.

case '6': { // the read method does not block, so have to manually wait // for all the parameters to arrive while (Serial.available() < 2) ; // Ignoring the channel parameter for now Serial.read(); unsigned char const val = Serial.read(); // Send the second parameter directly to the digitalWrite function analogWrite(analogOutPin, val); return; }

3.7.3. Digitalni izlaz

Komanda za podršku digitalnog izlaza ima kod koji odgovara ASCII vrijednosti znaka '5' i njegova implementacija se razlikuje od upravo navedene implementacije analognog izlaza samo u tome da se koristi funkcija digitalWrite umjesto analogWrite:

73

Page 74: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

case '5': { // the read method does not block, so have to manually wait // for all the parameters to arrive while (Serial.available() < 2) ; // Ignoring the line parameter for now Serial.read(); unsigned char const val = Serial.read(); // Send the second parameter directly to the digitalWrite function digitalWrite(digitalOutPin, val); return; }

3.7.4. Glavna petlja

Petlja koja se izvršava sve dok je Arduino uređaj uključen, definisana koristeći pomoćnu funkciju Arduino platforme, loop, u svakoj iteraciji najprije provjeri da li je potrebno izvršiti slanje neke vrijednosti na serijski izlaz, a zatim da li postoji nepročitana vrijednost sa serijskog ulaza. U slučaju da postoji, vrijednost se preuzima, dekodira i izvršava jedan od već objašnjenih metoda rješavanja komandi.

void loop() { if (toSend) { toSend = false; Serial.write(analogSample.buffer[0]); Serial.write(analogSample.buffer[1]); } // peek() je mnogo brza funkcija od available! if (Serial.peek() != -1) { char code = Serial.read(); switch (code) {

// ...// Vec objasnjeni i pokazani case blokovi// ...

} }}

74

Page 75: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.8. EtfArduinoConfig - GUI aplikacija

GUI aplikacija služi kao alat za registraciju Arduino uređaja koji sadrže odgovarajući program za komunikaciju sa EtfArduinoService servisom.

Ova aplikacija je implementirana koristeći .NET C++/CLI jezik. Razlog za ovaj izbor je činjenica da se na taj način može pristupiti .NET framework opcijama za jednostavnije kreiranje GUI-a, a u isto vrjieme koristiti već implementirana EtfArduinoService klasa za komunikaciju sa servisom.

Aplikacija pri pokretanju, koristeći odgovarajuće funkcije EtfArduinoService klase provjerava koji uređaji su već registrovani. Ova operacija se izvršava u posebnom threadu kako ne bi došlo do blokiranja GUI threada. Svi pronađeni registrovani uređaji se stavljaju u za to predviđen list box na formi.

Osim toga, pronalaze se i svi serijski portovi koji postoje na sistemu, koristeći statičku metodu GetPortNames .NET klase System::IO::Ports::SerialPort.

Upravo opisani ključni detalji implementacije aplikacije se mogu vidjeti u snippetu koda iz EtfArduinoConfig aplikacije.

private: delegate void ListUpdateDelegate(int deviceId, String^ portName);private: void DeviceDetectThread() {

// Go through IDs 0 to 10 and check if there are registered devices...EtfArduinoService service;for (int i = 0; i <= 10; ++i) {

TCHAR serialPortName[10];if (service.CheckDeviceRegistered(i, serialPortName)) { // Delegate the form update to the GUI thread this->BeginInvoke(

gcnew ListUpdateDelegate(this, &Form1::AddToDeviceList),i,gcnew String(serialPortName));

} }

}private: void InitDeviceDetectThread() {

ThreadStart^ start = gcnew ThreadStart(this, &Form1::DeviceDetectThread); Thread^ t = gcnew Thread(start); t->Start();

}private: void DetectSerialPorts() {

try { serialPorts = System::IO::Ports::SerialPort::GetPortNames();

} catch (Exception^ exc) { MessageBox::Show("Problem detecting ports..."); return;

}}

75

Page 76: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Svi serijski portovi na kojima nije registrovan niti jedan uređaj se stavljaju u drugi list box.

Odabirom nekog od tih serijskih portova iz liste i pritiskom na dugme za registraciju uređaja, izvršava se poziv metode RegisterDevice EtfArduinoService objekta.

Omogućeno je i osvježavanje liste registrovanih uređaja pritiskom na za to predviđeno dugme.

Screenshoti koji prikazuju izvršavanje aplikacije u različitim fazama se nalaze ispod.

76

Slika 11: EtfArduinoConfig aplikacija: otkriven port, uređaj neregistrovan

Slika 12: EtfArduinoConfig aplikacija: poruka o uspješnoj registraciji uređaja

Slika 13: EtfArduinoConfig aplikacija: poruka o neuspješnoj

registraciji uređaja

Page 77: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

3.9. Zaključak

U ovom poglavlju su predstavljene sve komponente i njihove implementacije.

Zahvaljujući named pipe mehanizmu međuprocesne komunikacije različiti procesi su u stanju zahtijevati usluge od EtfArduinoService servisa. Zbog dizajna koji koristi objektno-orijentisane tehnike i dizajn patterne, dodati podršku za nove funkcionalnosti – bilo u vidu novih komandi ili uređaja – je izuzetno olakšano.

Zbog modularnosti koja je postignuta razdvajanjem procesa za upravljanje uređajima i samog DLL adaptora, nije potrebno mijenjati kod DLL-a ukoliko dođe do promjene u implementaciji funkcija specifičnih za Arduino uređaj, kao što je komunikacija sa računarom.

Program za Arduino je zbog upotrebe timera i mehanizma prekida u stanju da generiše uzorke ulaznog signala s tačno onom frekvencijom koja je zadata. Ipak, ograničenje postoji u tome da period uzorkovanja izražen u mikrosekundama mora biti broj djeljiv sa 4.

77

Slika 14: EtfArduinoConfig aplikacija: uređaj registrovan

Page 78: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

4. Demonstracija4.1. Uvod

U ovom poglavlju su predstavljeni rezultati dobiveni korištenjem razvijenog sistema u laboratorijskim uslovima. Kroz odgovarajuće grafike i slike, prikazano je kako se rezultati prikupljeni akvizicijom signala različitih oblika odnose sa očitanjima osciloskopa za te iste signale. Također, pokazan je i rad analognog izlaza na bazi PWM tehnike. Prije svega, opisani su i potrebni koraci za pokretanje i instalaciju sistema ukoliko se posjeduju kompajlirane datoteke.

4.2. Setup

Da bi korištenje sistema za akviziciju bilo moguće, potrebno je da je zadovoljeno nekoliko preduslova.

Najprije, ukoliko etfarduino adaptor nije prethodno korišten na računaru, potrebno je izvršiti njegovu registraciju pri Data Acquisition Toolboxu kako bi engine bio u stanju locirati DLL s implementacijom potrebnih interfejsa. Ovo se postiže korištenjem komande daqregister u MATLAB okruženju:

daqregister etfarduino.dll

Pri tome etfarduino.dll se mora nalaziti u MATLAB putu ili trenutnom radnom direktoriju. Može se proslijediti i apsolutna putanja do DLL datoteke. Ukoliko je u pitanju Windows Vista ili noviji Windows operativni sistem, ova operacija mora biti izvršena s uzdignutim privilegijama, što se postiže pokretanjem MATLAB-a u Administrator modu (desni klik, Run as Administrator).

Sljedeći uslov je da je pokrenut servis za komunikaciju sa uređajem – EtfArduinoService.exe.

Na kraju, iako je ovo dovoljno kako bi adaptor radio, kako bi bilo moguće kreirati bilo koji objekat za akviziciju unutar Data Acquisition Toolboxa, potrebno je izvršiti registraciju Arduino uređaja koristeći EtfArduinoConfig GUI aplikaciju.

Naravno, Arduino uređaj mora biti ispravno spojen na računar s instaliranim EtfArduinoFirmware programom.

78

Page 79: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

4.3. Akvizicija sinusnog signala

Za demonstraciju rada sistema najprije je izvršena akvizicija sinusnog signala frekvencije 100 Hz generisanog pomoću generatora funkcija. Akvizicija je obavljena s frekvencijom uzorkovanja od 2 kHz i u trajanju 20 ms.

MATLAB kod kojim je ovo postignuto je:

ai = analoginput('etfarduino');addchannel(ai, 0);ai.SampleRate = 2000;ai.SamplesPerTrigger = ai.SampleRate * (20 / 1000); % 20 msstart(ai);wait(ai, 5);[data, t] = getdata(ai);plot(t, data);

Ispod se može vidjeti usporedba dobivenog rezultata akvizicije s očitanjem osciloskopa.

Može se zaključiti da i frekvencija i amplituda odgovaraju očekivanoj.

79

Slika 15: Grafik koji prikazuje podatke dobivene akvizicijom sinusoidnog signala frekvencije 100

Hz

Slika 16: Očitanje osciloskopa za sinusoidni signal frekvencije 100 Hz

Page 80: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

4.4. Akvizicija trouglastog signala

Zatim je izvršena akvizicija signala oblika trougla frekvencije 100 Hz. Korištena frekvencija uzorkovanja je također 2 kHz te vrijeme trajanja akvizicije 20 ms.

Ispod se nalaze slike na kojima se može vidjeti usporedba rezultata dobivenog akvizicijom i očitanja osciloskopa.

80

Slika 17: Grafik koji prikazuje podatke dobivene akvizicijom signala oblika trougla frekvencije 100

Hz

Slika 18: Očitanje osciloskopa za signal oblika trougla frekvencije 100 Hz

Page 81: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

4.5. Akvizicija signala oblika četvrtke

Sljedeće je urađena akvizicija signala oblika četvrtke frekvencije 100 Hz. Korištena frekvencija uzorkovanja je 2 kHz i vrijeme trajanja akvizicije 20 ms.

Ispod se može vidjeti usporedba rezultata dobivenog akvizicijom signala i očitanja osciloskopa.

81

Slika 19: Grafik koji prikazuje podatke dobivene akvizicijom signala oblika četvrtke frekvencije 100

Hz

Slika 20: Očitanje osciloskopa za signal oblika četvrtke frekvencije 100 Hz

Page 82: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

4.6. Akvizicija promjene napona na NTC otporniku

Sljedeći eksperiment se sastojao od akvizicije naponske vrijednosti na krajevima NTC otpornika koji je zatim izložen grijanju i hlađenju kako bi došlo do izmjene očitavanog napona.

Frekvencija uzorkovanja je postavljena na 1 kHz, a vrijeme trajanja akvizicije 1 min.Rezultujući grafik signala se može vidjeti ispod.

82

Slika 21: Grafik podataka dobivenih akvizicijom naponskog signala na krajevima NTC otpornika

Slika 22: Laboratorija za vrijeme izvršavanja akvizicije vrijednosti napona sa NTC otpornika

Page 83: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

4.7. Analogni izlaz

Za demonstraciju rada analognog izlaza, urađeno je slanje 5 različitih vrijednosti na izlaz te očitavanje rezultujućeg signala na osciloskopu. Signal je u obliku digitalnih pulseva, što je zbog već objašnjenog ograničenja sistema analognog izlaza Arduino uređaja.

Prva vrijednost koja je poslana je 0V. Na slici ispod se može vidjeti očitanje osciloskopa koje pokazuje da je signal konstantno u stanju 0V, što je i očekivano.

Druga vrijednost je bila 1.25V, što predstavlja jednu četvrtinu maksimalne vrijednosti od 5V. Širina pulseva, kako je već objašnjeno bi tada trebala biti jednaka četvrtini perioda. Na slici ispod se vidi očitanje osciloskopa pri ovoj vrijednosti izlaza.

83

Slika 23: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 0

V

Slika 24: Osciloskop prikazuje rezultat postavljanja analognog izlaza na

vrijednost 1.25 V

Page 84: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Sljedeća vrijednost je 2.5V, tj. polovina maksimalne vrijednosti od 5V. Ispod se nalazi očitanje osciloskopa.

Za predzadnju vrijednost je uzeto 3.75V, što je tri četvrtine maksimalne vrijednosti od 5V. Očitanje osciloskopa se nalazi na sljedećoj slici.

84

Slika 25: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 2.5 V

Slika 26: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 3.75 V

Page 85: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Na kraju, na izlaz je poslana vrijednost 5V te se rezultat koji je prikazan na osciloskopu može vidjeti ispod.

4.8. Zaključak

U ovom poglavlju su predstavljeni rezultati korištenja razvijenog sistema. Usporedbom grafika signala dobivenih analognom akvizicijom i onih na osciloskopima, može se zaključiti da je odstupanje minimalno. Uočena odstupanja se mogu objasniti relativno niskom frekvencijom uzorkovanja. Eksperimentom s akvizicijom napona s krajeva NTC otpornika je utvrđeno da je Arduino moguće koristiti i u situacijama gdje je potrebno da akvizicija traje duži vremenski period te da prati sporije promjene. Na kraju, analogni izlaz je proizveo PWM valne oblike koji su i očekivani za korištene vrijednosti.

85

Slika 27: Osciloskop prikazuje rezultat postavljanja analognog izlaza na vrijednost 5 V

Page 86: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

ZaključakKroz rad je razmatrana mogućnost korištenja Arduino uređaja kao akvizicionog modula.

Utvrđeno je da je najveća moguća frekvencija uzorkovanja koristeći Arduino 12.5 kHz. Razlog za to se pronalazi u dva aspekta, količina memorije koju uređaj posjeduje i brzina prenosa podataka prema računaru. Nedovoljan kapacitet memorije dovodi do nemogućnosti spašavanja podataka koji se prikupljaju na sam uređaj. Maksimalna brzina prenosa koju je bilo moguće postići, 256 kbaud, dovodi do navedenog ograničenja.

Za razvoj sistema je bilo potrebno razviti DLL sa COM komponentama koje su u stanju komunicirati sa Data Acquisition Engineom. Ta komunikacija se zasniva na implementaciji predefinisanih COM interfejsa, tj. njegovih metoda. Osim DLL-a, za postizanje modularnosti i efikasnosti, implementiran je i proces EtfArduinoService koji predstavlja servis koji klijentima omogućava pristup funkcionalnostima Arduino uređaja za akviziciju. Objektno-orijentisani principi dizajna koji su korišteni omogućavaju lako proširenje servisa dodatnim funkcionalnostima.

Za sam Arduino je razvijen program koji reaguje na primljene komande u dogovorenom formatu i vraća odgovarajuće rezultate. Pri akviziciji, korištenje prekida je omogućilo postizanje perioda akvizicije koji tačno odgovara zadatom, pod uslovom da je period, izražen u mikrosekundama, broj djeljiv s 4. PWM tehnika omogućava podršku analognog izlaza.

Kroz poglavlje Demonstracija može se primijetiti da je sistem uspješno iskorišten pri uslovima koji su vladali u tim eksperimentima. Odstupanje dobivenih vrijednosti od očitanja osciloskopa je bilo minimalno. Određeno izobličenje grafika koje se javilo na nekim od signala je rezultat niske frekvencije uzorkovanja. Akvizicija dužeg trajanja je uspješno izvršena i rezultat je pokazao kako je moguće vršiti akviziciju signala s sporijom promjenom. Analogni, tj. PWM, izlaz je također demonstriran da radi kako je i očekivano.

Zbog ovoga, razvijeni sistem se može koristiti kao zamjena za skuplje akvizicione module sve dok nije potrebno vršiti akviziciju signala izuzetno visokih frekvencija i dok je 10-bitna rezolucija ulaznih vrijednosti dovoljna.

Bez obzira na to, buduće unaprjeđenje sistema bi se moglo nastaviti u više pravaca. Jedan od njih je uvesti specifičnu podršku za druge Arduino uređaje koji ne bi bili ograničeni na 256 kbaud kao što je Uno zbog svog Atmega8u2 procesora koji vrši pretvorbu serijskog izlaza ATmega328 procesora u USB signal.

Druga mogućnost je istražiti druge vidove komunikacije računara i Arduino uređaja, kao što su Bluetooth, Ethernet, Wi-Fi i sl. Moguće je da bi se na taj način mogla postići veća brzina prenosa podataka što bi omogućilo i veću maksimalnu frekvenciju uzorkovanja. Obzirom na dizajn EtfArduinoService servisa, za ovo bi bilo potrebno samo izvršiti dodatnu implementaciju ArduinoDevice abstraktne klase.

Još jedna mogućnost je koristiti ne-Arduino uređaje. Bilo koji uređaj koji podržava vid komunikacije sa računarom i analogni ulaz i izlaz bi se mogao podržati u sistemu. Primjer bi bili ATmega328 zasnovani sklopovi koji za komunikaciju koriste serijski izlaz procesora i serijski port računara, gdje bi brzina komunikacije mogla biti 2 Mbaud. I u ovom slučaju, korišteni dizajn dozvoljava ovakva unaprjeđenja.

86

Page 87: Akvizicija podataka pomocu modula Arduino UNO u okviru MATLAB okruzenja-LalicBachelorsThesis

Literatura[1] Arduino Team. ArduinoUno documentation. http://arduino.cc/en/Main/ArduinoBoardUno.

Preuzeto august, 2012.

[2] Atmel Corporation (2012). ATmega48A/PA/88A/PA/168A/PA/328/P [DATASHEET]. Atmel Corporation.

[3] Atmel Corporation (2006). AVR120: Characterization and Calibration of the ADC on an AVR. Atmel Corporation.

[4] Atmel Corporation (2003). AVR131: Using the AVR's High-speed PWM. Atmel Corporation.

[5] Box, Don (1998). Essential COM. Addison Wesley Longman, Inc.

[6] Denver, Allen (1995). Serial Communications. http://msdn.microsoft.com/en-us/library/ff802693.aspx. MSDN Library. Preuzeto august, 2012.

[7] Microsoft Corporation. Interprocesss Communications. http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx. Preuzeto august, 2012.

[8] Microsoft Corporation. Microsoft COM: Component Object Model Technologies. http://www.microsoft.com/com/. Preuzeto august, 2012.

[9] The MathWorks, Inc. (2011). Data Acquisition Toolbox Adaptor Kit User's Guide. The MathWorks, Inc.

[10] The MathWorks, Inc. MATLAB documentation. http://www.mathworks.com/help/techdoc/. Preuzeto august, 2012.

[11] The MathWorks, Inc. (2011). Data Acquisition Toolbox User's Guide. The MathWorks, Inc.

[12] The MathWorks, Inc. MATLAB documentation. http://www.mathworks.com/help/techdoc/. Preuzeto august, 2012.

87