基于51单片机的健康检测仪设计

 一、设计任务简介

  1. 1、基于51单片机的健康检测仪,以完成血压、体温、脉搏的检测。
  2. 2、使用仿真软件Proteus来搭建系统硬件电路,调试测试。

二、设计说明书内容介绍

1、健康检测仪的总体结构

        整个系统的构成主要是由单片机最小系统按键,液晶显示器,光电传感器。等这几部分组成在本次设计中,还包含有三个人机交互俺家可以对当前设备进行设置,可以实现按键设置加减,来调节当前系统的阈值实现在设定阈值外报警的功能,由于人体测试这过程需要保证其测试量误差,所以人体检测在应用过程中需要保证人体平缓,并且没有受到外界干扰。作品功能:实现温度的测量、脉搏测量。能测出即时的温度和脉搏,显示在LCD屏上。

 2.健康检测仪的硬件设计

(1)心跳检测电路设计

(2)体温检测电路设计

(3)血压检测电路设计

(4)单片机最小系统电路设计

 3、健康检测仪的仿真实现

(1)仿真电路搭建

三、软件设计及代码展示

#include <reg52.h>
#include <intrins.h>
#include "adc0832.h"
#define uint		unsigned int
#define uchar		unsigned char
#define ulong		unsigned long                                           /* 宏定义 */
#define LCD_DATA	P0                                                      /* 定义P0口为LCD_DATA */
							 
sbit	LCD_RS	= P2 ^ 5;
sbit	LCD_RW	= P2 ^ 6;
sbit	LCD_E	= P2 ^ 7;                                                       /* 定义LCD控制引脚 */

sbit	Xintiao = P1 ^ 0;                                                       /* 心率检测输入端定义 */
sbit	speaker = P2 ^ 4;                                                       /* 蜂鸣器引脚定义 */
sbit	DQ	= P3 ^ 7;

uchar blood = 0;

void delay5ms( void );                                                          /* 误差 0us */


void LCD_WriteData( uchar LCD_1602_DATA );                                      /********LCD1602数据写入***********/


void LCD_WriteCom( uchar LCD_1602_COM );                                        /********LCD1602命令写入***********/


void lcd_1602_word( uchar Adress_Com, uchar Num_Adat, uchar *Adress_Data );     /*1602字符显示函数,变量依次为字符显示首地址,显示字符长度,所显示的字符*/


void InitLcd();                                                                 /* 液晶初始化函数 */


void Tim_Init();


uchar	Xintiao_Change = 0;                                                     /*  */
uint	Xintiao_Jishu;
uchar	stop;
uchar	View_Data[3];
uchar	View_L[3];
uchar	View_H[3];
uchar	Xintiao_H	= 100;                                                  /*上限 */
uchar	Xintiao_L	= 40;                                                   /*下限 */
uint	wendu		= 0;

uchar	Key_Change;
uchar	Key_Value;                                                              /*按键键值 */
uchar	View_Con;                                                               /* 设置的位(0正常工作,1设置上限,2设置下限) */
uchar	View_Change;

uchar bloodL = 139;
uchar bloodH = 160;
uint tempL = 360;
uint tempH = 373;


/*****延时子程序*****/
void Delay_DS18B20( int num )
{
	while ( num-- )
		;
}


/*****初始化DS18B20*****/
void Init_DS18B20( void )
{
	unsigned char x = 0;
	DQ = 1;                 /* DQ复位 */
	Delay_DS18B20( 8 );     /*稍做延时 */
	DQ = 0;                 /* 单片机将DQ拉低 */
	Delay_DS18B20( 80 );    /* 精确延时,大于480us */
	DQ = 1;                 /* 拉高总线 */
	Delay_DS18B20( 34 );
}


/*****读一个字节*****/
unsigned char ReadOneChar( void )
{
	unsigned char	i	= 0;
	unsigned char	dat	= 0;
	for ( i = 8; i > 0; i-- )
	{
		DQ	= 0;    /* 给脉冲信号 */
		dat	>>= 1;
		DQ	= 1;    /* 给脉冲信号 */
		if ( DQ )
			dat |= 0x80;
		Delay_DS18B20( 4 );
	}
	return(dat);
}


void WriteOneChar( unsigned char dat )
{
	unsigned char i = 0;
	for ( i = 8; i > 0; i-- )
	{
		DQ	= 0;
		DQ	= dat & 0x01;
		Delay_DS18B20( 5 );
		DQ	= 1;
		dat	>>= 1;
	}
}


/*****读取温度*****/
unsigned int ReadTemperature( void )
{
	unsigned char	a	= 0;
	unsigned char	b	= 0;
	unsigned int	t	= 0;
	float		tt	= 0;
	Init_DS18B20();
	WriteOneChar( 0xCC );           /* 跳过读序号列号的操作 */
	WriteOneChar( 0x44 );           /* 启动温度转换 */
	Init_DS18B20();
	WriteOneChar( 0xCC );           /* 跳过读序号列号的操作 */
	WriteOneChar( 0xBE );           /* 读取温度寄存器 */
	a	= ReadOneChar();        /* 读低8位 */
	b	= ReadOneChar();        /* 读高8位 */
	t	= b;
	t	<<= 8;
	t	= t | a;
	tt	= t * 0.0625;
	t	= tt * 10 + 0.5;        /* 放大10倍输出并四舍五入 */
	return(t);
}


/*
 * =====================================================================================
 * =====================================================================================
 * =====================================================================================
 */

void main()                                                     /* 主函数 */
{
	InitLcd();
	Tim_Init();

	lcd_1602_word( 0x80, 16, "Heart Rate:     " );          /* 初始化显示 */
	lcd_1602_word( 0xC0, 16, "Te:      BP:    " );          /* 显示第二行数据 */
	TR0	= 1;
	TR1	= 1;                                            /* 打开定时器 */
	while ( 1 )                                             /* 进入循环 */
	{
	  
		if ( View_Con == 0 )
		{
			wendu = ReadTemperature();
			lcd_1602_word( 0xC0, 3, "Te:" );        /* 显示第二行数据 */
			if ( wendu != 0 && wendu !=850)
			{
				LCD_WriteCom( 0x80 + 0x40 + 3 );
				LCD_WriteData( wendu / 100 + 0x30 );
				LCD_WriteData( wendu % 100 / 10 + 0x30 );
				LCD_WriteData( '.' );
				LCD_WriteData( wendu % 100 % 10 + 0x30 );
				LCD_WriteData( 0xdf );
				if(wendu>350 && wendu<450) {
					if (wendu >= tempH || wendu < tempL )       /* 不在范围内报警 */
						speaker = 0;                                                                            /* 蜂鸣器响 */
					else
						speaker = 1;
				}
			
			}

			lcd_1602_word( 0xC0 + 8, 4, " BP:" );                   /* 显示第二行数据 */

			LCD_WriteCom( 0x80 + 0x40 + 12 );
			LCD_WriteData( blood / 100 + 0x30 );
			LCD_WriteData( blood % 100 / 10 + 0x30 );
			LCD_WriteData( blood % 100 % 10 + 0x30 );
			lcd_1602_word( 0xC0 + 15, 1, " " );                     /* 显示第二行数据 */

			if (blood >= bloodH || blood < bloodL )       /* 不在范围内报警 */
				speaker = 0;                                                                            /* 蜂鸣器响 */
			else
				speaker = 1;
		}

		if ( Key_Change )                                               /*有按键按下并已经得出键值 */
		{
			Key_Change	= 0;                                    /* 将按键使能变量清零,等待下次按键按下 */
			View_Change	= 1;
			switch ( Key_Value )                                    /* 判断键值 */
			{
			case 1:                                                 /* 设置键按下 */
			{
				View_Con++;                                     /* 设置的位加 */
				if ( View_Con == 3 )                            /* 都设置好后将此变量清零 */
					View_Con = 0;
				break;                                          /* 跳出,下同 */
			}
			case 2:                                                 /* 加键按下 */
			{
				if ( View_Con == 2 )                            /* 判断是设置上限 */
				{
					if ( Xintiao_H < 150 )                  /*上限数值小于150 */
						Xintiao_H++;                    /*上限+ */
				}
				if ( View_Con == 1 )                            /* 如果是设置下限 */
				{
					if ( Xintiao_L < Xintiao_H - 1 )        /*下限值小于上限-1(下限值不能超过上限) */
						Xintiao_L++;                    /*下限值加 */
				}
				break;
			}
			case 3:                                                 /* 减键按下 */
			{
				if ( View_Con == 2 )                            /* 设置上限 */
				{
					if ( Xintiao_H > Xintiao_L + 1 )        /*上限数据大于下限+1(同样上限值不能小于下限) */
						Xintiao_H--;                    /*上限数据减 */
				}
				if ( View_Con == 1 )                            /* 设置下限 */
				{
					if ( Xintiao_L > 30 )                   /*下限数据大于30时 */
						Xintiao_L--;                    /*下限数据减 */
				}
				break;
			}
			}
		}
		if ( View_Change )                                              /* 开始显示变量 */
		{
			View_Change = 0;                                        /* 变量清零 */
			if ( stop == 0 )                                        /* 心率正常时 */
			{
				if ( View_Data[0] == 0x30 )                     /* 最高位为0时不显示 */
					View_Data[0] = ' ';
			}else   {                                               /* 心率不正常(计数超过5000,也就是两次信号时间超过5s)不显示数据 */
				View_Data[0]	= ' ';
				View_Data[1]	= ' ';
				View_Data[2]	= ' ';
			}

			switch ( View_Con )
			{
			case 0:                                                 /* 正常显示 */
			{
				lcd_1602_word( 0x80, 16, "Heart Rate:     " );  /* 显示一行数据 */

				lcd_1602_word( 0x8d, 3, View_Data );            /* 第1行显示心率 */

				break;
			}
			case 1:                                                 /* 设置下限时显示 */
			{
				lcd_1602_word( 0x80, 16, "Heart Rate:     " );  /* 第一行显示心率 */
				lcd_1602_word( 0x8d, 3, View_Data );

				View_L[0]	= Xintiao_L / 100 + 0x30;       /* 将下限数据拆字 */
				View_L[1]	= Xintiao_L % 100 / 10 + 0x30;
				View_L[2]	= Xintiao_L % 10 + 0x30;

				if ( View_L[0] == 0x30 )                        /* 最高位为0时,不显示 */
					View_L[0] = ' ';

				lcd_1602_word( 0xC0, 16, "Warning L :     " );  /* 第二行显示下限数据 */
				lcd_1602_word( 0xCd, 3, View_L );
				break;
			}
			case 2:                                                 /* 设置上限时显示(同上) */
			{
				lcd_1602_word( 0x80, 16, "Heart Rate:     " );
				lcd_1602_word( 0x8d, 3, View_Data );

				View_H[0]	= Xintiao_H / 100 + 0x30;
				View_H[1]	= Xintiao_H % 100 / 10 + 0x30;
				View_H[2]	= Xintiao_H % 10 + 0x30;

				if ( View_H[0] == 0x30 )
					View_H[0] = ' ';

				lcd_1602_word( 0xC0, 16, "Warning H :     " );
				lcd_1602_word( 0xCd, 3, View_H );
				break;
			}
			}
		}
	}
}


void Time1() interrupt 3                                        /* 定时器1服务函数 */
{
	static uchar Key_Con, Xintiao_Con;
	TH1	= 0xd8;                                         /* 10ms */
	TL1	= 0xf0;                                         /* 重新赋初值 */
	blood	= choiceADC( 0 );                               /* 读取ADC数值 */
	switch ( Key_Con )                                      /* 无按键按下时此值为0 */
	{
	case 0:                                                 /* 每10ms扫描此处 */
	{
		if ( (P3 & 0x07) != 0x07 )                      /* 扫描按键是否有按下 */
		{
			Key_Con++;                              /*有按下此值加1,值为1 */
		}
		break;
	}
	case 1:                                                 /* 10ms后二次进入中断后扫描此处(Key_Con为1) */
	{
		if ( (P3 & 0x07) != 0x07 )                      /* 第二次进入中断时,按键仍然是按下(起到按键延时去抖的作用) */
		{
			Key_Con++;                              /* 变量加1,值为2 */
			switch ( P3 & 0x07 )                    /* 判断是哪个按键按下 */
			{
			case 0x06: Key_Value	= 1; break;     /* 判断好按键后将键值赋值给变量Key_Value */
			case 0x05: Key_Value	= 2; break;
			case 0x03: Key_Value	= 3; break;
			}
		}else  {                                        /* 如果10ms时没有检测到按键按下(按下时间过短) */
			Key_Con = 0;                            /* 变量清零,重新检测按键 */
		}
		break;
	}
	case 2:                                                 /* 20ms后检测按键 */
	{
		if ( (P3 & 0x07) == 0x07 )                      /* 检测按键是否还是按下状态 */
		{
			Key_Change	= 1;                    /*有按键按下使能变量,(此变量为1时才会处理键值数据) */
			Key_Con		= 0;                    /* 变量清零,等待下次有按键按下 */
		}
		break;
	}
	}

	switch ( Xintiao_Con )                                  /* 此处与上面按键的检测类似 */
	{
	case 0:                                                 /* 默认Xintiao_Con是为0的 */
	{
		if ( !Xintiao )                                 /* 每10ms(上面的定时器)检测一次是否有信号 */
		{
			Xintiao_Con++;                          /* 如果有信号,变量加一,程序就会往下走了 */
		}
		break;
	}
	case 1:
	{
		if ( !Xintiao )                                 /* 每过10ms检测一下信号是否还存在 */
		{
			Xintiao_Con++;                          /* 存在就加一 */
		}else  {
			Xintiao_Con = 0;                        /* 如果不存在了,检测时间很短,说明检测到的不是信号,可能是其他干扰,将变量清零,跳出此次检测 */
		}
		break;
	}
	case 2:
	{
		if ( !Xintiao )
		{
			Xintiao_Con++;          /* 存在就加一 */
		}else  {
			Xintiao_Con = 0;        /* 如果不存在了,检测时间很短,说明检测到的不是信号,可能是其他干扰,将变量清零,跳出此次检测 */
		}
		break;
	}
	case 3:
	{
		if ( !Xintiao )
		{
			Xintiao_Con++;                                                                                          /* 存在就加一 */
		}else  {
			Xintiao_Con = 0;                                                                                        /* 如果不存在了,检测时间很短,说明检测到的不是信号,可能是其他干扰,将变量清零,跳出此次检测 */
		}
		break;
	}
	case 4:
	{
		if ( Xintiao )                                                                                                  /* 超过30ms一直有信号,判定此次是信号,执行以下程序 */
		{
			if ( Xintiao_Change == 1 )                                                                              /* 心率计原理为检测两次脉冲间隔时间计算心率,变量Xintiao_Change第一次脉冲时为0的,所有走下面的else,第二次走这里 */
			{
				View_Data[0]	= (60000 / Xintiao_Jishu) / 100 + 0x30;
				View_Data[1]	= (60000 / Xintiao_Jishu) % 100 / 10 + 0x30;
				View_Data[2]	= (60000 / Xintiao_Jishu) % 10 + 0x30;

				if ( ( (60000 / Xintiao_Jishu) >= Xintiao_H) || ( (60000 / Xintiao_Jishu) <= Xintiao_L) || tempL >= wendu )       /* 不在范围内报警 */
					speaker = 0;                                                                            /* 蜂鸣器响 */
				else
					speaker = 1;                                                                            /*不响 */

				View_Change	= 1;                                                                            /* 计算出心率后启动显示 */
				Xintiao_Jishu	= 0;                                                                            /* 心跳计数清零 */
				Xintiao_Change	= 0;                                                                            /* 计算出心率后该变量清零,准备下次检测心率 */
				stop		= 0;                                                                            /* 计算出心率后stop清零 */
				TR0		= 0;
				/*
				 *   wendu=ReadTemperature();
				 *   TR1=0;
				 */
			}else  { /* 第一次脉冲时Xintiao_Change为0 */
				Xintiao_Jishu	= 0;                                                                            /*脉冲计时变量清零,开始计时 */
				Xintiao_Change	= 1;                                                                            /* Xintiao_Change置1,准备第二次检测到脉冲时计算心率 */
				TR0		= 1;
			}
			Xintiao_Con = 0;                                                                                        /* 清零,准备检测下一次脉冲 */
			break;
		}
	}
	}
}


/**定时器T0工作函数**/
void Time0() interrupt 1
{
	TH0	= 0xfc;                 /* 1ms */
	TL0	= 0x18;                 /* 重新赋初值 */
	Xintiao_Jishu++;                /* 心跳计数加 */
	if ( Xintiao_Jishu == 5000 )    /* 心跳计数大于5000 */
	{
		Xintiao_Jishu	= 0;    /* 数据清零 */
		View_Change	= 1;    /* 显示位置1 */
		Xintiao_Change	= 0;    /* 置零,准备再次检测 */
		stop		= 1;    /* 心跳计数超过5000后说明心率不正常或者没有测出,stop置1 */
		speaker		= 1;    /* 关闭蜂鸣器 */
	}
}


/**定时器初始化函数**/
void Tim_Init()
{
	EA	= 1;    /* 打开中断总开关 */
	ET0	= 1;    /* 打开T0中断允许开关 */
	ET1	= 1;    /* 打开T1中断允许开关 */
	TMOD	= 0x11; /* 设定定时器状态 */
	TH0	= 0xfc; /* 1ms */
	TL0	= 0x18; /* 赋初值 */

	TH1	= 0xd8; /* 10ms */
	TL1	= 0xf0; /* 赋初值 */
}


/**Adress_Com显示地址,Num_Adat显示字符数量,Adress_Data显示字符串内容**/
void lcd_1602_word( uchar Adress_Com, uchar Num_Adat, uchar *Adress_Data )
{
	uchar	a = 0;
	uchar	Data_Word;
	LCD_WriteCom( Adress_Com );             /*选中地址 */
	for ( a = 0; a < Num_Adat; a++ )        /* for循环决定显示字符个数 */
	{
		Data_Word = *Adress_Data;       /* 读取字符串数据 */
		LCD_WriteData( Data_Word );     /* 显示字符串 */
		Adress_Data++;                  /* 显示地址加一 */
	}
}


/***************1602函数*******************/
void LCD_WriteData( uchar LCD_1602_DATA )       /********LCD1602数据写入***********/
{
	delay5ms();                             /* 操作前短暂延时,保证信号稳定 */
	LCD_E	= 0;
	LCD_RS	= 1;
	LCD_RW	= 0;
	_nop_();
	LCD_E		= 1;
	LCD_DATA	= LCD_1602_DATA;
	LCD_E		= 0;
	LCD_RS		= 0;
}


/********LCD1602命令写入***********/
void LCD_WriteCom( uchar LCD_1602_COM )
{
	delay5ms(); /* 操作前短暂延时,保证信号稳定 */
	LCD_E	= 0;
	LCD_RS	= 0;
	LCD_RW	= 0;
	_nop_();
	LCD_E		= 1;
	LCD_DATA	= LCD_1602_COM;
	LCD_E		= 0;
	LCD_RS		= 0;
}


void InitLcd()                  /* 初始化液晶函数 */
{
	delay5ms();
	delay5ms();
	LCD_WriteCom( 0x38 );   /* display mode */
	LCD_WriteCom( 0x38 );   /* display mode */
	LCD_WriteCom( 0x38 );   /* display mode */
	LCD_WriteCom( 0x06 );   /* 显示光标移动位置 */
	LCD_WriteCom( 0x0c );   /* 显示开及光标设置 */
	LCD_WriteCom( 0x01 );   /* 显示清屏 */
	delay5ms();
	delay5ms();
}


void delay5ms( void )           /* 5ms延时函数 */
{
	unsigned char a, b;
	for ( b = 185; b > 0; b-- )
		for ( a = 12; a > 0; a-- )
			;
}


含有的文件 

设计书目录

摘  要

第一章  绪论

第一节  健康检测仪研究背景

第二节  健康检测仪研究现状

第三节  本文的章节安排

第四节  本章小结

第二章  健康检测仪的设计方案

第一节  健康检测仪的设计要求

第二节  控制器的选择

第三节  脉搏、血压传感器的选择

第四节  体温传感器的选择

第五节  健康检测仪的总体结构

第六节  本章小结

第三章  健康检测仪的硬件设计

第一节  心跳检测电路设计

第二节  体温检测电路设计

第三节  血压检测电路设计

第四节  单片机最小系统电路设计

一、单片机介绍

二、单片机最小系统

第五节  显示器电路设计

第六节  电源电路设计

第七节  系统总电路设计

第八节  本章小结

第四章  健康检测仪的软件设计

第一节  健康检测仪的主程序设计

第二节  血压检测子程序设计

一、血压检测子程序设计流程

二、血压检测子程序

第三节  心跳检测子程序设计

一、心跳检测子程序设计流程

二、心跳检测子程序

第四节  体温检测子程序设计

一、体温检测子程序设计流程

二、体温检测子程序

第五节  液晶显示子程序设计

一、液晶显示子程序设计流程

二、液晶显示子程序

第六节  本章小结

第五章  健康检测仪的仿真实现

第一节  仿真软件介绍

第二节  仿真电路搭建

第三节  仿真实现及结果分析

一、体温、血压检测功能测试

二、按键功能测试

三、健康检测仪的综合测试

第四节  本章小结

结  论

有问题私聊。微信lwfw123456789

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

5132毕业设计

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值