LabVIEW心率监测装置

2023-11-04

LabVIEW大作业

LabVIEW心率采集装置

本设计为我的LabVIEW课程大作业,利用proteus实验仿真软件设计一个了基于stc12c5a单片机的心率采集系统,并在PC机上的Windows环境下利用LabVIEW软件实现心率数据的处理与显示。以下为效果演示视频:

心率监测装置

一、设计简介
设计目标:利用proteus实验仿真软件设计一个基于stc12c5a单片机的心率采集系统,并在PC机上的Windows环境下利用LabVIEW软件实现心率数据的处理与显示。
实现功能:
1、利用pulse sensor心率脉冲传感器实现对血管脉动进行采集;
2、利单片机可以通过串口通讯向PC机传输数据;
3、在PC机上的Windows环境下利用LabVIEW软件实现对心率的监视;
4、单片机实时显示心率;
4、进行心率分析,对异常心率有报警提示功能;
5、心率数据进行保存与发送;
实验设备:
1、PC机
2、安装LabVIEW软件
3、安装Keil uVision4软件
4、51单片机
5、pulse sensor心率脉冲传感器

二、总体设计
本设计主要利用pulse sensor心率脉冲传感器通过血管搏动时造成透光率变化影响感光器件阻值进而影响输出电压来反应心率变化。
系统总体图

通过单片机对传感器传输的模拟量进行数模转换,采取定时器查询方式检测转换计算心率,通过串口通讯向LabVIEW传输数据,labview对数据进行解析运算实现对心率的实时显示、对异常心率有报警提示、心率数据进行保存与发送等功能。

三、硬件设计

硬件选择:
设备电路板:51开发板;
芯片选择 :STC12C5A60S2;
单片机显示:LCD1602;
心率采集传感器:pulse sensor心率脉冲传感器;

在这里插入图片描述

四、软件设计
软件部分分为单片机程序编程与LabVIEW程序编程。
LabVIEW上位机编程部分:

在这里插入图片描述
五、程序
LabVIEW程序:

在这里插入图片描述
由于后来没时间所以未进行功能封装。

单片机程序:
main.c

//ADC PIN:P1.0
//SYSTEM CLOCK:11.0592MHz
//Baudrate:115200
//UART:P3.0/rxd P3.1/txd
#include <STC12C5A60S2.h>
#include "stdio.h"
#include <LCD1602.h>

#define false 0
#define true 1
#define FOSC 11059200L		    //系统时钟
#define BAUD 115200				//波特率
#define T0MS (65536-FOSC/12/500)//500HZ in 12T MODE

#define ADC_POWER 0x80			//ADC POWER CONTROL BIT
#define ADC_FLAG 0x10			//ADC COMPLETE FLAG
#define ADC_START 0x08;			//ADC START CONTROL BIT
#define ADC_SPEEDLL 0x00		//540 CLOCKS
#define ADC_SPEEDL 0x20			//360 CLOCKS
#define ADC_SPEEDH 0x40			//180 CLOCKS
#define ADC_SPEEDHH 0x60		//90 CLOCKS
#define ADC_MASK 0x01

void UART_init(void); 
void ADC_init(unsigned char channel);
void T0_init(void);
void sendDataToProcessing(char symbol, int dat);
void UART_send(char dat);

unsigned char PulsePin = 0;       // P1.0为传感器输入口)
int fadeRate = 0;               

volatile unsigned int BPM;               
volatile unsigned int Signal;             
volatile unsigned int IBI = 600;         
volatile bit Pulse = false;              
volatile bit QS = false;                  
volatile int rate[10];                    
volatile unsigned long sampleCounter = 0;  // 用于确定脉冲时序
volatile unsigned long lastBeatTime = 0;   
volatile int Peak =512;                    
volatile int Trough = 512;                 
volatile int thresh = 512;                 
volatile int amp = 100;                    
volatile bit firstBeat = true;             
volatile bit secondBeat = false;           
static unsigned char order=0;
							   
unsigned char code ucForum0[]="Heart rate  test";
unsigned char code ucForum1[]="  BPM:          ";
unsigned char DisBuff[4]={0};

void sys_init()
{
	UART_init();            
	ADC_init(PulsePin);
	T0_init();                   
	LCD1602_Init();	  //液晶初始化
}

void main(void)
{
	sys_init();
	LCD1602_DisplayString(ucForum0);	//显示的内容
	LCD1602_MoveToPosition(1,0);	    //显示位置移动到指定位置
	LCD1602_DisplayString(ucForum1);	//显示的内容
	while(1)
	{
		sendDataToProcessing('S', Signal);   //  发送数据
		if (QS == true)
		{                                    
			fadeRate = 255;                
			sendDataToProcessing('B',BPM);    
			sendDataToProcessing('Q',IBI);    
			QS = false;                      
			LCD1602_MoveToPosition(1,9);
			LCD1602_DisplayString(DisBuff);			 
		}
		delay(138);                          //  take a break 19.6ms	
	}
}

void sendDataToProcessing(char symbol, int dat )
{
    putchar(symbol);                
	printf("%d\n",dat);			//串口发送
}
void UART_init(void)
{
   PCON &= 0x7f;    //波特率不倍速
   SCON  = 0x50;    //8位数据,可变波特率
   BRT   = 0xFD;    //独立波特率产生器初值
   AUXR |= 0x04;    //时钟设置为1T模式
   AUXR |= 0x01;    //选择独立波特率产生器
   AUXR |= 0x10;    //启动波特率产生
}
 char putchar(unsigned char dat)
{
	TI=0;
	SBUF=dat;
	while(!TI);
	TI=0;	
	return SBUF;
}

void T0_init(void)
{                         
	TMOD |= 0x01;	 // 初始化定时器0,2mS一个中断。
	TL0=T0MS;
	TH0=T0MS>>8;
	TR0=1;		
	ET0=1;		
    EA=1;                   
} 

void ADC_init(unsigned char channel)
{
	P1ASF=ADC_MASK<<channel;	//启用PlusePin作为ADC输入
	ADC_RES=0;	
	ADC_RESL=0;	
	AUXR1 |= 0x04;          	//调整ADC结果的格式
	ADC_CONTR=channel|ADC_POWER|ADC_SPEEDLL|ADC_START;	//打开ADC电源并开始转换
}

unsigned int analogRead(unsigned char channel)
{
	unsigned int result;
	ADC_CONTR &=!ADC_FLAG;	//clear ADC FLAG
	result=ADC_RES;
	result=result<<8;
	result+=ADC_RESL;
	ADC_CONTR|=channel|ADC_POWER|ADC_SPEEDLL|ADC_START;
	return result;
}

// Timer 0中断子程序,每2MS中断一次,读取AD值,计算心率值
void Timer0_rountine(void) interrupt 1
{                       
	int N;
	unsigned char i;
	// 保持最后10个IBI值的总和
	unsigned int runningTotal = 0;                     	
	EA=0;                                      
	TL0=T0MS;
	TH0=T0MS>>8;			      			//重新加载16位计时器0
	Signal = analogRead(PulsePin);          
	sampleCounter += 2;                    
	N = sampleCounter - lastBeatTime;      	
										     
	if(Signal < thresh && N > (IBI/5)*3)
	{                                        // 通过等待最后一个IBI的3/5来避免二脉噪声 IBI
		if (Signal < Trough)
		{                                    //T是低谷
			Trough = Signal;                 //跟踪脉搏波的最低点 
		}
	}
	
	if(Signal > thresh && Signal > Peak)
	{    //避免噪音
		Peak = Signal;                       // P是峰值
	}                                        // 跟踪脉搏波的最高点	
											 // 每次有脉冲时,信号的值就会飙升
	if (N > 250)
	{                                        // avoid high frequency noise
		if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) )
		{        
			Pulse = true;                               // 当我们认为有脉冲时设置脉冲标志
			IBI = sampleCounter - lastBeatTime;         // 测量拍之间的时间(毫秒
			lastBeatTime = sampleCounter;               // 跟踪下一个脉冲的时间			
			if(secondBeat)
			{                         // 如果这是第二拍,如果secondBeat == TRUE
				secondBeat = false;   // 清除secondBeat标志
				for(i=0; i<=9; i++)
				{                     // 启动时获得实际的BPM
					rate[i] = IBI;                      
				}
			}	
			if(firstBeat)
			{                        
				firstBeat = false;                   
				secondBeat = true;                   
				EA=1;                                
				return;                             
			}   
			for(i=0; i<=8; i++)
			{                                     
				rate[i] = rate[i+1];              
				runningTotal += rate[i];          
			}	
			rate[9] = IBI;                       
			runningTotal += rate[9];             
			runningTotal /= 10;                     
			BPM = 60000/runningTotal;      // 一分钟能容纳多少拍子,BPM
			if(BPM>200)BPM=200;			   //限制BPM最高显示值
			if(BPM<30)BPM=30;			   //限制BPM最低显示值
			DisBuff[2]   = BPM%10+48;      //取个位数
			DisBuff[1]   = BPM%100/10+48;  //取十位数
			DisBuff[0]   = BPM/100+48;	   //百位数
			if(DisBuff[0]==48)
			DisBuff[0]=32;
			QS = true;                     //标志
		}                       
	}

	if (Signal < thresh && Pulse == true)
	{   // 当值下降时,节拍结束
		//    blinkPin=1;            
		Pulse = false;               
		amp = Peak - Trough;         
		thresh = amp/2 + Trough;    
		Peak = thresh;               
		Trough = thresh;
	}
	if (N > 2500)
	{                           // 如果2.5秒不停地过去
		thresh = 600;   		// 设置阈值默认值
		Peak = 600;             // 设置P默认值
		Trough = 600;                          
		lastBeatTime = sampleCounter;                  
		firstBeat = true;                      
		secondBeat = false;                    
	}
	EA=1;                                      
}

LCD1602.c

#include <STC12C5A60S2.h>
#include "stdio.h"
#include <LCD1602.h>
sbit LCD1602_RS = P3^5;	//位定义,液晶的数据/命令选择
sbit LCD1602_RW = P3^6;	//位定义,液晶的读写选择
sbit LCD1602_EN = P3^4;	//位定义,液晶使能信号
#define LCDPORT P0	    //液晶的数据口

/******************************************************************************
函数功能:忙检测
*******************************************************************************/
void LCD1602_CheckBusy(void)		
{
	unsigned char i = 255;
	LCDPORT = 0xFF;  //读之前先置位,准备读取IO口数据
	LCD1602_RS = 0;
	LCD1602_RW = 1;	 //使液晶处于读数据状态
	LCD1602_EN = 1;	 //使能液晶,高电平有效
	while((i--) && (LCDPORT & 0x80));	//忙检测
	LCD1602_EN = 0;
}

/******************************************************************************
向LCD1602液晶写入数据或者命令
*******************************************************************************/
void LCD1602_WriteInformation(unsigned char ucData,bit bComOrData)	 
{
	LCD1602_CheckBusy();	 //在写入数据或者命令前先进行忙检测
	LCDPORT = ucData;		 //先将数据或者命令送至IO
	LCD1602_RS = bComOrData; //确定是写入数据还是写命令
	LCD1602_RW = 0;		     //使液晶处于写入信息状态
	LCD1602_EN = 1;		     //使能液晶,高电平有效
	LCD1602_EN = 0;
}

/******************************************************************************
LCD1602_Init液晶初始化函数
*******************************************************************************/
void LCD1602_Init(void)		 
{
	LCD1602_WriteInformation(0x38,0);
	delay(300);
	LCD1602_WriteInformation(0x38,0);
	delay(100);
	LCD1602_WriteInformation(0x38,0);
	delay(100);
	LCD1602_WriteInformation(0x38,0); 	//写入命令,5x7点阵工作方式,8位数据接口
	delay(100);
	LCD1602_WriteInformation(0x0c,0);	//显示设置,开显示,光标不显示,不闪烁
	delay(20);
	LCD1602_WriteInformation(0x01,0);	//清屏指令
	delay(20);
}

/******************************************************************************
LCD1602_MoveToPosition将液晶的光标移动到指定的位置
*******************************************************************************/
void LCD1602_MoveToPosition(unsigned char x,unsigned char y)	
{
	if(0 == x)
		LCD1602_WriteInformation((0x80 | y),0);	   //光标定位到第一行的y列
	if(1 == x)
		LCD1602_WriteInformation((0xC0 | y),0);	   //光标定义到第二行的y列
}

/******************************************************************************
LCD1602在指定的位置上显示指定的字符
*******************************************************************************/
void LCD1602_DisplayOneCharOnAddr(unsigned char x,unsigned char y,unsigned char ucData)
{
	LCD1602_MoveToPosition(x,y);          //光标位置
	LCD1602_WriteInformation(ucData,1);	  //写入数据
}

/******************************************************************************
LCD1602显示字符串
*******************************************************************************/
void LCD1602_DisplayString(unsigned char *ucStr)	
{
	while(*ucStr != '\0')	   //字符串结束之前,循环显示
	{
		 LCD1602_WriteInformation(*ucStr,1);	 //依次写入每一个字符
		 ucStr++;								 //指针增加
	}
}

/******************************************************************************
延时函数
*******************************************************************************/
void delay(unsigned int n)
{
	unsigned int i,j;
	for(i=0;i<n;i++)
		for(j=0;j<100;j++);
}

LCD1602.h

#ifndef LCD1602_H
#define LCD1602_H

void delay(unsigned int uiCount);	//延时函数
void LCD1602_CheckBusy(void);	    //液晶忙检测
void LCD1602_WriteInformation(unsigned char ucData,bit bComOrData);	//在液晶上写数据或者写命令,0为命令,1为数据
void LCD1602_Init(void);	        //液晶初始化
void LCD1602_MoveToPosition(unsigned char x,unsigned char y);	                        //液晶的坐标移动到指定位置
void LCD1602_DisplayOneCharOnAddr(unsigned char x,unsigned char y,unsigned char ucData);//在液晶指定位置显示字符
void LCD1602_DisplayString(unsigned char *ucStr);	//在液晶上显示字符串
#endif  
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LabVIEW心率监测装置 的相关文章

  • linux进程调度,优先级、进程nice值

    我自己补充一下 APUE8 16中讲到进程调度 UNIX系统历史上对进程提供的只是基于调度优先级的粗粒度的控制 调度策略和调度优先级是由内核确定的 但是内核可以通过调整nice值选择以更低优先级运行 通过调整nice值降低它对cpu的占有
  • telnet mysql3306端口失败

    在linux上telnet远程mysql端口失败 经过上网查找后 找到多种方法 1 我在本地的Navicat上新增了一个用户 主机名是linux的ip 也可以是 百分号代表这个用户可以在任何地方对mysql进行远程连接 2 登录mysql
  • mipsel-openwrt-linux交叉编译zlog日志库并测试

    mipsel openwrt linux交叉编译zlog日志库并测试 文章目录 mipsel openwrt linux交叉编译zlog日志库并测试 一 准备 二 交叉编译测试 1 mipsel openwrt linux交叉编译过程 ar
  • 机器学习集成模型学习——Bagging集成学习(三)

    Bagging bagging的集成方式是 用1个模型 元模型 然后将这个元模型分成多个相同模型 每个模型使用训练集的一部分进行训练 得到多个基模型 最后测试时分别跑每个模型 平均结果得出这个集成模型的最终预测结果 案例代码 from sk

随机推荐

  • VSCode将QT(shadow build)编译输出到指定文件

    VSCode将QT shadow build 编译输出到指定文件 一 啥是shadow build 实际上就是将编译输出的文件跟源码文件放在不同地方 也就是out of source 0 00 在qtcreator中设置就很方便很方便 直接
  • C#将字符串格式化为Json

    private string ConvertStringToJson string str 格式化json字符串 JsonSerializer serializer new JsonSerializer TextReader tr new
  • 如何判断Javascript对象是否存在

    Javascript语言的设计不够严谨 很多地方一不小心就会出错 举例来说 请考虑以下情况 现在 我们要判断一个全局对象myObj是否存在 如果不存在 就对它进行声明 用自然语言描述的算法如下 if myObj不存在 声明myObj 你可能
  • 机器学习总结之第二章模型评估与选择

    2 1经验误差与过拟合 错误率 a个样本分类错误 m个样本 精度 1 错误率 误差 学习器实际预测输出与样本的真是输出之间的差异 训练误差 即经验误差 学习器在训练集上的误差 泛化误差 学习器在新样本上的误差 过拟合 学习器把训练样本学的
  • PHP自增、自减运算流程解析

    PHP自增运算解析 0x01 PHP自增运算 代码如下 0x02 PHP自减运算 代码如下 0x01 PHP自增运算 代码如下
  • Java判断一个时间是否在时间区间内

    package com liying tiger test import java text ParseException import java text SimpleDateFormat import java util Calenda
  • 图像处理——滤波器的比较

    滤波器 方框滤波 boxFilter 均值滤波 blur 高斯滤波 GaussianBlur 中值滤波 medianBlur 线性滤波器 线性滤波器经常用于剔除输入信号中不想要的频率或者从许多频率中选择一个想要的频率 常见的有 低通 高通
  • linux命令 chmod 755的含义 及drwxr-xr-x 的含义

    linux drwxr xr x 第一位表示文件类型 d是目录文件 l是链接文件 是普通文件 p是管道 第2 4位表示这个文件的属主拥有的权限 r是读 w是写 x是执行 第5 7位表示和这个文件属主所在同一个组的用户所具有的权限 第8 10
  • docker 安装node

    docker 安装node 1 使用docker安装node 使用docker安装 docker pull node 拉取镜像 docker run id name c node node 创建容器 可以看到已经装好了 启动node doc
  • Linux系统编程-C++ I/O库

    文章目录 一 总述 二 输出缓冲 三 文件输入输出 四 string流 五 输入输出格式 总述 1 控制布尔值的格式 2 指定整型值的进制 3 在输出中指出进制 4 控制浮点数格式 4 1 指定打印精度 5 输出空白 六 未格式化的输入输出
  • java 数组中存储26个英文字母_利用数组打印26个英文字母

    可以考虑下面两种程序 1 public class Letter public static void main String args for char c a c lt z c System out print c 2 class AB
  • 如何实现一个定时器?看这一篇就够了

    本文主要介绍定时器作用 实现定时器数据结构选取 并详细介绍了跳表 红黑树 时间轮实现定时器的思路和方法 定时器作用 定时器在各种场景都需要用到 比如游戏的Buff实现 Redis中的过期任务 Linux中的定时任务等等 顾名思义 定时器的主
  • Qt常用部件介绍

    这里先给大家介绍 Designer 界面设计器 中例举的常用部件 以便对 Qt 的部件有一定认识 其具体用法后面再作介绍 布局管理组 Layouts 空间间隔组 弹簧 Spacers 按钮组 buttons 项目视图组 Item Views
  • 设计模式深入浅出--21.命令模式简单实例及其在JDK中的应用

    命令模式 定义 将 请求 封装成对象 以便使用不同的请求 命令模式解决了应用程序中对象的职责以及它们之间的通信方式 类型 行为型 适用场景 请求调用者和请求接收者需要解耦 使得调用者和接收者不直接交互 需要抽象出等待执行的行为 优点 降低解
  • 数据表格(QTableWidget)

    一 简介 QTableWidget是QT对话框设计中常用的显示数据表格的控件 QTableWidget单元格数据是QTableWidgetItem对象来实现的 整个表格都需要用逐个单元格对象QTableWidgetItem构建起来 二 详解
  • Presto 与 Hive 语法学习

    Presto 与 Hive 语法学习 文章目录 Presto 与 Hive 语法学习 1 Presto语法 1 1 数据类型 布尔值 整数 浮点 固定精度 字符串 日期和时间 结构 网络地址 UUID HyperLogLog KHyperL
  • muduo1——编程风格:面向对象的编程和基于对象的编程(上)

    muduo库其实不是面向对象的编程 而是基于对象的编程 那么在进入正式的muduo源码分析之前 先来看看这两种编程风格 一 面向对象编程风格 通过对一个线程类的封装来进行讲解 Thread是一个抽象类不能实例化对象 TestThread是派
  • Hp DL380服务器瘫痪如何恢复服务器数据(多图)

    服务器数据恢复故障简介 需要进行数据恢复的是一台HP DL380服务器 三块300GSAS硬盘组成raid阵列 磁盘故障导致整个RAID组瘫痪 其中一块硬盘状态灯为红色 数据库存储在D分区 备份存储在E分区 存储故障 造成D分区不可识别 E
  • Python 关键字global全局变量详解

    变量作用域 一般在函数体外定义的变量成为全局变量 在函数内部定义的变量称为局部变量 全局变量所有作用域都可用 局部变量只能在本函数可用 变量的使用顺序是 局部变量 gt 全局变量 也就是说 优先使用局部变量 那么问题来了 如果想在函数内使用
  • LabVIEW心率监测装置

    LabVIEW大作业 LabVIEW心率采集装置 本设计为我的LabVIEW课程大作业 利用proteus实验仿真软件设计一个了基于stc12c5a单片机的心率采集系统 并在PC机上的Windows环境下利用LabVIEW软件实现心率数据的