Upload
others
View
8
Download
0
Embed Size (px)
Citation preview
RANCANG BANGUN ALAT UKUR
KAPASITAS VITAL PAKSA PARU DENGAN SENSOR
TEKANAN BERBASIS ARDUINO DAN LABVIEW
Skripsi
Oleh
IKA RIYANTI
NIM: 1113097000006
PROGRAM STUDI FISIKA
FAKULTAS SAINS DAN TEKNOLOGI
UNIVERSITAS ISLAM NEGERI
SYARIF HIDAYATULLAH
JAKARTA
1429 H/2018 M
RANCANG BANGUN ALAT UKUR
KAPASITAS VITAL PAKSA PARU DENGAN SENSOR
TEKANAN BERBASIS ARDUINO DAN LABVIEW
Skripsi
Diajukan kepada Fakultas Sains dan Teknologi untuk Memenuhi Persyaratan
Memperoleh Gelar Sarjana Sains (S.Si.)
Oleh
IKA RIYANTI
NIM: 1113097000006
PROGRAM STUDI FISIKA
FAKULTAS SAINS DAN TEKNOLOGI
UNIVERSITAS ISLAM NEGERI
SYARIF HIDAYATULLAH
JAKARTA
1429 H/2018 M
ii
LEMBAR PERSETUJUAN PEMBIMBING
iii
LEMBAR PENGESAHAN
iv
LEMBAR PERNYATAAN
Dengan ini saya menyatakan bahwa:
1. Skripsi ini merupakan hasil karya asli saya yang diajukan untuk memenuhi
salah satu persyaratan memperoleh gelar Sarjana Sains (S.Si) di UIN Syarif
Hidayatullah Jakarta.
2. Semua sumber yang saya gunakan dalam penelitian ini telah saya cantumkan
sesuai dengan ketentuan yang berlaku di UIN Syarif Hidayatullah Jakarta.
3. Jika di kemudian hari terbukti bahwa karya ini bukan hasil karya asli saya atau
merupakan hasil jiplakan dari karya orang lain, maka saya bersedia menerima
sanksi yang berlaku di UIN Syarif Hidayatullah Jakarta.
Jakarta, 18 Juli 2018
Ika Riyanti
v
ABSTRAK
Gangguan obstruktif dan restriktif pada paru-paru merupakan salah satu
penyebab kematian di dunia. Tes kapasitas vital paru menggunakan spirometer
adalah salah satu cara untuk mendiagnosis, tetapi berdasarkan survei diketahui
bahwa spirometer yang portabel memiliki harga mulai dari 10 juta rupiah sampai
80 juta rupiah. Penelitian ini bertujuan untuk merancang dan membangun
hardware dan software alat ukur kapasitas vital paksa paru menggunakan sensor
tekanan MPX5100DP, Arduino Uno R3 dan LabVIEW 2015 dan menentukan
karakteristik, hasil nilai FVC beserta indikasinya dari alat ukur kapasitas vital
paksa paru. Pengujian dilakukan dengan membandingkan alat ukur kapasitas vital
paksa paru dengan spirometer BTL-08 Spiro. Hasilnya telah berhasil merancang
bangun sebuah alat ukur kapasitas vital paksa paru menggunakan sensor tekanan
MPX5100DP, Arduino Uno R3 dan LabVIEW 2015 dengan dengan karakteristik
memiliki jangkauan pengukuran sensor , waktu respon ,
ketelitian sebesar , ketepatan sebesar , kesalahan rata-rata
dan dapat menampilkan indikasi kenormalan.
Kata Kunci: Arduino Uno R3, Kapasitas Vital Paksa, LabVIEW 2015, Sensor
Tekanan MPX5100DP
vi
ABSTRACT
Obstructive and restrictive disorders of the lungs are one of the leading
causes of death in the world. Testing vital capacity of pulmonary using a
spirometer is one way to diagnose, but based on surveys it is known that portable
spirometers have prices ranging from 10 million rupiah to 80 million rupiah. The
aim of this research is to design and build hardware and software of measuring
vital capacity of pulmonary force using pressure sensor MPX5100DP, Arduino
Uno R3 and LabVIEW 2015 and determine the characteristics, FVC value and its
indication from measuring forced vital capacity of pulmonary. The test was
performed by comparing the forced vital capacity measuring instrument with
BTL-08 Spiro spirometer. The result has succeeded in designing the build up of a
forced vital capacity of pulmonary measuring instrument using pressure sensor
MPX5100DP, Arduino Uno R3 and LabVIEW 2015 with characteristic of having
sensor measurement range of 0-100kPa, response time of 1ms, accuracy of
90.41%, precision of ± 0.01, average error of 9.59% and can display normal
indication.
Keywords: Arduino Uno R3, Forced Vital Capacity, LabVIEW 2015,
MPX5100DP Pressure Sensor
vii
KATA PENGANTAR
Assalamu‟alaikum warahmatullahi wabarakatuh
Alhamdulillah puji syukur atas kehadirat Allah Subhanahu wa Ta‟ala atas
rahmat dan rizki-Nya. Sholawat beserta salam semoga senantiasa tercurahkan
kepada baginda Rasulullah Muhammad Shalallahu „Alayhi wa Sallam beserta
keluarganya, para sahabatnya, tabi’in hingga kepada umatnya hingga akhir zaman,
Amin.
Skripsi yang berjudul “Rancang Bangun Alat Ukur Kapasitas Vital
Paksa Paru” dapat diselesaikan dengan baik oleh penulis sebagai syarat untuk
mendapatkan gelar sarjana Strata Satu (S.Si). Terwujudnya skripsi ini tidak
terlepas dari kerja sama, bantuan dan bimbingan dari berbagai pihak baik secara
langsung ataupun tidak langsung, maka dari itu penulis ingin menyampaikan rasa
terima kasih terhadap berbagai pihak tersebut, diantaranya:
1. Keluarga penulis, terutama ayah dan bunda yang telah bersabar menanti dan
selalu memberi segala dukungan baik secara materi maupun non materi.
2. Ibu Elvan Yuniarti, M.Si. selaku dosen pembimbing pertama dan Bapak Edi
Sanjaya, M.Si. selaku dosen pembimbing kedua, atas waktu yang telah
diluangkan untuk memberikan bimbingan kepada penulis.
3. Bapak Arif Tjahjono M.Si. selaku Ketua Program Studi Fisika dan Ibu Tati
Zera, M.Si selaku Sekretaris Program Studi Fisika
4. Bapak Dr. Agus Salim, M.Si selaku Dekan Fakultas Sains dan Teknologi
5. Fakultas Kedokteran UIN Syarif Hidayatullah Jakarta yang telah
memberikan ijin untuk melaksanakan penelitian
6. Bapak Chris selaku Kepala Laboratorium di Fakultas Kedokteran UIN
Syarif Hidayatullah, atas kesediaannya dalam membantu memproses ijin
pengujian
7. Bapak Manaf selaku laboran di Laboratorium Fisiologi Fakultas Kedokteran
UIN Syarif Hidayatullah, atas bimbingannya pada saat melakukan pengujian
8. Seluruh dosen-dosen Program Studi Fisika, atas ilmu yang telah diberikan
selama perkuliahan
viii
9. Teman-teman seperjuangan fisika angkatan 2013, khususnya peminatan
instrumentasi Agung Sedayu, Nizarrachman Hadi, Nurhanifiyah Azura dan
Susanto atas dukungan dan masa-masa indah pada saat perkuliahan
10. Agung Prasetyo, yang tidak pantang menyerah selalu memberi semangat
dan meyakinkan penulis dalam proses penyelesaian skripsi ini
11. Silvia Puji Lestari, Ratnawati, Ria Melita dan Rizki Rohman yang telah
bersedia membantu penulis dalam proses pembuatan skripsi
12. Semua pihak yang telah membantu penulis dalam penyusunan laporan ini
baik secara langsung maupun tidak langsung yang tidak dapat penulis
sebutkan satu per satu
Tak ada gading yang tak retak, penulis menyadari bahwa skripsi ini masih
jauh dari kata sempurna. Untuk itu penulis sangat megharapkan adanya kritik
saran dan masukan dari berbagai pihak. Penulis berharap skripsi ini dapat
bermanfaat bagi penulis maupun pembaca khususnya yang memerlukan.
Wassalamu‟alaikum warrahmatullahi wabarakatuh
Jakarta, 08 Juli 2018
Penulis
ix
DAFTAR ISI
LEMBAR PERSETUJUAN PEMBIMBING ......................................................... ii
LEMBAR PENGESAHAN .................................................................................. iii
LEMBAR PERNYATAAN ................................................................................... iv
ABSTRAK .............................................................................................................. v
ABSTRACT ............................................................................................................. vi
KATA PENGANTAR .......................................................................................... vii
DAFTAR ISI .......................................................................................................... ix
DAFTAR TABEL .................................................................................................. xi
DAFTAR GAMBAR ............................................................................................ xii
DAFTAR LAMPIRAN ........................................................................................ xiii
BAB I PENDAHULUAN ...................................................................................... 1
1.1. Latar Belakang ............................................................................................... 1
1.2. Rumusan Masalah .......................................................................................... 4
1.3. Batasan Masalah ............................................................................................ 5
1.4. Tujuan Penelitian ........................................................................................... 5
1.5. Manfaat Penelitian ......................................................................................... 5
1.6. Sistematika Penulisan .................................................................................... 6
BAB II DASAR TEORI......................................................................................... 7
2.1. Pernapasan ..................................................................................................... 7
2.2. Tabung Pitot ................................................................................................ 10
2.3. Sensor Tekanan MPX5100DP ..................................................................... 12
2.4. Arduino Uno ................................................................................................ 14
2.5. IDE Arduino ................................................................................................ 21
2.6. LabVIEW ..................................................................................................... 22
2.6.1. Menu Bar Icons ................................................................................ 26
2.6.2. NI-VISA ........................................................................................... 28
2.6.3. LabVIEW Interface for Arduino (LIFA) .......................................... 29
BAB III METODE PENELITIAN........................................................................ 31
x
3.1. Waktu dan Tempat Penelitian ...................................................................... 31
3.2. Alat dan Bahan Penelitian ........................................................................... 31
3.3. Tahap dan Alur Penelitian ........................................................................... 32
3.4. Tahap Perancangan Alat .............................................................................. 34
3.4.1. Perancangan Perangkat Keras (Hardware) ...................................... 34
3.4.2. Perancangan Perangkat Lunak (Software) ....................................... 36
3.5. Metode Pengambilan Data ........................................................................... 40
3.6. Spesifikasi Spirometer BTL-08 Spiro ......................................................... 40
BAB IV HASIL DAN PEMBAHASAN ............................................................. 42
4.1. Hasil Perancangan Hardware ...................................................................... 42
4.1.1. Perancangan Mouthpiece ................................................................. 42
4.1.2. Perancangan Alat Ukur Kapasitas Vital Paksa Paru ........................ 43
4.2. Hasil Perancangan Software ........................................................................ 46
4.2.1. Block Diagram ................................................................................. 46
4.2.2. Front Panel (User Interface) ........................................................... 47
4.3. Hasil Pengujian Karakteristik Alat Ukur Kapasitas Vital Paksa Paru ......... 50
4.3.1. Hasil Pengujian Linearitas Arduino (ADC) ..................................... 50
4.3.2. Hasil Pengujian Sensor Tekanan MPX5100DP............................... 52
4.3.3. Hasil Pengujian Kalibrasi Prediksi FVC Normal Alat BTL-08 Spiro
dengan Alat Ukur Kapasitas Vital Paksa Paru ................................. 54
4.3.4. Hasil Pengujian Nilai FVC Responden ........................................... 55
4.3.5. Hasil Indikasi Nilai FVC Responden ............................................... 59
BAB V KESIMPULAN DAN SARAN ............................................................... 61
5.1. Kesimpulan .................................................................................................. 61
5.2. Saran 61
DAFTAR PUSTAKA ........................................................................................... 62
LAMPIRAN .......................................................................................................... 64
xi
DAFTAR TABEL
Tabel 2. 1 Spesifikasi Board Arduino Uno ........................................................... 16
Tabel 2. 2 Bagian-bagian IDE Arduino ................................................................ 22
Tabel 2. 3 Item Menu Bar Icons............................................................................ 27
Tabel 4. 1. Spesifikasi Mouthpiece Alat Rancang ................................................ 43
Tabel 4. 2 Spesifikasi Alat Ukur Kapasitas Vital Paksa Paru ............................... 45
Tabel 4. 3. Spesifikasi Mouthpiece Alat Rancang ................................................ 48
Tabel 4. 4 Hasil Pengujian Pin ADC Arduino ...................................................... 51
Tabel 4. 5 Hasil Pengujian Sensor Tekanan MPX5100DP ................................... 53
Tabel 4. 6 Hasil Pengujian Nilai Prediksi FVC Normal ....................................... 54
Tabel 4. 7 Hasil Pengujian Nilai FVC .................................................................. 56
Tabel 4. 8 Perhitungan Ketepatan Alat Ukur Kapasitas Vital Paksa .................... 57
Tabel 4. 9 Hasil Indikasi Nilai FVC...................................................................... 59
xii
DAFTAR GAMBAR
Gambar 2. 1 Volume dan Kapasitas Paru ............................................................. 9
Gambar 2. 2 Tabung Pitot .................................................................................. 11
Gambar 2. 3 Bagan Sensor Tekanan MPX5100DP ........................................... 13
Gambar 2. 4 Tampilan Arduino Uno .................................................................. 15
Gambar 2. 5 Tampilan IDE Arduino .................................................................. 21
Gambar 2. 6 Tampilan Jendela LabVIEW 2015 ................................................ 23
Gambar 2. 7 Tampilan Saat Memulai LabVIEW 2015 ...................................... 24
Gambar 2. 9 Front Panel .................................................................................... 24
Gambar 2. 10 Block Diagram ............................................................................... 25
Gambar 2. 11 Control Pallete .............................................................................. 25
Gambar 2. 12 Functions Pallete ........................................................................... 26
Gambar 3. 1 Tahap dan Alur Penelitian ............................................................. 32
Gambar 3. 2 Desain Perancangan Perangkat Keras (Hardware) ....................... 35
Gambar 3. 3 Desain Mouthpiece ........................................................................ 35
Gambar 3. 5 Proses Konversi Nilai Tegangan Menjadi Volume ....................... 38
Gambar 3. 6 Flowchart Sistem Kerja Perangkat Lunak .................................... 39
Gambar 3. 7 Spirometer BTL-08 Spiro .............................................................. 41
Gambar 4. 1. Hasil Perancangan Mouthpiece ..................................................... 43
Gambar 4. 2 Tampilan Bagian Dalam Mouthpiece ............................................ 43
Gambar 4. 3 Bagian-bagian Alat Ukur Kapasitas Vital Paksa Paru .................. 44
Gambar 4. 4 Tampilan Atas dan Samping Alat Ukur Kapasitas Vital Paksa
Paru ................................................................................................ 44
Gambar 4. 5 Block Diagram Software Alat Ukur Kapasitas Vital Paksa Paru .. 47
Gambar 4. 6 Front Panel Program Alat Ukur Kapasitas Vital Paksa Paru ........ 48
Gambar 4. 7 Diagram Alir Pengambilan Data ................................................... 49
Gambar 4. 8 Grafik Linieritas ADC Arduino ..................................................... 52
Gambar 4. 9 Grafik Hasil Uji Nilai FVC BTL-08 Spiro dengan Alat Ukur
Kapasitas Vital Paksa Paru ............................................................ 58
xiii
DAFTAR LAMPIRAN
Lampiran 1 Sketch Program Firmware LIFA Base ............................................. 65
Lampiran 2 Block Diagram Alat Ukur Kapasitas Vital Paksa Paru .................... 90
Lampiran 3 Datasheet Sensor Tekanan MPX5100DP......................................... 91
Lampiran 4 Spesifikasi BTL-08 Spiro ................................................................. 96
Lampiran 5 Hasil Pengujian Menggunakan BTL-08 Spiro ................................. 99
Lampiran 6 Hasil Pengujian Menggunakan Alat Ukur Kapasitas Vital Paksa
Paru ................................................................................................ 100
1
BAB I
PENDAHULUAN
1.1. Latar Belakang
“Barangsiapa yang Allah menghendaki akan memberikan kepadanya
petunjuk, niscaya Dia melapangkan dadanya untuk (memeluk agama)
Islam. Dan barangsiapa yang dikehendaki Allah kesesatannya, niscaya
Allah menjadikan dadanya sesak lagi sempit, seolah-olah ia sedang
mendaki langit. Begitulah Allah menimpakan siksa kepada orang-orang
yang tidak beriman.”(Q.S. Al An‟am (6): 125)
Paru-paru merupakan organ penting pada sistem pernapasan karena
berperan dalam pertukaran antara oksigen dan karbondioksida di dalam darah.
Penyakit paru-paru membuat organ paru-paru tak bisa berfungsi maksimal
sehingga menghambat sistem pernapasan. Jika sistem pernapasan sampai
bermasalah akibat gangguan satu atau hal lain, maka itu bisa mencegah tubuh
mendapatkan asupan oksigen yang memadai sehingga harus ditangani dengan
seksama. Indonesia termasuk yang memiliki kesadaran rendah terkait PPOK,
tidak semua penderita merasakan atau bahkan menyadari gejalanya. Menurut Prof.
Dr. Faisal Yunus dari Departemen Pulmonologi dan Kedokteran Respirasi di
Fakultas Kedokteran Universitas Indonesia, kebanyakan orang akan berpikir
hanya penyakit batuk yang tidak kunjung sembuh padahal mereka mungkin
sedang menderita PPOK, kondisi yang jauh lebih serius, sehingga harus dilakukan
pemeriksaan spirometri dan toraks. Gejala PPOK antara lain napas yang pendek-
2
pendek, batuk kronis, kelelahan dan rasa sesak di dada yang berkembang secara
perlahan dan tak kerasa. Jika tidak diobati, kondisi ini bisa menyebabkan
kematian (Tempo.co, 2017).
Gangguan obstruktif dan restriktif pada paru-paru merupakan salah satu
penyebab kematian di dunia. Gangguan ini menyebabkan kematian di Amerika
Serikat 10.000-20.000 orang per tahun. Menurut World Health Organization
(WHO) pada tahun 2012, jumlah penderita PPOK mencapai 274 juta jiwa dan
diperkirakan meningkat menjadi 400 juta jiwa di tahun 2020 mendatang dan
setengah dari angka tersebut terjadi di negara berkembang, termasuk negara
Indonesia. Menurut Survey Kesehatan Rumah Tangga tahun 1986, angka kejadian
di Indonesia untuk penyakit asma, bronkitis kronik dan empisema atau sekarang
lebih dikenal dengan penyakit patu obstruktif kronis (PPOK) menempati
peringkat 5 tertinggi di dunia yaitu 7.8 juta jiwa dan diperkirakan pada tahun 2030
akan menjadi penyebab kematian ketiga di seluruh dunia. Selain itu, penyakit ini
juga menempati peringkat 6 dari 10 penyebab kematian tersering. Adapun catatan
laporan World Health Organization (WHO) dalam World Health Report pada
tahun 2012 menyebutkan ada lima penyakit paru utama yang menyebabkan 17.4%
dari seluruh kematian di dunia, kelima penyakit paru itu adalah infeksi paru 7.2%,
PPOK 4.8%, tuberkulosis 3.0%, kanker paru/trakea/bronkus 2.1% dan asma 0.3%.
Kurangnya kesadaran dan stigma sosial terkait penyakit tersebut, sehingga
hanya separuh dari sekitar 210 juta orang yang diperkirakan menderita PPOK
telah resmi didiagnosis. Riset Kesehatan Dasar Indonesia (Riskesdas) 2013
mengungkapkan bahwa jumlah pasien PPOK naik 3.7%. Jumlah penderita PPOK
3
meningkat akibat faktor genetik, pola hidup yang tidak sehat, asap rokok dan
polusi udara.
Salah satu pemeriksaan penunjang gangguan ini adalah dengan tes fungsi
paru, salah satunya adalah kapasitas vital paru menggunakan spirometer.
Kapasitas vital paru dapat bermanfaat untuk menjelaskan patofisiologi,
mengetahui prognosis dan sebagai evaluasi terapi yang sedang diberikan pada
penderita gangguan paru (Soegito, 1998). Spirometer menghasilkan spirogram
yang dapat memperlihatkan perubahan volume paru pada berbagai keadaan
pernapasan dalam bentuk grafik. Grafik yang dihasilkan dari proses pernapasan
merupakan hasil dari proses penghirupan dan penghembusan udara, sehingga
dapat digunakan untuk mengetahui volume dan kapasitas paru-paru. Spirometer
merupakan instrumen yang paling efektif untuk menentukan gangguan saluran
pernapasan antara gangguan saluran napas obstruktif (misalnya asma) dan
penyakit restriktif (dimana ukuran dari paru-paru berkurang, misalnya penyakit
paru-paru fibrosis) atau dapat juga menentukan tingkat keparahan penyakit kronis
pada paru.
Permasalahannya saat ini, berdasarkan survei melalui Google pada beberapa
web online baik yang menjual perlengkapan umum ataupun khusus alat-alat
kesehatan seperti www.medicalogy.com, www.alatkesehatan.id dan
www.tokopedia.com, diketahui bahwa spirometer yang portabel dan
terkomputerisasi memiliki harga mulai dari 10 juta rupiah sampai 80 juta rupiah.
Hal ini membuat spirometer hanya dimiliki oleh rumah sakit besar, lembaga atau
laboratorium tertentu khususnya yang bergerak di bidang kesehatan.
4
Berdasarkan permasalahan tersebut, peneliti merancang bangun sebuah
spirometer sederhana yang dapat mengukur kapasitas vital paksa paru agar dapat
digunakan dalam melakukan pemeriksaan dini. Sebelumnya Zainudin, dkk (2015)
telah melakukan pengukuran volume paru-paru dengan memanfaatkan sensor
tekanan MPX5100DP, hanya saja pada penelitiannya belum menampilkan grafik
hasil pengujian secara otomatis dan pengambilan responden pun dilakukan
random tidak menghiraukan jenis kelamin. Sedangkan peneliti akan merancang
bangun menggunakan perangkat Arduino Uno R3 dikarenakan Arduino Uno
merupakan board yang mudah ditemukan, mudah digunakan, harganya murah dan
sering digunakan dalam project eksperimental. Selain itu, pada penampilan hasil
pengukuran peneliti menggunakan bantuan software LabVIEW 2015, hal ini
dikarenakan dalam pengoperasiannya LabVIEW menggunakan ikon grafis serta
dapat menghasilkan user interface yang mudah dipahami oleh pengguna sehingga
dapat menghasilkan grafik secara otomatis.
1.2. Rumusan Masalah
Berdasarkan latar belakang yang telah dipaparkan, maka dapat ditarik
beberapa rumusan masalah, yaitu
1. Bagaimana merancang bangun sebuah alat ukur yang dapat mengukur
kapasitas vital paksa paru dengan menggunakan sensor tekanan?
2. Bagaimana menghubungkan LabVIEW 2015 dengan Arduino Uno R3 agar
menjadi sebuah sistem kesatuan yang menghasilkan keluaran yang mudah
dibaca, dipahami dan sesuai dengan alat spirometer yang telah ada?
5
1.3. Batasan Masalah
Agar penelitian ini lebih fokus maka diberikan batasan-batasan masalah
sebagai berikut:
1. Hanya mengukur kapasitas vital paksa paru saat ekspirasi
2. Mikrokontroler yang digunakan adalah Arduino Uno R3
3. Bagian dari perangkat Arduino Uno R3 yang digunakan hanya pin tegangan
5V, ground dan ADC untuk membaca data masukan
4. Sensor tekanan yang digunakan adalah sensor tekanan MPX5100DP
5. Software utama yang digunakan untuk membuat program dan user interface
adalah LabVIEW 2015
6. Hasil hanya menginformasikan paru normal atau tidak normal
1.4. Tujuan Penelitian
Adapun tujuan dari penelitian ini, yaitu:
1. Merancang dan membangun hardware dan software alat ukur kapasitas vital
paksa paru menggunakan sensor tekanan MPX5100DP, Arduino Uno R3
dan LabVIEW 2015
2. Menentukan karakteristik Alat Ukur Kapasitas Vital Paksa Paru
3. Menentukan hasil pengujian nilai FVC dari responden beserta indikasinya
1.5. Manfaat Penelitian
Adapun manfaat dari perancangan alat ukur kapasitas vital paksa paru ini
adalah agar tercipta sebuah alat yang dapat mengukur kapasitas vital paksa paru
dengan perangkat yang sederhana atau umum dimiliki serta dapat menampilkan
hasil yang mudah dipahami dalam pengoperasian maupun pembacaan hasilnya.
6
1.6. Sistematika Penulisan
Untuk memberikan gambaran ringkasan pada skripsi ini, peneliti
menyajikan dalam bentuk sistematika penulisan skripsi. Sistem yang digunakan
sebagai berikut:
BAB I PENDAHULUAN, berisi latar belakang, pembatasan masalah,
perumusan masalah, tujuan penelitian, manfaat penelitian, sistematika penulisan.
BAB II DASAR TEORI, berisi bab-bab yang mengandung dasar teori yang
disesuaikan dengan penelitian yang dilakukan, dasar teori ini nantinya akan
menjadi acuan saat penelitian berjalan.
BAB III METODOLOGI PENELITIAN, menjelaskan mengenai waktu
dan tempat penelitian, alat dan bahan yang digunakan, tahapan penyusunan,
perancangan dan metode analisis.
BAB IV HASIL PENELITIAN, menyajikan hasil penelitian berupa hasil
rancangan hardware maupun software, hasil uji coba, hasil rancangan serta
pembahasan mengenai hasil rancangan tersebut.
BAB V PENUTUP, berisi tentang kesimpulan penelitian yang telah
dilakukan dan saran-saran yang diberikan oleh peneliti untuk peneliti selanjutnya.
7
BAB II
DASAR TEORI
2.1. Pernapasan
Pernapasan merupakan bagian dari sistem respirasi, respirasi adalah suatu
peristiwa ketika tubuh kekurangan oksigen (O2) dan O2 yang berada di luar tubuh
dihirup (inspirasi) melalui organ pernapasan. Pada keadaan tertentu tubuh
kelebihan karbon dioksida (CO2), maka tubuh berusaha untuk mengeluarkan
kelebihan tersebut dengan menghembuskan napas (ekspirasi) sehingga terjadi
suatu keseimbangan antara O2 dan CO2 di dalam tubuh. Sistem respirasi berperan
untuk menukar udara ke permukaan dalam paru. Udara masuk dan menetap dalam
sistem pernapasan dan masuk dalam pernapasan otot.
Pernapasan memiliki beberapa fungsi, diantaranya mengambil O2 dari luar
masuk ke dalam tubuh, mengeluarkan CO2 yang terjadi dari sisa-sisa hasil
pembakaran, melindungi sistem permukaan dari kekurangan cairan dan mengubah
suhu tubuh, melindungi sistem pernapasan dari jaringan lain terhadap serangan
patogenik dan pembentukan komunikasi seperti berbicara, bernyanyi, berteriak
dan menghasilkan suara (Syaifuddin, 2010).
Volume paru-paru bertambah pada waktu menarik napas sedangkan pada
waktu ekspirasi udara dalam paru-paru akan menurun. Pada waktu
inspirasi/menarik napas akan terlihat flow rate meningkat sedangkan tekanan
intrapleura menurun. Sedangkan pada waktu ekspirasi, terjadi peningkatan
tekanan sedangkan flow rate menurun (Sutrisno dan Ahmiarti, 2007).
8
Ada empat volume paru bila semua dijumlahkan sama dengan volume
maksimal paru yang mengembang, masing-masing volume itu adalah:
a. Volume tidal (VT), volume udara yang diinspirasikan dan diekspirasikan di
setiap pernapasan normal
b. Volume cadangan inspirasi (VCI), volume tambahan udara yang dapat
diinspirasikan di atas volume tidal normal
c. Volume cadangan ekspirasi (VCE), jumlah udara yang masih dapat
dikeluarkan dengan ekspirasi tidal yang normal
d. Volume Residu (VR), volume udara yang masih tersisa di dalam paru
setelah kebanyakan ekspirasi kuat
Dalam siklus paru perlu menyatukan dua volume atau lebih yang disebut
kapasitas paru, berikut macam-macam kapasitas paru (Syaifuddin, 2010):
1. Kapasitas inspirasi, sama dengan volume tidal, ditambah dengan volume
cadangan inspirasi. Jumlah udara yang dapat dihirup oleh seseorang mulai
pada tingkat ekspirasi normal dan mengembangkan parunya sampai jumlah
maksimum
2. Kapasitas sisa fungsional, sama dengan volume cadangan ekspirasi
ditambah volume sisa. Jumlah udara yang tersisa di dalam paru pada akhir
ekspirasi.
3. Kapasitas vital, sama dengan volume cadangan inspirasi ditambah dengan
volume tidal dan volume cadangan ekspirasi. Jumlah udara maksimum
yang dapat dikeluarkan dari paru-paru setelah ia mengisinya sampai batas
maksimum dan kemudian mengeluarkan sebanyak-banyaknya
9
4. Kapasitas total paru, volume maksimum pengembangan paru dengan usaha
inspirasi
Gambar 2. 1 Volume dan Kapasitas Paru
Sumber: Fachrial dan Endah, 2012
Ada dua macam kapasitas vital paru berdasarkan cara pengukurannya, yaitu
vital capacity (VC) dengan subjek tidak perlu melakukan aktivitas pernapasan
dengan kekuatan penuh dan forced vital capacity (FVC) dengan subjek
melakukan aktivitas pernapasan degan kekuatan maksimal secepat mungkin
(Alsagaff, 2008).
Volume udara yang dihirup dan dihembuskan dalam siklus pernapasan yang
tenang atau kuat bervariasi dengan ukuran, usia dan jenis kelamin untuk
memungkinkan evaluasi fungsi paru. Volume pernapasan yang kurang dari 80%
rata-rata normal biasanya mengindikasikan beberapa bentuk penyakit paru.
Metode untuk meneliti ventilasi paru adalah dengan merekam volume
pergerakan udara yang masuk dan keluar paru menggunakan alat spirometri
yang menghasilkan spirogram sehingga dapat memperlihatkan perubahan dalam
volume paru pada berbagai keadaan pernapasan (Syaifuddin, 2010).
10
2.2. Tabung Pitot
Dalam aliran stasioner, tiap partikel mempunyai garis aliran tertentu, dan
untuk luas penampang yang sama tiap partikel mempunai laju aliran yang sama
besar. Untuk fluida tak kompresibel, hasil kali laju aliran fluida dengan
penampangnya selalu bernilai tetap yang disebut persamaan kontinuitas.
(1)
dengan:
Luas Penampang di posisi 1
Luas penampang di posisi 2
Laju aliran fluida di posisi 1
Laju aliran di posisi 2
Hasil kali antara laju aliran fluida dengan luas penampangnya dikenal juga
dengan sebutan debit sehingga besaran debit dirumuskan sebagai:
(2)
dengan:
Luas penampang aliran
Laju aliran fluida
Debit fluida
Hukum Bernoulli adalah suatu hukum yang dapat digunakan untuk
menjelaskan gejala yang berhubungan dengan gerakan zat alir melalui suatu
penampang pipa. Berdasarkan persamaan Bernoulli juga diperoleh bahwa jumlah
tekanan , energi kinetis persatuan volume ⁄ dan energi potensial
11
persatuan volume mempunyai nilai yang sama di setiap titik sepanjang
aliran:
⁄ (3)
Tabung pitot memiliki luas penampang yang sama. Pada tabung pitot, ada
bagian dari pipa manometer yang menembus ke dalam tabung. Pipa manometer
yang menembus tabung pitot tersebut dihadapkan ke arah datangnya fluida,
dengan demikian fluida yang mengalir akan menghasilkan tekanan dan menekan
permukaan raksa yang menempati pipa manometer, pada umumnya tabung pitot
digunakan untuk mengukur kecepatan udara atau gas di dalam pipa tertutup.
Gambar 2. 2 Tabung Pitot
Sumber: Kamajaya, 2007
Dengan mengukur perbedaan tinggi permukaan raksa di dalam manometer,
dapat ditentukan kelajuan fluida di dalam tabung pitot. Berdasarkan persamaan
Bernoulli dapat diperoleh:
(4)
Fluida di bagian pipa manometer (1) tidak dapat mengalir karena tertahan oleh
ujung pipa manometer sehingga . Diketahui pula ketinggian tabung (1) dan
12
tabung (2) sama tinggi diukur dari bidang acuan karena tabung
ditempatkan mendatar sehingga persamaan Bernoulli akan menjadi:
(5)
Dengan menggunakan persamaan tekanan hidrostatis, bahwa tekanan di titik P
sama dengan tekanan di titik Q dapat diperoleh:
(6)
Dengan menggabungkan persamaan (5) dan persamaan (6) akan didapatkan:
√
(7)
Jadi, secara umum kecepatan aliran fluida di dalam tabung pitot adalah:
√
(8)
dengan keterangan:
massa jenis fluida di dalam tabung pitot
massa jenis raksa
perbedaan tinggi raksa di dalam manometer
kecepatan fluida di dalam tabung pitot
2.3. Sensor Tekanan MPX5100DP
Sensor adalah alat yang mengubah fenomena fisik menjadi sinyal listrik.
Sensor tekanan mengubah tekanan input menjadi keluaran listrik untuk mengukur
tekanan, gaya dan aliran udara. Sebagian besar sensor tekanan, tekanan dan aliran
udara dibuat dengan menggunakan teknik pemrosesan silikon yang biasa
13
dilakukan di industri semikonduktor. Sensor tekanan sebagian dikategorikan oleh
jenis tekanan yang mereka ukur. Sebagian besar sensor dibuat berbeda yang
dirancang untuk mengukur berbagai jenis tekanan, seperti gauge, differential,
absolute, atau vacuum gauge (Wilson, 2005).
Sensor tekanan MPX5100DP menggunakan bahan Silicon Stress Strain
Gauge, jenis piezoresistive tranduser berbahan silikon yang terintegrasi dalam
sebuah chip, bekerja pada tekanan 0kPa sampai 100kPa (0psi sampai 14,5psi) atau
15kPa sampai 115kPa (2,18psi sampai 16,68psi) dengan tegangan output 0,2volt
sampai 4,7volt.
Gambar 2. 3 Bagan Sensor Tekanan MPX5100DP
Sumber: Freescale Semiconductor. Inc, 2010
Seri MPX5100 dirancang untuk berbagai aplikasi terutama yang
menggunakan mikrokontroler atau mikroprosesor dengan input A/D. Ada
beberapa fitur yang dimiliki oleh sensor tekanan gas seri MPX5100, yaitu:
14
1. Kesalahan maksimum 2,5% di atas 0 hingga 85
2. Idealnya digunakan untuk mikroprosesor atau sistem berbasis
mikrokontroler
3. Dibuat menggunakan bahan Silicon Stress Strain Gauge
4. Tersedia dalam ukuran absolute, differensial dan gauge
5. Ideal untuk aplikasi otomotif dan non otomotif
Kedua sisi sensor tekanan adalah sisi Pressure (P1) dan sisi Vacuum (P2).
Sisi pressure (P1) adalah sisi yang mengandung gel silikon fluoro yang
melindungi bagian ‘die’ dari media yang keras. Sensor tekanan MPX dirancang
untuk beroperasi dengan tekanan diferensial positif, P1>P2
(http://cache.freescale.com/files/sensors/doc/data_sheet/MPX5100.pdf).
2.4. Arduino Uno
Arduino board ialah modul yang menggunakan mikrokontroler AVR dan
menggunakan seri yang lebih canggih, sehingga dapat digunakan untuk
membangun sistem elektronika berukuran minimalis namun handal dan cepat.
Arduino terdiri dari beberapa board, sehingga dapat digunakan sesuai kebutuhan
dan menggunakan software open source yang dapat dijalankan pada Windows,
Mac dan Linux. Mikrokontroler ini menggunakan Arduino programming
language berbasiskan wiring dan Arduino development environment berbasiskan
processing. Arduino menggunakan koneksi USB dengan chip FTDI untuk
melakukan pemrograman dan biasanya pada chip Arduino sudah dimasukkan
bootloader, sehingga dapat dilakukan pemrograman langsung ke dalam chip
menggunakan software Arduino (Budiharto, 2011).
15
Arduino dapat digunakan untuk mengembangkan objek interaktif mandiri
atau dapat dihubungkan ke perangkat lunak pada komputer (seperti Flash,
pemrosesan, VVVV atau Max/MSP). Ada banyak variasi arduino yang tersedia
diantaranya: Uno, Leonardo, duemilanove, mega 2560, mega ADK, fio, arduino
Ethernet, mini, nano, lilypad dan arduinos Bluetooth. Tetapi arduino yang paling
umum digunakan adalah Arduino Uno (Banzi, 2011) (www.arduino.cc).
Gambar 2. 4 Tampilan Arduino Uno
Sumber: www.arduino.cc
"Uno" berarti satu dalam bahasa Italia dan dipilih untuk menandai perilisan
Arduino Software (IDE) 1.0. Uno board dan versi 1.0 dari Arduino Software
(IDE) adalah versi referensi Arduino, sekarang berevolusi ke rilis yang lebih baru.
UNO adalah papan terbaik dan kuat untuk memulai dengan elektronik dan
pemrograman. UNO berisi semua yang dibutuhkan untuk mendukung
mikrokontroler; cukup menghubungkan ke komputer dengan kabel USB atau
nyalakan dengan adaptor AC-ke-DC atau baterai untuk memulai
(https://store.arduino.cc/usa/arduino-uno-rev3). Papan Arduino UNO adalah
papan pengembangan yang disarankan untuk belajar pemrograman Arduino. Ada
banyak perisai Arduino yang melekat serta sebagian tutorial dan buku
menggunakan Arduino UNO sebagai papan eksperimental, sehingga memudahkan
16
untuk bekerja dengan perangkat sensor dan aktuator (Kurniawan, 2017). Berikut
ini adalah spesifikasi dari board Arduino Uno:
Tabel 2. 1 Spesifikasi Board Arduino Uno
Mikrokontroler ATmega328P
Tegangan Operasi 5V
Tegangan Masukan (Disarankan) 7-12V
Tegangan Masukan (limit) 6-20V
Pin I/O Digital 14 (of which 6 provide PWM output)
Pin I/O Digital PWM 6
Pin Input Analog 6
Arus DC per pin I/O 20mA 20mA
Arus DC untuk pin 3.3V 50 mA
Flash Memory 32 KB (ATmega328P) of which 0.5KB
used by bootloader
SRAM 2 KB (ATmega328P)
EEPROM 1 KB (ATmega328P)
Clock Speed 16 MHz
LED_BUILTIN Pin 13
Sumber: www.arduino.cc
Arduino Uno memiliki polyfuse yang dapat dipulihkan yang melindungi
port USB komputer dari arus pendek atau berlebih. Meskipun kebanyakan
komputer menyediakan perlindungan internal mereka sendiri, sekering
menyediakan lapisan perlindungan ekstra. Jika lebih dari 500 mA diterapkan ke
port USB, sekering akan secara otomatis memutus koneksi sampai arus singkat
atau berlebih dilepaskan. Uno berbeda dari semua papan sebelumnya karena tidak
menggunakan chip driver USB-to-serial FTDI. Sebagai gantinya, fitur
Atmega16U2 (Atmega8U2 sampai versi R2) diprogram sebagai konverter USB-
to-serial. Alih-alih membutuhkan penekanan fisik tombol reset sebelum
17
mengunggah, papan Arduino/Genuino Uno dirancang sedemikian rupa sehingga
memungkinkannya diatur ulang oleh perangkat lunak yang berjalan pada
komputer yang terhubung.
Bagian-bagian dari arduino uno, yaitu:
a. Mikrokontroler ATmega328
ATmega328 di Arduino Uno diprogram ulang dengan bootloader yang
memungkinkan Anda mengunggah kode baru ke dalamnya. tanpa menggunakan
programmer perangkat keras eksternal, ini berkomunikasi dengan menggunakan
protokol STK500 yang asli. ATmega328 memiliki 32KB (dengan 0,5KB
ditempati oleh bootloader). Ini juga memiliki 2KB SRAM dan 1KB EEPROM
(yang dapat dibaca dan ditulis dengan EEPROM Library). ATmega328
menyediakan komunikasi serial UART TTL (5V), yang tersedia pada pin digital
0 (RX) dan 1 (TX).
b. 14 pin input/output digital (0-13)
Masing-masing dari 14 pin digital di Uno dapat digunakan sebagai input
atau output, dengan menggunakan fungsi pinMode(), digitalWrite() dan
digitalRead(). Mereka beroperasi pada 5V. Setiap pin dapat menyediakan atau
menerima 20mA sesuai kondisi operasi yang direkomendasikan dan memiliki
resistor pull-up internal (terputus secara default) 20-50kohm. Maksimal 40mA
adalah nilai yang tidak boleh dilampaui pada pin I/O manapun untuk
menghindari kerusakan permanen pada mikrokontroler. Selain itu, beberapa pin
memiliki fungsi khusus:
18
1) Serial: 0 (RX) dan 1 (TX). Digunakan untuk menerima (RX) dan
mengirimkan (TX) data serial TTL. Pin ini dihubungkan ke pin-pin
ATmega8U2 USB-to-TTL Serial yang sesuai.
2) Interupsi Eksternal: 2 dan 3. Pin ini dapat dikonfigurasi untuk memicu
interupsi pada nilai rendah, tepi naik atau turun, atau perubahan nilai. Lihat
fungsi attachInterrupt() untuk rinciannya.
3) PWM: 3, 5, 6, 9, 10 dan 11. Sediakan output PWM 8 bit dengan fungsi
analogWrite().
4) SPI: 10 (SS), 11 (MIA), 12 (MISO), 13 (SCK). Pin ini mendukung
komunikasi SPI dengan menggunakan perpustakaan SPI.
5) LED: 13. Ada LED built-in yang digerakkan oleh pin digital 13. Bila pin
bernilai HIGH, LED menyala, bila pinnya LOW, tidak menyala.
c. 6 Pin Input Analog
Uno memiliki 6 input analog, diberi label A0 sampai A5, masing-masing
memberikan resolusi 10bit (yaitu 1024 nilai yang berbeda). Secara default
mereka mengukur dari ground ke 5V, meskipun apakah mungkin untuk
mengubah ujung atas jangkauan mereka menggunakan pin AREF dan fungsi
analogReference(). Pin A4 atau SDA dan pin A5 atau SCL disebut dengan pin
TWI. mendukung komunikasi TWI menggunakan Wire Library.
d. Pin Power
Pin Power adalah sebagai berikut:
1) Vin. Tegangan masukan ke papan Arduino/Genuino saat menggunakan
sumber daya eksternal (berlawanan dengan 5V dari koneksi USB atau
19
sumber listrik yang diatur lainnya). Jika mensuplai voltase melalui colokan
listrik, akseslah melalui pin ini.
2) 5V. Pin ini mengeluarkan 5V yang diatur dari regulator pada papan. Papan
dapat disuplai dengan daya dari colokan listrik DC (7-12V), konektor USB
(5V) atau pin Vin papan (7-12V). Menyediakan tegangan melalui pin 5V
atau 3,3V bypasses regulator dan jika berlebihan dapat merusak board.
3) 3V3. Pasokan 3,3V yang dihasilkan oleh regulator on-board. Maksimum
arus adalah 50mA.
4) GND. Pin Ground
5) IOREF. Pin pada papan Arduino/Genuino Uno ini memberikan referensi
tegangan di mana mikrokontroler beroperasi. Perisai yang dikonfigurasi
dengan benar dapat membaca tegangan pin IOREF dan memilih sumber
daya yang sesuai.
6) AREF. Tegangan referensi untuk input analog. Digunakan dengan
analogReference().
e. USB Connection
Berfungsi untuk:
1) Memuat program dari komputer ke dalam papan
2) Komunikasi serial antara papan dan komputer
3) Memberi daya listrik kepada papan
f. Power Jack
Daya eksternal (non-USB) bisa datang baik dari adaptor AC-ke-DC atau
baterai. Adaptor dapat dihubungkan dengan memasang steker positif pusat
20
2,1mm ke power jack pada board. Jika menggunakan baterai, ujung dari baterai
dapat dimasukkan ke dalam pin GND dan Vin dari power jack catu daya
eksternal. Sumber daya dipilih secara otomatis.
Papan dapat beroperasi pada suplai eksternal dari 6 sampai 20volt. Jika
dipasok dengan kurang dari 7V, pin 5V mungkin memasok kurang dari 5V dan
board-nya menjadi tidak stabil. Jika menggunakan lebih dari 12V, regulator
tegangan mungkin terlalu panas dan merusak board. Kisaran yang disarankan
adalah 7 sampai 12V.
g. Q1-Kristal (Quartz Crystal Oscillator)
Jika mikrokontroler dianggap sebagai sebuah otak, maka kristal adalah
jantungnya karena komponen ini menghasilkan detak-detak yang dikirim kepada
mikrokontroler agar melakukan sebuah operasi untuk setiap detaknya. Kristal ini
dipilih yang berdetak 16 juta kali per detik (16MHz).
h. Tombol Reset
Untuk me-reset papan sehingga program akan mulai lagi dari awal.
Perhatikan bahwa tombol reset ini bukan untuk menghapus program atau
mengosongkan mikrokontroler.
i. In-Circuit Serial Programming (ICSP)
Port ICSP memungkinkan pengguna untuk memprogram mikrokontroler
secara langsung, tanpa melalui bootloader.
j. LED TX dan RX
LED RX dan TX di papan akan berkedip saat data dikirim melalui chip
USB-to-serial dan koneksi USB ke komputer (tapi tidak pada pin 0 dan 1).
21
2.5. IDE Arduino
IDE (Integrated Development Environment) adalah aplikasi bawaan dari
Arduino untuk memprogram board Arduino yang berfungsi untuk membuat,
membuka dan mengedit source code Arduino, source code yang ditulis untuk
Arduino, disebut ‘sketch‟. Sketch merupakan source code yang berisi logika dan
algoritma yang akan di-upload ke dalam IC mikrokontroler (Arduino). Arduino
membuat semua menjadi sederhana dengan menyembunyikan sebanyak
mungkin kerumitan pemrograman mikrokontroler, seperti saat menekan tombol
yang mengunggah sketsa ke papan tulis maka kode yang telah ditulis
diterjemahkan ke dalam bahasa C dan dikirimkan ke kompiler AVR-GCC.
Gambar 2. 5 Tampilan IDE Arduino Sumber: IDE Arduino 1.6.7
Verify
Upload New
Open Save Serial Monitor
Tempat Sketch
Line Number Port Keterangan Aplikasi Konsol
22
Bagian-bagian IDE Arduino terdiri dari (Banzi, 2011):
Tabel 2. 2 Bagian-bagian IDE Arduino
Nama Bagian Penjelasan
Verify
Pada versi sebelumnya dikenal dengan istilah Compile. Sebelum
aplikasi di-upload ke board Arduino, biasakan untuk
memverifikasi terlebih dahulu sketch yang dibuat. Jika ada
kesalahan pada sketch, nanti akan muncul error. Proses
Verify/Compile mengubah sketch ke binary code untuk di-upload
ke mikrokontroler.
Upload
Tombol ini berfungsi untuk meng-upload sketch ke board
Arduino. Walaupun kita tidak mengklik tombol verify, maka
sketch akan di-compile, kemudian langsung di-upload ke board.
Berbeda dengan tombol verify yang hanya berfungsi untuk
memverifikasi source code saja.
New Membuka window dan membuat sketch baru
Open Membuka sketch yang sudah pernah dibuat. Sketch yang dibuat
dengan IDE Arduino akan disimpan dengan ekstensi file .ino
Save Menyimpan sketch, tapi tidak disertai meng-compile
Serial Monitor Membuka interface untuk komunikasi serial
Tempat Sketch Bagian dimana program atau perintah diketikkan
Keterangan
Aplikasi
Pesan-pesan yang dilakukan aplikasi akan muncul di sini, misal
"Compiling" dan "Done Uploading" ketika kita meng-compile
dan meng-upload sketch ke board Arduino
Konsol
Pesan-pesan yang dikerjakan aplikasi dan pesan-pesan tentang
sketch akan muncul pada bagian ini. Misal, ketika aplikasi meng-
compile atau ketika ada kesalahan pada sketch yang kita buat,
maka informasi error dan baris akan diinformasikan di bagian
ini.
Line Number Bagian ini akan menunjukkan posisi baris kursor yang sedang
aktif pada sketch.
Port Bagian ini menginformasikan port yang dipakai oleh board
Arduino
Sumber: Banzi, 2011
2.6. LabVIEW
LabVIEW adalah sebuah software pemrograman yang diproduksi oleh
Nasional instruments dengan konsep yang berbeda. Seperti bahasa pemrograman
lainnya yaitu C++, Matlab atau Visual Basic, LabVIEW juga mempunyai fungsi
23
dan peranan yang sama, perbedaannya bahwa LabVIEW menggunakan bahasa
pemrograman berbasis grafis atau blok diagram sementara bahasa pemrograman
lainnya menggunakan basis teks. Program LabVIEW dikenal dengan sebutan VI
atau Virtual Instruments karena penampilan dan operasinya dapat meniru sebuah
instrument. Pada LabVIEW, user pertama-tama membuat user interface atau front
panel dengan menggunakan kontrol dan indikator, yang dimaksud dengan kontrol
adalah knobs, push buttons, dials dan peralatan input lainnya sedangkan yang
dimaksud dengan indikator adalah graph, LED dan peralatan display lainnya.
Setelah menyusun user interface, lalu user menyusun block diagram yang berisi
kode-kode VIs untuk mengontrol front panel (Sulistiawan, 2017).
Gambar 2. 6 Tampilan Jendela LabVIEW 2015
Sumber: Software LabVIEW 2015
Begitu aplikasi LabVIEW dibuka, secara pasti dua jendela kosong terbuka
secara bersamaan, yaitu front panel dan block diagram. VIs adalah jantung dan
jiwa dari LabVIEW. Kedua hal itulah yang membedakan LabVIEW dari semua
pengembangan berbasis teks lainnya. Dalam LabVIEW, semua adalah obyek yang
diwakili grafis (Ehsani, 2016).
24
Gambar 2. 7 Tampilan Saat Memulai LabVIEW 2015
Sumber: Software LabVIEW 2015
Software LabVIEW terdiri dari empat komponen utama, yaitu (Sulistiawan,
2017):
a. Front Panel
Front panel adalah bagian window yang berlatar belakang abu-abu serta
mengandung kontrol dan indikator. Front panel digunakan untuk membangun
sebuah VI, menjalankan program dan men-debug program.
Gambar 2. 8 Front Panel
Sumber: Software LabVIEW 2015
b. Blok Diagram dari VI
Blok diagram adalah bagian window yang berlatar belakang putih berisi
source code yang dibuat dan berfungsi sebagai instruksi untuk front panel.
25
Gambar 2. 9 Block Diagram Sumber: Software LabVIEW 2015
c. Control Pallete
Control pallete merupakan tempat beberapa kontrol dan indikator pada front
panel, control pallete hanya tersedia di front panel, untuk menampilkan control
pallete dapat dilakukan dengan mengklik windows>>show control pallete atau
klik kanan pada front panel.
Gambar 2. 10 Control Pallete
Sumber: Software LabVIEW 2015
d. Functions Pallete
Function pallete digunakan untuk membangun sebuah block diagram,
functions pallete hanya tersedia pada blok diagram, untuk menampilkannya
26
dapat dilakukan dengan mengklik windows>>show control pallete atau klik
kanan pada lembar kerja blok diagram.
Gambar 2. 11 Functions Pallete
Sumber: Software LabVIEW 2015
Sebuah VI dapat terdiri dari beberapa atau ratusan objek tertanam di banyak
subVIs. Representasi while loop yang sederhana, konsep matematika yang
kompleks seperti interpolasi polinomial atau hanya konstanta boolean, semuanya
ditunjukkan secara grafis. Untuk menggunakan objek, klik kanan di dalam
diagram blok atau jendela front panel, daftar palet muncul. Ikuti panah dan pilih
objek dari daftar objek dari palet berikutnya dan letakkan di jendela yang sesuai.
2.6.1. Menu Bar Icons
Menu dan submenu yang sebenarnya melakukan pekerjaan utama dan
user harus terbiasa dengan fungsionalitas banyak menu dan submenu dan panel
berikutnya. Berikut adalah item yang benar-benar diperlukan yang harus
diketahui pengguna untuk mulai bekerja di LabVIEW (Ehsani, 2016):
27
Tabel 2. 3 Item Menu Bar Icons
No. Tombol Penjelasan/Fungsi
1
Run
Untuk memulai eksekusi VI yang telah dibuat di block
diagram. Tombol ini berada pada kedua jendela, baik pada
front panel atau block diagram, dapat dijalankan dengan
menekan melalui salah satu jendela saja
2
Run (error)
Kesalahan link yang rusak mengubah bentuk tombol run.
Tombol run akan berubah bentuk menjadi bentuk ini jika:
Pemasangan kabel input dan/atau output pada block
diagram tidak benar
Ada kesalahan koneksi
Benda yang tidak dikehendaki ditempatkan di dua
jendela utama VI
3
Run
Continuously
Untuk menjalankan VI terus menerus. Tombol run
continously (aktif) akan mengeksekusi VI berkali-kali
meskipun logika VI sebenarnya tidak tersedia untuk berjalan
lebih dari satu kali.
4
Stop
Untuk menghentikan VI yang sedang berjalan
5 Pause
Untuk menghentikan sementara VI yang sedang berjalan
6 Highlight
Execution
Untuk melihat aliran data dari setiap objek dan nilai yang
dibawa oleh kawat atau output dari fungsi. Saat ini ditekan,
LabVIEW akan memperlambat eksekusi program,
kemungkinan beberapa titik pergerakan pada kabel yang
berbeda yang sedang dieksekusi dapat dilacak oleh mata dan
kecepatan manusia.
7 Text Setting
Untuk mengubah bentuk huruf, ukuran, perataan dan warna
pada teks
8 Retain wire
value
Untuk menyimpan nilai data di setiap titik ketika program
dijalankan
9
Step into
Untuk menjalankan program setiap step (langkah) dari node
ke node, sebuah loop atau subVI
10
Untuk melompati step pada sebuah loop atau subVI
28
No. Tombol Penjelasan/Fungsi
Step over
11 Step out
Untuk keluar dari suatu node atau loop dan masuk ke node
berikutnya
12 Align object
Untuk menata posisi beberapa objek supaya rata, termasuk
rata kanan, rata kiri, rata atas dan rata bawah
13 Distribute object
Untuk menata posisi antarobjek dengan jarak yang sama
14 Resize object
Untuk memperbesar atau memperkecil ukuran objek
15 Reorder
Untuk mengatur posisi objek pada lapisan tertentu, seperti di
depan atau di belakang objek lain. Sering digunakan dalam
penataan pada front panel.
16 Clean up
diagram
Untuk membantu mengatur ulang keseluruhan VI atau
segmen kode yang dipilih dengan pasti. Namun, terkadang
ada situasi dimana pembersihan dapat membuat block
diagram lebih cantik namun mungkin juga menyebabkan
block diagram menjadi lebih sulit dibaca.
17 Hide Context
Help Window
Untuk mengaktifkan tombol bantuan yang secara otomatis
membuka jendela dengan tentang objek itu, dokumen terkait
dan bahkan tautan ke contoh dan informasi penggunaan.
Sumber: Ehsani, 2016
2.6.2. NI-VISA
Virtual Instrument Software Architecture (VISA) adalah standar untuk
mengkonfigurasi, memprogram, dan memecahkan masalah sistem instrumentasi
yang terdiri dari interface GPIB, VXI, PXI, serial (RS232/RS485), Ethernet/LXI
dan/atau USB. VISA menyediakan interface pemrograman antara lingkungan
perangkat keras dan pengembangan seperti LabVIEW, LabWindows/CVI dan
Measurement Studio untuk Microsoft Visual Studio.
29
NI-VISA adalah penerapan Instrumen Nasional standar VISA I/O. NI-
VISA mencakup perpustakaan perangkat lunak, utilitas interaktif seperti NI I/O
Trace dan VISA Interactive Control, dan program konfigurasi melalui
Measurement & Automation Explorer untuk semua kebutuhan pengembangan.
NI-VISA adalah standar di lini produk National Instruments. Fitur baru termasuk
LXI autodiscovery dengan informasi perangkat LXI yang disempurnakan di NI
Measurement & Automation Explorer (MAX), pengaturan VISA Conflict
Manager di MAX, menambahkan dukungan untuk Mandriva Linux 2009,
mendukung openSUSE 11.0, dan arsitektur plug-in VISA multivendor untuk
versi 64 -bit edisi Windows Vista (https://www.ni.com/visa/).
2.6.3. LabVIEW Interface for Arduino (LIFA)
Interface LabVIEW untuk Arduino (LIFA) Toolkit adalah unduhan gratis
yang memungkinkan pengembang dalam mengakuisisi data dari mikrokontroler
Arduino dan memprosesnya di lingkungan LabVIEW Graphical Programming
(https://vipm.jki.net/package/national_instruments_lib_labview_interface_for_ar
duino).
LabVIEW Interface for Arduino menyediakan interface yang mudah
digunakan untuk platform mikrokontroler Arduino. Interface LabVIEW untuk
Arduino memungkinkan dengan cepat dan mudah membuat antarmuka
pengguna grafis untuk hampir semua komponen yang kompatibel dengan
mikrokontroler Arduino. Toolkit open source ini dibuat untuk kustomisasi yang
memungkinkan pengguna membuat driver khusus untuk sensor mereka
(https://forums.ni.com/t5/LabVIEW-Interface-for-Arduino/ct-p/7008).
30
Dalam penggunaannya hubungan antara LabVIEW dan Arduino
membutuhkan LIFA Base, LIFA Base adalah firmware/sketsa yang di-download
ke Arduino Uno agar dapat berinteraksi dengan menggunakan LabVIEW. Jika
tidak menggunakan LabVIEW, maka sketsa dapat ditulis sendiri
(https://forum.arduino.cc/index.php?topic=343184.0).
LabVIEW Interface for Arduino saat ini kompatibel dengan versi
Windows atau Mac yang mendukung LabVIEW 2009 atau yang lebih baru.
Toolkit ini juga akan bekerja pada versi Linux yang mendukung LabVIEW 2009
atau yang lebih baru namun saat ini tidak ada installer (JKI VI Package
Manager) untuk Linux (https://forums.ni.com/t5/LabVIEW-Interface-for-
Arduino/LabVIEW-Interface-for-Arduino-FAQ/ta-p/3521717).
31
BAB III
METODE PENELITIAN
3.1. Waktu dan Tempat Penelitian
Perancangan dan penulisan dilaksanakan mulai dari bulan Agustus 2017
sampai dengan bulan Juni 2018. Perancangan alat dilaksanakan di Pusat
Laboratorium Terpadu UIN Syarif Hidayatullah Jakarta yang terletak di Jalan Ir.
H. Juanda No. 95, Ciputat, Cempaka Putih, Ciputat Timur, Kota Tangerang
Selatan, 15412 dan untuk pengujian alat dilaksanakan di Laboratorium Fisiologi
Fakultas Kedokteran UIN Syarif Hidayatullah Jakarta yang terletak di Jalan
Kertamukti No.5, Pisangan, Ciputat Timur, Kota Tangerang Selatan, 15412.
3.2. Alat dan Bahan Penelitian
Dalam perancangan alat ukur kapasitas vital paksa paru digunakan beberapa
alat dan bahan untuk merancang bangun hardware dan software. Berikut ini
adalah alat dan bahan yang digunakan:
1. Perangkat Keras (Hardware)
Laptop/Komputer/PC, Sensor Tekanan MPX5100DP, Arduino Uno R3,
USB Cable Serial A/B, Project Board dan kabel male-female, clip nose,
multimeter, power supply, pipa PVC, sambungan pipa PVC, sedotan plastik,
PVC Board, dan triplek.
32
2. Perangkat Lunak (Software)
Arduino IDE 1.6.7, LabVIEW 2015, NI-VISA dan LabVIEW Interface for
Arduino (LIFA).
3.3. Tahap dan Alur Penelitian
Gambar 3. 1 Tahap dan Alur Penelitian
Sumber: Data Olahan Sendiri, 2018
1. Tahap Persiapan
Pada tahap ini, proses yang dilakukan adalah pencarian informasi dengan
studi pustaka dari beberapa buku, jurnal ilmiah dan tugas akhir yang memiliki
Tahap Persiapan
Perancangan Mouthpiece
Karakterisasi Sensor MPX5100DP
Perancangan Hardware
Perancangan Software
Uji Alat
Analisis Data
Data
Data
Alat Rancang
Peneliti
Peneliti
Spirometer Laboratorium
Fisiologi
Kesimpulan
33
kata kunci maupun yang berhubungan dengan alat ukur kapasitas vital paksa
paru.
2. Perancangan Mouthpiece
Setelah melakukan tahap-tahap persiapan, kemudian peneliti membuat
racangan skema mouthpiece untuk alat ukur yang peneliti rancang. Mouthpiece
ini nantinya akan digunakan sebagai media untuk menghembuskan napas dari
mulut responden agar udara yang dihembuskan dapat ditangkap sensor.
3. Karakterisasi Sensor MPX5100DP
Karakterisasi sensor merupakan suatu kegiatan untuk menganalisis karakter
sensor. Pada tahap karakterisasi sensor ini peneliti tidak menguji linieritas
sensor, melainkan peneliti menguji tekanan awal sensor yang akan digunakan
sebelum sensor mendapatkan tekanan.
4. Perancangan Perangkat Keras (Hardware)
Pada tahap perancangan hardware ini, peneliti merancang dengan
menggabungkan beberapa perangkat keras yang diantaranya sensor tekanan
MPX5100DP, Arduino dan laptop/PC agar dapat menangkap, mengolah dan
menampilkan tekanan yang diberikan saat responden menghembuskan udara.
5. Perancangan Perangkat Lunak (Software)
Pada perancangan software, peneliti membuat sebuah program agar
rangkaian perangkat keras dapat bekerja dan menghasilkan nilai sebagaimana
yang diinginkan. Pada proses perancangan software ini terdapat beberapa proses,
yaitu: proses konversi dari tegangan yang terbaca oleh perangkat keras
dikonversi menjadi tekanan lalu di konversi lagi menjadi volume dengan melalui
34
beberapa proses, proses penyimpanan sementara hasil pengukuran, proses
pembandingan hasil pengukuran dengan literatur yang digunakan agar dapat
menampilkan indikator hasil di layar lapop/PC.
6. Pengujian Alat
Pengujian yang bertujuan untuk mengetahui kesesuaian perangkat yang
dirancang bangun menggunakan sensor tekanan MPX5100DP dengan
spirometer yang dapat mengukur kapasitas vital paksa paru yang telah
berstandar dan digunakan di pasaran.
7. Kesimpulan
Pada tahapan akhir ini, peneliti melakukan penarikan kesimpulan setelah
mendapatkan hasil perbandingan antara alat ukur kapasitas vital paksa paru yang
dibuat peneliti dengan alat uji (spirometer) di Laboratorium Fisiologi Fakultas
Kedokteran UIN Syarif Hidayatullah Jakarta.
3.4. Tahap Perancangan Alat
Terdapat dua bagian perancangan yang dibuat untuk menjadikan sebuat alat
ukur kapasitas vital paksa paru, yaitu:
3.4.1. Perancangan Perangkat Keras (Hardware)
Pada alat ukur kapasitas vital paksa paru akan dirancang agar dapat
diprogram melalui PC menggunakan koneksi kabel serial dan dilengkapi sensor
tekanan MPX5100DP serta sebuah mouthpiece sebagai media untuk
menghembuskan napas. Desain perancangan perangkat keras (hardware) pada
penelitian ini dapat dilihat pada Gambar 3.2.
35
Gambar 3. 2 Desain Perancangan Perangkat Keras (Hardware)
Sumber: Data Olahan Sendiri, 2018
Berikut penjelasan dari masing-masing perangkat keras (hardware) yang
digunakan:
a. Mouthpiece
Mouthpiece yang dirancang berbentuk seperti tabung pitot, yaitu berupa
sebuah pipa yang memiliki dua lubang yang nantinya terhubung pada sensor
tekanan. Mouthpiece merupakan media yang terhubung oleh responden melalui
mulut agar dapat hembusan napas dapat diterima oleh sensor tekanan.
Gambar 3. 3 Desain Mouthpiece
Sumber: Data Olahan Sendiri, 2018
b. Sensor Tekanan MPX5100DP
MPX5100DP adalah strain gauge jenis piezoresistive tranduser berbahan
silikon yang terintegrasi dalam sebuah chip, bekerja pada tekanan 0kPa sampai
100kPa (0psi sampai 14,5psi) atau 15kPa sampai 115kPa (2,18psi sampai
16,68psi) dengan tegangan output 0,2V sampai 4,7V. Ada beberapa fitur yang
dimiliki oleh sensor tekanan gas seri MPX5100, yaitu:
1) Kesalahan maksimum 2,5% di atas 0 hingga 85
Mouthpiece Sensor MPX5100DP Arduino Uno Laptop/PC
36
2) Idealnya digunakan untuk mikroprosesor atau sistem berbasis
mikrokontroler
3) Dibuat menggunakan bahan Silicon Stress Strain Gauge
4) Tersedia dalam ukuran absolute, differensial dan gauge
5) Ideal untuk aplikasi otomotif dan non otomotif
c. Arduino Uno
Arduino/Genuino Uno adalah papan mikrokontroler berdasarkan
ATmega328P yang beroperasi pada tegangan 5V, memiliki 14 pin input/output
digital (6 diantaranya dapat digunakan untuk output PWM), 6 input analog, 16
MHz crystal oscillator, USB connection, power jack, ICSP header dan reset
button.
d. Laptop/ PC
Spesifikasi laptop/PC yang digunakan untuk menjalankan software dan
menampilkan hasil pengukuran alat yaitu sebagai berikut:
Operating System: Windows 7 Professional Service Pack 1
System Type: 32-bit or 64-bit operating system
Processor: Intel(R) Pentium(R) Dual CPU E2160 @1,80GHz
Installed Memory (RAM) : 3,00 GB
3.4.2. Perancangan Perangkat Lunak (Software)
Perancangan software untuk alat ukur kapasitas vital paksa paru
menggunakan beberapa program, diantaranya NI LabVIEW 2015, IDE arduino
1.6.7, NI-VISA Driver dan LabVIEW Interface for Arduino (LIFA).
Perancangan software untuk alat ukur ini terbagi menjadi dua, yaitu
37
pemrograman pada arduino sebagai pembaca sensor dan pemrograman pada PC
sebagai penampil input data dan hasil pengukuran.
a. Pemrograman Arduino
Arduino berperan sebagai perangkat yang menerima hasil keluaran sensor
tekanan , agar arduino dapat bekerja maka didalamnya harus diisikan program
yang berupa source code, menggunakan IDE Arduino di-input program
LIFA_Base.ino yang didapatkan dari LabVIEW Interface for Arduino (LIFA).
b. Pemrograman PC
Pada pemrograman untuk PC, program yang digunakan yaitu NI LabVIEW
2015. LabVIEW merupakan program utama yang digunakan dalam
pemrograman untuk alat ukur kapasitas vita paksa paru. Berikut beberapa tugas
yang dilakukan oleh LabVIEW, yaitu membaca data dari arduino, menyimpan
sementara data dari arduino, mengkonversi data supaya menjadi nilai yang
diinginkan, mendesain tampilan front panel menjadi sebuah interface pada PC
yang memudahkan pengguna meng-input data ataupun mengoperasikan dan
menampilkan hasil pengukuran berupa indikator dan grafik
Pemrograman dengan LabVIEW terbagi menjadi dua, yaitu pada bagian
block diagram berisi rancangan program untuk mengolah data sampai dapat
menampilkan hasil, dan pada bagian front panel menampilkan hasil rancangan
program pada block diagram sebagai interface untuk pengguna. Untuk dapat
menggunakan arduino, LabVIEW membutuhkan NI-VISA Driver dan
LabVIEW Interface for Arduino (LIFA). NI-VISA Driver, berfungsi agar
arduino yang dihubungkan ke laptop/PC menggunakan kabel USB serial dapat
38
terdeteksi oleh LabVIEW yang terdapat di laptop/PC, sedangkan LabVIEW
Interface for Arduino (LIFA) berfungsi agar ikon grafik arduino dapat tampil
di LabVIEW sehingga memungkinkan dengan cepat dan mudah membuat
antarmuka pengguna grafis untuk hampir semua komponen yang kompatibel
dengan mikrokontroler Arduino. Selain itu, di dalam LIFA juga terdapat
LIFA_Base.ino, yaitu source code untuk di-upload ke arduino agar arduino
dapat terhubung dengan LAbVIEW.
Pada perancangan program terdapat proses konversi dari nilai tegangan
sampai menjadi nilai volume. Untuk konversi dari tekanan menjadi volume
harus melalui beberapa proses konversi seperti pada Gambar 3.5.
Gambar 3. 4 Proses Konversi Nilai Tegangan Menjadi Volume
Sumber: Data Olahan Sendiri, 2018
Untuk penentuan prediksi nilai FVC digunakan rumus nilai prediksi faal
paru normal orang Indonesia dari Pneumobile Project Indonesia (Alsagaff dan
Mangunegoro, 1993)
Perempuan :
Laki-laki :
dengan:
umur
tinggi badan (cm)
𝑣 √ ∆𝑃
𝜌
Kecepatan
Aliran
𝑄 𝐴𝑣
Debit
𝑉 𝑄 𝑑𝑡
Volume
𝑃 𝑇𝑒𝑔𝑎𝑛𝑔𝑎𝑛
𝑚𝑉 𝑘𝑃𝑎
Tekanan
𝑇𝑒𝑔𝑎𝑛𝑔𝑎𝑛
39
Berikut flowchart sistem kerja perangkat lunak yang akan dirancang:
Gambar 3. 5 Flowchart Sistem Kerja Perangkat Lunak
Sumber: Data Olahan Sendiri, 2018
40
3.5. Metode Pengambilan Data
Pengambilan data alat ukur kapasitas vital paksa paru dilakukan pada
responden laki-laki dan perempuan dengan jenjang usia 16-22 tahun. Data yang
diambil dalam pengukuran ini yaitu kapasitas vital paksa (FVC) yang
diekspirasikan secara kuat dan cepat setelah mengambil napas secara maksimal.
Untuk setiap responden pengambilan dilakukan bergantian antara alat ukur
kapasitas vital paksa paru dan spirometer BTL-08 Spiro dengan istirahat minimal
30 detik untuk setiap pengulangan, akan lebih baik apabila istirahat yang
diberikan lebih dari 30 detik.
3.6. Spesifikasi Spirometer BTL-08 Spiro
Alat uji coba yang digunakan sebagai pembanding dengan alat ukur
kapasitas vital paksa paru adalah spirometer BTL-08 Spiro yang terdapat di
Laboratorium Fisiologi Fakultas Kedokteran UIN Syarif Hidayatullah Jakarta.
BTL-08 Spiro diproduksi sesuai dengan arahan EU Medical Devices oleh
BTL Industries Ltd. yang berlokasi di jalan Cleveland 161 Stevenage,
Hertfordshire, SG1 6BU, United Kingdom. BTL-08 Spiro dikembangkan sesuai
dengan pengetahuan dan rekomendasi terbaru serta memenuhi referensi ATS/ERS
2005 dan Standar Eropa untuk spirometer EN 13826.
BTL-08 Spiro adalah perangkat modern untuk pemeriksaan spirometri dasar
dan tambahan tertentu (misalnya pasca medis). Alat ini memberikan analisis rinci,
interpretasi otomatis dan cetak kurva spirometri. Semua proses ditampilkan secara
transparan pada alat ini sehingga dapat dengan mudah dan cepat dikembangkan
oleh siapa saja. Perangkat ini memungkinkan pengguna untuk hanya
41
menyesuaikan nilai standar (nilai prediktif), secara metodis memilih hingga 15
parameter untuk pengukuran yang sebenarnya.
Perangkat BTL-08 Spiro dilengkapi dengan layar grafis beresolusi tinggi
dan memungkinkan melihat grafik volume-aliran dan grafik volume-waktu secara
real time. Tampilan layar besar berwarna unggul dalam gambar berkualitas dan
dilengkapi dengan tombol layar sentuh. Sensor untuk mengukur suhu ruangan,
tekanan barometrik dan kelembapan relatif, sehingga dapat melakukan koreksi
otomatis parameter ke kondisi BTPS. Terintegrasi dengan printer selebar 112 mm
printer yang dapat mencetak dalam format A5, dengan demikian semua hasil
grafik dapat dicetak bersama dengan nilai yang terukur. Menerapkan perekaman
pasien dan sebuah file pengukuran tertentu, memungkinkan untuk mendaftar dan
menyimpan hingga 250 catatan pengukuran dalam memori dan cukup
mencetaknya dengan printer internal (termal) atau dapat menggunakan printer
eksternal yang terhubung melalui USB. Dilengkapi dengan baterai penyimpanan
membuat perangkat ini sepenuhnya portabel, pengukuran dapat dimulai segera
setelah perangkat dinyalakan, namun perlu untuk mengatur data pribadi pasien
sebelum akhirnya memilih dari catatan pasien.
Gambar 3. 6 Spirometer BTL-08 Spiro
Sumber: BTL Industtries Ltd, 2007
42
BAB IV
HASIL DAN PEMBAHASAN
Alat ukur kapasitas vital paksa paru bertujuan untuk mengukur kapasitas
vital paksa paru-paru seseorang atau biasa disebut nilai FVC. Setelah mengukur
kapasitas vital paksa (FVC), alat ini dapat memberikan informasi atau diagnosa
terkait paru-paru seseorang, apakah paru-paru seseorang bekerja secara normal
atau terdapat masalah pada paru-paru orang tersebut (tidak normal).
Peneliti melakukan dua tahap perancangan yaitu, perancangan hardware
dan software. Berikut hasil rancang bangun dari kedua perancangan tersebut:
4.1. Hasil Perancangan Hardware
Perancangan hardware pada penelitian ini meliputi perancangan mouthpiece
dan perancangan alat ukur kapasitas vital paksa paru.
4.1.1. Perancangan Mouthpiece
Mouthpiece merupakan salah satu bagian dari alat ukur kapasitas vital
paksa paru yang berfungsi sebagai media bagi responden untuk menghembuskan
udara pernapasan melalui mulut agar dapat diterima oleh sensor. Mouthpiece
rancangan peneliti menerapkan hukum tabung pitot, mouthpiece ini terdiri dari 2
bagian yang dapat dilepas dan disambungkan kembali. Pada bagian belakang
mouthpiece terdapat 2 lubang, satu lubang terdapat sebuah sedotan berbentuk L
mengarah ke dalam dan satu lagi sedotan hanya dimasukan ke dalam lubang
hingga rata dengan pipa. Bagian ujung kedua sedotan yang berada di luar lubang
terhubung dengan sensor.
43
Gambar 4. 1 Hasil Perancangan Mouthpiece
Sumber: Data Olahan Sendiri, 2018
Tampilan bagian dalam dari kedua bagian mouthpiece (bagian depan dan
belakang) ditampilkan pada Gambar 4.2.
Gambar 4. 2 Tampilan Bagian Dalam Mouthpiece
Sumber: Data Olahan Sendiri, 2018
Berikut spesifikasi mouthpiece rancangan peneliti:
Tabel 4. 1. Spesifikasi Mouthpiece Alat Rancang
Material : Pipa PVC
Diameter : ( )
Total Panjang : (terdiri dari 2 bagian)
Panjang Bagian Depan : (terhubung ke mulut)
Panjang Bagian Belakang : (terhubung ke sensor melalui lubang)
Diameter lubang : (2 lubang)
Sumber: Data Olahan Sendiri, 2018
4.1.2. Perancangan Alat Ukur Kapasitas Vital Paksa Paru
Alat ukur kapasitas vital paksa paru dirancang bangun dari beberapa
komponen, diantaranya arduino, sensor tekanan gas MPX5100DP, project board
dan beberapa kabel male-female. Perangkat tersebut dirangkai dan diletakkan di
dalam sebuah kotak yang tertutup sebagaimana terlihat pada Gambar 4.3.
Bagian Depan Bagian Belakang
Lubang Penghubung ke Sensor
Bagian belakang Bagian depan
44
Gambar 4. 3 Bagian-bagian Alat Ukur Kapasitas Vital Paksa Paru
Sumber: Data Olahan Sendiri, 2018
Keterangan :
1 = Mouthpiece
2 = Kotak Alat Ukur
3 = Cover Kotak Alat Ukur
4 = Sensor Tekanan MPX5100DP
5 = Kabel Male-Female
6 = Project Board
7 = Arduino Uno R3
8 = Port USB
Gambar 4. 4 Tampilan Atas dan Samping Alat Ukur Kapasitas Vital Paksa Paru
Sumber: Data Olahan Sendiri, 2018
Pada Gambar 4.4 dapat terlihat, kotak alat ukur kapasitas vital paksa paru
dapat dibuka di bagian atas pada cover, hal ini dirancang agar dapat
7
3
2
4
6
8
1
5
Dilihat dari atas Dilihat dari samping
45
memudahkan dalam melakukan pengecekan atau penggantian salah satu bagian
apabila terdapat masalah. Pada bagian samping terdapat port USB yang
berfungsi untuk memberikan tegangan dari PC dan mengkomunikasikannya
dengan PC. Berikut spesifikasi alat ukur kapasitas vital paksa paru:
Tabel 4. 2 Spesifikasi Alat Ukur Kapasitas Vital Paksa Paru
Dimensi (cm)
(belum termasuk mouthpiece)
Berat Alat Ukur (kg)
Material Kotak
Triplek dan PVC Board
Mouthpiece
Display
Layar monitor pada PC
Input Device
Keyboard dan Mouse pada PC
Memori Data
Catatan Tersimpan
Sebanyak memori pada PC
Parameter Pengukuran
Forced Profile : FVC
Nilai Prediksi : Tim Pneumobile Project Indonesia
Operating Characteristics
Jangkauan Sensor Tekanan :
Tegangan Masukan : from PC (use USB Cable type A-B)
Waktu Respon (ms) :
Ketelitian (Accuracy) :
Ketepatan (Precision) :
PC Connection
USB Cable type A-B
Sumber: Data Olahan Sendiri, 2018
46
Alat ini memiliki cara kerja dengan menerima laju aliran udara hasil
ekspirasi manusia yang dihembuskan melalui mouthpiece yang selanjutnya akan
dilakukan pembacaan nilai tekanan oleh sensor tekanan MPX5100DP lalu
diteruskan pembacaan melalui Arduino yang didalamnya terdapat
mikrokontroler ATmega32 yang memiliki ADC (Analog to Digital Converter)
internal.
4.2. Hasil Perancangan Software
Perancangan software alat ukur kapasitas vital paksa paru menggunakan
program utama LabVIEW 2015 yang dibantu oleh beberapa program pendukung
seperti IDE Arduino yang berfungsi untuk memprogram arduino agar dapat
terhubung dengan LabVIEW 2015, NI-VISA yang berfungsi agar port arduino
dapat terbaca di LabVIEW 2015 dan LIFA yang berfungsi untuk memudahkan
pengguna dalam melakukan pemrograman dengan ikon grafis arduino. Pada hasil
perancancangan software dengan LabVIEW 2015 akan menghasilkan dua
tampilan yaitu block diagram dan front panel.
4.2.1. Block Diagram
Block diagram menampilkan rangkaian alur pemrograman dalam bentuk
ikon/grafis yang telah dibuat untuk menjalankan dan mengontrol hardware.
Selain itu pada block diagram juga diprogram bagaimana pembacaan data dan
proses konversi seperti mengkonversi dari nilai analog menjadi digital, konversi
nilai tegangan menjadi tekanan, tekanan menjadi laju aliran, laju aliran menjadi
debit dan debit menjadi nilai volume. Tampilan block diagram dapat dilihat pada
Gambar 4.5.
47
Gambar 4. 5 Block Diagram Software Alat Ukur Kapasitas Vital Paksa Paru
Sumber: Output LabVIEW 2015, 2018
4.2.2. Front Panel (User Interface)
Front panel merupakan bagian yang berisi tampilan dari blok diagram
yang dijadikan sebagai user interface sebagaimana dapat dilihat pada Gambar
4.6, pada bagian ini pengguna dapat mengatur, meng-input, melihat hasil
pengukuran baik dalam bentuk angka maupun grafik.
48
Gambar 4. 6 Front Panel Program Alat Ukur Kapasitas Vital Paksa Paru
Sumber: Output LabVIEW 2015, 2018
Berikut ini bagian-bagian pada front panel beserta penjelasannya:
Tabel 4. 3. Spesifikasi Mouthpiece Alat Rancang
No. Bagian Penjelasan
Konfigurasi Port (Port Configuration)
1 Sumber VISA
(VISA Resource) Menentukan port USB yang digunakan
2 Pin Masukan
(Input Pin) Menentukan pin ADC arduino yang digunakan
3 On/Off Lampu indikator yang menandakan alat menyala dan siap
mengukur
4 Calibration Lampu indikator yang apabila menyala, menandakan bahwa
alat butuh kalibrasi
Data Diri (Personal Data)
5 Jenis Kelamin (Gender) Harus diisi dengan jenis kelamin responden yang diuji
6 Umur (Age) Harus diisi dengan umur responden yang diuji
7 Tinggi Badan (Height) Harus diisi dengan tinggi badan responden yang diuji
8 Merekam (Record)
Tombol untuk memulai dan menghentikan perekaman data.
Sesaat setelah tombol ini ditekan, akan keluar tampilan menu
yang meminta pengguna menentukan lokasi dimana data
sementara akan disimpan dan dengan menggunakan nama apa
data tersebut disimpan.
9 Tanggal dan Waktu Menampilkan hari, tanggal, bulan, tahun dan waktu sesuai
dengan yang tertera pada PC pada saat pengukuran berlangsung
Analisis (Analysis)
49
No. Bagian Penjelasan
8 Direktori Penyimpanan
(Storage Directory)
Menampilkan lokasi penyimpanan serta nama yang diberikan
oleh pengguna saat perekaman
9 Mulai Analisis
(Start Analysis)
Tombol untuk memulai proses analisis data , sesaat setelah
pengguna menekan tombol tersebut, akan keluar jendela menu
yang meminta pengguna memilih data pengukuran yang akan
dianalisis mulai dari nama dan lokasi penyimpanannya.
10 Reset (Reset) Tombol untuk mengembalikan seluruh pengaturan ke awal
11 Tabel Hasil Menampilkan hasil pengukuran dari mulai tegangan awal,
tegangan ADC, tekanan, laju aliran dan debit.
Hasil (Result)
12 Waktu (Time) Menampilkan lama waktu pengukuran
13 FVC Normal
(Normal FVC) Menampilkan nilai FVC normal dari responden yang diuji
14 Hasil Pengukuran
(Measurement Result)
Menampilkan hasil pengukuran FVC hembusan napas
responden yang diuji
15 Persentase Hasil
(Persentase of Result)
Menampilkan persentase hasil perbandingan antara FVC
pengukuran dengan FVC normal responden yang diuji
16 Indikator Hasil
(Indicator of Result)
Menampilkan hasil pengukuran berupa indikasi normal atau
tidak normal
17
Grafik Hasil Pengukuran
(Graphic of
Measurement Result)
Menampilkan grafik laju aliran udara pernapasan yang
dihembuskan per satuan waktu.
Sumber: Data Olahan Sendiri, 2018
Langkah-langkah yang harus dilakukan dalam proses pengambilan data
pada alat ukur kapasitas vital paksa paru dapat dilihat pada Gambar 4.7 berikut:
Gambar 4. 7 Diagram Alir Pengambilan Data
Sumber: Data Olahan Sendiri, 2018
Mulai
Hubungkan alat ukur
dengan PC (kabel
USB tipe A-B)
Pasang mouthpiece
(pastikan bersih
dan kering)
Mengatur
konfigurasi port
(port USB dan pin
masukan)
Memasukkan data diri
responden yang diuji (jenis
kelamin, umur, usia)
Tekan tombol
run pada
LabVIEW
Berikan nama
dan atur lokasi
penyimpanan file
OK
Tekan tombol selesai untuk
mengakhiri pengukuran
OK
Tekan
tombol mulai
analisis
Pilih nama dan
lokasi file yang
akan dianalisis
Hasil pengukuran dan analisis tampil
pada kolom tabel dan bagian hasil Klik dua kali pada tombol reset untuk
mengosongkan kembali seluruh bagian Selesai
Responden siap
untuk ekspirasi
paksa (aba-aba)
Pada akhir ekspirasi, responden
harus tetap bertahan bernapas
selama 6 detik
Tekan tombol
merekam
(record)
50
4.3. Hasil Pengujian Karakteristik Alat Ukur Kapasitas Vital Paksa Paru
Pada pengujian ini terdapat tiga hal yang diujikan yaitu, pengujian linearitas
arduino (ADC), pengujian sensor tekanan MPX5100DP, pengujian kalibrasi
prediksi nilai FVC dari masing-masing responden dan nilai FVC yang dihasilkan
responden pada saat pengukuran.
4.3.1. Hasil Pengujian Linearitas Arduino (ADC)
Pada saat perancangan alat ini dilakukan pengujian terhadap masing-
masing komponen yang digunakan agar hasil rancangan yang dihasilkan dapat
sesuai dengan perencanaan dan hasil rancangan memiliki nilai ketepatan yang
baik. Pengujian Arduino ini dilakukan untuk mengetahui tingkat kesalahan
output Arduino saat diberikan input tegangan yang bervariasi dari power supply.
Pada pengujian Arduino, Arduino diaktifkan menggunakan tegangan yang
berasal dari PC dan dihubungkan melalui kabel USB Serial Type A-B. Hasil
yang dihasilkan oleh ADC harus dikonversi terlebih dahulu agar keluarannya
berupa satuan tegangan. Konversi sinyal analog ke digital melalui proses
perhitungan berikut:
dimana:
= tegangan keluaran dari pin ADC
= tegangan referensi (nilainya )
= besarnya bit ADC (dalam penelitian bit)
51
Kesalahan hasil keluaran Arduino dapat terbagi menjadi kesalahan
absolut dan persentase kesalahan relatif dengan rumus perhitungan:
| |
Berikut hasil pengujian pin ADC arduino saat diberikan input yang
bervariasi dari power supply:
Tabel 4. 4 Hasil Pengujian Pin ADC Arduino
No. Tegangan Kesalahan
Masukan Arduino Absolut Relatif
1
2
3
4
5
6
7
8
9
10
11
12
13
14 Sumber: Data Olahan Sendiri, 2018
Berdasarkan Tabel 4.4, dapat diketahui bahwa semakin besar nilai input
yang terbaca oleh arduino maka nilai kesalahan yang dihasilkan oleh output
arduino pun semakin besar. Hal ini terjadi dikarenakan menurut hukum ohm,
tegangan berbanding lurus dengan arus, dan arus merupakan muatan elektron
yang mengalir per satuan waktu. Sehingga semakin besar tegangan yang
diberikan maka semakin besar arus yang mengalir maka semakin banyak muatan
elektron yang dialirkan, karena bertambah banyaknya elektron yang dialirkan
52
maka akan ada elektron yang terhambat atau tidak tersampaikan sehingga selisih
antara input dan output pin ADC pada arduino pun semakin besar saat tegangan
input yang diberikan semakin besar.
Berdasarkan tabel tersebut juga dapat diketahui bahwa arduino mulai
memiliki selisih output saat mendapatkan tegangan input sebesar dan
diketahui arduino memiliki kesalahan yang terbesar yaitu ketika diberikan
tegangan maksimum 5V. Input pin ADC Arduino Uno R3 dapat dikatakan linear
dengan output-nya seperti yang dapat dilihat pada Gambar 4.8.
Gambar 4. 8 Grafik Linieritas ADC Arduino
Sumber: Output Microsoft Excel 2010, 2018
4.3.2. Hasil Pengujian Sensor Tekanan MPX5100DP
Pengujian sensor tekanan MPX5100DP dilakukan dengan tujuan untuk
mengetahui nilai awal yang dimiliki sensor MPX5100DP pada saat sebelum
mendapatkan tekanan. Sensor MPX5100DP memiliki karakteristik sensitivitas
sebesar . Pengujian ini dilakukan saat sensor diaktifkan dengan
y = 1.06x - 0.0132
R² = 1
-1
0
1
2
3
4
5
6
0 1 2 3 4 5
Input
(Vo
lt)
Output (Volt)
Grafik Linearitas ADC Arduino
53
tegangan yang berasal dari arduino lalu diukur hasil output-nya dengan
multimeter. Berikut data pengujian sensor tekanan MPX5100DP tanpa tekanan:
Tabel 4. 5 Hasil Pengujian Sensor Tekanan MPX5100DP
Waktu
Tekanan Awal [Pa]
Uji 1 Uji 2 Uji 3
Waktu
Tekanan Awal [Pa]
Uji 1 Uji 2 Uji 3
Min 27.31055 27.31055 26.74696
Max 28.43772 28.43772 28.43772
Average 27.80838 27.74263 27.59234
Sumber: Output LabVIEW 2015, 2018
Tabel 4.5 merupakan hasil dari pengujian sensor tekanan MPX5100DP
saat tidak menerima tekanan yang dilakukan selama 6 detik dengan 3 kali
pengulangan pengujian, berdasarkan tabel tersebut dapat diketahui bahwa nilai
54
awal sensor saat belum mendapatkan tekanan adalah minimum sebesar
dan nilai maksimum . Nilai hasil pengujian sensor
diperoleh setelah dikonversi dari ADC dan dibagi dengan nilai sensitivitas
sensor. Nilai awal inilah yang akan digunakan sebagai faktor koreksi agar
perhitungan hasil pengukuran dimulai dari nilai nol.
4.3.3. Hasil Pengujian Kalibrasi Prediksi FVC Normal Alat BTL-08 Spiro
dengan Alat Ukur Kapasitas Vital Paksa Paru
Setelah melakukan pengujian pada masing-masing komponen,
selanjutnya dilakukan pengujian alat ukur kapasitas vital paru secara
keseluruhan. Pengujian ini dilakukan untuk memastikan apakah hasilnya telah
sesuai dengan kebenaran pada alat asli atau belum, pada penelitian ini digunakan
spirometer BTL-08 Spiro dengan cara membandingkan.
Untuk menentukan prediksi nilai FVC normal pada alat ukur Kapasitas
Vital Paksa Paru digunakan rumus nilai prediksi faal paru normal orang
Indonesia dari Pneumobile Project Indonesia. Pada penentuan prediksi nilai
FVC ini ada beberapa parameter penting yang dijadikan acuan pada penelitian
ini yaitu, jenis kelamin, usia dan tinggi badan. Berikut ini merupakan data
perbandingan hasil pengujian nilai prediksi FVC normal pada spirometer BTL-
08 Spiro dengan alat ukur kapasitas vital paksa paru:
Tabel 4. 6 Hasil Pengujian Nilai Prediksi FVC Normal
Responden
Ke-
Umur
(Tahun)
Tinggi
(cm)
Jenis
Kelamin
Prediksi FVC Selisih
Persentase
Selisih BTL-08 Spiro Alat Ukur KVP
1 16 160 Perempuan
2 21 175 Laki-laki
3 22 155 Perempuan
Sumber: Output BTL-08 Spirodan LabVIEW 2015, 2018
55
Berdasarkan hasil pengujian pada Tabel 4.6 dapat diketahui bahwa
adanya perbedaan yang besar antara anak-anak, dewasa laki-laki dan dewasa
perempuan dengan besar selisih untuk anak-anak berumur tahun sebesar
, dewasa laki-laki tahun sebesar dan untuk dewasa
perempuan. Perbedaan yang terjadi berdasarkan jenis kelamin sesuai dengan
penelitian yang dilakukan oleh Oviera, dkk (2016) bahwa ada hubungan antara
jenis kelamin dengan kapasitas vital paru. Hal ini dapat mempengaruhi hasil
akhir dari indikasi kondisi kenormalan paru-paru responden, karena nilai
prediksi FVC inilah yang dijadikan bahan perbandingan dalam penentuan
apakah paru seseorang normal atau tidak normal.
4.3.4. Hasil Pengujian Nilai FVC Responden
Pada pengujian nilai FVC responden, pengambilan data dilakukan pada
hembusan napas dari beberapa manusia yang berbeda dengan pengulangan
sebanyak 6 kali dengan 3 kali di hari pertama dan 3 kali di hari kedua, proses
tersebut dilakukan secara bergantian dari spirometer BTL-08 Spiro dan alat ukur
kapasitas vital paksa paru. Pada saat pengujian, responden diminta untuk
bernapas normal beberapa kali dengan menggunakan mulut, lalu mencoba
menarik napas maksimal lalu mengeluarkannya secara maksimal, lalu menarik
napas secara cepat maksimal dengan paksaan lalu mengeluarkan napas tersebut
secara kencang, cepat, maksimal dengan paksaan dan tetap menghembuskan
napas selama 6 detik. Pengukuran dimulai pada saat responden akan
mengeluarkan napas secara kencang, cepat, maksimal dengan paksaan yang
ditandai dengan pemberian aba-aba oleh responden. Pengulangan pengujian
56
dilakukan apabila responden telah diberikan waktu selama minimal 30 detik atau
lebih dari pengujian sebelumnya. Dari hasil pengujian didapatkan data dari tiga
responden dengan total 36 data, 18 data dari alat ukur kapasitas vital paru dan 18
data dari spirometer BTL-08 Spiro. Berikut data hasil pengujian nilai FVC:
Tabel 4. 7 Hasil Pengujian Nilai FVC
Responden Keadaan Uji Pengujian Nilai FVC
Selisih FVC Error BTL-08 Spiro Alat Ukur KVP
1
(Perempuan,16th)
1
1
2
3
2
1
2
3
2
(Laki-laki, 21th)
1
1
2
3
2
1
2
3
3
(Perempuan, 22th)
1
1
2
3
2
1
2
3
172.68
Sumber: Output BTL-08 Spirodan LabVIEW 2015, 2018
Berdasarkan Tabel 4.7, diketahui kesalahan paling kecil yaitu liter
atau , kesalahan paling besar liter atau , dan kesalahan rata-
rata alat ukur yaitu:
∑
∑
57
Tabel 4. 8 Perhitungan Ketepatan Alat Ukur Kapasitas Vital Paksa
Data Ke- Selisih FVC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Sumber: Output Microsoft Excel 2010, 2018
∑
∑
√∑
√
Berdasarkan data hasil pengujian pada Tabel 4.7 terdapat selisih nilai
terbesar yaitu liter sedangkan selisih terkecil sebesar liter dan nilai
selisih rata-rata sebesar , dengan didasarkan nilai selisih rata-rata dapat
diketahui nilai ketelitian alat adalah sebesar dan memiliki nilai presisi
sebesar .
58
Gambar 4. 9 Grafik Hasil Uji Nilai FVC BTL-08 Spiro dengan Alat Ukur Kapasitas Vital Paksa Paru
Sumber: Output Microsoft Excel 2010, 2018
Perbedaan-perbedaan nilai kapasitas vital paksa (FVC) yang diperoleh
antara spirometer BTL-08 Spiro dengan alat ukur kapasitas vital paksa paru
dapat disebabkan karena hembusan napas setiap orang tidak dapat dikontrol
secara pasti, antara pernapasan pertama dan kedua pada orang yang sama pasti
mengalami perbedaan sekecil apapun itu, ditambah lagi jika pengukuran
dilakukan pada hari yang berbeda, secara otomatis kondisi tubuh seseorang juga
pasti akan berbeda sehingga hal tersebut dapat mempengaruhi hasil pengujian
nilai kapasitas vital paksa (FVC) dari orang tersebut. Hal-hal itu yang
menyebabkan terdapatnya perbedaan hasil antara alat asli dengan alat ukur
kapasitas vital paksa paru.
1.5
2
2.5
3
3.5
4
4.5
5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Vo
lum
e (L
Iter
)
Uji Coba
Grafik Hasil Uji Nilai FVC
BTL-08 Spiro dengan Alat Ukur Kapasitas Vital Paru
BTL-08 Spiro Alat Ukur Kapasitas Vital Paksa
59
4.3.5. Hasil Indikasi Nilai FVC Responden
Menurut Syaifuddin (2010), nilai FVC dapat mengindikasikan kondisi
paru-paru seseorang, volume pernapasan yang kurang dari 80% rata-rata normal
biasanya mengindikasikan beberapa bentuk penyakit paru. Berdasarkan
penyataan tersebut maka dapat dilakukan indikasi kenormalan paru-paru secara
umum seperti berikut:
Tabel 4. 9 Hasil Indikasi Nilai FVC
Keadaan Uji
Hasil Uji BTL-08 Spiro Hasil Uji Alat Rancang
Prediksi
FVC
BTL-
08
Spiro
Indikator
Alat
Ukur
KVP
Indikator Prediksi
FVC
BTL-
08
Spiro
Indikator
Alat
Ukur
KVP
Indikator
Responden 1 (Perempuan, 16 tahun)
1
1
2.81
61.09 Tidak
Normal 61.21
Tidak
Normal
2.81
61.12 Tidak
Normal 62.97
Tidak
Normal
2 68.31 Tidak
Normal 68.33
Tidak
Normal 68.23
Tidak
Normal 78.15
Tidak
Normal
3 65.39 Tidak
Normal 65.48
Tidak
Normal 65.39
Tidak
Normal 73.67
Tidak
Normal
2
1 59.91 Tidak
Normal 59.79
Tidak
Normal 59.70
Tidak
Normal 73.67
Tidak
Normal
2 61.01 Tidak
Normal 61.21
Tidak
Normal 61.12
Tidak
Normal 67.41
Tidak
Normal
3 57.88 Tidak
Normal 58.01
Tidak
Normal 57.93
Tidak
Normal 62.97
Tidak
Normal
Responden 2 (Laki-laki, 21 tahun)
1
1
4.64
90.84 Normal 90.95 Normal
4.32
97.64 Normal 102 Normal
2 88.37 Normal 88.36 Normal 94.86 Normal 97.36 Normal
3 89.77 Normal 89.87 Normal 96.48 Normal 93.42 Normal
2
1 87.05 Normal 87.07 Normal 93.47 Normal 88.73 Normal
2 86.43 Normal 86.42 Normal 92.78 Normal 99.14 Normal
3 84.04 Normal 84.05 Normal 90.23 Normal 84.61 Normal
Responden 3 (Perempuan, 22 tahun)
1
1
3.04
64.72 Tidak
Normal 66.45
Tidak
Normal
2.80
72.02 Tidak
Normal 67.64
Tidak
Normal
2 68.64 Tidak
Normal 70.72
Tidak
Normal 76.66
Tidak
Normal 63.18
Tidak
Normal
3 71.63 Tidak
Normal 71.38
Tidak
Normal 77.37
Tidak
Normal 63.18
Tidak
Normal
2
1 68.89 Tidak
Normal 69.74
Tidak
Normal 75.59
Tidak
Normal 67.64
Tidak
Normal
2 66.89 Tidak
Normal 66.78
Tidak
Normal 72.38
Tidak
Normal 63.18
Tidak
Normal
3 67.85 Tidak
Normal 67.76
Tidak
Normal 73.45
Tidak
Normal 78.41
Tidak
Normal
Sumber: Output BTL-08 Spiro dan LabVIEW 2015, 2018
60
Berdasarkan data pada Tabel 4.9, dapat diketahui dari tiga responden
terdapat 2 responden yang terindikasi tidak normal dan 1 orang terindikasi
normal, hasil indikasi ini sama antara BTL-08 Spiro dengan alat ukur kapasitas
vital paru. Indikasi tidak normal terhadap kedua responden tersebut tidak dapat
menyatakan bahwa kedua responden tersebut menderita penyakit paru, masih
harus dilakukan pengukuran lebih lanjut lagi karena ada beberapa parameter
yang harus diukur untuk menentukan apakah ketidaknormalan tersebut
dikarenakan penyakit.
Ketidaknormalan pada hasil pengujian bisa jadi karena disebabkan
aktivitas atau lingkungan tempat sebelumnya responden berada. Karena
penelitian Oviera, dkk (2016) mengatakan bahwa ada hubungan antara
kebiasaan merokok dengan kapasitas vital paru. Secara tidak langsung dapat kita
ketahui bahwa polusi asap baik asap rokok ataupun asap kendaraan bermotor di
jalan raya yang terhirup oleh paru dapat mempengaruhi kapasitas vital paru.
Selain itu, ada beberapa hal yang dapat mempengaruhi kemampuan pernapasan
seseorang menurut BTL-08 Spiro instruction manual, diantaranya nyeri paru
atau sakit perut, nyeri pada mulut atau wajah, stress, demensia atau gangguan
mental, merokok kurang dari 1 jam sebelum pengujian, mengkonsumsi alkohol
kurang dari 4 jam sebelum pengujian, aktivitas yang melelahkan kurang dari 30
menit sebelum pengujian, kekenyangan/mengkonsumsi makan besar kurang dari
2 jam sebelum pengujian, pakaian yang berat dan ketat dapat mempengaruhi
pernapasan maksimal.
61
BAB V
KESIMPULAN DAN SARAN
5.1. Kesimpulan
Berdasarkan hasil perancangan dan pengujian yang telah dilakukan oleh
peneliti, dapat diambil beberapa kesimpulan sebagai berikut:
1. Telah berhasil merancang bangun sebuah alat ukur kapasitas vital paksa
paru menggunakan sensor tekanan MPX5100DP, Arduino Uno R3 dan
LabVIEW 2015
2. Karakterisasi alat ukur kapasitas vital paksa paru memiliki jangkauan
pengukuran sensor , waktu respon , ketelitian sebesar
dan ketepatan sebesar
3. Pengujian nilai FVC pada responden memiliki kesalahan rata-rata
dan dapat menampilkan indikasi kenormalan
5.2. Saran
Disarankan bagi peneliti selanjutnya agar melakukan pengembangan pada
beberapa hal agar alat ukur hasil perancangan peneliti dapat menjadi lebih baik,
diantaranya:
1. Melakukan optimasi agar lebih banyak parameter yang dapat diukur dan
dapat melakukan pengukuran saat inspirasi
2. Mengembangkan alat ukur kapasitas vital paksa paru yang dapat
menyimpan data secara keseluruhan sebagai satu kesatuan sampai dengan
proses pencetakan
62
DAFTAR PUSTAKA
Alsagaff H, Mangunegoro H. 1993. Nilai normal faal paru orang Indonesia pada
usia sekolah dan pekerja dewasa berdasarkan rekomendasi American
Thoracic Society (ATS) 1987. Surabaya: Airlangga University Press
BTL Industries Ltd. 2007. BTL-08 Spiro, Instruction Manual. United Kingdom:
BTL Industries Ltd.
Freescale Semiconductor, Inc. 2010. Integrated Silicon Pressure Sensor On-Chip
Signal Conditioned, Temperature Compensated and Calibrated MPX5100
Series. www.freescale.com/support. 12 Juni 2017
Iqlimah, Atika. 2013. Perancangan Alat Ukur Pernapasan Manusia. Jurnal
Skripsi
Kementerian Kesehatan Republik Indonesia. 2013. Riset Kesehatan Dasar
(Riskesdas) 2013. Jakarta: Badan Penelitian dan Pengembangan Kesehatan
Kurniawan, Agus. 2017. Arduino Programming with .NET and Sketch. Apress.
https://books.google.co.id/books?id=zntZDgAAQBAJ&pg=PA2&dq=ardui
no+uno&hl=id&sa=X&redir_esc=y#v=onepage&q=arduino%20uno&f=fals
e. 12 Juni 2017
National Instruments. LabVIEW Interface for Arduino (LIFA).
https://forums.ni.com/t5/LabVIEW-Interface-for-Arduino/ct-p/7008. 12 Juni
2017
National Instruments. LabVIEW Interface for Arduino.
https://vipm.jki.net/package/national_instruments_lib_labview_interface_fo
r_arduino. 12 Juni 2017
Oviera, A. Siswi J., Suroto. 2016. Faktor-Faktor yang Berhubungan dengan
Kapasitas Vital Paru pada Pekerja Industri Pengolahan Kayu di PT. X
Jepara. Jurnal Kesehatan Masyarakat. 4(1): 267-276
Paul A. Tipler. 1998. FISIKA (Untuk Sains dan Teknik), Ed. 3, Jilid 1. Jakarta:
Erlangga
Rifa’i, Achmad. 2013. Aplikasi Sensor Tekanan Gas MPX5100 dalam Alat Ukur
Kapasitas Vital Paru-paru. UPJ. 2(1): 18-23
63
Schwartz, Marco dan Oliver M. 2015. Programming Arduino with LabVIEW.
https://play.google.com/books/reader?id=3-
ZrBgAAQBAJ&printsec=frontcover&output=reader&hl=id&pg=GBS.PP1.
12 Juni 2017
Sears, Zermansky. 1982. Fisika untuk Universitas 1, Mekanika, Panas, Bunyi.
Cet.4. Jakarta: Binacipta
Soegito. 1998. Manfaat Pemeriksaan Faal Paru Kotamadya Medan Tahun 1998.
Tesis. Fakultas Kedokteran Universitas Sumatera Utara: Medan
Sulistiawan, Markus Heri. 2017. Sensor Kelembaban Tanah Multi Point Nirkabel
dengan Tampilan Grafik. Skripsi. Fakultas Sains dan Teknologi Universitas
Sanata Dharma: Yogyakarta
Sutrisno, Sitti A. 2007. FISIKA DASAR (Mekanika, Fluida & Gelombang).
Jakarta: UI Jakarta Press
Syaifuddin. 2010. Anatomi Fisiologi: Kurikulum Berbasis Kompetensi untuk
Keperawatan dan Kebidanan, Ed. 4. Jakarta: Penerbit Buku Kedokteran
AEGC
Tempo.co, 2017. Kesadaran terhadap penyakit paru obstruktif kronis masih
rendah. https://www.msn.com/id-id/kesehatan/health-news/kesadaran-
terhadap-penyakit-paru-obstruktif-kronis-masih-rendah/ar-BBFbjRC?pfr=1.
14 Juli 2017
Wilson, Jon S. 2005. Sensor Technology Handbook. Newnes: Elsevier Inc
Yunus, F. 1990. Proyek Pneumobile Indonesia Paru. 10: 35-7
Zainudin, A., Endah, R., Dzulkiflih. 2015. Pengukuran Volume Paru-paru dengan
memanfaatkan Sensor Tekanan. Jurnal Inovasi Fisika Indonesia 4(3): 127-
132
64
LAMPIRAN-LAMPIRAN
LAMPIRAN
65
Lampiran 1
Sketch Program Firmware LIFA Base
LIFA_Base /************************************
** LVFA_Firmware - Provides Basic Arduino
Sketch For Interfacing With LabVIEW.
** Written By: Sam Kristoff - National
Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort -
National Instruments
** This File May Be Modified And Re-
Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At
www.ni.com/arduino.
**************************************/
/************************************
** Includes.
******************************/
// Standard includes. These should always be
included.
#include <Wire.h>
#include <SPI.h>
#include <Servo.h>
#include "LabVIEWInterface.h"
/*************************************
** setup()
** Initialize the Arduino and setup serial
communication.
** Input: None
** Output: None
**************************************/
void setup()
{
// Initialize Serial Port With The Default
Baud Rate
syncLV();
// Place your custom setup code here
}
/************************************
** loop()
** The main loop. This loop runs
continuously on the Arduino. It
** receives and processes serial commands
from LabVIEW.
** Input: None
** Output: None
**************************************/
void loop()
{
// Check for commands from LabVIEW and
process them.
checkForCommand();
// Place your custom loop code here (this
may slow down communication with LabVIEW)
if(acqMode==1)
{
sampleContinously();
}
}
AFMotor.cpp
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
#include <avr/io.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif #include "AFMotor.h"
static uint8_t latch_state;
#if (MICROSTEPS == 8)
uint8_t microstepcurve[] = {0, 50, 98, 142,
180, 212, 236, 250, 255};
#elif (MICROSTEPS == 16)
uint8_t microstepcurve[] = {0, 25, 50, 74,
98, 120, 141, 162, 180, 197, 212, 225, 236,
244, 250, 253, 255};
#endif
AFMotorController::AFMotorController(void) {
}
void AFMotorController::enable(void) {
// setup the latch
/*
LATCH_DDR |= _BV(LATCH);
ENABLE_DDR |= _BV(ENABLE);
CLK_DDR |= _BV(CLK);
SER_DDR |= _BV(SER);
*/
pinMode(MOTORLATCH, OUTPUT);
pinMode(MOTORENABLE, OUTPUT);
pinMode(MOTORDATA, OUTPUT);
pinMode(MOTORCLK, OUTPUT);
latch_state = 0;
latch_tx(); // "reset"
//ENABLE_PORT &= ~_BV(ENABLE); // enable
the chip outputs!
digitalWrite(MOTORENABLE, LOW);
}
void AFMotorController::latch_tx(void) {
uint8_t i;
//LATCH_PORT &= ~_BV(LATCH);
digitalWrite(MOTORLATCH, LOW);
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
for (i=0; i<8; i++) {
//CLK_PORT &= ~_BV(CLK);
digitalWrite(MOTORCLK, LOW);
if (latch_state & _BV(7-i)) {
//SER_PORT |= _BV(SER);
digitalWrite(MOTORDATA, HIGH);
} else {
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
}
//CLK_PORT |= _BV(CLK);
digitalWrite(MOTORCLK, HIGH);
}
//LATCH_PORT |= _BV(LATCH);
digitalWrite(MOTORLATCH, HIGH);
}
static AFMotorController MC;
/****************************************
MOTORS
****************************************/
inline void initPWM1(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino
pin #11)
TCCR2A |= _BV(COM2A1) | _BV(WGM20) |
_BV(WGM21); // fast PWM, turn on oc2a
TCCR2B = freq & 0x7;
OCR2A = 0;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
66
// on arduino mega, pin 11 is now PB5
(OC1A)
TCCR1A |= _BV(COM1A1) | _BV(WGM10); //
fast PWM, turn on oc1a
TCCR1B = (freq & 0x7) | _BV(WGM12);
OCR1A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(11, OUTPUT);
}
inline void setPWM1(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino
pin #11)
OCR2A = s;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5
(OC1A)
OCR1A = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM2(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2B (pin 3)
TCCR2A |= _BV(COM2B1) | _BV(WGM20) |
_BV(WGM21); // fast PWM, turn on oc2b
TCCR2B = freq & 0x7;
OCR2B = 0;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
// on arduino mega, pin 3 is now PE5
(OC3C)
TCCR3A |= _BV(COM1C1) | _BV(WGM10); //
fast PWM, turn on oc3c
TCCR3B = (freq & 0x7) | _BV(WGM12);
OCR3C = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(3, OUTPUT);
}
inline void setPWM2(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino
pin #11)
OCR2B = s;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5
(OC1A)
OCR3C = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM3(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__) // use PWM from timer0A / PD6 (pin 6)
TCCR0A |= _BV(COM0A1) | _BV(WGM00) |
_BV(WGM01); // fast PWM, turn on OC0A
//TCCR0B = freq & 0x7;
OCR0A = 0;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3
(OC4A)
TCCR4A |= _BV(COM1A1) | _BV(WGM10); //
fast PWM, turn on oc4a
TCCR4B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR4A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(6, OUTPUT);
}
inline void setPWM3(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino
pin #6)
OCR0A = s;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3
(OC4A)
OCR4A = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM4(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0B / PD5 (pin 5)
TCCR0A |= _BV(COM0B1) | _BV(WGM00) |
_BV(WGM01); // fast PWM, turn on oc0a
//TCCR0B = freq & 0x7;
OCR0B = 0;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
// on arduino mega, pin 5 is now PE3
(OC3A)
TCCR3A |= _BV(COM1A1) | _BV(WGM10); //
fast PWM, turn on oc3a
TCCR3B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR3A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(5, OUTPUT);
}inline void setPWM4(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino
pin #6)
OCR0B = s;
#elif defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3
(OC4A)
OCR3A = s;
#else
67
#error "This chip is not supported!"
#endif
}
AF_DCMotor::AF_DCMotor(uint8_t num, uint8_t
freq) {
motornum = num;
pwmfreq = freq;
MC.enable();
switch (num) {
case 1:
latch_state &= ~_BV(MOTOR1_A) &
~_BV(MOTOR1_B);//set both motor pins to 0
MC.latch_tx();
initPWM1(freq);
break;
case 2:
latch_state &= ~_BV(MOTOR2_A) &
~_BV(MOTOR2_B);//set both motor pins to 0
MC.latch_tx();
initPWM2(freq);
break;
case 3:
latch_state &= ~_BV(MOTOR3_A) &
~_BV(MOTOR3_B);//set both motor pins to 0
MC.latch_tx();
initPWM3(freq);
break;
case 4:
latch_state &= ~_BV(MOTOR4_A) &
~_BV(MOTOR4_B);//set both motor pins to 0
MC.latch_tx();
initPWM4(freq);
break;
}
}
void AF_DCMotor::run(uint8_t cmd) {
uint8_t a, b;
switch (motornum) {
case 1:
a = MOTOR1_A; b = MOTOR1_B; break;
case 2:
a = MOTOR2_A; b = MOTOR2_B; break;
case 3:
a = MOTOR3_A; b = MOTOR3_B; break;
case 4:
a = MOTOR4_A; b = MOTOR4_B; break;
default:
return;
}
switch (cmd) {
case FORWARD:
latch_state |= _BV(a);
latch_state &= ~_BV(b);
MC.latch_tx();
break;
case BACKWARD:
latch_state &= ~_BV(a);
latch_state |= _BV(b);
MC.latch_tx();
break;
case RELEASE:
latch_state &= ~_BV(a);
latch_state &= ~_BV(b);
MC.latch_tx();
break;
}
}
void AF_DCMotor::setSpeed(uint8_t speed) {
switch (motornum) {
case 1:
setPWM1(speed); break;
case 2:
setPWM2(speed); break;
case 3:
setPWM3(speed); break;
case 4:
setPWM4(speed); break;
}
} /****************************************
STEPPERS
****************************************/
AF_Stepper::AF_Stepper(uint16_t steps,
uint8_t num) {
MC.enable();
revsteps = steps;
steppernum = num;
currentstep = 0;
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) &
~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all
motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);
digitalWrite(11, HIGH);
digitalWrite(3, HIGH);
// use PWM for microstepping support
initPWM1(MOTOR12_64KHZ);
initPWM2(MOTOR12_64KHZ);
setPWM1(255);
setPWM2(255);
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) &
~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all
motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
// use PWM for microstepping support
// use PWM for microstepping support
initPWM3(1);
initPWM4(1);
setPWM3(255);
setPWM4(255);
}
}
void AF_Stepper::setSpeed(uint16_t rpm) {
usperstep = 60000000 / ((uint32_t)revsteps
* (uint32_t)rpm);
steppingcounter = 0;
}
void AF_Stepper::release(void) {
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) &
~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all
motor pins to 0
MC.latch_tx();
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) &
~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all
motor pins to 0
MC.latch_tx();
}
}
void AF_Stepper::step(uint16_t steps, uint8_t
dir, uint8_t style) {
uint32_t uspers = usperstep;
uint8_t ret = 0;
if (style == INTERLEAVE) {
uspers /= 2;
}
else if (style == MICROSTEP) {
uspers /= MICROSTEPS;
steps *= MICROSTEPS;
#ifdef MOTORDEBUG
68
Serial.print("steps = ");
Serial.println(steps, DEC);
#endif
}
while (steps--) {
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
if (style == MICROSTEP) {
while ((ret != 0) && (ret != MICROSTEPS))
{
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
}
}
uint8_t AF_Stepper::onestep(uint8_t dir,
uint8_t style) {
uint8_t a, b, c, d;
uint8_t ocrb, ocra;
ocra = ocrb = 255;
if (steppernum == 1) {
a = _BV(MOTOR1_A);
b = _BV(MOTOR2_A);
c = _BV(MOTOR1_B);
d = _BV(MOTOR2_B);
} else if (steppernum == 2) {
a = _BV(MOTOR3_A);
b = _BV(MOTOR4_A);
c = _BV(MOTOR3_B);
d = _BV(MOTOR4_B);
} else {
return 0;
}
// next determine what sort of stepping
procedure we're up to
if (style == SINGLE) {
if ((currentstep/(MICROSTEPS/2)) % 2) {
// we're at an odd step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
}
else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next even
step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
}
else {
currentstep -= MICROSTEPS;
}
}
} else if (style == DOUBLE) {
if (! (currentstep/(MICROSTEPS/2) % 2)) {
// we're at an even step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next odd step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
} else {
currentstep -= MICROSTEPS;
} }
} else if (style == INTERLEAVE) {
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
}
if (style == MICROSTEP) {
if (dir == FORWARD) {
currentstep++;
} else {
// BACKWARDS
currentstep--;
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
ocra = ocrb = 0;
if ( (currentstep >= 0) && (currentstep <
MICROSTEPS)) {
ocra = microstepcurve[MICROSTEPS -
currentstep];
ocrb = microstepcurve[currentstep];
} else if ( (currentstep >= MICROSTEPS)
&& (currentstep < MICROSTEPS*2)) {
ocra = microstepcurve[currentstep -
MICROSTEPS];
ocrb = microstepcurve[MICROSTEPS*2 -
currentstep];
} else if ( (currentstep >=
MICROSTEPS*2) && (currentstep <
MICROSTEPS*3)) {
ocra = microstepcurve[MICROSTEPS*3 -
currentstep];
ocrb = microstepcurve[currentstep -
MICROSTEPS*2];
} else if ( (currentstep >=
MICROSTEPS*3) && (currentstep <
MICROSTEPS*4)) {
ocra = microstepcurve[currentstep -
MICROSTEPS*3];
ocrb = microstepcurve[MICROSTEPS*4 -
currentstep];
}
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
#ifdef MOTORDEBUG
Serial.print("current step: ");
Serial.println(currentstep, DEC);
Serial.print(" pwmA = "); Serial.print(ocra,
DEC);
Serial.print(" pwmB = ");
Serial.println(ocrb, DEC);
#endif
if (steppernum == 1) {
setPWM1(ocra);
setPWM2(ocrb);
} else if (steppernum == 2) {
setPWM3(ocra);
setPWM4(ocrb);
}
// release all
latch_state &= ~a & ~b & ~c & ~d; // all
motor pins to 0
//Serial.println(step, DEC);
if (style == MICROSTEP) {
if ((currentstep >= 0) && (currentstep <
MICROSTEPS))
latch_state |= a | b;
if ((currentstep >= MICROSTEPS) &&
(currentstep < MICROSTEPS*2))
latch_state |= b | c;
if ((currentstep >= MICROSTEPS*2) &&
(currentstep < MICROSTEPS*3))
latch_state |= c | d;
69
if ((currentstep >= MICROSTEPS*3) &&
(currentstep < MICROSTEPS*4))
latch_state |= d | a;
} else {
switch (currentstep/(MICROSTEPS/2)) {
case 0:
latch_state |= a; // energize coil 1
only
break;
case 1:
latch_state |= a | b; // energize coil
1+2
break;
case 2:
latch_state |= b; // energize coil 2
only
break;
case 3:
latch_state |= b | c; // energize coil
2+3
break;
case 4:
latch_state |= c; // energize coil 3
only
break;
case 5:
latch_state |= c | d; // energize coil
3+4
break;
case 6:
latch_state |= d; // energize coil 4
only
break;
case 7:
latch_state |= d | a; // energize coil
1+4
break;
}
}
MC.latch_tx();
return currentstep;
}
AFMotor.h
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
#ifndef _AFMotor_h_
#define _AFMotor_h_
#include <inttypes.h>
#include <avr/io.h>
//#define MOTORDEBUG 1
#define MICROSTEPS 16 // 8 or 16
#define MOTOR12_64KHZ _BV(CS20) // no
prescale
#define MOTOR12_8KHZ _BV(CS21) // divide by
8
#define MOTOR12_2KHZ _BV(CS21) | _BV(CS20) //
divide by 32
#define MOTOR12_1KHZ _BV(CS22) // divide by
64
#define MOTOR34_64KHZ _BV(CS00) // no
prescale
#define MOTOR34_8KHZ _BV(CS01) // divide by
8
#define MOTOR34_1KHZ _BV(CS01) | _BV(CS00)
// divide by 64
#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR4_A 0
#define MOTOR4_B 6
#define MOTOR3_A 5
#define MOTOR3_B 7
#define FORWARD 1
#define BACKWARD 2 #define BRAKE 3
#define RELEASE 4
#define SINGLE 1
#define DOUBLE 2
#define INTERLEAVE 3
#define MICROSTEP 4
/*
#define LATCH 4
#define LATCH_DDR DDRB
#define LATCH_PORT PORTB
#define CLK_PORT PORTD
#define CLK_DDR DDRD
#define CLK 4
#define ENABLE_PORT PORTD
#define ENABLE_DDR DDRD
#define ENABLE 7
#define SER 0
#define SER_DDR DDRB
#define SER_PORT PORTB
*/
// Arduino pin names
#define MOTORLATCH 12
#define MOTORCLK 4
#define MOTORENABLE 7
#define MOTORDATA 8
class AFMotorController
{
public:
AFMotorController(void);
void enable(void);
friend class AF_DCMotor;
void latch_tx(void);
};
class AF_DCMotor
{
public:
AF_DCMotor(uint8_t motornum, uint8_t freq =
MOTOR34_8KHZ);
void run(uint8_t);
void setSpeed(uint8_t);
private:
uint8_t motornum, pwmfreq;
};
class AF_Stepper {
public:
AF_Stepper(uint16_t, uint8_t);
void step(uint16_t steps, uint8_t dir,
uint8_t style = SINGLE);
void setSpeed(uint16_t);
uint8_t onestep(uint8_t dir, uint8_t
style);
void release(void);
uint16_t revsteps; // # steps per
revolution
uint8_t steppernum;
uint32_t usperstep, steppingcounter;
private:
uint8_t currentstep;
};
uint8_t getlatchstate(void);
#endif
AccelStepper.cpp
// AccelStepper.cpp
// Copyright (C) 2009 Mike McCauley
// $Id: AccelStepper.cpp,v 1.4 2011/01/05
01:51:01 mikem Exp $
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "AccelStepper.h"
void AccelStepper::moveTo(long absolute)
{
_targetPos = absolute;
70
computeNewSpeed();
}
void AccelStepper::move(long relative)
{
moveTo(_currentPos + relative);
}
// Implements steps according to the current
speed
// You must call this at least once per step
// returns true if a step occurred
boolean AccelStepper::runSpeed()
{
unsigned long time = micros();
// if ( (time >= (_lastStepTime +
_stepInterval)) // okay if both current time
and next step time wrap
// || ((time < _lastRunTime) && (time
> (0xFFFFFFFF-
(_lastStepTime+_stepInterval)))) ) // check
if only current time has wrapped
// unsigned long nextStepTime =
_lastStepTime + _stepInterval;
// if ( ((nextStepTime < _lastStepTime)
&& (time < _lastStepTime) && (time >=
nextStepTime))
// || ((nextStepTime >= _lastStepTime) &&
(time >= nextStepTime)))
// TESTING:
//time += (0xffffffff - 10000000);
// Gymnastics to detect wrapping of
either the nextStepTime and/or the current
time
unsigned long nextStepTime =
_lastStepTime + _stepInterval;
if ( ((nextStepTime >= _lastStepTime)
&& ((time >= nextStepTime) || (time <
_lastStepTime)))
|| ((nextStepTime < _lastStepTime) &&
((time >= nextStepTime) && (time <
_lastStepTime))))
{
if (_speed > 0.0f)
{
// Clockwise
_currentPos += 1;
}
else if (_speed < 0.0f)
{
// Anticlockwise
_currentPos -= 1;
}
step(_currentPos & 0x7); // Bottom 3
bits (same as mod 8, but works with + and -
numbers)
// _lastRunTime = time;
_lastStepTime = time;
return true;
}
else
{
// _lastRunTime = time;
return false;
}
}
long AccelStepper::distanceToGo()
{
return _targetPos - _currentPos;
}
long AccelStepper::targetPosition()
{
return _targetPos;
}
long AccelStepper::currentPosition()
{
return _currentPos;
}
// Useful during initialisations or after
initial positioning void AccelStepper::setCurrentPosition(long
position)
{
_targetPos = _currentPos = position;
computeNewSpeed(); // Expect speed of 0
}
void AccelStepper::computeNewSpeed()
{
setSpeed(desiredSpeed());
}
// Work out and return a new speed.
// Subclasses can override if they want
// Implement acceleration, deceleration and
max speed
// Negative speed is anticlockwise
// This is called:
// after each step
// after user changes:
// maxSpeed
// acceleration
// target position (relative or absolute)
float AccelStepper::desiredSpeed()
{
float requiredSpeed;
long distanceTo = distanceToGo();
// Max possible speed that can still
decelerate in the available distance
// Use speed squared to avoid using sqrt
if (distanceTo == 0)
return 0.0f; // We're there
else if (distanceTo > 0) // Clockwise
requiredSpeed = (2.0f * distanceTo *
_acceleration);
else // Anticlockwise
requiredSpeed = -(2.0f * -distanceTo *
_acceleration);
float sqrSpeed = (_speed * _speed) *
((_speed > 0.0f) ? 1.0f : -1.0f);
if (requiredSpeed > sqrSpeed)
{
if (_speed == _maxSpeed) // Reduces
processor load by avoiding extra calculations
below
{
// Maintain max speed
requiredSpeed = _maxSpeed;
}
else
{
// Need to accelerate in clockwise
direction
if (_speed == 0.0f)
requiredSpeed = sqrt(2.0f *
_acceleration);
else
requiredSpeed = _speed +
abs(_acceleration / _speed);
if (requiredSpeed > _maxSpeed)
requiredSpeed = _maxSpeed;
}
}
else if (requiredSpeed < sqrSpeed)
{
if (_speed == -_maxSpeed) // Reduces
processor load by avoiding extra calculations
below
{
// Maintain max speed
requiredSpeed = -_maxSpeed;
}
else
{
// Need to accelerate in clockwise
direction
71
if (_speed == 0.0f)
requiredSpeed = -sqrt(2.0f *
_acceleration);
else
requiredSpeed = _speed -
abs(_acceleration / _speed);
if (requiredSpeed < -_maxSpeed)
requiredSpeed = -_maxSpeed;
}
}
else // if (requiredSpeed == sqrSpeed)
requiredSpeed = _speed;
// Serial.println(requiredSpeed);
return requiredSpeed;
}
// Run the motor to implement speed and
acceleration in order to proceed to the
target position
// You must call this at least once per step,
preferably in your main loop
// If the motor is in the desired position,
the cost is very small
// returns true if we are still running to
position
boolean AccelStepper::run()
{
if (_targetPos == _currentPos)
return false;
if (runSpeed())
computeNewSpeed();
return true;
}
AccelStepper::AccelStepper(uint8_t pins,
uint8_t pin1, uint8_t pin2, uint8_t pin3,
uint8_t pin4)
{
_pins = pins;
_currentPos = 0;
_targetPos = 0;
_speed = 0.0;
_maxSpeed = 1.0;
_acceleration = 1.0;
_stepInterval = 0;
// _lastRunTime = 0;
_minPulseWidth = 1;
_lastStepTime = 0;
_pin1 = pin1;
_pin2 = pin2;
_pin3 = pin3;
_pin4 = pin4;
//_stepInterval = 20000;
//_speed = 50.0;
//_lastRunTime = 0xffffffff - 20000;
//_lastStepTime = 0xffffffff - 20000 - 10000;
enableOutputs();
}
AccelStepper::AccelStepper(void (*forward)(),
void (*backward)())
{
_pins = 0;
_currentPos = 0;
_targetPos = 0;
_speed = 0.0;
_maxSpeed = 1.0;
_acceleration = 1.0;
_stepInterval = 0;
// _lastRunTime = 0;
_minPulseWidth = 1;
_lastStepTime = 0;
_pin1 = 0;
_pin2 = 0;
_pin3 = 0;
_pin4 = 0;
_forward = forward;
_backward = backward;
}
void AccelStepper::setMaxSpeed(float speed)
{ _maxSpeed = speed;
computeNewSpeed();
}
void AccelStepper::setAcceleration(float
acceleration)
{
_acceleration = acceleration;
computeNewSpeed();
}
void AccelStepper::setSpeed(float speed)
{
if (speed == _speed)
return;
if ((speed > 0.0f) && (speed >
_maxSpeed))
_speed = _maxSpeed;
else if ((speed < 0.0f) && (speed < -
_maxSpeed))
_speed = -_maxSpeed;
else
_speed = speed;
_stepInterval = abs(1000000.0 / _speed);
}
float AccelStepper::speed()
{
return _speed;
}
// Subclasses can override
void AccelStepper::step(uint8_t step)
{
switch (_pins)
{
case 0:
step0();
break;
case 1:
step1(step);
break;
case 2:
step2(step);
break;
case 4:
step4(step);
break;
case 8:
step8(step);
break;
}
}
// 0 pin step function (ie for functional
usage)
void AccelStepper::step0()
{
if (_speed > 0) {
_forward();
} else {
_backward();
}
}
// 1 pin step function (ie for stepper
drivers)
// This is passed the current step number (0
to 7)
// Subclasses can override
void AccelStepper::step1(uint8_t step)
{
digitalWrite(_pin2, _speed > 0); //
Direction
// Caution 200ns setup time
digitalWrite(_pin1, HIGH);
// Delay the minimum allowed pulse width
72
delayMicroseconds(_minPulseWidth);
digitalWrite(_pin1, LOW);
}
// 2 pin step function
// This is passed the current step number (0
to 7)
// Subclasses can override
void AccelStepper::step2(uint8_t step)
{
switch (step & 0x3)
{
case 0: /* 01 */
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
break;
case 1: /* 11 */
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, HIGH);
break;
case 2: /* 10 */
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
break;
case 3: /* 00 */
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
break;
}
}
// 4 pin step function for half stepper
// This is passed the current step number (0
to 7)
// Subclasses can override
void AccelStepper::step4(uint8_t step)
{
switch (step & 0x3)
{
case 0: // 1010
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 1: // 0110
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 2: //0101
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 3: //1001
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
}
}
// 4 pin step function
// This is passed the current step number (0
to 3)
// Subclasses can override
void AccelStepper::step8(uint8_t step)
{
switch (step & 0x7)
{
case 0: // 1000
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW); digitalWrite(_pin4, LOW);
break;
case 1: // 1010
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 2: // 0010
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 3: // 0110
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 4: // 0100
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
break;
case 5: //0101
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 6: // 0001
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 7: //1001
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
}
}
// Prevents power consumption on the outputs
void AccelStepper::disableOutputs()
{
if (! _pins) return;
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
if (_pins == 4 || _pins == 8)
{
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
}
}
void AccelStepper::enableOutputs()
{
if (! _pins) return;
pinMode(_pin1, OUTPUT);
pinMode(_pin2, OUTPUT);
if (_pins == 4 || _pins == 8)
{
pinMode(_pin3, OUTPUT);
pinMode(_pin4, OUTPUT);
}
}
void AccelStepper::setMinPulseWidth(unsigned
int minWidth)
{
_minPulseWidth = minWidth;
}
73
// Blocks until the target position is
reached
void AccelStepper::runToPosition()
{
while (run())
;
}
boolean AccelStepper::runSpeedToPosition()
{
return _targetPos!=_currentPos ?
runSpeed() : false;
}
// Blocks until the new target position is
reached
void AccelStepper::runToNewPosition(long
position)
{
moveTo(position);
runToPosition();
}
AccelStepper.cpp
// AccelStepper.h
/// \mainpage AccelStepper library for
Arduino
/// This is the Arduino AccelStepper library.
/// It provides an object-oriented interface
for 2 or 4 pin stepper motors.
/// The standard Arduino IDE includes the
Stepper library
(http://arduino.cc/en/Reference/Stepper) for
stepper motors. It is
/// perfectly adequate for simple, single
motor applications.
/// AccelStepper significantly improves on
the standard Arduino Stepper library in
several ways:
/// \li Supports acceleration and
deceleration
/// \li Supports multiple simultaneous
steppers, with independent concurrent
stepping on each stepper
/// \li API functions never delay() or block
/// \li Supports 2 and 4 wire steppers, plus
4 wire half steppers.
/// \li Supports alternate stepping functions
to enable support of AFMotor
(https://github.com/adafruit/Adafruit-Motor-
Shield-library)
/// \li Supports stepper drivers such as the
Sparkfun EasyDriver (based on 3967 driver
chip)
/// \li Very slow speeds are supported
/// \li Extensive API
/// \li Subclass support
///
/// The latest version of this documentation
can be downloaded from
///
http://www.open.com.au/mikem/arduino/AccelSte
pper
///
/// Example Arduino programs are included to
show the main modes of use.
///
/// The version of the package that this
documentation refers to can be downloaded
/// from
http://www.open.com.au/mikem/arduino/AccelSte
pper/AccelStepper-1.9.zip
/// You can find the latest version at
http://www.open.com.au/mikem/arduino/AccelSte
pper
///
/// Tested on Arduino Diecimila and Mega with
arduino-0018 & arduino-0021
/// on OpenSuSE 11.1 and avr-libc-1.6.1-1.15, /// cross-avr-binutils-2.19-9.1, cross-avr-
gcc-4.1.3_20080612-26.5.
///
/// \par Installation
/// Install in the usual way: unzip the
distribution zip file to the libraries
/// sub-folder of your sketchbook.
///
/// This software is Copyright (C) 2010 Mike
McCauley. Use is subject to license
/// conditions. The main licensing options
available are GPL V2 or Commercial:
///
/// \par Open Source Licensing GPL V2
/// This is the appropriate option if you
want to share the source code of your
/// application with everyone you distribute
it to, and you also want to give them
/// the right to share who uses it. If you
wish to use this software under Open
/// Source Licensing, you must contribute all
your source code to the open source
/// community in accordance with the GPL
Version 2 when your application is
/// distributed. See
http://www.gnu.org/copyleft/gpl.html
///
/// \par Commercial Licensing
/// This is the appropriate option if you are
creating proprietary applications
/// and you are not prepared to distribute
and share the source code of your
/// application. Contact [email protected] for
details.
///
/// \par Revision History
/// \version 1.0 Initial release
///
/// \version 1.1 Added speed() function to
get the current speed.
/// \version 1.2 Added runSpeedToPosition()
submitted by Gunnar Arndt.
/// \version 1.3 Added support for stepper
drivers (ie with Step and Direction inputs)
with _pins == 1
/// \version 1.4 Added functional contructor
to support AFMotor, contributed by Limor,
with example sketches.
/// \version 1.5 Improvements contributed by
Peter Mousley: Use of microsecond steps and
other speed improvements
/// to increase max stepping
speed to about 4kHz. New option for user to
set the min allowed pulse width.
/// Added checks for already
running at max speed and skip further calcs
if so.
/// \version 1.6 Fixed a problem with
wrapping of microsecond stepping that could
cause stepping to hang.
/// Reported by Sandy Noble.
/// Removed redundant
_lastRunTime member.
/// \version 1.7 Fixed a bug where
setCurrentPosition() did always work as
expected. Reported by Peter Linhart.
/// Reported by Sandy Noble.
/// Removed redundant
_lastRunTime member.
/// \version 1.8 Added support for 4 pin
half-steppers, requested by Harvey Moon
/// \version 1.9 setCurrentPosition() now
also sets motor speed to 0.
///
///
/// \author Mike McCauley
74
// Copyright (C) 2009 Mike McCauley
// $Id: AccelStepper.h,v 1.5 2011/03/21
00:42:15 mikem Exp mikem $
#ifndef AccelStepper_h
#define AccelStepper_h
#include <stdlib.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include <pins_arduino.h>
#else
#include <wiring.h>
#endif
// These defs cause trouble on some versions
of Arduino
#undef round
////////////////////////////
/// \class AccelStepper AccelStepper.h
<AccelStepper.h>
/// \brief Support for stepper motors with
acceleration etc.
///
/// This defines a single 2 or 4 pin stepper
motor, or stepper moter with fdriver chip,
with optional
/// acceleration, deceleration, absolute
positioning commands etc. Multiple
/// simultaneous steppers are supported, all
moving
/// at different speeds and accelerations.
///
/// \par Operation
/// This module operates by computing a step
time in microseconds. The step
/// time is recomputed after each step and
after speed and acceleration
/// parameters are changed by the caller. The
time of each step is recorded in
/// microseconds. The run() function steps
the motor if a new step is due.
/// The run() function must be called
frequently until the motor is in the
/// desired position, after which time run()
will do nothing.
///
/// \par Positioning
/// Positions are specified by a signed long
integer. At
/// construction time, the current position
of the motor is consider to be 0. Positive
/// positions are clockwise from the initial
position; negative positions are
/// anticlockwise. The curent position can be
altered for instance after
/// initialization positioning.
///
/// \par Caveats
/// This is an open loop controller: If the
motor stalls or is oversped,
/// AccelStepper will not have a correct
/// idea of where the motor really is (since
there is no feedback of the motor's
/// real position. We only know where we
_think_ it is, relative to the
/// initial starting point).
///
/// The fastest motor speed that can be
reliably supported is 4000 steps per
/// second (4 kHz) at a clock frequency of 16
MHz. However, any speed less than that
/// down to very slow speeds (much less than
one per second) are also supported,
/// provided the run() function is called
frequently enough to step the motor
/// whenever required for the speed set.
class AccelStepper
{
public:
/// Constructor. You can have multiple
simultaneous steppers, all moving /// at different speeds and
accelerations, provided you call their run()
/// functions at frequent enough
intervals. Current Position is set to 0,
target
/// position is set to 0. MaxSpeed and
Acceleration default to 1.0.
/// The motor pins will be initialised to
OUTPUT mode during the
/// constructor by a call to
enableOutputs().
/// \param[in] pins Number of pins to
interface to. 1, 2 or 4 are
/// supported. 1 means a stepper driver
(with Step and Direction pins)
/// 2 means a 2 wire stepper. 4 means a 4
wire stepper. 8 means a 4 wire half stepper
/// Defaults to 4 pins.
/// \param[in] pin1 Arduino digital pin
number for motor pin 1. Defaults
/// to pin 2. For a driver (pins==1),
this is the Step input to the driver. Low to
high transition means to step)
/// \param[in] pin2 Arduino digital pin
number for motor pin 2. Defaults
/// to pin 3. For a driver (pins==1),
this is the Direction input the driver. High
means forward.
/// \param[in] pin3 Arduino digital pin
number for motor pin 3. Defaults
/// to pin 4.
/// \param[in] pin4 Arduino digital pin
number for motor pin 4. Defaults
/// to pin 5.
AccelStepper(uint8_t pins = 4, uint8_t
pin1 = 2, uint8_t pin2 = 3, uint8_t pin3 = 4,
uint8_t pin4 = 5);
/// Alternate Constructor which will call
your own functions for forward and backward
steps.
/// You can have multiple simultaneous
steppers, all moving
/// at different speeds and
accelerations, provided you call their run()
/// functions at frequent enough
intervals. Current Position is set to 0,
target
/// position is set to 0. MaxSpeed and
Acceleration default to 1.0.
/// Any motor initialization should
happen before hand, no pins are used or
initialized.
/// \param[in] forward void-returning
procedure that will make a forward step
/// \param[in] backward void-returning
procedure that will make a backward step
AccelStepper(void (*forward)(), void
(*backward)());
/// Set the target position. The run()
function will try to move the motor
/// from the current position to the
target position set by the most
/// recent call to this function.
/// \param[in] absolute The desired
absolute position. Negative is
/// anticlockwise from the 0 position.
void moveTo(long absolute);
/// Set the target position relative to
the current position
/// \param[in] relative The desired
position relative to the current position.
Negative is
/// anticlockwise from the current
position.
75
void move(long relative);
/// Poll the motor and step it if a step
is due, implementing
/// accelerations and decelerations to
achive the ratget position. You must call
this as
/// fequently as possible, but at least
once per minimum step interval,
/// preferably in your main loop.
/// \return true if the motor is at the
target position.
boolean run();
/// Poll the motor and step it if a step
is due, implmenting a constant
/// speed as set by the most recent call
to setSpeed().
/// \return true if the motor was
stepped.
boolean runSpeed();
/// Sets the maximum permitted speed. the
run() function will accelerate
/// up to the speed set by this function.
/// \param[in] speed The desired maximum
speed in steps per second. Must
/// be > 0. Speeds of more than 1000
steps per second are unreliable.
void setMaxSpeed(float speed);
/// Sets the acceleration and
deceleration parameter.
/// \param[in] acceleration The desired
acceleration in steps per second
/// per second. Must be > 0.
void setAcceleration(float
acceleration);
/// Sets the desired constant speed for
use with runSpeed().
/// \param[in] speed The desired constant
speed in steps per
/// second. Positive is clockwise. Speeds
of more than 1000 steps per
/// second are unreliable. Very slow
speeds may be set (eg 0.00027777 for
/// once per hour, approximately. Speed
accuracy depends on the Arduino
/// crystal. Jitter depends on how
frequently you call the runSpeed() function.
void setSpeed(float speed);
/// The most recently set speed
/// \return the most recent speed in
steps per second
float speed();
/// The distance from the current
position to the target position.
/// \return the distance from the current
position to the target position
/// in steps. Positive is clockwise from
the current position.
long distanceToGo();
/// The most recently set target
position.
/// \return the target position
/// in steps. Positive is clockwise from
the 0 position.
long targetPosition();
/// The currently motor position.
/// \return the current motor position
/// in steps. Positive is clockwise from
the 0 position.
long currentPosition();
/// Resets the current position of the
motor, so that wherever the motor
/// happens to be right now is considered
to be the new 0 position. Useful
/// for setting a zero position on a
stepper after an initial hardware
/// positioning move.
/// Has the side effect of setting the
current motor speed to 0.
/// \param[in] position The position in
steps of wherever the motor /// happens to be right now.
void setCurrentPosition(long
position);
/// Moves the motor to the target
position and blocks until it is at
/// position. Dont use this in event
loops, since it blocks.
void runToPosition();
/// Runs at the currently selected speed
until the target position is reached
/// Does not implement accelerations.
boolean runSpeedToPosition();
/// Moves the motor to the new target
position and blocks until it is at
/// position. Dont use this in event
loops, since it blocks.
/// \param[in] position The new target
position.
void runToNewPosition(long position);
/// Disable motor pin outputs by setting
them all LOW
/// Depending on the design of your
electronics this may turn off
/// the power to the motor coils, saving
power.
/// This is useful to support Arduino low
power modes: disable the outputs
/// during sleep and then reenable with
enableOutputs() before stepping
/// again.
void disableOutputs();
/// Enable motor pin outputs by setting
the motor pins to OUTPUT
/// mode. Called automatically by the
constructor.
void enableOutputs();
/// Sets the minimum pulse width allowed
by the stepper driver.
/// \param[in] minWidth The minimum pulse
width in microseconds.
void setMinPulseWidth(unsigned int
minWidth);
protected:
/// Forces the library to compute a new
instantaneous speed and set that as
/// the current speed. Calls
/// desiredSpeed(), which can be
overridden by subclasses. It is called by
/// the library:
/// \li after each step
/// \li after change to maxSpeed through
setMaxSpeed()
/// \li after change to acceleration
through setAcceleration()
/// \li after change to target position
(relative or absolute) through
/// move() or moveTo()
void computeNewSpeed();
/// Called to execute a step. Only called
when a new step is
/// required. Subclasses may override to
implement new stepping
/// interfaces. The default calls
step1(), step2(), step4() or step8()
depending on the
/// number of pins defined for the
stepper.
/// \param[in] step The current step
phase number (0 to 7)
virtual void step(uint8_t step);
/// Called to execute a step using
stepper functions (pins = 0) Only called when
a new step is
/// required. Calls _forward() or
_backward() to perform the step
virtual void step0(void);
76
/// Called to execute a step on a stepper
drover (ie where pins == 1). Only called when
a new step is
/// required. Subclasses may override to
implement new stepping
/// interfaces. The default sets or
clears the outputs of Step pin1 to step,
/// and sets the output of _pin2 to the
desired direction. The Step pin (_pin1) is
pulsed for 1 microsecond
/// which is the minimum STEP pulse width
for the 3967 driver.
/// \param[in] step The current step
phase number (0 to 7)
virtual void step1(uint8_t step);
/// Called to execute a step on a 2 pin
motor. Only called when a new step is
/// required. Subclasses may override to
implement new stepping
/// interfaces. The default sets or
clears the outputs of pin1 and pin2
/// \param[in] step The current step
phase number (0 to 7)
virtual void step2(uint8_t step);
/// Called to execute a step on a 4 pin
motor. Only called when a new step is
/// required. Subclasses may override to
implement new stepping
/// interfaces. The default sets or
clears the outputs of pin1, pin2,
/// pin3, pin4.
/// \param[in] step The current step
phase number (0 to 7)
virtual void step4(uint8_t step);
/// Called to execute a step on a 4 pin
half-steper motor. Only called when a new
step is
/// required. Subclasses may override to
implement new stepping
/// interfaces. The default sets or
clears the outputs of pin1, pin2,
/// pin3, pin4.
/// \param[in] step The current step
phase number (0 to 7)
virtual void step8(uint8_t step);
/// Compute and return the desired speed.
The default algorithm uses
/// maxSpeed, acceleration and the
current speed to set a new speed to
/// move the motor from teh current
position to the target
/// position. Subclasses may override
this to provide an alternate
/// algorithm (but do not block). Called
by computeNewSpeed whenever a new speed neds
to be
/// computed.
virtual float desiredSpeed();
private:
/// Number of pins on the stepper motor.
Permits 2 or 4. 2 pins is a
/// bipolar, and 4 pins is a unipolar.
uint8_t _pins; // 2 or 4
/// Arduino pin number for the 2 or 4
pins required to interface to the
/// stepper motor.
uint8_t _pin1, _pin2, _pin3,
_pin4;
/// The current absolution position in
steps.
long _currentPos; //Steps
/// The target position in steps. The
AccelStepper library will move the
/// motor from teh _currentPos to the
_targetPos, taking into account the
/// max speed, acceleration and
deceleration
long _targetPos; //Steps /// The current motos speed in steps per
second
/// Positive is clockwise
float _speed;//Steps per second
/// The maximum permitted speed in steps
per second. Must be > 0.
float _maxSpeed;
/// The acceleration to use to accelerate
or decelerate the motor in steps
/// per second per second. Must be> 0
float _acceleration;
/// The current interval between steps in
microseconds
unsigned long _stepInterval;
/// The last run time (when runSpeed()
was last called) in microseconds
// unsigned long _lastRunTime;
/// The last step time in microseconds
unsigned long _lastStepTime;
/// The minimum allowed pulse width in
microseconds
unsigned int _minPulseWidth;
// The pointer to a forward-step
procedure
void (*_forward)();
// The pointer to a backward-step
procedure
void (*_backward)();
};
#endif
IRremote.cpp
/*
* IRremote
* Version 0.11 August, 2009
* Copyright 2009 Ken Shirriff
* For details, see
http://arcfn.com/2009/08/multi-protocol-
infrared-remote-library.html
* Interrupt code based on NECIRrcv by Joe
Knapp
* http://www.arduino.cc/cgi-
bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by
http://zovirl.com/2008/11/12/building-a-
universal-remote-with-an-arduino/
*/
#include "IRremote.h"
#include "IRremoteInt.h"
// Provides ISR
#include <avr/interrupt.h>
volatile irparams_t irparams;
// These versions of MATCH, MATCH_MARK, and
MATCH_SPACE are only for debugging.
// To use them, set DEBUG in IRremoteInt.h
// Normally macros are used for efficiency
#ifdef DEBUG
int MATCH(int measured, int desired) {
Serial.print("Testing: ");
Serial.print(TICKS_LOW(desired), DEC);
Serial.print(" <= ");
Serial.print(measured, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired), DEC);
return measured >= TICKS_LOW(desired) &&
measured <= TICKS_HIGH(desired);
}
int MATCH_MARK(int measured_ticks, int
desired_us) {
Serial.print("Testing mark ");
Serial.print(measured_ticks * USECPERTICK,
DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
77
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us +
MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us +
MARK_EXCESS), DEC);
return measured_ticks >=
TICKS_LOW(desired_us + MARK_EXCESS) &&
measured_ticks <= TICKS_HIGH(desired_us +
MARK_EXCESS);
}
int MATCH_SPACE(int measured_ticks, int
desired_us) {
Serial.print("Testing space ");
Serial.print(measured_ticks * USECPERTICK,
DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us -
MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us -
MARK_EXCESS), DEC);
return measured_ticks >=
TICKS_LOW(desired_us - MARK_EXCESS) &&
measured_ticks <= TICKS_HIGH(desired_us -
MARK_EXCESS);
}
#endif
void IRsend::sendNEC(unsigned long data, int
nbits)
{
enableIROut(38);
mark(NEC_HDR_MARK);
space(NEC_HDR_SPACE);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(NEC_BIT_MARK);
space(NEC_ONE_SPACE);
}
else {
mark(NEC_BIT_MARK);
space(NEC_ZERO_SPACE);
}
data <<= 1;
}
mark(NEC_BIT_MARK);
space(0);
}
void IRsend::sendSony(unsigned long data, int
nbits) {
enableIROut(40);
mark(SONY_HDR_MARK);
space(SONY_HDR_SPACE);
data = data << (32 - nbits);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(SONY_ONE_MARK);
space(SONY_HDR_SPACE);
}
else {
mark(SONY_ZERO_MARK);
space(SONY_HDR_SPACE);
}
data <<= 1;
}
}
void IRsend::sendRaw(unsigned int buf[], int
len, int hz)
{
enableIROut(hz);
for (int i = 0; i < len; i++) {
if (i & 1) {
space(buf[i]); }
else {
mark(buf[i]);
}
}
space(0); // Just to be sure
}
// Note: first bit must be a one (start bit)
void IRsend::sendRC5(unsigned long data, int
nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC5_T1); // First start bit
space(RC5_T1); // Second start bit
mark(RC5_T1); // Second start bit
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
space(RC5_T1); // 1 is space, then mark
mark(RC5_T1);
}
else {
mark(RC5_T1);
space(RC5_T1);
}
data <<= 1;
}
space(0); // Turn off at end
}
// Caller needs to take care of flipping the
toggle bit
void IRsend::sendRC6(unsigned long data, int
nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC6_HDR_MARK);
space(RC6_HDR_SPACE);
mark(RC6_T1); // start bit
space(RC6_T1);
int t;
for (int i = 0; i < nbits; i++) {
if (i == 3) {
// double-wide trailer bit
t = 2 * RC6_T1;
}
else {
t = RC6_T1;
}
if (data & TOPBIT) {
mark(t);
space(t);
}
else {
space(t);
mark(t);
}
data <<= 1;
}
space(0); // Turn off at end
}
void IRsend::mark(int time) {
// Sends an IR mark for the specified
number of microseconds.
// The mark output is modulated at the PWM
frequency.
TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM
output
delayMicroseconds(time);
}
/* Leave pin off for time (given in
microseconds) */
void IRsend::space(int time) {
// Sends an IR space for the specified
number of microseconds.
// A space is no output, so the PWM output
is disabled.
78
TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3
PWM output
delayMicroseconds(time);
}
void IRsend::enableIROut(int khz) {
// Enables IR output. The khz value
controls the modulation frequency in
kilohertz.
// The IR output will be on pin 3 (OC2B).
// This routine is designed for 36-40KHz;
if you use it for other values, it's up to
you
// to make sure it gives reasonable
results. (Watch out for overflow / underflow
/ rounding.)
// TIMER2 is used in phase-correct PWM
mode, with OCR2A controlling the frequency
and OCR2B
// controlling the duty cycle.
// There is no prescaling, so the output
frequency is 16MHz / (2 * OCR2A) // To turn
the output on and off, we leave the PWM
running, but connect and disconnect the
output pin.
// A few hours staring at the ATmega
documentation and this will all make sense.
// See my Secrets of Arduino PWM at
http://arcfn.com/2009/07/secrets-of-arduino-
pwm.html for details.
// Disable the Timer2 Interrupt (which is
used for receiving IR)
TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow
Interrupt
pinMode(3, OUTPUT);
digitalWrite(3, LOW); // When not sending
PWM, we want it low
// COM2A = 00: disconnect OC2A
// COM2B = 00: disconnect OC2B; to send
signal set to 10: OC2B non-inverted
// WGM2 = 101: phase-correct PWM with OCRA
as top
// CS2 = 000: no prescaling
TCCR2A = _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS20);
// The top value for the timer. The
modulation frequency will be SYSCLOCK / 2 /
OCR2A.
OCR2A = SYSCLOCK / 2 / khz / 1000;
OCR2B = OCR2A / 3; // 33% duty cycle
}
IRrecv::IRrecv(int recvpin)
{
irparams.recvpin = recvpin;
irparams.blinkflag = 0;
}
// initialization
void IRrecv::enableIRIn() {
// setup pulse clock timer interrupt
TCCR2A = 0; // normal mode
//Prescale /8 (16M/8 = 0.5 microseconds per
tick)
// Therefore, the timer interval can range
from 0.5 to 128 microseconds
//depending on the reset value (255 to 0)
cbi(TCCR2B,CS22);
sbi(TCCR2B,CS21);
cbi(TCCR2B,CS20);
//Timer2 Overflow Interrupt Enable
sbi(TIMSK2,TOIE2);
RESET_TIMER2;
sei(); // enable interrupts
// initialize state machine variables
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
// set pin modes
pinMode(irparams.recvpin, INPUT);
}
// enable/disable blinking of pin 13 on IR
processing void IRrecv::blink13(int blinkflag)
{
irparams.blinkflag = blinkflag;
if (blinkflag)
pinMode(BLINKLED, OUTPUT);
}
// TIMER2 interrupt code to collect raw data.
// Widths of alternating SPACE, MARK are
recorded in rawbuf.
// Recorded in ticks of 50 microseconds.
// rawlen counts the number of entries
recorded so far.
// First entry is the SPACE between
transmissions.
// As soon as a SPACE gets long, ready is
set, state switches to IDLE, timing of SPACE
continues.
// As soon as first MARK arrives, gap width
is recorded, ready is cleared, and new
logging starts
ISR(TIMER2_OVF_vect)
{
RESET_TIMER2;
uint8_t irdata =
(uint8_t)digitalRead(irparams.recvpin);
irparams.timer++; // One more 50us tick
if (irparams.rawlen >= RAWBUF) {
// Buffer overflow
irparams.rcvstate = STATE_STOP;
}
switch(irparams.rcvstate) {
case STATE_IDLE: // In the middle of a gap
if (irdata == MARK) {
if (irparams.timer < GAP_TICKS) {
// Not big enough to be a gap.
irparams.timer = 0;
}
else {
// gap just ended, record duration
and start recording transmission
irparams.rawlen = 0;
irparams.rawbuf[irparams.rawlen++] =
irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
}
break;
case STATE_MARK: // timing MARK
if (irdata == SPACE) { // MARK ended,
record time
irparams.rawbuf[irparams.rawlen++] =
irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_SPACE;
}
break;
case STATE_SPACE: // timing SPACE
if (irdata == MARK) { // SPACE just
ended, record it
irparams.rawbuf[irparams.rawlen++] =
irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
else { // SPACE
if (irparams.timer > GAP_TICKS) {
// big SPACE, indicates gap between
codes
// Mark current code as ready for
processing
// Switch to STOP
// Don't reset timer; keep counting
space width
irparams.rcvstate = STATE_STOP;
79
}
}
break;
case STATE_STOP: // waiting, measuring gap
if (irdata == MARK) { // reset gap timer
irparams.timer = 0;
}
break;
}
if (irparams.blinkflag) {
if (irdata == MARK) {
PORTB |= B00100000; // turn pin 13 LED
on
}
else {
PORTB &= B11011111; // turn pin 13 LED off
}
}
}
void IRrecv::resume() {
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
}
// Decodes the received IR message
// Returns 0 if no data ready, 1 if data
ready.
// Results of decoding are stored in results
int IRrecv::decode(decode_results *results) {
results->rawbuf = irparams.rawbuf;
results->rawlen = irparams.rawlen;
if (irparams.rcvstate != STATE_STOP) {
return ERR;
}
#ifdef DEBUG
Serial.println("Attempting NEC decode");
#endif
if (decodeNEC(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting Sony decode");
#endif
if (decodeSony(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting RC5 decode");
#endif
if (decodeRC5(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting RC6 decode");
#endif
if (decodeRC6(results)) {
return DECODED;
}
if (results->rawlen >= 6) {
// Only return raw buffer if at least 6
bits
results->decode_type = UNKNOWN;
results->bits = 0;
results->value = 0;
return DECODED;
}
// Throw away and start over
resume();
return ERR;
}
long IRrecv::decodeNEC(decode_results
*results) {
long data = 0;
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset],
NEC_HDR_MARK)) {
return ERR;
}
offset++; // Check for repeat
if (irparams.rawlen == 4 &&
MATCH_SPACE(results->rawbuf[offset],
NEC_RPT_SPACE) &&
MATCH_MARK(results->rawbuf[offset+1],
NEC_BIT_MARK)) {
results->bits = 0;
results->value = REPEAT;
results->decode_type = NEC;
return DECODED;
}
if (irparams.rawlen < 2 * NEC_BITS + 4) {
return ERR;
}
// Initial space
if (!MATCH_SPACE(results->rawbuf[offset],
NEC_HDR_SPACE)) {
return ERR;
}
offset++;
for (int i = 0; i < NEC_BITS; i++) {
if (!MATCH_MARK(results->rawbuf[offset],
NEC_BIT_MARK)) {
return ERR;
}
offset++;
if (MATCH_SPACE(results->rawbuf[offset],
NEC_ONE_SPACE)) {
data = (data << 1) | 1;
}
else if (MATCH_SPACE(results-
>rawbuf[offset], NEC_ZERO_SPACE)) {
data <<= 1;
}
else {
return ERR;
}
offset++;
}
// Success
results->bits = NEC_BITS;
results->value = data;
results->decode_type = NEC;
return DECODED;
}
long IRrecv::decodeSony(decode_results
*results) {
long data = 0;
if (irparams.rawlen < 2 * SONY_BITS + 2) {
return ERR;
}
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset],
SONY_HDR_MARK)) {
return ERR;
}
offset++;
while (offset + 1 < irparams.rawlen) {
if (!MATCH_SPACE(results->rawbuf[offset],
SONY_HDR_SPACE)) {
break;
}
offset++;
if (MATCH_MARK(results->rawbuf[offset],
SONY_ONE_MARK)) {
data = (data << 1) | 1;
}
else if (MATCH_MARK(results-
>rawbuf[offset], SONY_ZERO_MARK)) {
data <<= 1;
}
else {
return ERR;
}
offset++;
80
}
// Success
results->bits = (offset - 1) / 2;
if (results->bits < 12) {
results->bits = 0;
return ERR;
}
results->value = data;
results->decode_type = SONY;
return DECODED;
}
// Gets one undecoded level at a time from
the raw buffer.
// The RC5/6 decoding is easier if the data
is broken into time intervals.
// E.g. if the buffer has MARK for 2 time
intervals and SPACE for 1,
// successive calls to getRClevel will return
MARK, MARK, SPACE.
// offset and used are updated to keep track
of the current position.
// t1 is the time interval for a single bit
in microseconds.
// Returns -1 for error (measured time
interval is not a multiple of t1).
int IRrecv::getRClevel(decode_results
*results, int *offset, int *used, int t1) {
if (*offset >= results->rawlen) {
// After end of recorded buffer, assume
SPACE.
return SPACE;
}
int width = results->rawbuf[*offset];
int val = ((*offset) % 2) ? MARK : SPACE;
int correction = (val == MARK) ?
MARK_EXCESS : - MARK_EXCESS;
int avail;
if (MATCH(width, t1 + correction)) {
avail = 1;
}
else if (MATCH(width, 2*t1 + correction)) {
avail = 2;
}
else if (MATCH(width, 3*t1 + correction)) {
avail = 3;
}
else {
return -1;
}
(*used)++;
if (*used >= avail) {
*used = 0;
(*offset)++;
}
#ifdef DEBUG
if (val == MARK) {
Serial.println("MARK");
}
else {
Serial.println("SPACE");
}
#endif
return val;
}
long IRrecv::decodeRC5(decode_results
*results) {
if (irparams.rawlen < MIN_RC5_SAMPLES + 2)
{
return ERR;
}
int offset = 1; // Skip gap space
long data = 0;
int used = 0;
// Get start bits
if (getRClevel(results, &offset, &used,
RC5_T1) != MARK) return ERR;
if (getRClevel(results, &offset, &used,
RC5_T1) != SPACE) return ERR; if (getRClevel(results, &offset, &used,
RC5_T1) != MARK) return ERR;
int nbits;
for (nbits = 0; offset < irparams.rawlen;
nbits++) {
int levelA = getRClevel(results, &offset,
&used, RC5_T1);
int levelB = getRClevel(results, &offset,
&used, RC5_T1);
if (levelA == SPACE && levelB == MARK) {
// 1 bit
data = (data << 1) | 1;
}
else if (levelA == MARK && levelB ==
SPACE) {
// zero bit
data <<= 1;
}
else {
return ERR;
}
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = RC5;
return DECODED;
}
long IRrecv::decodeRC6(decode_results
*results) {
if (results->rawlen < MIN_RC6_SAMPLES) {
return ERR;
}
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset],
RC6_HDR_MARK)) {
return ERR;
}
offset++;
if (!MATCH_SPACE(results->rawbuf[offset],
RC6_HDR_SPACE)) {
return ERR;
}
offset++;
long data = 0;
int used = 0;
// Get start bit (1)
if (getRClevel(results, &offset, &used,
RC6_T1) != MARK) return ERR;
if (getRClevel(results, &offset, &used,
RC6_T1) != SPACE) return ERR;
int nbits;
for (nbits = 0; offset < results->rawlen;
nbits++) {
int levelA, levelB; // Next two levels
levelA = getRClevel(results, &offset,
&used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure
second half matches
if (levelA != getRClevel(results,
&offset, &used, RC6_T1)) return ERR;
}
levelB = getRClevel(results, &offset,
&used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure
second half matches
if (levelB != getRClevel(results,
&offset, &used, RC6_T1)) return ERR;
}
if (levelA == MARK && levelB == SPACE) {
// reversed compared to RC5
// 1 bit
81
data = (data << 1) | 1;
}
else if (levelA == SPACE && levelB ==
MARK) {
// zero bit
data <<= 1;
}
else {
return ERR; // Error
}
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = RC6;
return DECODED;
}
IRremote.h
/* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see
http://arcfn.com/2009/08/multi-protocol-
infrared-remote-library.html
* Interrupt code based on NECIRrcv by Joe
Knapp
* http://www.arduino.cc/cgi-
bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by
http://zovirl.com/2008/11/12/building-a-
universal-remote-with-an-arduino/
*/
#include <Arduino.h>
#ifndef IRremoteint_h
#define IRremoteint_h
#ifndef IRremote_h
#include "IRremote.h"
#endif
#define CLKFUDGE 5 // fudge factor for
clock interrupt overhead
#define CLK 256 // max value for clock
(timer 2)
#define PRESCALE 8 // timer2 clock
prescale
#define SYSCLOCK 16000000 // main Arduino
clock
#define CLKSPERUSEC
(SYSCLOCK/PRESCALE/1000000) // timer clocks
per microsecond
#define ERR 0
#define DECODED 1
#define BLINKLED 13
// defines for setting and clearing register
bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &=
~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |=
_BV(bit))
#endif
// clock timer reset value
#define INIT_TIMER_COUNT2 (CLK -
USECPERTICK*CLKSPERUSEC + CLKFUDGE)
#define RESET_TIMER2 TCNT2 =
INIT_TIMER_COUNT2
// pulse parameters in usec
#define NEC_HDR_MARK 9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE 560
#define NEC_RPT_SPACE 2250
#define SONY_HDR_MARK 2400
#define SONY_HDR_SPACE 600 #define SONY_ONE_MARK 1200
#define SONY_ZERO_MARK 600
#define SONY_RPT_LENGTH 45000
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#define RC6_RPT_LENGTH 46000
#define TOLERANCE 25 // percent tolerance in
measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)
#define _GAP 5000 // Minimum map between
transmissions
#define GAP_TICKS (_GAP/USECPERTICK)
#define TICKS_LOW(us) (int)
(((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int)
(((us)*UTOL/USECPERTICK + 1))
#ifndef DEBUG
#define MATCH(measured_ticks, desired_us)
((measured_ticks) >= TICKS_LOW(desired_us) &&
(measured_ticks) <= TICKS_HIGH(desired_us))
#define MATCH_MARK(measured_ticks,
desired_us) MATCH(measured_ticks,
(desired_us) + MARK_EXCESS)
#define MATCH_SPACE(measured_ticks,
desired_us) MATCH((measured_ticks),
(desired_us) - MARK_EXCESS)
// Debugging versions are in IRremote.cpp
#endif
// receiver states
#define STATE_IDLE 2
#define STATE_MARK 3
#define STATE_SPACE 4
#define STATE_STOP 5
// information for the interrupt handler
typedef struct {
uint8_t recvpin; // pin for IR
data from detector
uint8_t rcvstate; // state machine
uint8_t blinkflag; // TRUE to
enable blinking of pin 13 on IR processing
unsigned int timer; // state timer,
counts 50uS ticks.
unsigned int rawbuf[RAWBUF]; // raw data
uint8_t rawlen; // counter of
entries in rawbuf
}
irparams_t;
// Defined in IRremote.cpp
extern volatile irparams_t irparams;
// IR detector output is active low
#define MARK 0
#define SPACE 1
#define TOPBIT 0x80000000
#define NEC_BITS 32
#define SONY_BITS 12
#define MIN_RC5_SAMPLES 11
#define MIN_RC6_SAMPLES 1
#endif
IRremoteInt.h
/* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see
http://arcfn.com/2009/08/multi-protocol-
infrared-remote-library.htm http://arcfn.com
* Interrupt code based on NECIRrcv by Joe
Knapp
* http://www.arduino.cc/cgi-
bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by
http://zovirl.com/2008/11/12/building-a-
universal-remote-with-an-arduino/
82
*/
#ifndef IRremote_h
#define IRremote_h
// The following are compile-time library
options.
// If you change them, recompile the library.
// If DEBUG is defined, a lot of debugging
output will be printed during decoding.
// TEST must be defined for the IRtest
unittests to work. It will make some
// methods virtual, which will be slightly
slower, which is why it is optional.
// #define DEBUG
// #define TEST
// Results returned from the decoder
class decode_results {
public:
int decode_type; // NEC, SONY, RC5, UNKNOWN
unsigned long value; // Decoded value
int bits; // Number of bits in decoded
value
volatile unsigned int *rawbuf; // Raw
intervals in .5 us ticks
int rawlen; // Number of records in rawbuf.
};
// Values for decode_type
#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define UNKNOWN -1
// Decoded value for NEC when a repeat code
is received
#define REPEAT 0xffffffff
// main class for receiving IR
class IRrecv
{
public:
IRrecv(int recvpin);
void blink13(int blinkflag);
int decode(decode_results *results);
void enableIRIn();
void resume();
private:
// These are called by decode
int getRClevel(decode_results *results, int
*offset, int *used, int t1);
long decodeNEC(decode_results *results);
long decodeSony(decode_results *results);
long decodeRC5(decode_results *results);
long decodeRC6(decode_results *results);
}
;
// Only used for testing; can remove virtual
for shorter code
#ifdef TEST
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif
class IRsend
{
public:
IRsend() {}
void sendNEC(unsigned long data, int
nbits);
void sendSony(unsigned long data, int
nbits);
void sendRaw(unsigned int buf[], int len,
int hz);
void sendRC5(unsigned long data, int
nbits);
void sendRC6(unsigned long data, int
nbits);
// private:
void enableIROut(int khz);
VIRTUAL void mark(int usec);
VIRTUAL void space(int usec); }
;
// Some useful constants
#define USECPERTICK 50 // microseconds per
clock interrupt tick
#define RAWBUF 76 // Length of raw duration
buffer
// Marks tend to be 100us too long, and
spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100
#endif
LabVIEWInterface.h
/**LVFA_Firmware - Provides Functions For
Interfacing With The Arduino Uno
** Written By: Sam Kristoff - National
Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort -
National Instruments
** This File May Be Modified And Re-
Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At
www.ni.com/arduino.**************/
/*******Define Constants
** Define directives providing meaningful
names for constant values.***********/
#define FIRMWARE_MAJOR 02
#define FIRMWARE_MINOR 00
#if defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
#define DEFAULTBAUDRATE 9600 // Defines
The Default Serial Baud Rate (This must match
the baud rate specifid in LabVIEW)
#else
//#define DEFAULTBAUDRATE 115200
#endif
#define MODE_DEFAULT 0 // Defines
Arduino Modes (Currently Not Used)
#define COMMANDLENGTH 15 // Defines
The Number Of Bytes In A Single LabVIEW
Command (This must match the packet size
specifid in LabVIEW)
#define STEPPER_SUPPORT 1 // Defines
Whether The Stepper Library Is Included -
Comment This Line To Exclude Stepper Support
// Declare Variables
unsigned char currentCommand[COMMANDLENGTH];
// The Current Command For The Arduino To
Process
//Globals for continuous aquisition
unsigned char acqMode;
unsigned char contAcqPin;
float contAcqSpeed;
float acquisitionPeriod;
float iterationsFlt;
int iterations;
float delayTime;
/** syncLV
** Synchronizes with LabVIEW and sends info
about the board and firmware (Unimplemented)
** Input: None
** Output: None
**************************************/
void syncLV();
/**************************************
** setMode
** Sets the mode of the Arduino (Reserved
For Future Use)
** Input: Int - Mode
** Output: None
**************************************/
void setMode(int mode);
83
/****************************************
checkForCommand
** Checks for new commands from LabVIEW and
processes them if any exists.
** Input: None
** Output: 1 - Command received and
processed
** 0 - No new command
**************************************/
int checkForCommand(void);
/**************************************
** processCommand
** Processes a given command
** Input: command of COMMANDLENGTH bytes
** Output: 1 - Command received and
processed
** 0 - No new command
**************************************/
void processCommand(unsigned char command[]);
/****************************************
writeDigitalPort
**
** Write values to DIO pins 0 - 13. Pins
must first be configured as outputs.
** Input: Command containing digital port
data
** Output: None
**************************************/
void writeDigitalPort(unsigned char
command[]);
/**************************************
** analogReadPort
** Reads all 6 analog input ports, builds 8
byte packet, send via RS232.
** Input: None
** Output: None
**************************************/
void analogReadPort();
/**************************************
** sevenSegment_Config
** Configure digital I/O pins to use for
seven segment display. Pins are stored in
sevenSegmentPins array.
** Input: Pins to use for seven segment LED
[A, B, C, D, E, F, G, DP]
** Output: None
**************************************/
void sevenSegment_Config(unsigned char
command[]);
/**************************************
** sevenSegment_Write
** Write values to sevenSegment display.
Must first use sevenSegment_Configure
** Input: Eight values to write to seven
segment display
** Output: None
**************************************/
void sevenSegment_Write(unsigned char
command[]);
/**************************************
** spi_setClockDivider
** Set the SPI Clock Divisor
** Input: SPI Clock Divider 2, 4, 8, 16,
32, 64, 128
** Output: None
**************************************/
void spi_setClockDivider(unsigned char
divider);
/****************************************
spi_sendReceive
** Sens / Receive SPI Data
** Input: Command Packet
** Output: None (This command sends one
serail byte back to LV for each data byte.
**************************************/
void spi_sendReceive(unsigned char
command[]);
/****************************************
checksum_Compute ** Compute Packet Checksum
** Input: Command Packet
** Output: Char Checksum Value
*************************************/
unsigned char checksum_Compute(unsigned char
command[]);
/****************************************
checksum_Test
** Compute Packet Checksum And Test Against
Included Checksum
** Input: Command Packet
** Output: 0 If Checksums Are Equal, Else 1
*************************************/
int checksum_Test(unsigned char command[]);
/**************************************
** AccelStepper_Write
** Parse command packet and write speed,
direction, and number of steps to travel
** Input: Command Packet
** Output: None
**************************************/
void AccelStepper_Write(unsigned char
command[]);
/****************************************
SampleContinuosly
** Returns several analog input points at
once.
** Input: void
** Output: void
************************************/
void sampleContinously(void);
/****************************************
finiteAcquisition
** Returns the number of samples specified
at the rate specified.
** Input: pin to sampe on, speed to sample
at, number of samples
** Output: void
************************************/
void finiteAcquisition(int analogPin, float
acquisitionSpeed, int numberOfSamples );
/****************************************
lcd_print
** Prints Data to the LCD With The Given
Base
** Input: Command Packet
** Output: None*********/
void lcd_print(unsigned char command[]);
LabVIEWInterface
/*** LVIFA_Firmware - Provides Functions For
Interfacing With The Arduino Uno
** Written By: Sam Kristoff - National
Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort -
National Instruments
** This File May Be Modified And Re-
Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At
www.ni.com/arduino.********/
#include <Wire.h>
#include <SPI.h>
#include <LiquidCrystal.h>
//Includes for IR Remote
#ifndef IRremoteInt_h
#include "IRremoteInt.h"
#endif
#ifndef IRremote_h
#include "IRremote.h"
#endif
/**************************************
Optionally Include And Configure Stepper
Support
************************************/
#ifdef STEPPER_SUPPORT
84
// Stepper Modifications
#include "AFMotor.h"
#include "AccelStepper.h"
// Adafruit shield
AF_Stepper motor1(200, 1);
AF_Stepper motor2(200, 2);
// you can change these to DOUBLE or
INTERLEAVE or MICROSTEP
// wrappers for the first motor
void forwardstep1() {
motor1.onestep(FORWARD, SINGLE);
}
void backwardstep1() {
motor1.onestep(BACKWARD, SINGLE);
}
// wrappers for the second motor
void forwardstep2() {
motor2.onestep(FORWARD, SINGLE);
}
void backwardstep2() {
motor2.onestep(BACKWARD, SINGLE);
}
AccelStepper steppers[8]; //Create array
of 8 stepper objects
#endif
// Variables
unsigned int retVal;
int sevenSegmentPins[8];
int currentMode;
unsigned int freq;
unsigned long duration;
int i2cReadTimeouts = 0;
char spiBytesToSend = 0;
char spiBytesSent = 0;
char spiCSPin = 0;
char spiWordSize = 0;
Servo *servos;
byte customChar[8];
LiquidCrystal lcd(0,0,0,0,0,0,0);
unsigned long IRdata;
IRsend irsend;
// Sets the mode of the Arduino (Reserved For
Future Use)
void setMode(int mode)
{
currentMode = mode;
}
// Checks for new commands from LabVIEW and
processes them if any exists.
int checkForCommand(void)
{
#ifdef STEPPER_SUPPORT
// Call run function as fast as possible to
keep motors turning
for (int i=0; i<8; i++){
steppers[i].run();
}
#endif
int bufferBytes = Serial.available();
if(bufferBytes >= COMMANDLENGTH)
{
// New Command Ready, Process It
// Build Command From Serial Buffer
for(int i=0; i<COMMANDLENGTH; i++)
{
currentCommand[i] = Serial.read();
}
processCommand(currentCommand);
return 1;
}
else
{
return 0;
}
}
// Processes a given command
void processCommand(unsigned char command[])
{ // Determine Command
if(command[0] == 0xFF &&
checksum_Test(command) == 0)
{
switch(command[1])
{
/**************************************
** LIFA Maintenance Commands
***********************************/
case 0x00: // Sync Packet
Serial.print("sync");
Serial.flush();
break;
case 0x01: // Flush Serial Buffer
Serial.flush();
break;
/************************************** **
Low Level - Digital I/O Commands
************************************/
case 0x02: //Set Pin As Input Or
Output
pinMode(command[2], command[3]);
Serial.write('0');
break;
case 0x03: // Write Digital Pin
digitalWrite(command[2], command[3]);
Serial.write('0');
break;
case 0x04: //Write Digital Port 0
writeDigitalPort(command);
Serial.write('0');
break;
case 0x05: //Tone
freq = ( (command[3]<<8) + command[4]);
duration=(command[8]+ (command[7]<<8)+
(command[6]<<16)+(command[5]<<24));
if(freq > 0)
{
tone(command[2], freq, duration);
}
else
{
noTone(command[2]);
}
Serial.write('0');
break;
case 0x06: // Read Digital Pin
retVal = digitalRead(command[2]);
Serial.write(retVal);
break;
case 0x07: // Digital Read Port
retVal = 0x0000;
for(int i=0; i <=13; i++)
{
if(digitalRead(i))
{
retVal += (1<<i);
}
}
Serial.write( (retVal & 0xFF));
Serial.write( (retVal >> 8));
break;
/****************************************
** Low Level - Analog Commands
***************************************/
case 0x08: // Read Analog Pin
retVal = analogRead(command[2]);
Serial.write( (retVal >> 8));
Serial.write( (retVal & 0xFF));
break;
case 0x09: // Analog Read Port
analogReadPort();
break;
/****************************************
** Low Level - PWM Commands
****************************************/
85
case 0x0A: // PWM Write Pin
analogWrite(command[2], command[3]);
Serial.write('0');
break;
case 0x0B: // PWM Write 3 Pins
analogWrite(command[2], command[5]);
analogWrite(command[3], command[6]);
analogWrite(command[4], command[7]);
Serial.write('0');
break;
/****************************************
** Sensor Specific Commands
****************************************/
case 0x0C: // Configure Seven Segment
Display
sevenSegment_Config(command);
Serial.write('0');
break;
case 0x0D: // Write To Seven Segment
Display
sevenSegment_Write(command);
Serial.write('0');
break;
/****************************************
** I2C
****************************************/
case 0x0E: // Initialize I2C
Wire.begin();
Serial.write('0');
break;
case 0x0F: // Send I2C Data
Wire.beginTransmission(command[3]);
for(int i=0; i<command[2]; i++)
{
#if defined(ARDUINO) && ARDUINO >=
100
Wire.write(command[i+4]);
#else
Wire.send(command[i+4]);
#endif
}
Wire.endTransmission();
Serial.write('0');
break;
case 0x10: // I2C Read
i2cReadTimeouts = 0;
Wire.requestFrom(command[3],
command[2]);
while(Wire.available() < command[2])
{
i2cReadTimeouts++;
if(i2cReadTimeouts > 100)
{
return;
}
else
{
delay(1);
}
}
for(int i=0; i<command[2]; i++)
{
#if defined(ARDUINO) && ARDUINO >=
100
Serial.write(Wire.read());
#else
Serial.write(Wire.receive());
#endif
}
break;
/****************************************
** SPI
***************************************/
case 0x11: // SPI Init
SPI.begin();
Serial.write('0');
break;
case 0x12: // SPI Set Bit Order (MSB
LSB) if(command[2] == 0)
{
SPI.setBitOrder(LSBFIRST);
}
else
{
SPI.setBitOrder(MSBFIRST);
}
Serial.write('0');
break;
case 0x13: // SPI Set Clock Divider
spi_setClockDivider(command[2]);
Serial.write('0');
break;
case 0x14: // SPI Set Data Mode
switch(command[2])
{
case 0:
SPI.setDataMode(SPI_MODE0);
break;
case 1:
SPI.setDataMode(SPI_MODE1);
break;
case 2:
SPI.setDataMode(SPI_MODE2);
break;
case 3:
SPI.setDataMode(SPI_MODE3);
break;
default:
break;
}
Serial.write('0');
break;
case 0x15: // SPI Send / Receive
spi_sendReceive(command);
break;
case 0x16: // SPI Close
SPI.end();
Serial.write('0');
break;
/********Servos ****************/
case 0x17: // Set Num Servos
free(servos);
servos = (Servo*)
malloc(command[2]*sizeof(Servo));
for(int i=0; i<command[2]; i++)
{
servos[i] = Servo();
}
if(servos == 0)
{
Serial.write('1');
}
else
{
Serial.write('0');
}
break;
case 0x18: // Configure Servo
servos[command[2]].attach(command[3]);
Serial.write('0');
break;
case 0x19: // Servo Write
servos[command[2]].write(command[3]);
Serial.write('0');
break;
case 0x1A: // Servo Read Angle
Serial.write(servos[command[2]].read());
break;
case 0x1B: // Servo Write uS Pulse
servos[command[2]].writeMicroseconds(
(command[3] + (command[4]<<8)) );
Serial.write('0');
break;
case 0x1C: // Servo Read uS Pulse
86
retVal =
servos[command[2]].readMicroseconds();
Serial.write ((retVal & 0xFF));
Serial.write( (retVal >> 8));
break;
case 0x1D: // Servo Detach
servos[command[2]].detach();
Serial.write('0');
break;
/***********LCD **********************/
case 0x1E: // LCD Init
lcd.init(command[2], command[3],
command[4], command[5], command[6],
command[7], command[8], command[9],
command[10], command[11], command[12],
command[13]);
Serial.write('0');
break;
case 0x1F: // LCD Set Size
lcd.begin(command[2], command[3]);
Serial.write('0');
break;
case 0x20: // LCD Set Cursor Mode
if(command[2] == 0)
{
lcd.noCursor();
}
else
{
lcd.cursor();
}
if(command[3] == 0)
{
lcd.noBlink();
}
else
{
lcd.blink();
}
Serial.write('0');
break;
case 0x21: // LCD Clear
lcd.clear();
Serial.write('0');
break;
case 0x22: // LCD Set Cursor Position
lcd.setCursor(command[2],
command[3]);
Serial.write('0');
break;
case 0x23: // LCD Print
lcd_print(command);
break;
case 0x24: // LCD Display Power
if(command[2] == 0)
{
lcd.noDisplay();
}
else
{
lcd.display();
}
Serial.write('0');
break;
case 0x25: // LCD Scroll
if(command[2] == 0)
{
lcd.scrollDisplayLeft();
}
else
{
lcd.scrollDisplayRight();
}
Serial.write('0');
break;
case 0x26: // LCD Autoscroll
if(command[2] == 0)
{ lcd.noAutoscroll();
}
else
{
lcd.autoscroll();
}
Serial.write('0');
break;
case 0x27: // LCD Print Direction
if(command[2] == 0)
{
lcd.rightToLeft();
}
else
{
lcd.leftToRight();
}
Serial.write('0');
break;
case 0x28: // LCD Create Custom Char
for(int i=0; i<8; i++)
{
customChar[i] = command[i+3];
}
lcd.createChar(command[2],
customChar);
Serial.write('0');
break;
case 0x29: // LCD Print Custom Char
lcd.write(command[2]);
Serial.write('0');
break;
/****************************************
** Continuous Aquisition
****************************************/
case 0x2A: // Continuous Aquisition
Mode On
acqMode=1;
contAcqPin=command[2];
contAcqSpeed=(command[3])+(command[4]<<8)
acquisitionPeriod=1/contAcqSpeed;
iterationsFlt =.08/acquisitionPeriod;
iterations=(int)iterationsFlt;
if(iterations<1)
{
iterations=1;
}
delayTime= acquisitionPeriod;
if(delayTime<0)
{
delayTime=0;
}
break;
case 0x2B: // Continuous Aquisition
Mode Off
acqMode=0;
break;
case 0x2C: // Return Firmware Revision
Serial.write(byte(FIRMWARE_MAJOR));
Serial.write(byte(FIRMWARE_MINOR));
break;
case 0x2D: // Perform Finite Aquisition
Serial.write('0');
finiteAcquisition(command[2],(command[3])+(co
mmand[4]<<8),command[5]+(command[6]<<8));
break;
/****************************************
** Stepper
****************************************/
#ifdef STEPPER_SUPPORT
case 0x30: // Configure Stepper
if (command[2] == 5){ // Support
AFMotor Shield
switch (command[3]){
case 0:
87
steppers[command[3]] =
AccelStepper(forwardstep1, backwardstep1);
break;
case 1:
steppers[command[3]] =
AccelStepper(forwardstep2, backwardstep2);
break;
default:
break;
}
}
else if(command[2]==6) {
// All other stepper configurations
steppers[command[3]] =
AccelStepper(1,
command[4],command[5],command[6],command[7]);
}
else{
steppers[command[3]] =
AccelStepper(command[2],
command[4],command[5],command[6],command[7]);
}
Serial.write('0');
break;
case 0x31: // Stepper Write
AccelStepper_Write(command);
Serial.write('0');
break;
case 0x32: // Stepper Detach
steppers[command[2]].disableOutputs();
Serial.write('0');
break;
case 0x33: // Stepper steps to go
retVal = 0;
for(int i=0; i<8; i++){
retVal +=
steppers[i].distanceToGo();
}
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 8) );
break;
#endif
/****************************************
** IR Transmit
****************************************/
case 0x34: // IR Transmit
IRdata = ((unsigned long)command [4] <<
24) | ((unsigned long)command [5] << 16) |
((unsigned long)command [6] << 8) |
((unsigned long)command [7]);
switch(command[2])
{
case 0x00: // NEC
irsend.sendNEC(IRdata, command[3]);
break;
case 0x01: //Sony
irsend.sendSony(IRdata,
command[3]);
break;
case 0x02: //RC5
irsend.sendRC5(IRdata, command[3]);
break;
case 0x03: //RC6
irsend.sendRC6(IRdata, command[3]);
break;
}
Serial.write((IRdata>>16) & 0xFF);
break;
/****************************************
** Unknown Packet
****************************************/
default: // Default Case
Serial.flush();
break;
}
}
else{
// Checksum Failed, Flush Serial Buffer Serial.flush();
}
}
/******************************************
Functions
****************************************/
// Writes Values To Digital Port (DIO 0-13).
Pins Must Be Configured As Outputs Before
Being Written To
void writeDigitalPort(unsigned char
command[])
{
digitalWrite(13, (( command[2] >> 5) &
0x01) );
digitalWrite(12, (( command[2] >> 4) &
0x01) );
digitalWrite(11, (( command[2] >> 3) &
0x01) );
digitalWrite(10, (( command[2] >> 2) &
0x01) );
digitalWrite(9, (( command[2] >> 1) & 0x01)
);
digitalWrite(8, (command[2] & 0x01) );
digitalWrite(7, (( command[3] >> 7) & 0x01)
);
digitalWrite(6, (( command[3] >> 6) & 0x01)
);
digitalWrite(5, (( command[3] >> 5) & 0x01)
);
digitalWrite(4, (( command[3] >> 4) & 0x01)
);
digitalWrite(3, (( command[3] >> 3) & 0x01)
);
digitalWrite(2, (( command[3] >> 2) & 0x01)
);
digitalWrite(1, (( command[3] >> 1) & 0x01)
);
digitalWrite(0, (command[3] & 0x01) );
}
// Reads all 6 analog input ports, builds 8
byte packet, send via RS232.
void analogReadPort()
{
// Read Each Analog Pin
int pin0 = analogRead(0);
int pin1 = analogRead(1);
int pin2 = analogRead(2);
int pin3 = analogRead(3);
int pin4 = analogRead(4);
int pin5 = analogRead(5);
//Build 8-Byte Packet From 60 Bits of Data
Read
char output0 = (pin0 & 0xFF);
char output1 = ( ((pin1 << 2) & 0xFC) | (
(pin0 >> 8) & 0x03) );
char output2 = ( ((pin2 << 4) & 0xF0) | (
(pin1 >> 6) & 0x0F) );
char output3 = ( ((pin3 << 6) & 0xC0) | (
(pin2 >> 4) & 0x3F) );
char output4 = ( (pin3 >> 2) & 0xFF);
char output5 = (pin4 & 0xFF);
char output6 = ( ((pin5 << 2) & 0xFC) | (
(pin4 >> 8) & 0x03) );
char output7 = ( (pin5 >> 6) & 0x0F );
// Write Bytes To Serial Port
Serial.print(output0);
Serial.print(output1);
Serial.print(output2);
Serial.print(output3);
Serial.print(output4);
Serial.print(output5);
Serial.print(output6);
Serial.print(output7);
}
// Configure digital I/O pins to use for
seven segment display
88
void sevenSegment_Config(unsigned char
command[])
{
// Configure pins as outputs and store in
sevenSegmentPins array for use in
sevenSegment_Write
for(int i=2; i<10; i++)
{
pinMode(command[i], OUTPUT);
sevenSegmentPins[(i-1)] = command[i];
}
}
// Write values to sevenSegment display.
Must first use sevenSegment_Configure
void sevenSegment_Write(unsigned char
command[])
{
for(int i=1; i<9; i++)
{
digitalWrite(sevenSegmentPins[(i-1)],
command[i]);
}
}
// Set the SPI Clock Divisor
void spi_setClockDivider(unsigned char
divider)
{
switch(divider)
{
case 0:
SPI.setClockDivider(SPI_CLOCK_DIV2);
break;
case 1:
SPI.setClockDivider(SPI_CLOCK_DIV4);
break;
case 2:
SPI.setClockDivider(SPI_CLOCK_DIV8);
break;
case 3:
SPI.setClockDivider(SPI_CLOCK_DIV16);
break;
case 4:
SPI.setClockDivider(SPI_CLOCK_DIV32);
break;
case 5:
SPI.setClockDivider(SPI_CLOCK_DIV64);
break;
case 6:
SPI.setClockDivider(SPI_CLOCK_DIV128);
break;
default:
SPI.setClockDivider(SPI_CLOCK_DIV4);
break;
}
}
void spi_sendReceive(unsigned char command[])
{
if(command[2] == 1) //Check to see
if this is the first of a series of SPI
packets
{
spiBytesSent = 0;
spiCSPin = command[3];
spiWordSize = command[4];
// Send First Packet's 8 Data Bytes
for(int i=0; i<command[5]; i++)
{
// If this is the start of a new word
toggle CS LOW
if( (spiBytesSent == 0) ||
(spiBytesSent % spiWordSize == 0) )
{
digitalWrite(spiCSPin, LOW);
}
// Send SPI Byte
Serial.print(SPI.transfer(command[i+6])); spiBytesSent++;
// If word is complete set CS High
if(spiBytesSent % spiWordSize == 0)
{
digitalWrite(spiCSPin, HIGH);
}
}
}
else
{
// SPI Data Packet - Send SPI Bytes
for(int i=0; i<command[3]; i++)
{
// If this is the start of a new word
toggle CS LOW
if( (spiBytesSent == 0) ||
(spiBytesSent % spiWordSize == 0) )
{
digitalWrite(spiCSPin, LOW);
}
// Send SPI Byte
Serial.write(SPI.transfer(command[i+4]));
spiBytesSent++;
// If word is complete set CS High
if(spiBytesSent % spiWordSize == 0)
{
digitalWrite(spiCSPin, HIGH);
}
}
}
}
// Synchronizes with LabVIEW and sends info
about the board and firmware (Unimplemented)
void syncLV()
{
Serial.begin(9600);
i2cReadTimeouts = 0;
spiBytesSent = 0;
spiBytesToSend = 0;
Serial.flush();
}
// Compute Packet Checksum
unsigned char checksum_Compute(unsigned char
command[])
{
unsigned char checksum;
for (int i=0; i<(COMMANDLENGTH-1); i++)
{
checksum += command[i];
}
return checksum;
}
// Compute Packet Checksum And Test Against
Included Checksum
int checksum_Test(unsigned char command[])
{
unsigned char checksum =
checksum_Compute(command);
if(checksum == command[COMMANDLENGTH-1])
{
return 0;
}
else
{
return 1;
}
}
// Stepper Functions
#ifdef STEPPER_SUPPORT
void AccelStepper_Write(unsigned char
command[]){
int steps = 0;
int step_speed = 0;
int acceleration = 0;
89
//Number of steps & speed are a 16 bit
values, split for data transfer. Reassemble 2
bytes to an int 16
steps = (int)(command[5] << 8) +
command[6];
step_speed = (int)(command[2] << 8) +
command[3];
acceleration = (int)(command[7] << 8) +
command[8];
steppers[command[4]].setMaxSpeed(step_speed);
if (acceleration == 0){
//Workaround AccelStepper bug that
requires negative speed for negative step
direction
if (steps < 0) step_speed = -
step_speed;
steppers[command[4]].setSpeed(step_speed);
steppers[command[4]].move(steps);
}
else {
steppers[command[4]].setAcceleration(accelera
tion);
steppers[command[4]].move(steps);
}
}
#endif
void sampleContinously()
{
for(int i=0; i<iterations; i++)
{
retVal = analogRead(contAcqPin);
if(contAcqSpeed>1000) //delay
Microseconds is only accurate for values less
that 16383
{
Serial.write( (retVal >> 2));
delayMicroseconds(delayTime*1000000); //Delay
for neccesary amount of time to achieve
desired sample rate
}
else
{
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 8));
delay(delayTime*1000);
}
}
}
void finiteAcquisition(int analogPin, float
acquisitionSpeed, int numberOfSamples)
{
//want to exit this loop every 8ms
acquisitionPeriod=1/acquisitionSpeed;
for(int i=0; i<numberOfSamples; i++)
{
retVal = analogRead(analogPin);
if(acquisitionSpeed>1000)
{
Serial.write( (retVal >> 2));
delayMicroseconds(acquisitionPeriod*1000000);
}
else
{
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 8));
delay(acquisitionPeriod*1000);
}
}
}
void lcd_print(unsigned char command[])
{
if(command[2] != 0)
{
// Base Specified By User
int base = 0;
switch(command[2])
{
case 0x01: // BIN base = BIN;
break;
case 0x02: // DEC
base = DEC;
break;
case 0x03: // OCT
base = OCT;
break;
case 0x04: // HEX
base = HEX;
break;
default:
break;
}
for(int i=0; i<command[3]; i++)
{
lcd.print(command[i+4], base);
}
}
else
{
for(int i=0; i<command[3]; i++)
{
lcd.print((char)command[i+4]);
}
}
Serial.write('0');
}
90
Lampiran 2
Block Diagram Alat Ukur Kapasitas Vital Paksa Paru
91
Lampiran 3
Datasheet Sensor Tekanan MPX5100DP
92
93
94
95
96
Lampiran 4
Spesifikasi BTL-08 Spiro
97
98
99
Lampiran 5
Hasil Pengujian Menggunakan BTL-08 Spiro
Hasil Pengujian Alat BTL-08 Spiro
Keadaan 1 Keadaan 2
Responden 1 (Perempuan, 16 tahun)
Responden 2 (Laki-laki, 21 tahun)
Responden 3 (Perempuan, 22 tahun)
100
Lampiran 6
Hasil Pengujian Menggunakan Alat Ukur Kapasitas Vital Paksa Paru
Keadaan
Hasil Pengujian Alat Ukur Kapasitas Vital Paksa Paru
Uji 1 Uji 2 Uji 3
Responden 1 (Perempuan, 16 tahun)
1
2
Responden 2 (Laki-laki, 21 tahun)
1
101
2
Responden 3 (Perempuan, 21 tahun)
1
2