Rangkaian Minimum Sistem
+5v
R5
PC0
5k
INPUT DAC
IC 1 A T m e g a 8 -D I L 2 8
PC6 1 28 PC5
+5v PD0 2 P C 6 (R E S E T )(S C L /A D C 5 ) P C 5 27 PC4
+5v PD1 3 P D 0 (R x D ) (S D A / A D C 4 ) P C 4 26 PC3
PD2 4 P D 1 (T x D ) (A D C 3 ) P C 3 25 PC2
R2 PD3 5 P D 2 (I N T 0 ) (A D C 2 ) P C 2 24 PC1
1k PD4 6 P D 3 (I N T 1 ) (A D C 1 ) P C 1 23 PC0
VCC 7 P D 4 (X C K /T 0 ) (A D C 0 ) P C 0 22 GND
GND 8 VCC AGND 21 VCC
R 4 1k PB6 9 GND AREF 20 VCC
PC6 PB7 10 P B 6 (X T1 /T O S C 1 ) AVCC 19 PB5
PD5 11 P B 7 (X T2 /T O S C 2 ) (S C K ) P B 5 18 PB4
+ C4 PD6 12 P D 5 (T 1 ) (M I S O ) P B 4 17 PB3
10uF SW 1 PD7 13 P D 6 (A IN 0 ) (O C 2 /M O S I ) P B 3 16 PB2
PB0 14 P D 7 (A IN 1 ) (S S /O C 1 B ) P B 2 15 PB1
GND S W P U S H B U TTO N P B 0 (IC P ) (O C 1 A ) P B 1
J5
MOSI PB3
6 M IS O PB4
5 SCK PB5
4 R3 PC6
C 5 22p 3 VCC 220
2
PB6 1 +5v
16M Y1
C6 PB7 CON6
22p
Rangkaian DAC
+5v U2
1
VDD VO U TA
8 INPUT R
6
VREFA
NETWORK
OUTPUT 2
3 ~C S
SCK
MIKRO 4
5 SDI
~LD AC
C1 7
0 .1 u F AVSS
M C P 4 9 2 1 -E /P
Rangkaian Resistor Network
J1
1
J2 2
2 J3
1 R 1
TP 1
2
D A C IN R 2 R 3
560 ohm
7k4 n 12 k4 LL
R 4
2k2 J5
J4
2 R 5 1
1 3k9 2
R 6 SW 1
10 ohm R 7
G N D 2k2 LA
J6
22k R 8
1
R 9 2
10 ohm S W D I P -4
J7 2k2
R A J8
1
2 1
2
R 10 J9
10 ohm R 11 V4
1 R L
2
J10
3k9 R 12
V3 1
2
R 13 J11
10 ohm 3k9 R 14
V5 1
2
2k R 15
V6
J12
33k R 16
1
2
J13
2k R 17
V1 1
2
2k7 R 18
V2
2k4
Listing Program Arduino
#include <LiquidCrystal_I2C.h>
// ECG SIMULATOR
//
//
// Programmer: Rahmat Zulfiqri Eriyanto
#include "SPI.h" // support SPI interface ke D/A
converter
#include <Wire.h> // butuh Wire library
// various constants used by the waveform generator
#define INIT 0
#define IDLE 1
#define QRS 2
#define FOUR 4
#define THREE 3
#define TWO 2
#define ONE 1
// y_data[543] - digitized sinyal ecg, sampel dari 1.0
msec
// skala sinyal ecg untuk 12-bit D/A converter (0 ..
4096)
// 60 beat/min ECG akan membutuhkan sampel sinyal
ini (543 samples) di tambah 457 sampel
// pertama nilai y_data[0] dari 936 sampel.
const short y_data[] = {
507, 509, 510, 512, 513, 514, 516, 517, 521, 527,
534, 540, 546, 552, 558, 564, 570, 577, 583, 594,
605, 615, 626, 637, 648, 662, 676, 691, 705, 714,
720, 726, 732, 737, 743, 749, 755, 763, 772, 781,
789, 798, 806, 815, 823, 830, 837, 844, 851, 859,
866, 873, 877, 881, 885, 890, 894, 898, 903, 902,
900, 897, 894, 891, 888, 885, 882, 879, 876, 873,
871, 868, 865, 862, 857, 852, 846, 841, 835, 830,
825, 821, 816, 812, 808, 803, 799, 794, 786, 779,
772, 764, 757, 750, 743, 737, 731, 725, 719, 714,
708, 702, 695, 686, 677, 668, 660, 651, 642, 633,
622, 611, 601, 591, 581, 571, 562, 556, 552, 547,
543, 539, 534, 530, 526, 522, 519, 515, 511, 508,
506, 508, 509, 510, 512, 513, 515, 516, 516, 516,
516, 516, 516, 516, 516, 517, 520, 522, 524, 527,
529, 532, 534, 536, 537, 537, 537, 537, 537, 537,
535, 532, 528, 524, 521, 517, 514, 510, 506, 500,
493, 486, 478, 471, 464, 457, 446, 424, 372, 274,
129, 71, 17, 158, 233, 295, 357, 459, 551, 603,
655, 721, 846, 971, 1097, 1811, 1994, 2253, 2337, 2390,
2442, 2504, 2945, 3004, 3063, 3097, 3208, 3309, 3410,
3510,
3765, 3813, 3862, 3758, 3354, 3365, 3188, 2910, 2645,
2634,
1970, 2007, 1591, 1411, 1288, 721, 525, 453, 312, 317,
323, 329, 334, 340, 345, 351, 356, 362, 368, 373,
379, 384, 392, 401, 409, 418, 427, 435, 444, 454,
468, 482, 497, 511, 525, 543, 575, 607, 633, 636,
639, 642, 645, 648, 651, 653, 654, 653, 653, 652,
652, 651, 651, 650, 650, 649, 649, 648, 647, 647,
646, 646, 645, 645, 644, 644, 643, 643, 643, 643,
643, 643, 643, 643, 643, 643, 643, 643, 643, 643,
643, 643, 643, 643, 643, 643, 643, 643, 643, 643,
643, 643, 643, 643, 641, 640, 639, 637, 636, 635,
633, 632, 630, 629, 628, 626, 625, 624, 622, 621,
620, 618, 617, 615, 614, 613, 611, 610, 610, 610,
610, 610, 610, 610, 610, 610, 610, 610, 610, 610,
610, 610, 610, 610, 610, 610, 610, 610, 610, 610,
610, 610, 610, 610, 610, 610, 610, 611, 615, 619,
622, 626, 629, 633, 637, 640, 644, 647, 651, 655,
658, 662, 665, 669, 672, 676, 680, 683, 689, 696,
703, 710, 717, 725, 732, 739, 746, 753, 760, 768,
775, 782, 789, 796, 803, 811, 818, 825, 832, 838,
844, 850, 856, 862, 868, 874, 880, 885, 891, 897,
903, 909, 915, 921, 927, 932, 939, 945, 951, 957,
963, 969, 975, 982, 988, 994, 1000, 1006, 1012, 1018,
1025, 1031, 1037, 1043, 1049, 1055, 1062, 1071, 1081,
1090, 1099, 1109, 1118, 1127, 1137, 1146, 1155, 1164,
1174, 1183, 1192, 1202, 1212, 1221, 1231, 1241, 1251,
1261, 1271, 1281, 1290, 1300, 1310, 1319, 1321, 1324,
1327, 1330, 1332, 1335, 1338, 1341, 1343, 1346, 1349,
1352, 1354, 1357, 1360, 1363, 1365, 1368, 1371, 1370,
1367, 1365, 1362, 1360, 1358, 1355, 1353, 1350, 1348,
1345, 1343, 1341, 1338, 1336, 1333, 1331, 1328, 1321,
1313, 1305, 1297, 1290, 1282, 1274, 1266, 1258, 1251,
1243, 1235, 1227, 1219, 1211, 1204, 1196, 1188, 1180,
1167, 1152, 1136, 1121, 1105, 1090, 1075, 1059, 1044,
1028, 1013, 998, 982, 968, 954, 941, 928, 914, 901, 887,
874, 861, 849, 840, 830, 820, 811, 801, 791, 781,
772, 762, 752, 743, 733, 725, 721, 717, 714, 710,
706, 703, 699, 696, 692, 688, 685, 681, 677, 674,
670, 667, 663, 660, 656, 653, 650, 647, 644, 641,
638, 635, 632, 629, 626, 623, 620, 617, 614, 611};
// variabel umum yang digunakan dalam program
unsigned int NumSamples = sizeof(y_data) / 2;
//Jumlah sampel y_data diatas
unsigned int QRSCount = 0;
//running QRS period msec count
unsigned int IdleCount = 0;
//menjalankan perhitungan mode periode diam (msec)
unsigned long IdlePeriod = 0;
// mode periode diam yg dibuah oleh potensiometer
untuk mengubah BPM
unsigned int State = INIT;
// states = INIT, QRS, and IDLE
unsigned int tcnt2;
// inisialisasi timer2
float BeatsPerMinute;
// inisialisasi BPM (float)
unsigned int Bpm;
// inisialisasi BPM (integer) (x10)
unsigned int BpmLow;
// BPM terrendah yang diijinkan (x10)
unsigned int BpmHigh;
// BPM tertinggi yang diijinkan (x10)
int Value;
// nilai awal analog input
unsigned long BpmValues[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0};
//tahan 32 sampel anolog input untuk digunakan untuk
membuat rata2 display bpm agar stabil..
unsigned long BpmAverage = 0;
//digunakan untuk mencari rata2 BPM
unsigned char Index = 0;
//digunakan untuk mencari rata2 BPM
unsigned int DisplayValue = 0;
// nilai hasil bpm setelah di rata2 yg ditampilkan
LiquidCrystal_I2C lcd(0x3F, 16, 2); // lcd i2c
void setup()
{
// Configurasi output ports (1 msec interupsi indicator
dan D/A SPI support)
pinMode(10, OUTPUT);
// memilih ic D/A converter ("0" untuk memilih)
pinMode(11, OUTPUT); // SDI data
pinMode(13, OUTPUT); // SCK clock
// inisialisasi SPI interface
SPI.begin(); // memulai SPI.
SPI.setDataMode(0); // mode: CPHA=0,
data yg diambil saat waktu berjalan (low ke high)
SPI.setClockDivider(SPI_CLOCK_DIV64); // system
clock / 64
SPI.setBitOrder(MSBFIRST); // keluar per 7 bit
// mengatur jumlah BPM yg diijinkan
// BpmLow = 300 (30 bpm x 10)
// BpmHigh = (60.0 / (NumSamples * 0.001)) * 10 =
(60.0 / .543) * 10 = 1104 (110.49 x 10) // rubah dari 60
ke 163 untuk mencapai bpm 300 max tp harus merubah
idle period nya juga
BpmLow = 300;
BpmHigh = (60.0 / ((float)NumSamples * 0.001)) * 10;
// Serial.begin(9600);
// mematikan timer overflow interrupt saat sedang
menyeting ( BPM )
TIMSK2 &= ~(1<<TOIE2);
// configurasi timer2 dalam normal mode (hanya
berfungsi untuk menghitung tidak ada PWM etc.)
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
// memilih internal clock
ASSR &= ~(1<<AS2);
// menonaktifkan pembanding overflow interupsi (hanya
yg overflow)
TIMSK2 &= ~(1<<OCIE2A);
// konfigurasi prescaler ke CPU clock dibagi 128
TCCR2B |= (1<<CS22) | (1<<CS20); // mengatur
berapa bit yang di pakai
TCCR2B &= ~(1<<CS21); // Clear bit
// menghitung nilai yang tepat untuk me-load counter
timer
// Berikut ini me-load nilai 131 ke Timer 2 counter
register
// (Frekuensi CPU) // (nilai prescaler) = 125000 Hz =
8us
// (Periode yang diinginkan) // 8us = 125.
// MAX (uint8) + 1-125 = 131;
// Simpan nilai nya untuk digunakan lg di ISR
tcnt2 = 131;
// load dan mengaktifkan timer
TCNT2 = tcnt2;
TIMSK2 |= (1<<TOIE2);
lcd.begin();
lcd.backlight();
}
void loop()
{
// baca adc dari heart rate pot (Analog Input 0)
Value = analogRead(0);
// map Analog Input 0 range (0 .. 1023) ke Bpm range
(300 .. 1104)
Bpm = map(Value, 0, 1023, BpmLow, BpmHigh);
// untuk menguragi bpm acak pada tampilan
// filter rata2 (32 sampel).
BpmValues[Index++] = Bpm; //
menambah sampel terakhir ke 8 elemen aray
if (Index == 32) { // menangani
keseluruhan sampel
Index = 0;
}
BpmAverage = 0;
for (int i = 0; i < 32; i++) { // penjumlahan
dari semua niai2 dalam aray
BpmAverage += BpmValues[i];
}
BpmAverage >>= 5; // dibagi 32
untuk mendapat rata2
// update display
// update display itu mengunakan multi-byte transfer,
jadi menonaktifkan sementara interupsi sampai
updatenya selesai
noInterrupts();
DisplayValue = BpmAverage;
interrupts();
// mengatur nilai pot (BPM) lalu dibaca adc dan
menghitung periode diam (msec)
// nilai ini digunakan oleh Timer2 1.0 msec interupsi
berkelanjutan
BeatsPerMinute = (float)Bpm / 10.0;
lcd.setCursor(2,0);
lcd.print("Setting BPM");
lcd.setCursor(5,1);
lcd.print(BeatsPerMinute);
//Serial.println(BeatsPerMinute);
noInterrupts();
IdlePeriod = (unsigned int)((float)60000.0 /
BeatsPerMinute) - (float)NumSamples; // rubah periode
dapat merubah min-max bpm // 60000.0
interrupts();
delay(20);
}
// Timer2 Interupsi Service Rutin
// Interrupt Service Rutin (ISR) untuk overflow Timer2 di
1.000 msec.
// fungsi interupsi Timer2 digunakan untuk mengirim 16-
bit titik gelombang
// Ke Microchip MCP4921 D / A converter menggunakan
antarmuka SPI.
// fungsi inetrupsi Timer2 juga digunakan untuk
mengirim denyut jantung
// yg dibaca dari potensiometer setiap 50ms
// Pot tersebut dibaca dan denyut jantung dihitung dalam
loop latar belakang.
// Dengan menjalankan SPI periperal di tingkat interupsi,
// saya menjalakan program berurutan untuk menghindari
Korupsi transmisi SPI terganggu oleh yang lain.
// Modul diimplementasikan untuk mencapai hal ini :
// INIT - pada dasarnya membersihkan counter dan
menetapkan keadaan untuk QRS.
// QRS - output titik gelombang data EKG berikutnya
setiap 1,0 msec
// Ada 543 dari QRS titik-titik data yang kompleks.
// IDLE - periode variabel setelah bagian QRS.
// D / A memegang nilai EKG pertama (936) untuk
semua periode IDLE.
// Periode idle bervariasi untuk memungkinkan
penyesuaian denyut jantung dasar;
// Nilai nol msec untuk periode siaga memberikan 110,4
denyut per menit
// Sedangkan periode menganggur/diam maksimum 457
msec memberikan 30,0 bpm.
// Perhatikan bahwa periode diam dihitung di latar
belakang utama
// Loop dengan membaca pot dan mengkonversi range
yang cocok
// Untuk periode latar belakang. Interupsi rutin membaca
// Nilai ini untuk menentukan kapan harus menghentikan
periode diam.
// Transmisi titik data berikutnya ke D / A converter
melalui SPI mengambil
// Sekitar 63us (yang mencakup transmisi byte SPI).
ISR(TIMER2_OVF_vect) {
// Reload timer
TCNT2 = tcnt2;
// Modul proses
switch (State) {
case INIT:
// me-nolkan QRS dan IDLE counter
QRSCount = 0;
IdleCount = 0;
// DisplayCount = 0;
// mengatur proses selanjutnya QRS
State = QRS;
break;
case QRS:
// output sampel berikutnya dalam bentuk gelombang
QRS ke D / A converter
DTOA_Send(y_data[QRSCount]);
// melanjutkan sample counter
QRSCount++;
if (QRSCount >= NumSamples) {
// menjalankan IDLE period dan output sampel
pertama ke DTOA
QRSCount = 0;
DTOA_Send(y_data[0]);
State = IDLE;
}
break;
case IDLE:
// Karena D / A converter akan terus menahan nilai
sebelumnya yg ditulis, yg harus dilakuakan
// adalah menentukan berapa lama periode IDLE/diam .
// melanjutkan sample counter
IdleCount++;
// periode diam dihitung dalam main loop (dari pot)
if (IdleCount >= IdlePeriod) {
IdleCount = 0;
State = QRS;
}
break;
default:
break;
}
}
// void DTOA_Send(unsigned short)
// Tujuan: mengirim nilai 12-bit D/A ke Microchip
MCP4921 D/A converter ( 0 .. 4096 )
// Input: DtoAValue - 12-bit D/A value ( 0 .. 4096 )
// The DtoAValue di tambahkan di awal dengan
A/B, BUF, GA, dan SHDN bits sebelum transmisi.
//
// WRITE COMMAND
//
|--------|--------|--------|--------|----------------------------------
----------------|
// | A/B | BUF | GA | SHDN | D11 D10
D09 D08 D07 D06 D05 D04 D03 D02 D01 D00 |
// | | | | |
|
// |setting:|setting:|setting:|Setting:|
DtoAValue (12 bits) |
// | 0 | 0 | 1 | 1 |
|
// | DAC-A |unbuffer| 1x |power-on| ( 0 .. 4096
will output as 0 volts .. 5 volts ) |
//
|--------|--------|--------|--------|----------------------------------
----------------|
// 15 14 13 12 11
0
// To D/A
<========================================
=========================================
=====
//
// Note: WriteCommand is clocked out with bit 15
first!
//
//
// Returns: -
//
//
// I/O Resources: Digital Pin 10 = chip select (low
untuk memilih pin out)
// Digital Pin 13 = SPI Clock
// Digital Pin 11 = SPI Data
//
// Note: karena pin LDAC di sambung ke ground, SPI
data akan di clock dan di kunci kedalam
// D/A converter ketika pin input mendapat '1 atau
high di akhir transmisi.
//
// Proses ini membutuhkan 63 usec menggunakan
rangkaian arduino UNO
//
**********************************************
**********************************************
*******
void DTOA_Send(unsigned short DtoAValue)
{
byte Data = 0;
// memilih pin out untuk D/A chip (low)
digitalWrite(10, 0); // chip select low
// pertama mengirim bit high dahulu 0011xxxx
Data = highByte(DtoAValue);
Data = 0b00001111 & Data;
Data = 0b00110000 | Data;
SPI.transfer(Data);
// selanjutnya mengirim bit low xxxxxxxx
Data = lowByte(DtoAValue);
SPI.transfer(Data);
// selesai, Reset pin out ke D/A (ini akan mengulang
main loop dan akan memberi D/A Converter nilai yang
baru)
digitalWrite(10, 1); // chip select high
}