Part of the Pacemaker Project; this models the Pacemaker.

Dependencies:   mbed TextLCD mbed-rtos

Committer:
chadnach1
Date:
Wed Dec 02 05:31:09 2015 +0000
Revision:
42:2e4ed3a53c64
Parent:
41:d806d68f7969
Parent:
40:e401b1cb71c0
Child:
43:f28bc869321e
Latest with Matt's calculations for BPM display

Who changed what in which revision?

UserRevisionLine numberNew contents of line
chadnach1 0:d92e0b71c6b5 1 #include "mbed.h"
lucastai 2:5e9c4d83d038 2 #include "LPC17xx.h"
lucastai 2:5e9c4d83d038 3 #include "TextLCD.h"
lucastai 2:5e9c4d83d038 4 #include "rtos.h"
lucastai 2:5e9c4d83d038 5 #include "Thread.h"
lucastai 2:5e9c4d83d038 6 using namespace rtos;
chadnach1 0:d92e0b71c6b5 7
chadnach1 0:d92e0b71c6b5 8 // This is for the pacemaker
lucastai 2:5e9c4d83d038 9 volatile unsigned short timer_count;
lucastai 2:5e9c4d83d038 10 Serial pc(USBTX, USBRX);
lucastai 2:5e9c4d83d038 11 TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD20x4); // rs, e, d4-d7
lucastai 2:5e9c4d83d038 12
mhowar 41:d806d68f7969 13 Ticker rate_monitor;
mhowar 41:d806d68f7969 14
mhowar 5:9eee15818b0e 15 int keyboard_needs_numeric = 0; // boolean - is in middle of interval input?
chadnach1 0:d92e0b71c6b5 16
chadnach1 0:d92e0b71c6b5 17 int h_clock;
amiche 3:44d132582373 18 int pm_clock;
chadnach1 27:2c5aefcf3000 19 Timer avi_clk;
chadnach1 32:c58b6651336c 20 Timer t_count;
chadnach1 0:d92e0b71c6b5 21
amiche 38:ceabf8f1dfa0 22 int LRI = 100;
amiche 38:ceabf8f1dfa0 23 int AVI = 30;
amiche 38:ceabf8f1dfa0 24 int PVARP = 150;
amiche 38:ceabf8f1dfa0 25 int VRP = 100;
lucastai 2:5e9c4d83d038 26
lucastai 2:5e9c4d83d038 27 // constants
lucastai 2:5e9c4d83d038 28 int MAX_PM_RT = 180;
lucastai 2:5e9c4d83d038 29 int MIN_PM_RT = 40;
lucastai 2:5e9c4d83d038 30 enum mode {NORMAL, SLEEP, EXERCISE, MANUAL};
lucastai 2:5e9c4d83d038 31
lucastai 2:5e9c4d83d038 32 // counters
mhowar 41:d806d68f7969 33 volatile int beats = 0;
lucastai 2:5e9c4d83d038 34
lucastai 2:5e9c4d83d038 35 // state variables
lucastai 2:5e9c4d83d038 36 int upper_bound = 100;
lucastai 2:5e9c4d83d038 37 int lower_bound = 40;
lucastai 2:5e9c4d83d038 38 int obs_int = 10;
lucastai 2:5e9c4d83d038 39 mode curr_mode = NORMAL;
lucastai 2:5e9c4d83d038 40
amiche 19:f3615321b5c4 41 // alarms
lucastai 14:a16b636c2bbc 42 DigitalOut led_apace(LED1);
lucastai 14:a16b636c2bbc 43 DigitalOut led_vpace(LED2);
chadnach1 33:b68c1648206e 44 DigitalOut led_asense(LED3);
chadnach1 33:b68c1648206e 45 DigitalOut led_vsense(LED4);
lucastai 2:5e9c4d83d038 46
chadnach1 27:2c5aefcf3000 47 DigitalIn agetSignal(p24);
chadnach1 27:2c5aefcf3000 48 DigitalIn vgetSignal(p23);
chadnach1 27:2c5aefcf3000 49 DigitalOut apaceSignal(p22);
chadnach1 27:2c5aefcf3000 50 DigitalOut vpaceSignal(p21);
chadnach1 27:2c5aefcf3000 51
chadnach1 27:2c5aefcf3000 52 bool v_sense;
chadnach1 27:2c5aefcf3000 53 bool a_sense;
chadnach1 27:2c5aefcf3000 54
chadnach1 27:2c5aefcf3000 55 void asense()
chadnach1 27:2c5aefcf3000 56 {
chadnach1 27:2c5aefcf3000 57 a_sense = 1;
chadnach1 33:b68c1648206e 58 led_asense = 1;
chadnach1 27:2c5aefcf3000 59 Thread::wait(10);
chadnach1 33:b68c1648206e 60 led_asense = 0;
chadnach1 27:2c5aefcf3000 61 a_sense = 0;
chadnach1 27:2c5aefcf3000 62 }
lucastai 18:d4cd9d12345e 63
chadnach1 27:2c5aefcf3000 64 void vsense()
chadnach1 27:2c5aefcf3000 65 {
chadnach1 27:2c5aefcf3000 66 v_sense = 1;
chadnach1 33:b68c1648206e 67 led_vsense = 1;
chadnach1 27:2c5aefcf3000 68 Thread::wait(10);
chadnach1 33:b68c1648206e 69 led_vsense = 0;
chadnach1 27:2c5aefcf3000 70 v_sense = 0;
mhowar 41:d806d68f7969 71 beats++;
chadnach1 27:2c5aefcf3000 72 }
chadnach1 27:2c5aefcf3000 73
chadnach1 27:2c5aefcf3000 74 void apace()
chadnach1 27:2c5aefcf3000 75 {
chadnach1 27:2c5aefcf3000 76 apaceSignal = 1;
chadnach1 27:2c5aefcf3000 77 led_apace = 1;
chadnach1 27:2c5aefcf3000 78 Thread::wait(10);
chadnach1 33:b68c1648206e 79 led_apace = 0;
chadnach1 27:2c5aefcf3000 80 apaceSignal = 0;
chadnach1 27:2c5aefcf3000 81
chadnach1 27:2c5aefcf3000 82 }
chadnach1 27:2c5aefcf3000 83
chadnach1 27:2c5aefcf3000 84 void vpace()
chadnach1 27:2c5aefcf3000 85 {
chadnach1 27:2c5aefcf3000 86 vpaceSignal = 1;
chadnach1 27:2c5aefcf3000 87 led_vpace = 1;
chadnach1 27:2c5aefcf3000 88 Thread::wait(10);
chadnach1 33:b68c1648206e 89 led_vpace = 0;
chadnach1 27:2c5aefcf3000 90 vpaceSignal = 0;
chadnach1 27:2c5aefcf3000 91 }
amiche 24:81cd9ef5c4f6 92
lucastai 2:5e9c4d83d038 93 // hardware interrupt handler, adapted from code in piazza post by Dagaen
chadnach1 33:b68c1648206e 94 /*extern "C" void TIMER0_IRQHandler (void)
lucastai 2:5e9c4d83d038 95 {
amiche 19:f3615321b5c4 96 if((LPC_TIM0->IR & 0x01) == 0x01) { // if MR0 interrupt, proceed
amiche 19:f3615321b5c4 97 LPC_TIM0->IR |= 1 << 0; // Clear MR0 interrupt flag
amiche 19:f3615321b5c4 98 timer_count++; //increment timer_count
lucastai 2:5e9c4d83d038 99 }
lucastai 2:5e9c4d83d038 100 }
chadnach1 33:b68c1648206e 101 */
chadnach1 33:b68c1648206e 102 /*// init the hardware interrupt (timer0), adapted same as above
lucastai 2:5e9c4d83d038 103 void timer0_init(void)
lucastai 2:5e9c4d83d038 104 {
lucastai 2:5e9c4d83d038 105 LPC_SC->PCONP |=1<1; //timer0 power on
lucastai 2:5e9c4d83d038 106 LPC_SC-> PCLKSEL0 |= 1 << 2; // set timer clock to CCLCK nondivided (1 clock cycle = 1 increment)
lucastai 2:5e9c4d83d038 107 LPC_TIM0->MR0 = 1000000; //100mhz clock cycle, 1 cycle = 10ns, 10ms = 10 000 000 ns = 1M cycles
lucastai 2:5e9c4d83d038 108 LPC_TIM0->MCR = 3; //interrupt and reset control
amiche 19:f3615321b5c4 109 //3 = Interrupt & reset timer0 on match (111) sets all three bits
lucastai 2:5e9c4d83d038 110 NVIC_EnableIRQ(TIMER0_IRQn); //enable timer0 interrupt
chadnach1 33:b68c1648206e 111 }*/
chadnach1 0:d92e0b71c6b5 112
lucastai 2:5e9c4d83d038 113
chadnach1 27:2c5aefcf3000 114 void PM_ALARM(void const *args)
amiche 19:f3615321b5c4 115 {
chadnach1 29:5cec671cb80d 116 while (1) {
chadnach1 29:5cec671cb80d 117 // min hr alarm
chadnach1 29:5cec671cb80d 118 if( beats < MIN_PM_RT) {
chadnach1 30:97db5a684eaa 119 lcd.cls();
chadnach1 29:5cec671cb80d 120 lcd.locate(0,1);
chadnach1 30:97db5a684eaa 121 lcd.printf("!<\n");
chadnach1 29:5cec671cb80d 122 }
chadnach1 31:7f0e865e3d4b 123
chadnach1 29:5cec671cb80d 124 // max hr alarm
chadnach1 29:5cec671cb80d 125 if(beats > MAX_PM_RT) {
chadnach1 30:97db5a684eaa 126 lcd.cls();
chadnach1 29:5cec671cb80d 127 lcd.locate(0,1);
chadnach1 30:97db5a684eaa 128 lcd.printf("!>\n");
chadnach1 29:5cec671cb80d 129 }
amiche 19:f3615321b5c4 130 }
amiche 19:f3615321b5c4 131
chadnach1 0:d92e0b71c6b5 132 }
chadnach1 0:d92e0b71c6b5 133
lucastai 2:5e9c4d83d038 134 // hw interrupt callback, deal with the keyboard input from PC
lucastai 2:5e9c4d83d038 135
chadnach1 27:2c5aefcf3000 136 void pm_sense(void const *args)
amiche 19:f3615321b5c4 137 {
amiche 19:f3615321b5c4 138
chadnach1 4:f04eb7f96f4b 139 while(1) {
chadnach1 33:b68c1648206e 140 /*if (agetSignal == 0) {
chadnach1 33:b68c1648206e 141 pc.printf("Aget:LO\n");
chadnach1 33:b68c1648206e 142 }
chadnach1 33:b68c1648206e 143
chadnach1 33:b68c1648206e 144 if (vgetSignal == 0) {
chadnach1 33:b68c1648206e 145 pc.printf("Vget:LO\n");
chadnach1 33:b68c1648206e 146 }
chadnach1 33:b68c1648206e 147 if (agetSignal == 1) {
chadnach1 33:b68c1648206e 148 pc.printf("Aget:HI\n");
chadnach1 33:b68c1648206e 149 }
chadnach1 33:b68c1648206e 150
chadnach1 33:b68c1648206e 151 if (vgetSignal == 1) {
chadnach1 33:b68c1648206e 152 pc.printf("Vget:HI\n");
chadnach1 33:b68c1648206e 153 }*/
chadnach1 33:b68c1648206e 154
amiche 19:f3615321b5c4 155
chadnach1 33:b68c1648206e 156 if (t_count.read_ms() >= VRP && vgetSignal == 1) {
chadnach1 34:b4b50ca26e8c 157
amiche 24:81cd9ef5c4f6 158 // Valid_V state
chadnach1 32:c58b6651336c 159 t_count.reset();
amiche 24:81cd9ef5c4f6 160 vsense();
amiche 24:81cd9ef5c4f6 161
chadnach1 33:b68c1648206e 162 } else if (t_count.read_ms() < VRP && vgetSignal == 1) {
chadnach1 34:b4b50ca26e8c 163 //pc.printf("invalid v state\n");
chadnach1 32:c58b6651336c 164
chadnach1 20:dc272bfaa276 165 // Invalid_V state
chadnach1 4:f04eb7f96f4b 166 }
amiche 19:f3615321b5c4 167
chadnach1 33:b68c1648206e 168 if (t_count.read_ms() < PVARP && agetSignal == 1) {
chadnach1 20:dc272bfaa276 169 // Invalid_A state
chadnach1 34:b4b50ca26e8c 170
chadnach1 34:b4b50ca26e8c 171 //pc.printf("invalid a state\n");
chadnach1 33:b68c1648206e 172 } else if (t_count.read_ms() >= PVARP && agetSignal == 1) {
chadnach1 20:dc272bfaa276 173 // Valid_A state
amiche 24:81cd9ef5c4f6 174 asense();
chadnach1 4:f04eb7f96f4b 175 }
chadnach1 4:f04eb7f96f4b 176 }
amiche 3:44d132582373 177 }
amiche 3:44d132582373 178
chadnach1 27:2c5aefcf3000 179 void pm_response(void const *args)
amiche 19:f3615321b5c4 180 {
chadnach1 4:f04eb7f96f4b 181 while(1) {
chadnach1 34:b4b50ca26e8c 182
chadnach1 27:2c5aefcf3000 183 bool goInitalState = 1;
chadnach1 33:b68c1648206e 184 if (t_count.read_ms() >= LRI - AVI) {
chadnach1 33:b68c1648206e 185
chadnach1 27:2c5aefcf3000 186 goInitalState = 0;
chadnach1 34:b4b50ca26e8c 187
amiche 19:f3615321b5c4 188 // PM_A! sets the LED high
amiche 19:f3615321b5c4 189 led_apace = 1;
amiche 19:f3615321b5c4 190
amiche 19:f3615321b5c4 191 avi_clk.reset();
amiche 19:f3615321b5c4 192
amiche 19:f3615321b5c4 193 apace();
chadnach1 34:b4b50ca26e8c 194
amiche 19:f3615321b5c4 195 // At Atrial Event State
chadnach1 33:b68c1648206e 196 while (avi_clk.read_ms() < AVI) {
chadnach1 34:b4b50ca26e8c 197
chadnach1 27:2c5aefcf3000 198 if (v_sense == 1) {
chadnach1 27:2c5aefcf3000 199 goInitalState = 1;
amiche 24:81cd9ef5c4f6 200 break;
amiche 24:81cd9ef5c4f6 201 }
amiche 24:81cd9ef5c4f6 202 }
chadnach1 27:2c5aefcf3000 203 if (!goInitalState) {
amiche 24:81cd9ef5c4f6 204 // Ventricular Event
chadnach1 32:c58b6651336c 205 t_count.reset();
amiche 19:f3615321b5c4 206
amiche 24:81cd9ef5c4f6 207 // PM_V! sets the LED high
amiche 24:81cd9ef5c4f6 208 led_vpace = 1;
amiche 19:f3615321b5c4 209
chadnach1 32:c58b6651336c 210 t_count.reset();
amiche 24:81cd9ef5c4f6 211 vpace();
amiche 24:81cd9ef5c4f6 212 }
chadnach1 33:b68c1648206e 213 } else if (t_count.read_ms() < LRI - AVI) {
chadnach1 34:b4b50ca26e8c 214
amiche 24:81cd9ef5c4f6 215 // if Asense, move on to atrial event
chadnach1 27:2c5aefcf3000 216 if (a_sense == 1) {
chadnach1 27:2c5aefcf3000 217 goInitalState = 0;
chadnach1 34:b4b50ca26e8c 218
amiche 24:81cd9ef5c4f6 219 avi_clk.reset();
amiche 19:f3615321b5c4 220
amiche 24:81cd9ef5c4f6 221 // At Atrial Event State
amiche 24:81cd9ef5c4f6 222 while (avi_clk.read() < AVI) {
chadnach1 27:2c5aefcf3000 223 if (v_sense == 1) {
chadnach1 27:2c5aefcf3000 224 goInitalState = 1;
amiche 24:81cd9ef5c4f6 225 break;
amiche 24:81cd9ef5c4f6 226 }
amiche 24:81cd9ef5c4f6 227 }
amiche 19:f3615321b5c4 228
amiche 24:81cd9ef5c4f6 229 // Ventricular Event
chadnach1 32:c58b6651336c 230 t_count.reset();
amiche 24:81cd9ef5c4f6 231
amiche 24:81cd9ef5c4f6 232 // PM_V! sets the LED high
amiche 24:81cd9ef5c4f6 233 led_vpace = 1;
amiche 24:81cd9ef5c4f6 234
chadnach1 32:c58b6651336c 235 t_count.reset();
amiche 24:81cd9ef5c4f6 236 vpace();
amiche 24:81cd9ef5c4f6 237 }
amiche 19:f3615321b5c4 238 }
amiche 19:f3615321b5c4 239 }
amiche 3:44d132582373 240 }
lucastai 2:5e9c4d83d038 241
mhowar 41:d806d68f7969 242 /* Every observation interval, calculate beats per minute and display
mhowar 41:d806d68f7969 243 *
mhowar 41:d806d68f7969 244 */
mhowar 41:d806d68f7969 245 void update_display() {
mhowar 41:d806d68f7969 246 double rate = beats / (double) obs_int / 60;
mhowar 41:d806d68f7969 247 //reset count
mhowar 41:d806d68f7969 248 beats = 0;
mhowar 41:d806d68f7969 249 lcd.cls();
mhowar 41:d806d68f7969 250 lcd.locate(0,0);
mhowar 41:d806d68f7969 251 lcd.printf("BPM: %.1f ");
mhowar 41:d806d68f7969 252 }
mhowar 41:d806d68f7969 253
amiche 19:f3615321b5c4 254 int main()
amiche 19:f3615321b5c4 255 {
chadnach1 16:ae9df4194011 256 // https://developer.mbed.org/users/chadnach1/code/PacemakerController/
lucastai 2:5e9c4d83d038 257 // connect the serial device (PC keybd) to the interrupt
amiche 19:f3615321b5c4 258
chadnach1 16:ae9df4194011 259 // Start LED's Off
chadnach1 17:c89cddf30925 260 led_apace = 0;
chadnach1 17:c89cddf30925 261 led_vpace = 0;
amiche 19:f3615321b5c4 262
chadnach1 16:ae9df4194011 263 // Start the avi_clock
chadnach1 16:ae9df4194011 264 avi_clk.start();
chadnach1 33:b68c1648206e 265 avi_clk.reset();
amiche 19:f3615321b5c4 266
chadnach1 30:97db5a684eaa 267 Thread t1(pm_sense, (void *)"");
chadnach1 30:97db5a684eaa 268 Thread t2(pm_response, (void *)"");
chadnach1 31:7f0e865e3d4b 269 Thread t3(PM_ALARM, (void *)"");
mhowar 41:d806d68f7969 270
mhowar 41:d806d68f7969 271 //update_display
mhowar 41:d806d68f7969 272 rate_monitor.attach(&update_display, obs_int);
mhowar 41:d806d68f7969 273
chadnach1 33:b68c1648206e 274 t_count.start();
chadnach1 33:b68c1648206e 275 t_count.reset();
chadnach1 31:7f0e865e3d4b 276
chadnach1 31:7f0e865e3d4b 277 while(1) {
mhowar 35:b5e8650a7669 278 if (pc.readable()) {
mhowar 35:b5e8650a7669 279
mhowar 35:b5e8650a7669 280 char a = pc.getc();
mhowar 35:b5e8650a7669 281
mhowar 35:b5e8650a7669 282 // Handle different keyboard inputs
mhowar 35:b5e8650a7669 283 if (keyboard_needs_numeric) {
mhowar 35:b5e8650a7669 284 if (a >= '0' && a <= '9') {
mhowar 35:b5e8650a7669 285 // update observation interval
mhowar 35:b5e8650a7669 286 obs_int = (a - '0' + 1) * 5;
mhowar 35:b5e8650a7669 287 keyboard_needs_numeric = 0;
mhowar 41:d806d68f7969 288 rate_monitor.attach(&update_display, obs_int);
mhowar 41:d806d68f7969 289 pc.printf("Set observation interval to %d seconds\n", obs_int);
mhowar 35:b5e8650a7669 290 } else {
mhowar 35:b5e8650a7669 291 pc.printf("Expected numeric key\n");
mhowar 35:b5e8650a7669 292 }
mhowar 35:b5e8650a7669 293 } else if(a == 'N') {
mhowar 35:b5e8650a7669 294 // if the char is N, update bounds to normal mode
mhowar 35:b5e8650a7669 295 curr_mode = NORMAL;
mhowar 35:b5e8650a7669 296 upper_bound = 100;
amiche 38:ceabf8f1dfa0 297 LRI = 100;
mhowar 35:b5e8650a7669 298 lower_bound = 40;
mhowar 35:b5e8650a7669 299 pc.printf("MODE IS N\n");
mhowar 35:b5e8650a7669 300 // if the char is S, set bounds to sleep
mhowar 35:b5e8650a7669 301 } else if (a == 'S') {
mhowar 35:b5e8650a7669 302 curr_mode = SLEEP;
mhowar 35:b5e8650a7669 303 upper_bound = 60;
amiche 38:ceabf8f1dfa0 304 LRI = 60;
mhowar 35:b5e8650a7669 305 lower_bound = 30;
mhowar 35:b5e8650a7669 306 pc.printf("MODE IS S\n");
mhowar 35:b5e8650a7669 307 // if the char is E, set bounds to exercise
mhowar 35:b5e8650a7669 308 } else if (a == 'E') {
mhowar 35:b5e8650a7669 309 curr_mode = EXERCISE;
mhowar 35:b5e8650a7669 310 upper_bound = 175;
amiche 38:ceabf8f1dfa0 311 LRI = 175;
mhowar 35:b5e8650a7669 312 lower_bound = 100;
mhowar 35:b5e8650a7669 313 pc.printf("MODE IS E\n");
mhowar 35:b5e8650a7669 314 // if the char is M, set to manual
mhowar 35:b5e8650a7669 315 } else if (a == 'M') {
mhowar 35:b5e8650a7669 316 curr_mode = MANUAL;
mhowar 35:b5e8650a7669 317 upper_bound = 175;
amiche 38:ceabf8f1dfa0 318 LRI = 175;
mhowar 35:b5e8650a7669 319 lower_bound = 30;
mhowar 35:b5e8650a7669 320 pc.printf("MODE IS MANUAL\n");
mhowar 35:b5e8650a7669 321 // check for A if mode is manual
mhowar 35:b5e8650a7669 322 } else if (a == 'A') {
mhowar 35:b5e8650a7669 323 if(curr_mode == MANUAL) {
chadnach1 39:51c4ec84f6fd 324 apace();
chadnach1 39:51c4ec84f6fd 325 pc.printf("MODE IS MANUAL SENT APACE\n");
mhowar 35:b5e8650a7669 326 }
mhowar 35:b5e8650a7669 327 // check for V is mode is manual
mhowar 35:b5e8650a7669 328 } else if (a == 'V') {
mhowar 35:b5e8650a7669 329 if(curr_mode == MANUAL) {
chadnach1 39:51c4ec84f6fd 330 vpace();
chadnach1 39:51c4ec84f6fd 331 pc.printf("MODE IS MANUAL SENT VPACE\n");
mhowar 35:b5e8650a7669 332 }
mhowar 35:b5e8650a7669 333 } else if (a == 'O') {
mhowar 35:b5e8650a7669 334 keyboard_needs_numeric = 1;
mhowar 35:b5e8650a7669 335 } else {
mhowar 35:b5e8650a7669 336 // do nothing for invalid char
mhowar 35:b5e8650a7669 337 }
chadnach1 31:7f0e865e3d4b 338 }
chadnach1 31:7f0e865e3d4b 339 }
chadnach1 31:7f0e865e3d4b 340 }