多通道ECG心率监测系统

简介: 多通道ECG心率监测系统

项目背景

心脏运作可以揭露人体许多极具价值的信息,包括其健康状态、生活方式,甚至是情绪状态及心脏疾病的早期发病等。传统的医疗设备中,监测心跳速率和心脏活动是经由测量电生理讯号与心电图 (ECG) 来完成的,需要将电极连接到身体来量测心脏组织中所引发电气活动的信

整体方案

本项目系统上位机使用 LabVIEW VI,可以形象的看到6路心电信号,下位机则使用arduino开发板,连接我们的Olimex ECG/EMG扩展板,Arduino ADC 6路读取模拟输入, LabVIEW上位机以图形方式呈现读数, 并可以保存到文件中。

下位机设计

下位机则使用arduino开发板,arduino ARDUINO UNO 中介绍 ADC(模数转换)的概念。Arduino 板有六个 ADC 通道,如下图所示。其中任何一个或全部都可以用作模拟电压的输入。Arduino Uno ADC具有10 位分辨率(因此整数值来自 (0-(2^10) 1023))。这意味着它将 0 到 5 伏之间的输入电压映射为 0 到 1023 之间的整数值。

SHIELD-EKG-EMG是一个扩展模块, 用于ARDUINO兼容电路板, 如OLIMEXINO-328, OLIMEXINO-STM32和PIC32-PINGUINO及其它. 此子板也可兼容ARDUINO电路板, 包括ARDUINO UNO. 电路板配有安装用连接器. 此产品为EKG/EMG子板, 允许Arduino类的电路板捕捉心电图肌电图信号. 此子板添加了进行生物实验反馈的新途径. 此程序可使用户可监视心跳并记录脉搏, 通过监视和分析肌肉动作来识别姿势动作.

可堆叠子板(经针座)

开放硬件,开放软件项目(用户可访问所有的设计文件)

D4/D9数字输出生成校准信号

精确的微调电位器用于校准

输入连接器, 用于无源或有源电极.

可运行3.3V和5V Arduino电路板

从Olimex ECG/EMG心电图/肌电图扩展板读取Arduino模拟输入,以图形方式呈现读数,并保存到“记录的示例”文件夹中的文件。

将工程中的库文件夹中的文件复制到你自己的Arduino库中。一般为“C:\用户\您的名称\文档\Arduino\库”。

281ef4ed0e234292a8f9f589c57d9043.png

#include <compat/deprecated.h>
#include <FlexiTimer2.h>
//http://www.arduino.cc/playground/Main/FlexiTimer2
// All definitions
#define NUMCHANNELS 6
#define HEADERLEN 4
#define PACKETLEN (NUMCHANNELS * 2 + HEADERLEN + 1)
#define SAMPFREQ 256                      // ADC sampling rate 256
#define TIMER2VAL (1024/(SAMPFREQ))       // Set 256Hz sampling frequency                    
#define LED1  13
#define CAL_SIG 9
// Global constants and variables
volatile unsigned char TXBuf[PACKETLEN];  //The transmission packet
volatile unsigned char TXIndex;           //Next byte to write in the transmission packet.
volatile unsigned char CurrentCh;         //Current channel being sampled.
volatile unsigned char counter = 0;   //Additional divider used to generate CAL_SIG
volatile unsigned int ADC_Value = 0;    //ADC current value
//~~~~~~~~~~
// Functions
//~~~~~~~~~~
/****************************************************/
/*  Function name: Toggle_LED1                      */
/*  Parameters                                      */
/*    Input   :  No                             */
/*    Output  :  No                                 */
/*    Action: Switches-over LED1.                   */
/****************************************************/
void Toggle_LED1(void){
 if((digitalRead(LED1))==HIGH){ digitalWrite(LED1,LOW); }
 else{ digitalWrite(LED1,HIGH); }
}
/****************************************************/
/*  Function name: toggle_GAL_SIG                   */
/*  Parameters                                      */
/*    Input   :  No                             */
/*    Output  :  No                                 */
/*    Action: Switches-over GAL_SIG.                */
/****************************************************/
void toggle_GAL_SIG(void){
 if(digitalRead(CAL_SIG) == HIGH){ digitalWrite(CAL_SIG, LOW); }
 else{ digitalWrite(CAL_SIG, HIGH); }
}
/****************************************************/
/*  Function name: setup                            */
/*  Parameters                                      */
/*    Input   :  No                             */
/*    Output  :  No                                 */
/*    Action: Initializes all peripherals           */
/****************************************************/
void setup() {
 noInterrupts();  // Disable all interrupts before initialization
 // LED1
 pinMode(LED1, OUTPUT);  //Setup LED1 direction
 digitalWrite(LED1,LOW); //Setup LED1 state
 pinMode(CAL_SIG, OUTPUT);
 //Write packet header and footer
 TXBuf[0] = 0xa5;    //Sync 0
 TXBuf[1] = 0x5a;    //Sync 1
 TXBuf[2] = 2;       //Protocol version
 TXBuf[3] = 0;       //Packet counter
 TXBuf[4] = 0x02;    //CH1 High Byte
 TXBuf[5] = 0x00;    //CH1 Low Byte
 TXBuf[6] = 0x02;    //CH2 High Byte
 TXBuf[7] = 0x00;    //CH2 Low Byte
 TXBuf[8] = 0x02;    //CH3 High Byte
 TXBuf[9] = 0x00;    //CH3 Low Byte
 TXBuf[10] = 0x02;   //CH4 High Byte
 TXBuf[11] = 0x00;   //CH4 Low Byte
 TXBuf[12] = 0x02;   //CH5 High Byte
 TXBuf[13] = 0x00;   //CH5 Low Byte
 TXBuf[14] = 0x02;   //CH6 High Byte
 TXBuf[15] = 0x00;   //CH6 Low Byte 
 TXBuf[2 * NUMCHANNELS + HEADERLEN] =  0x01;  // Switches state
 // Timer2
 // Timer2 is used to setup the analag channels sampling frequency and packet update.
 // Whenever interrupt occures, the current read packet is sent to the PC
 // In addition the CAL_SIG is generated as well, so Timer1 is not required in this case!
 FlexiTimer2::set(TIMER2VAL, Timer2_Overflow_ISR);
 FlexiTimer2::start();
 // Serial Port
 Serial.begin(57600);
 //Set speed to 57600 bps
 // MCU sleep mode = idle.
 //outb(MCUCR,(inp(MCUCR) | (1<<SE)) & (~(1<<SM0) | ~(1<<SM1) | ~(1<<SM2)));
 interrupts();  // Enable all interrupts after initialization has been completed
}
/****************************************************/
/*  Function name: Timer2_Overflow_ISR              */
/*  Parameters                                      */
/*    Input   :  No                             */
/*    Output  :  No                                 */
/*    Action: Determines ADC sampling frequency.    */
/****************************************************/
void Timer2_Overflow_ISR()
{
  // Toggle LED1 with ADC sampling frequency /2
  Toggle_LED1();
  //Read the 6 ADC inputs and store current values in Packet
  for(CurrentCh=0;CurrentCh<6;CurrentCh++){
    ADC_Value = analogRead(CurrentCh);
    TXBuf[((2*CurrentCh) + HEADERLEN)] = ((unsigned char)((ADC_Value & 0xFF00) >> 8));  // Write High Byte
    TXBuf[((2*CurrentCh) + HEADERLEN + 1)] = ((unsigned char)(ADC_Value & 0x00FF)); // Write Low Byte
  }
  // Send Packet
  for(TXIndex=0;TXIndex<17;TXIndex++){
    Serial.write(TXBuf[TXIndex]);
  }
  // Increment the packet counter
  TXBuf[3]++;     
  // Generate the CAL_SIGnal
  counter++;    // increment the devider counter
  if(counter == 12){  // 250/12/2 = 10.4Hz ->Toggle frequency
    counter = 0;
    toggle_GAL_SIG(); // Generate CAL signal with frequ ~10Hz
  }
}
/****************************************************/
/*  Function name: loop                             */
/*  Parameters                                      */
/*    Input   :  No                             */
/*    Output  :  No                                 */
/*    Action: Puts MCU into sleep mode.             */
/****************************************************/
void loop() {
 __asm__ __volatile__ ("sleep");
}`

上位机设计


设计一个 LabVIEW VI,

VI需要一些时间才能开始工作, 直到 LabVIEW 与 Arduino的串口输出同步。此时“当前状态”将从“初始状态”更改为“已校正偏移”。可以更改保存文件的名称。如果您想加入自己的信号处理算法,可以在“消费者循环”中执行此操作。

77f84674fb3d4a87a7ed1bb09317ad98.png


最后效果图:

3dc4ba811f034916a7399f57f5482fc1.png


总结

下位机程序已经在文章中了,需要下位机库文件和上位机labview程序的可以在评论区留下邮箱,如果这篇文章帮助了你,请好评三连呀!


目录
相关文章
|
7月前
|
传感器
光学雨量计红外雨量传感器在降水监测上具有许多优势和特点
光学雨量计红外雨量传感器在降水监测上具有许多优势和特点
光学雨量计红外雨量传感器在降水监测上具有许多优势和特点
|
7月前
|
传感器 安全
光学雨量计红外雨量传感器在降水监测上的优势与特点
光学雨量计红外雨量传感器在降水监测上的优势与特点
光学雨量计红外雨量传感器在降水监测上的优势与特点
|
7月前
光学雨量计自动化、高精度和实时监测降水量
光学雨量计是一种高精度测量降水量的理想解决方案。随着科技的进步,传统的雨量计存在一些局限性,如需要人工读取数据、易受环境影响等。而光学雨量计则利用光学原理,实现了自动化、高精度和实时监测降水量的功能。
光学雨量计自动化、高精度和实时监测降水量
|
7月前
|
数据采集 传感器 存储
光学雨量计雨量传感器的工作原理与实时数据采集
光学雨量计雨量传感器的工作原理与实时数据采集
光学雨量计雨量传感器的工作原理与实时数据采集
|
7月前
|
数据采集 机器学习/深度学习 传感器
LabVIEW在高铁温度与振动监测中的应用
LabVIEW在高铁温度与振动监测中的应用
39 4
|
7月前
|
存储 算法 数据可视化
LabVIEW实现基于DCT的野生动物监测无线图像传输
LabVIEW实现基于DCT的野生动物监测无线图像传输
45 3
|
7月前
|
数据采集 传感器 监控
LabVIEW变压器振动信号数据采集与分析
LabVIEW变压器振动信号数据采集与分析
77 2
|
传感器 安全 数据处理
无线振弦采集仪在边坡变形实时安全监测的应用介绍
边坡变形实时的安全监测一直是地质工程中的重要问题,给山区交通建设和人民生命财产带来很大的威胁。随着科技的不断发展,无线振弦采集仪作为一种新型的地质监测设备,正在被越来越广泛地应用于边坡变形实时的安全监测中。
无线振弦采集仪在边坡变形实时安全监测的应用介绍
|
7月前
振弦采集仪振动信号来评估结构的健康状况
振弦采集仪是一种常用于结构健康监测的设备,其主要用途是通过采集结构振动信号来评估结构的健康状况
|
传感器 监控 安全
红外雨量计(光学雨量传感器)检测降雨量,预防内涝
随着城市化进程的加快,城市内涝成为一个愈发严峻的问题。短时间内大量的降雨,不仅会给城市交通带来困难,也会对城市的基础设施和居民的生活造成很大的影响。因此,有效预防内涝也成为城市管理者和居民关注的焦点。
红外雨量计(光学雨量传感器)检测降雨量,预防内涝