林林 发表于 2016-7-19 10:29:54

【Arduino】+智能健康计

本帖最后由 林林 于 2016-8-25 18:04 编辑

【开源硬件】机智云智能硬件创新大赛http://club.gizwits.com/thread-2646-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显示模块按照以下方式连接:IICOLED:   VCC ­——VCC             ArduinoGND ——GNDSCL ——SCLSDA ——SDAPulse 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已经被使用了,这时我们就需要其他定时器来做定时中断处理(arduinoUNO内部有3个定时器,time0不可被使用)。配置完定时器之后,我们需要在ISR( )函数接口中说明我们使用到了哪一个接口,这里在附录中列一些定时器1、2的地址和对应的ISR(   )入口:


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

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

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

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

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

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

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


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

      for(int i=0; i<=8; i++){                // shift data in the rate array
      rate = rate;                  // and drop the oldest IBI value
      runningTotal += rate;            // add up the 9 oldest IBI values
      }

      rate = IBI;                        // add the latest IBI to the rate array
      runningTotal += rate;                // add the latest IBI to runningTotal
      runningTotal /= 10;                     // average the last 10 IBI values
      BPM = 60000/runningTotal;               // how many beats can fit into a minute? that's BPM!
      QS = true;                              // set Quantified Self flag
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }                     
}

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

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

sei();                                 // enable interrupts when youre done!
}// end isr<b><font size="4">附录:</font></b>

Timer2

    Pulse Sensor Arduino UNO uses Timer2 by default.
    Use of Timer2 interferes with PWM on pins 3 and 11.
    There is also a conflict with the Tone library, so if you want tones, use Timer1 below.
   
      void interruptSetup(){   
      // Initializes Timer2 to throw an interrupt every 2mS.
      TCCR2A = 0x02;   // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
      TCCR2B = 0x06;   // DON'T FORCE COMPARE, 256 PRESCALER
      OCR2A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
      TIMSK2 = 0x02;   // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A
      sei();             // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED      
      }

    use the following interrupt vector with Timer2
   
<font color="#ff0000">      ISR(TIMER2_COMPA_vect)</font>
      
>> Timer1
   
    Use of Timer1 interferes with PWM on pins 9 and 10.
    The Servo library also uses Timer1, so if you want servos, use Timer2 above.
   
      void interruptSetup(){   
      // Initializes Timer1 to throw an interrupt every 2mS.
      TCCR1A = 0x00; // DISABLE OUTPUTS AND PWM ON DIGITAL PINS 9 & 10
      TCCR1B = 0x11; // GO INTO 'PHASE AND FREQUENCY CORRECT' MODE, NO PRESCALER
      TCCR1C = 0x00; // DON'T FORCE COMPARE
      TIMSK1 = 0x01; // ENABLE OVERFLOW INTERRUPT (TOIE1)
      ICR1 = 16000;// TRIGGER TIMER INTERRUPT EVERY 2mS
      sei();         // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED   
      }
      
    Use the following ISR vector for the Timer1 setup above
   
<font color="#ff0000">      ISR(TIMER1_OVF_vect)</font>            除此之外细心的小伙伴还会发现在我的源码中还定义了一个int blinkPin = 13; 这个引脚可以接一个小灯,它会随着信号值的改变而随着改变,通过它你也能够直观的看到自己的心跳哦~
          最后附上本次的代码。这一个是基于Gokit2的心率测量和连接入网功能的源码:。这一个是本地的显示源码:。另外附上原本的传感器源码和菜单程序给大家一起玩玩:、。小伙伴们以上均是在Arduino的IDE下实现的呢~



maomaodemao 发表于 2016-11-26 00:18:55

arduino的项目啊,支持到底,arduino的项目太少了,感觉官方的案例也很少,谢谢楼主的分享

jan 发表于 2016-7-19 10:45:58

楼主加油!期待楼主的新成果

admin 发表于 2016-7-19 10:39:37

帅气的林林 感觉作品会很棒很实用

林林 发表于 2016-7-19 10:59:09

admin 发表于 2016-7-19 10:39
帅气的林林 感觉作品会很棒很实用

谢谢谢谢我会加油的

林林 发表于 2016-7-19 11:00:37

jan 发表于 2016-7-19 10:45
楼主加油!期待楼主的新成果

谢谢支持,到时我尽力开源出来大家一起玩昂,这套东西加起来也不过几十块钱,极大的提高了开发效率同时极低的成本管理。

林林 发表于 2016-8-25 18:05:00

完成咯,虽然很Low,还是咬牙提交了

安安 发表于 2016-8-25 22:39:38

看了一下,感觉还不错,期待可以上市:lol:)

林林 发表于 2016-8-26 13:02:50

安安 发表于 2016-8-25 22:39
看了一下,感觉还不错,期待可以上市

距离市场还有很大的差距呢

true 发表于 2016-9-9 15:14:46

非常棒的Arduino项目

林林 发表于 2016-9-9 23:09:40

true 发表于 2016-9-9 15:14
非常棒的Arduino项目

但是有个小小的不足,就是arduino的flash只有32k,本地显示再加原本的代码之后,容量远远的不够,考虑是否添加一个外部存储器来处理。另外考虑用bmd101来试试,换种测量当时可能会很好。谢谢你的评价。

淡忘瞬间 发表于 2016-10-1 21:24:38

也很想做一个医疗物联网方面的项目 加油

林林 发表于 2016-11-29 14:44:52

maomaodemao 发表于 2016-11-26 00:18
arduino的项目啊,支持到底,arduino的项目太少了,感觉官方的案例也很少,谢谢楼主的分享 ...

嘿嘿嘿,arduino的太简单了其实

019 发表于 2017-1-25 19:30:04

厉害!学习了!

HsuehBo 发表于 2017-5-14 09:21:14

您好大佬,我现在在做一个类似的项目,非常渴望得到您的帮助,由于我是小白,有很多不懂得地方,非常希望能够得到跟您讨教的机会!也不知道您的联系方式,只能麻烦您看到这个消息之后加一下我QQ了,249172993,若能得到您的帮助,定将感激不尽!

清木 发表于 2018-7-17 00:09:00

好多用arduino的,我还在学51单片机,悲剧的很

sany123 发表于 2018-10-22 15:18:24

感谢楼主分享。学习,学习。。。

小爬虫 发表于 2018-11-23 00:34:34

新手 求问 product secret 怎么获得?

woshizhazha 发表于 2019-3-5 07:41:34

楼主,求具体的链接方法,2686014036@qq.com

woshizhazha 发表于 2019-3-5 07:59:47

林林 发表于 2016-9-9 23:09
但是有个小小的不足,就是arduino的flash只有32k,本地显示再加原本的代码之后,容量远远的不够,考虑是 ...

你好,求具体的实物连接方式,小白刚刚学习arduino,可能有些生疏,但是arduino的项目不多,请求大佬赐教2686014036@qq.com
页: [1]
查看完整版本: 【Arduino】+智能健康计