Part of the Pacemaker Project; this models the Pacemaker.

Dependencies:   mbed TextLCD mbed-rtos

Committer:
chadnach1
Date:
Wed Dec 02 07:23:57 2015 +0000
Revision:
45:ec9e76ccec6c
Parent:
44:dfa38e4b3146
Child:
46:2d9cf50b4bc3
New Timing Cycles for Pacemaker Modes and Matt's clock cycle fix, thanks!

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