查看: 3104|回复: 46

OLED心率示波仪

[复制链接]
  • TA的每日心情
    开心
    2021-1-15 05:20
  • 签到天数: 800 天

    [LV.10]以坛为家III

    发表于 2019-12-19 17:52 | 显示全部楼层 |阅读模式
    本帖最后由 lwq1947 于 2019-12-19 18:18 编辑

    在ARDUINO UNO开发板上插上一片0.96寸OLED显示屏并上传已下简单的程序就能构成一个OLED心率示波仪,

    #include <SPI.h>
    #include <Wire.h>
    #include <MsTimer2.h>
    //#include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>

    #define OLED_MOSI  11
    #define OLED_CLK   12
    #define OLED_DC    9
    #define OLED_CS    8
    #define OLED_RESET 10
    Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
    #define NUMFLAKES 10
    #define XPOS 0
    #define YPOS 1
    #define DELTAY 2

    #define LOGO16_GLCD_HEIGHT 16
    #define LOGO16_GLCD_WIDTH  16

    int a,b,x,y,k,t1,t2,Vmin,Vmax,Vmid,t,BPM;
    int Buffer[128];
    static const uint8_t PROGMEM Heart_16x16[] = {
    0x00,0x00,0x18,0x18,0x3C,0x3C,0x7E,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0x7F,0xFE,0x3F,0xFC,0x1F,0xF8,0x0F,0xF0,0x07,0xE0,0x03,0xC0,0x00,0x00};
    static const uint8_t PROGMEM x_16x16[] ={
    0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x80,0x00,0x80,0x04,0x00,0x04,0x08,0x24,0x04,
    0x24,0x04,0x24,0x02,0x44,0x02,0x44,0x12,0x84,0x10,0x04,0x10,0x03,0xF0,0x00,0x00};
    static const uint8_t PROGMEM l_16x16[] ={
    0x02,0x00,0x01,0x00,0x7F,0xFC,0x02,0x00,0x44,0x44,0x2F,0x88,0x11,0x10,0x22,0x48,
    0x4F,0xE4,0x00,0x20,0x01,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00};
    static const uint8_t PROGMEM s_16x16[] ={
    0x00,0x00,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x01,0x00,0x01,0x00,
    0x11,0x20,0x11,0x10,0x21,0x08,0x41,0x0C,0x81,0x04,0x01,0x00,0x05,0x00,0x02,0x00};
    static const uint8_t PROGMEM b_16x16[] ={
    0x20,0x40,0x10,0x40,0x10,0x40,0x07,0xFE,0x84,0x44,0x54,0x40,0x54,0x40,0x17,0xF8,
    0x25,0x08,0x24,0x90,0xE4,0x90,0x24,0x60,0x28,0x60,0x28,0x98,0x31,0x0E,0x26,0x04};
    static const uint8_t PROGMEM y_16x16[] ={
    0x08,0x80,0x08,0x40,0x10,0x68,0x12,0x48,0x22,0x08,0x62,0x10,0xA1,0x10,0x21,0x10,
    0x20,0xA0,0x20,0xA0,0x20,0x40,0x20,0xA0,0x21,0x10,0x22,0x0E,0x2C,0x04,0x20,0x00};

    void flash()  
    {
    digitalWrite(5, !digitalRead(5));
    }
    void setup()   {   
      Serial.begin(9600);
      MsTimer2::set(500, flash);
       MsTimer2::start();
    pinMode(13,OUTPUT);
    digitalWrite(13,HIGH);
    pinMode(5,OUTPUT);
    digitalWrite(5,LOW);
    pinMode(A0, INPUT);

    display.begin(SSD1306_SWITCHCAPVCC);
    display.clearDisplay();
    display.drawBitmap(20,0,x_16x16,16,16,WHITE);
    display.drawBitmap(40,0,l_16x16,16,16,WHITE);
    display.drawBitmap(60,0,s_16x16,16,16,WHITE);
    display.drawBitmap(80,0,b_16x16,16,16,WHITE);
    display.drawBitmap(100,0,y_16x16,16,16,WHITE);
    display.display();
    Vmax=40;
    Vmin=40;
    Vmid=40;
    b=63;
    }
    void loop() {
    k=0;
    a=0;
    for(x=0;x<128;x++){
    y=63-analogRead(A0)/30;//根据心率传感器输出模拟电压大小来调整倍率,这里输入的是PIN5输出BPM为60的方波.
    Buffer[x] = y;
    if(Buffer[x]>Vmax)
        Vmax=Buffer[x];
         if(Buffer[x]<Vmin)
        Vmin=Buffer[x];
        if(x>1&&k<1&&Buffer[x-2]<Vmid&&Buffer[x-1]>=Vmid)
    {   t1=x;
      k=1;}
    if(k==1&&Buffer[x-1]<Vmid&&Buffer[x]>=Vmid)
    {  t2=x;
    k=2;}
    display.drawLine(a, b, x, y, WHITE);
    display.display();
    delay(7);
    a=x;
    b=y;
      for(y=20;y<64;y++)
    display.drawPixel(0,y,BLACK);
      for(y=20;y<64;y++)
    display.drawPixel(x+1,y,BLACK);
    }
    display.partclearDisplay();//自定义函数清除头16行缓存显示.
    Vmid=(Vmax+Vmin)/2;
      t=t2-t1;
      if(t>0)
      BPM=1820/t;
      else
      BPM=0;
      display.drawBitmap(8,0,Heart_16x16,16,16,WHITE);
    display.setTextSize(2);
      display.setTextColor(WHITE);
      display.setCursor(36,0);
      display.println("BPM:");
      display.setCursor(90,0);
      display.println(BPM);

    }
    该心率示波仪A0口可接入输出为模拟量的心率模块.(图片显示的是自带的每分60次的方波信号)其特点是与医用心电图形显示模式一样为逐列更新波形..
    3859da6e3ea06d6f388fa024d2309fda.jpg
  • TA的每日心情
    开心
    2020-1-14 13:13
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2019-12-21 09:32 | 显示全部楼层
    不错,支持创新,这个论坛回答的人太少了,帮顶。
  • TA的每日心情
    开心
    2021-1-15 05:20
  • 签到天数: 800 天

    [LV.10]以坛为家III

     楼主| 发表于 2019-12-21 10:16 | 显示全部楼层
    feng4253 发表于 2019-12-21 09:32
    不错,支持创新,这个论坛回答的人太少了,帮顶。

    感谢你的支持,下面再给出I2C OLED显示器的程序:
    #include <SPI.h>
    #include <Wire.h>
    #include <MsTimer2.h>
    //#include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>

    #define OLED_RESET 4
    Adafruit_SSD1306 display(OLED_RESET);

    #define NUMFLAKES 10
    #define XPOS 0
    #define YPOS 1
    #define DELTAY 2


    #define LOGO16_GLCD_HEIGHT 16
    #define LOGO16_GLCD_WIDTH  16

    int a,b,x,y,k,t1,t2,Vmin,Vmax,Vmid,t,BPM;
    int Buffer[128];
    static const uint8_t PROGMEM Heart_16x16[] = {
    0x00,0x00,0x18,0x18,0x3C,0x3C,0x7E,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0x7F,0xFE,0x3F,0xFC,0x1F,0xF8,0x0F,0xF0,0x07,0xE0,0x03,0xC0,0x00,0x00};
    static const uint8_t PROGMEM x_16x16[] ={
    0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x80,0x00,0x80,0x04,0x00,0x04,0x08,0x24,0x04,
    0x24,0x04,0x24,0x02,0x44,0x02,0x44,0x12,0x84,0x10,0x04,0x10,0x03,0xF0,0x00,0x00};
    static const uint8_t PROGMEM l_16x16[] ={
    0x02,0x00,0x01,0x00,0x7F,0xFC,0x02,0x00,0x44,0x44,0x2F,0x88,0x11,0x10,0x22,0x48,
    0x4F,0xE4,0x00,0x20,0x01,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00};
    static const uint8_t PROGMEM s_16x16[] ={
    0x00,0x00,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x01,0x00,0x01,0x00,
    0x11,0x20,0x11,0x10,0x21,0x08,0x41,0x0C,0x81,0x04,0x01,0x00,0x05,0x00,0x02,0x00};
    static const uint8_t PROGMEM b_16x16[] ={
    0x20,0x40,0x10,0x40,0x10,0x40,0x07,0xFE,0x84,0x44,0x54,0x40,0x54,0x40,0x17,0xF8,
    0x25,0x08,0x24,0x90,0xE4,0x90,0x24,0x60,0x28,0x60,0x28,0x98,0x31,0x0E,0x26,0x04};
    static const uint8_t PROGMEM y_16x16[] ={
    0x08,0x80,0x08,0x40,0x10,0x68,0x12,0x48,0x22,0x08,0x62,0x10,0xA1,0x10,0x21,0x10,
    0x20,0xA0,0x20,0xA0,0x20,0x40,0x20,0xA0,0x21,0x10,0x22,0x0E,0x2C,0x04,0x20,0x00};

    void flash()  
    {
    digitalWrite(5, !digitalRead(5));
    }
    void setup()   {   
      Serial.begin(9600);
      MsTimer2::set(500, flash);
       MsTimer2::start();
    pinMode(13,OUTPUT);
    digitalWrite(13,HIGH);
    pinMode(5,OUTPUT);
    digitalWrite(5,LOW);
    pinMode(A0, INPUT);
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    display.clearDisplay();
    display.drawBitmap(20,0,x_16x16,16,16,WHITE);
    display.drawBitmap(40,0,l_16x16,16,16,WHITE);
    display.drawBitmap(60,0,s_16x16,16,16,WHITE);
    display.drawBitmap(80,0,b_16x16,16,16,WHITE);
    display.drawBitmap(100,0,y_16x16,16,16,WHITE);
    display.display();
    Vmax=40;
    Vmin=40;
    Vmid=40;
    b=63;
    }
    void loop() {
    k=0;
    a=0;
    t1=0;
    t2=0;
    for(x=0;x<128;x++){
    y=63-analogRead(A0)/30;
    Buffer[x] = y;
    if(Buffer[x]>Vmax)
        Vmax=Buffer[x];
         if(Buffer[x]<Vmin)
        Vmin=Buffer[x];
        if(x>1&&k<1&&Buffer[x-2]<Vmid&&Buffer[x-1]>=Vmid)
    {   t1=x;
      k=1;
    }
    if(k==1&&Buffer[x-1]<Vmid&&Buffer[x]>=Vmid)
    {  t2=x;
    k=2;
    }
    display.drawLine(a, b, x, y, WHITE);
    display.display();
    delay(7);
    a=x;
    b=y;
      for(y=20;y<64;y++)
    display.drawPixel(0,y,BLACK);
      for(y=20;y<64;y++)
    display.drawPixel(x+1,y,BLACK);
    }

    display.partclearDisplay();
    Vmid=(Vmax+Vmin)/2;
      t=t2-t1;
      if(t>0)
      BPM=1200/t;
      else
      BPM=0;
      display.drawBitmap(8,0,Heart_16x16,16,16,WHITE);
    display.setTextSize(2);
      display.setTextColor(WHITE);
      display.setCursor(36,0);
      display.println("BPM:");
      display.setCursor(90,0);
      display.println(BPM);

    }
  • TA的每日心情
    开心
    2020-7-8 19:59
  • 签到天数: 22 天

    [LV.4]偶尔看看III

    发表于 2020-1-15 21:41 | 显示全部楼层
    赞赞赞赞赞

    该用户从未签到

    发表于 2020-8-13 13:36 | 显示全部楼层
    谢谢分享,顶一顶。
    大家来学习学习。

    该用户从未签到

    发表于 2020-10-2 20:08 | 显示全部楼层
    请教大神代码里的partclearDisplay部分缺失如何解决
  • TA的每日心情
    开心
    2021-1-15 05:20
  • 签到天数: 800 天

    [LV.10]以坛为家III

     楼主| 发表于 2020-10-3 06:12 | 显示全部楼层
    wulitz 发表于 2020-10-2 20:08
    请教大神代码里的partclearDisplay部分缺失如何解决

    在Adafruit_SSD1306.h库的CPP文件中
    void Adafruit_SSD1306::clearDisplay(void) {
      memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8));
    }后面自行添加
    void Adafruit_SSD1306::partclearDisplay(void) {
      memset(buffer, 0, (256));
    }
    就可以了.
    如果自己不方便改可用下面我改好的库文件,为了安全可先将你的Adafruit_SSD1306.h库从libraries中移出在粘贴我的库.

    Adafruit_SSD1306.rar

    20.19 KB, 下载次数: 12

    库文件

    该用户从未签到

    发表于 2020-10-3 10:35 | 显示全部楼层
    lwq1947 发表于 2020-10-3 06:12
    在Adafruit_SSD1306.h库的CPP文件中
    void Adafruit_SSD1306::clearDisplay(void) {
      memset(buffer, 0,  ...

    谢谢大神,这个问题解决了,但心率监测器检测十分不稳定,bpm经常两百多。。。现在还找不到啥好的解决方法,大神有啥建议可以参考一下吗
  • TA的每日心情
    开心
    2021-1-15 05:20
  • 签到天数: 800 天

    [LV.10]以坛为家III

     楼主| 发表于 2020-10-3 12:10 | 显示全部楼层
    wulitz 发表于 2020-10-3 10:35
    谢谢大神,这个问题解决了,但心率监测器检测十分不稳定,bpm经常两百多。。。现在还找不到啥好的解决方 ...

    能看到波行吗,如果波形小而杂乱是测不准的,你用的是什么传感器.

    该用户从未签到

    发表于 2020-10-3 16:47 | 显示全部楼层
    lwq1947 发表于 2020-10-3 12:10
    能看到波行吗,如果波形小而杂乱是测不准的,你用的是什么传感器.

    用的pulsesensor,现在发现的问题有:
    不放手指bpm会有示数
    放手指大概率无波形
    轻按会有规律的波形,会不会是信号需要放大呢
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    热门推荐

    ps2遥控小车——uno实现
    ps2遥控小车——uno实现
    前几天在阁楼发现了好久以前3d打印,激光切割的底盘,于是决定做这个东西 正好手上又
    【干货分享】mega2560原理图PCB图纸altium designer18
    【干货分享】mega2560原理
    分享一下mega2560的板子 AD版本 **** 本内容被作者隐藏 **** ergo
    【教程】使用分离式蓝牙gps做一块Twatch运动手表
    【教程】使用分离式蓝牙gp
    使用分离式蓝牙gps做一块Twatch运动手表 【前言】 我喜欢跑步,也喜欢
    收集的几种连杆机构:机器人行走背后的机械原理
    收集的几种连杆机构:机器
    机器人概念已经红红火火好多年了,目前确实有不少公司已经研制出了性能非常优越的机器
    按键中断无法触发
    按键中断无法触发
    如题,按键中断无法触发,设成电平变化触发中断程序,但是flag的状态一直不变 void
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
    快速回复 返回顶部 返回列表