当前位置: 首页 > news >正文

基于STC89C52单片机的脉搏测量仪设计

目 录
摘要 I
Abstract II
引言 1
第一章 概述 2
1.1 选题的背景和意义 2
1.2 脉搏测量仪的发展与应用 3
第二章 总体方案的论证与设计 5
2.1主控模块的选型和论证 5
2.2显示模块的选型和论证 5
2.3传感器的选型和论证 5
2.4系统整体设计概述 6
第三章 系统硬件电路设计 8
3.1主控模块 8
3.1.1 STC89C52单片机主要特性 8
3.1.2 STC89C52单片机的中断系统 12
3.1.3单片机最小系统设计 12
3.2显示模块电路 12
3.3信号采集电路设计 16
3.3.1传感器简介 16
3.3.2滤波电路 17
3.3.3放大整形电路 17
第四章 系统软件设计 17
4.1系统软件总体设计 17
4.2程序设计原理 19
第五章 系统调试 21
5.1软件调试 21
5.2硬件调试 21
5.3调试结果 22
5.4误差分析 22
结论 24
致谢 25
参考文献 26
附录 27
第二章 总体方案的论证与设计
2.1主控模块的选型和论证
方案一:
采用MSP430系列单片机,该单片机是TI公司1996年开始推向市场的一种16位超低功耗的混合信号处理器。其内部集成了很多模拟电路、数字电路和微处理器,提供强大的功能。不过该芯片昂贵不适合一般的设计开发[3]。
方案二
采用51系列的单片机,该单片机是一个高可靠性,超低价,无法解密,高性能的8位单片机,32个IO口,且STC系列的单片机可以在线编程、调试,方便地实现程序的下载与整机的调试。
因此选用方案二中的51系列单片机作为主控芯片。
2.2显示模块的选型和论证
方案一:
采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较合适,如采用在显示数字显得太浪费,且价格也相对较高,所以不用此种作为显示。
方案二:
采用LED数码管动态扫描,LED数码管价格虽适中,对于显示数字也最合适,而且采用动态扫描法与单片机连接时,占用单片机口线少。
所以本设计中方案二中的数码管显示屏作为显示模块。
2.3传感器的选型和论证
方案一:
采用压电传感器用来提取人的脉搏信号,压电传感器是利用某些电介质受力后产生的压电效应制成的传感器。所谓压电效应是指某些电介质在受到某一方向的外力作用而发生形变(包括弯曲和伸缩形变)时,由于内部电荷的极化现象,会在其表面产生电荷的现象。通过此现象可以提取出人的脉搏信号。
方案二:
采用光电传感器提取人体脉搏信号,授予手指组织可以分成皮肤、肌肉、骨骼等非血液组织和血液组织,其中非血液组织的光吸收量是恒定的,而在血液中,静脉血的搏动相对动脉血是十分微弱的,本文转载自http://www.biyezuopin.vip/onews.asp?id=14914可以忽略,因此可以认为光透过手指后的变化仅由动脉血的充盈而引起,那么在恒定波长的光源的照射下,通过检测透过手指的光强将可以间接测量到人体的脉搏信号[4]。
由于光电传感器较压电传感器容易在一般的地方可以买得到,因此这里选用光电传感器来提取人体脉搏信号。
2.5系统整体设计概述

系统总体设计由STC89C52、按键、数码管、光电传感器、时钟模块、运放等构成,如图2.1所示,系统设有四个按键,可以设置上下限脉搏数,当超过范围的时候单片机会驱动蜂鸣器发响,脉搏测量的时候需要人把手轻轻的按在光电传感器上面,由于人脉搏跳动的时候,血液的透光性不一样会导致接收器那边接收的信号强弱不一样,间接的把人脉搏信号传回,通过运放对其进行放大、整形后连接到单片机的IO口,单片机利用外部中断对其进行计数,最终换算成人一分钟脉搏的跳动次数,最终显示在数码管上。

#include <reg52.h>	         //调用单片机头文件
#define uchar unsigned char  //无符号字符型 宏定义	变量范围0~255
#define uint  unsigned int	 //无符号整型 宏定义	变量范围0~65535
#include <intrins.h>


bit flag_300ms ;

uchar menu_1;           //菜单设计的变量
uchar smg_i = 3;    //显示数码管的个位数


uchar code table_num[]="0123456789abcdefg";

      //数码管段选定义 0     1    2    3 	  4	   5	6	 7	  8	   9	
uchar code smg_du[]={0x14,0x77,0x4c,0x44,0x27,0x82,0x84,0x87,0x04,0x05,
//					   A	B	 C	  D	   E   F	不显示
				 	   0x06,0xa4,0x9c,0x64,0x8c,0x8e,0xff};	 //断码	
uchar dis_smg[8]   ={0};

//数码管位选定义
sbit smg_we1 = P2^4;	    //数码管位选定义
sbit smg_we2 = P2^5;
sbit smg_we3 = P2^6;
sbit smg_we4 = P2^7;

unsigned char i=0,timecount=0,displayOK=0,rate=0,aa=0;
unsigned int time[6]={0};


/***********************1ms延时函数*****************************/
void delay_1ms(uint q)
{
	uint i,j;
	for(i=0;i<q;i++)
		for(j=0;j<110;j++);
}


/***********************数码位选函数*****************************/
void smg_we_switch(uchar i)
{
	switch(i)
	{
		case 0: smg_we1 = 0;  smg_we2 = 1; smg_we3 = 1;  smg_we4 = 1; break;
		case 1: smg_we1 = 1;  smg_we2 = 0; smg_we3 = 1;  smg_we4 = 1; break;
		case 2: smg_we1 = 1;  smg_we2 = 1; smg_we3 = 0;  smg_we4 = 1; break;
		case 3: smg_we1 = 1;  smg_we2 = 1; smg_we3 = 1;  smg_we4 = 0; break;
	}	
}

/***********************数码显示函数*****************************/
void display()
{
	static uchar i;   
	i++;
	if(i >= smg_i)
		i = 0;	
	P0 = 0xff;		 //段选	        
	smg_we_switch(i);		 //位选
	P0 = dis_smg[i];		 //段选	        
}


/*************定时器0初始化程序***************/
void time_init()	  
{
	EA   = 1;	 	  //开总中断
	TMOD = 0X01;	  //定时器0、定时器1工作方式1
	ET0  = 1;		  //开定时器0中断 
	TR0  = 1;		  //允许定时器0定时
}


/***********外部中断0初始化程序****************/
void init_int0()	  //外部中断0初始化程序
{
	EX0=1;			  //允许外部中断0中断
	EA=1;	 		  //开总中断
	IT0 = 1; 		  //外部中断0负跳变中断
}

/****************主函数***************/
void main()
{	
	static uint value;
	time_init();                    //初始化定时器 
	init_int0();	  //外部中断0初始化程序
	while(1)
	{			
		value ++;
		if(value >= 300)  //300ms
		{
			value = 0;
			if(displayOK==0)//如果显示关
			{
			 	rate = 0;
			}
			else//如果显示开
			{
				rate=60000/(time[1]+time[2]+time[3]+time[4]+time[5])/5;
			}
			dis_smg[0] = smg_du[rate % 10];		 //显示
			dis_smg[1] = smg_du[rate / 10 % 10];
			dis_smg[2] = smg_du[rate / 100 % 10]; 	

		}
		display();    //数码管显示函数
		delay_1ms(1);
	}
}

void int0() interrupt 0
{
		EX0=0;//暂时关外部中断
		if(timecount<8)   //当连续两次检测时间间隔小于8*50ms=400ms不处理
		{
				TR0=1;//开定时器
		}
		else
		{
			time[i]=timecount+TH0+TL0;//算出间隔时间
			TH0 = 0x3c;
			TL0 = 0xb0;     // 50ms	 12M
			timecount=0;//50ms计数清零
			i++;
			if(i==6)//记录到超过等于6次时间
			{
				i=1;//计数从1开始
			}								
		}
		EX0=1;
}

/*************定时器0中断服务程序***************/
void time0_int() interrupt 1
{	
	TH0 = 0x3c;
	TL0 = 0xb0;     // 50ms	 12M
	timecount++;//每50ms一次计数
	if(timecount>25)     //当超过25*50ms=1.5s没有检测到信号停止显示
	{
			i=0;//数据个数清零
			timecount=0;//50ms计数清零
			displayOK=0;//显示关
			TR0=0;//定时器关
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相关文章:

  • 你不知道的达梦数据库
  • 3. python:列表、元组、字典、集合
  • 【Linux】Tomcat简介及二进制安装
  • 【Java基础】Java8集合[ArrayList 常用方法讲解](源码分析+底层原理)
  • STM32F405+4G模块OTA固件升级调试记录
  • MYSQL--数据库面试题
  • 【cloud Alibaba】(二)流量控制、熔断降级(上)——Sentinel
  • 【牛客网刷题】VL1 四选一多路器
  • ES6 集合
  • Poco库使用:使用http协议通信
  • 浅谈Python+requests+pytest接口自动化测试框架的搭建
  • 【算法面试必刷Java版十八】二维数组中的查找
  • 基于AT89C51单片机的液位检测及显示电路设计
  • 深入浅出地理解Youtube DNN推荐模型
  • Group ViT(Semantic Segmentation Emerges from Text Supervision)
  • [PHP内核探索]PHP中的哈希表
  • 【React系列】如何构建React应用程序
  • CentOS从零开始部署Nodejs项目
  • EventListener原理
  • Less 日常用法
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • MySQL几个简单SQL的优化
  • Redis 中的布隆过滤器
  • scala基础语法(二)
  • SpiderData 2019年2月25日 DApp数据排行榜
  • Swoft 源码剖析 - 代码自动更新机制
  • 闭包--闭包之tab栏切换(四)
  • 从0实现一个tiny react(三)生命周期
  • 聊聊hikari连接池的leakDetectionThreshold
  • 聊聊redis的数据结构的应用
  • 排序(1):冒泡排序
  • 深入浏览器事件循环的本质
  • 学习笔记TF060:图像语音结合,看图说话
  • 原生 js 实现移动端 Touch 滑动反弹
  • 最近的计划
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • 积累各种好的链接
  • ​configparser --- 配置文件解析器​
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • $.ajax()参数及用法
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (转)人的集合论——移山之道
  • (转载)Google Chrome调试JS
  • (转载)Linux网络编程入门
  • 、写入Shellcode到注册表上线
  • .net core开源商城系统源码,支持可视化布局小程序
  • .NET 服务 ServiceController
  • .net专家(张羿专栏)
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • // an array of int
  • @ModelAttribute使用详解
  • @RequestBody的使用