8306浏览
查看: 8306|回复: 0

【Arduino】+智能健康计

[复制链接]
原创申明:如转载请注明来源:http://club.gizwits.com/thread-2865-1-1.html

一、作品说明及使用场景
        目前国内的老年化问题越来越突出,老年人的健康问题已经不容小视,如何借助快速发展的科技水平来解决老年人的看病难的问题,这在国内得到了广泛的关注和讨论。在这样的背景下智慧医疗的出现,希望能够为医疗行业的发展带来一次变革。何谓智能医疗?它是通过打造健康档案区域医疗信息平台,利用最先进的物联网技术,实现患者与医务人员、医疗机构、医疗设备之间的互动,逐步达到信息化。在不久的将来医疗行业将融入更多人工智慧、传感技术等高科技,使医疗服务走向真正意义的智能化,推动医疗事业的繁荣发展。
随着智能硬件的发展,将极大的降低开发者的开发流程和开发门槛,届时任何人都能够DIY 出自己的作品。我的创意就是来自于中老年人一方面对于自身健康的重视,另一方面就是就医的难度增大(需要坐车去医院、排队挂号等等十分繁琐)。我想借助云服务的平台和DIY硬件打造一个集方便、快捷的本地检测、本地显示、云端查看等方式来将为中老年人的健康提供保障。让他们足不出户也能够实时的检测自己的心率、体重等数据,数据同时上传到医院患者的电子病历(假设)和子女的手机端显示,以及历史查询等功能。以期帮助中老年人打造健康的生活环境。

二、作品所使用的BOM清单以及硬件部分
         硬件清单:
         两块Arduino开发板;
        一块gokit的扩展板;
        一个心率脉搏传感器;
        一个4针的OLED显示模块;
        一个轻触式按键开关;
        开发板的供电线两根;
        面包板一块;
        杜邦线若干。
         

        工作原理:光电容积法的基本原理是利用人体组织在血管搏动时造成透光率不同来进行脉搏测量的。其使用的传感器由光源和光电变换器两部分组成,通过绑带或夹子固定在病人的手指或耳垂上。光源一般采用对动脉血中氧和血红蛋白有选择性的一定波长(500nm~700nm)的发光二极管。当光束透过人体外周血管,由于动脉搏动充血容积变化导致这束光的透光率发生改变,此时由光电变换器接收经人体组织反射的光线,转变为电信号并将其放大和输出。由于脉搏是随心脏的搏动而周期性变化的信号,动脉血管容积也周期性变化,因此光电变换器的电信号变化周期就是脉搏率。
       这里先连接上实物电路:gokit中下载好源码Pulse_arduino进行连接,这里选择的是arduino作为底板,然后将预留的A1引脚作为心率脉搏传感器的连接口:
Pulse Sensor——>A1;

本地显示模块的连接,将Menulib源码下载到另一块的arduino中,将4针IICD的OLED显示模块按照以下方式连接:
IIC  OLED:     VCC -——VCC             Arduino
GND ——GND
SCL ——SCL
SDA ——SDA
Pulse Sensor S-pin——>A0;
                                                                                                                                                                                                                                                     之所以用到两块arduino是因为源码占用了很大一部分的内存,这里就将他们分开来执行相应的功能。在Pulse_arduino.zip\Pulse_arduino\libraries\GizWits\GizWits.h中修改下我们的pk(这里是我们的Pk                                                                      号:7fc4e47382514c518c44e4fc36f4fcd3,欢迎测试),然后将源码下载成功之后,长按key2进入AirLink模式,RGB灯绿色,进入到对应的配置步骤中,配置过程参照机智云的官网介绍,这里不必累述。
        这里是我设定的三个数据点,它分别用来测量测试者周围的温湿度和使用者的心率(及脉搏,这里没有列出,它是可以测量脉搏的,后续大家可以添加试试,我自己还增加了称重模块、人体温度,这里不一一上传)。
这里是显示模块的连接,连线之间略显有点乱,所以呢小伙伴呢要重点注意布线,当然小伙伴也可以向我一样散漫些昂:

       连线完成后我满简单的介绍下,这里我的显示模块有一个小小的菜单功能,为了实现这个功能占用了对于arduino来说自身很大的内存,这点我是比较心疼的,但是丝毫呢不影响它的处理。绿色的这个就是我们简单的心率脉搏传感器,我们将其固定在面包板上,这里原本我是打算做一个精巧的包装给它打扮一下,结果未能够使实现,动手能力强或者有一定基础的可以自己打印一个美美的外壳。因为考虑到它的输出端要供给两块板子,所以需要在面包板上跳线接到两块板子上。完成上述之后会发现如来它是如此简单,因此它也将会是非常时候自己DIY使用的。

       给设备上电完成完成系统的初始化,可将中指或者食指轻放到Pulse Sensor 白色的心型部分,然后我们就可以通过本地模块以及手机端的APP进行测量者自身的心率等情况以及结合周围的环境温度给病人制定一个合理的解决方案。
APP端实时显示界面:

系统初始化前
数据上传之后数据实时的显示


本地显示:
系统初始化:
按下按键之后接入到测量界面:
实时的测量中:
测量中


三、代码分析以及功能分析
   Pulse_arduino.zip\Pulse_arduino\libraries\GizWits\GizWits.h中修改下我们的pk,这里可以使用我的PK号:7fc4e47382514c518c44e4fc36f4fcd3。这里重点的要说明下这部分的代码,其他的都是基于宠物屋的arduino版本进行修改的,不需要进行太多的说明。
       这里是利用定时器每2ms产生一个中断信号,然后来检测Pulse Sensor传感器的数据引脚输出的电信号,按照光电容积的原理算法处理后得到人体的心率,并将其通过串口打印或者显示模块等方式来将数据信息显示出来。
       interruptSetup()是使用arduino的定时器1,我发现宠物屋的源码中,定时器2已经被使用了,这时我们就需要其他定时器来做定时中断处理(arduino  UNO内部有3个定时器,time0不可被使用)。配置完定时器之后,我们需要在ISR( )函数接口中说明我们使用到了哪一个接口,这里在附录中列一些定时器1、2的地址和对应的ISR(   )入口:


  1. /*******************************************************************************
  2. * Function Name  : interruptSetup
  3. * Description    : Set Time1
  4. * Input          : None
  5. * Output         : None
  6. * Return         : None
  7. * Attention     :
  8. *******************************************************************************/
  9. void interruptSetup(){     
  10.         // Initializes Timer1 to throw an interrupt every 2mS.
  11.         TCCR1A = 0x00; // DISABLE OUTPUTS AND PWM ON DIGITAL PINS 9 & 10
  12.         TCCR1B = 0x11; // GO INTO 'PHASE AND FREQUENCY CORRECT' MODE, NO PRESCALER
  13.         TCCR1C = 0x00; // DON'T FORCE COMPARE
  14.         TIMSK1 = 0x01; // ENABLE OVERFLOW INTERRUPT (TOIE1)
  15.         ICR1 = 16000;  // TRIGGER TIMER INTERRUPT EVERY 2mS  
  16.         sei();         // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED   
  17. }

  18. /*******************************************************************************
  19. * Function Name  : ISR(TIMER1_COMPA_vect)
  20. * Description    : Callback function , Judge Wifi statue
  21. * Input          : None
  22. * Output         : None
  23. * Return         : None
  24. * Attention     :
  25. *******************************************************************************/
  26. ISR(TIMER1_OVF_vect){                         // triggered when Timer2 counts to 124
  27.   cli();                                      // disable interrupts while we do this
  28.   Signal = analogRead(pulsePin);              // read the Pulse Sensor
  29.   sampleCounter += 2;                         // keep track of the time in mS with this variable
  30.   int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise

  31.     //  find the peak and trough of the pulse wave
  32.   if(Signal < thresh && N > (IBI/5)*3){       // avoid dichrotic noise by waiting 3/5 of last IBI
  33.     if (Signal < T){                        // T is the trough
  34.       T = Signal;                         // keep track of lowest point in pulse wave
  35.     }
  36.   }

  37.   if(Signal > thresh && Signal > P){          // thresh condition helps avoid noise
  38.     P = Signal;                             // P is the peak
  39.   }                                        // keep track of highest point in pulse wave

  40.   //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  41.   // signal surges up in value every time there is a pulse
  42.   if (N > 250){                                   // avoid high frequency noise
  43.     if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){        
  44.       Pulse = true;                               // set the Pulse flag when we think there is a pulse
  45.       digitalWrite(blinkPin,HIGH);                // turn on pin 13 LED
  46.       IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
  47.       lastBeatTime = sampleCounter;               // keep track of time for next pulse

  48.       if(secondBeat){                        // if this is the second beat, if secondBeat == TRUE
  49.         secondBeat = false;                  // clear secondBeat flag
  50.         for(int i=0; i<=9; i++){             // seed the running total to get a realisitic BPM at startup
  51.           rate[i] = IBI;                     
  52.         }
  53.       }

  54.       if(firstBeat){                         // if it's the first time we found a beat, if firstBeat == TRUE
  55.         firstBeat = false;                   // clear firstBeat flag
  56.         secondBeat = true;                   // set the second beat flag
  57.         sei();                               // enable interrupts again
  58.         return;                              // IBI value is unreliable so discard it
  59.       }   


  60.       // keep a running total of the last 10 IBI values
  61.       word runningTotal = 0;                  // clear the runningTotal variable   

  62.       for(int i=0; i<=8; i++){                // shift data in the rate array
  63.         rate[i] = rate[i+1];                  // and drop the oldest IBI value
  64.         runningTotal += rate[i];              // add up the 9 oldest IBI values
  65.       }

  66.       rate[9] = IBI;                          // add the latest IBI to the rate array
  67.       runningTotal += rate[9];                // add the latest IBI to runningTotal
  68.       runningTotal /= 10;                     // average the last 10 IBI values
  69.       BPM = 60000/runningTotal;               // how many beats can fit into a minute? that's BPM!
  70.       QS = true;                              // set Quantified Self flag
  71.       // QS FLAG IS NOT CLEARED INSIDE THIS ISR
  72.     }                       
  73.   }

  74.   if (Signal < thresh && Pulse == true){   // when the values are going down, the beat is over
  75.     digitalWrite(blinkPin,LOW);            // turn off pin 13 LED
  76.     Pulse = false;                         // reset the Pulse flag so we can do it again
  77.     amp = P - T;                           // get amplitude of the pulse wave
  78.     thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
  79.     P = thresh;                            // reset these for next time
  80.     T = thresh;
  81.   }

  82.   if (N > 2500){                           // if 2.5 seconds go by without a beat
  83.     thresh = 512;                          // set thresh default
  84.     P = 512;                               // set P default
  85.     T = 512;                               // set T default
  86.     lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date        
  87.     firstBeat = true;                      // set these to avoid noise
  88.     secondBeat = false;                    // when we get the heartbeat back
  89.   }

  90.   sei();                                   // enable interrupts when youre done!
  91. }// end isr
复制代码
  1. <b><font size="4">附录:</font></b>

  2. Timer2

  3.     Pulse Sensor Arduino UNO uses Timer2 by default.
  4.     Use of Timer2 interferes with PWM on pins 3 and 11.
  5.     There is also a conflict with the Tone library, so if you want tones, use Timer1 below.

  6.       void interruptSetup(){     
  7.         // Initializes Timer2 to throw an interrupt every 2mS.
  8.         TCCR2A = 0x02;     // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
  9.         TCCR2B = 0x06;     // DON'T FORCE COMPARE, 256 PRESCALER
  10.         OCR2A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
  11.         TIMSK2 = 0x02;     // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A
  12.         sei();             // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED      
  13.       }

  14.     use the following interrupt vector with Timer2

  15. <font color="#ff0000">      ISR(TIMER2_COMPA_vect)</font>

  16. >> Timer1

  17.     Use of Timer1 interferes with PWM on pins 9 and 10.
  18.     The Servo library also uses Timer1, so if you want servos, use Timer2 above.

  19.       void interruptSetup(){     
  20.         // Initializes Timer1 to throw an interrupt every 2mS.
  21.         TCCR1A = 0x00; // DISABLE OUTPUTS AND PWM ON DIGITAL PINS 9 & 10
  22.         TCCR1B = 0x11; // GO INTO 'PHASE AND FREQUENCY CORRECT' MODE, NO PRESCALER
  23.         TCCR1C = 0x00; // DON'T FORCE COMPARE
  24.         TIMSK1 = 0x01; // ENABLE OVERFLOW INTERRUPT (TOIE1)
  25.         ICR1 = 16000;  // TRIGGER TIMER INTERRUPT EVERY 2mS  
  26.         sei();         // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED     
  27.       }

  28.     Use the following ISR vector for the Timer1 setup above

  29. <font color="#ff0000">      ISR(TIMER1_OVF_vect)</font>
复制代码

除此之外细心的小伙伴还会发现在我的源码中还定义了一个int blinkPin = 13; 这个引脚可以接一个小灯,它会随着信号值的改变而随着改变,通过它你也能够直观的看到自己的心跳哦~
          最后附上本次的代码。这一个是基于Gokit2的心率测量和连接入网功能的源码: Pulse_arduino.zip (64.51 KB, 下载次数: 4) 。这一个是本地的显示源码: Menulib.zip (181.69 KB, 下载次数: 1)。另外附上原本的传感器源码和菜单程序给大家一起玩玩: Graphics.zip (181 KB, 下载次数: 1) PulseSensorAmped_Arduino_1dot2.zip (4.55 KB, 下载次数: 17) 。小伙伴们以上均是在Arduino的IDE下实现的呢~

注:源码下载请移步到原始论坛:http://club.gizwits.com/thread-2865-1-1.html

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail