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

1、设计需求及目标

本课题需要设计一种基于51单片机的脉搏测量仪。系统以STC89C52单片机为核心,以光电传感器利用单片机系统内部定时器来计算时间,由光电传感器感应产生信号,单片机通过对信号累加得到脉搏跳动次数,时间由定时器定时而得。系统运行中可以通过观察指示灯闪烁,若均匀闪烁说明测量值准确。系统停止运行时,能够显示总的脉搏次数和时间。

2、设计思路及方案

本设计利用红外光电传感器产生脉冲信号,经过放大整形后,输入单片机内进行相应的控制,从而测量出一分钟内的脉搏跳动次数,快捷方便。系统可以供用户测量当时的脉搏次数,同时还可以设定上限次数和下限次数,当测量的范围超过设定的范围则驱动蜂鸣器报警提醒,除此外用户还可以设定每天闹钟提醒测量,时间可以自行设定,结果最终可以把采集到的脉搏信号显示在LCD1602上。硬件电路:

3、程序主函数

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


bit flag_300ms ;
uchar flag_en;


uchar code table_num[]="0123456789abcdefg";

sbit rs=P1^2;	 //寄存器选择信号 H:数据寄存器  	L:指令寄存器
sbit e =P1^4;	 //片选信号   下降沿触发

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

float rate1[6];


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


/********************************************************************
* 名称 : delay_uint()
* 功能 : 小延时。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay_uint(uint q)
{
	while(q--);
}

/********************************************************************
* 名称 : write_com(uchar com)
* 功能 : 1602命令函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void write_com(uchar com)
{
	e=0;
	rs=0;
	P0=com;
	delay_uint(25);
	e=1;
	delay_uint(100);
	e=0;
}

/********************************************************************
* 名称 : write_data(uchar dat)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
***********************************************************************/
void write_data(uchar dat)
{
	e=0;
	rs=1;
	P0=dat;
	delay_uint(25);
	e=1;
	delay_uint(100);
	e=0;	
}

/********************************************************************
* 名称 : write_string(uchar hang,uchar add,uchar *p)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
	 	 write_string(1,5,"ab cd ef;")
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void write_string(uchar hang,uchar add,uchar *p)
{
	if(hang==1)   
		write_com(0x80+add);
	else
		write_com(0x80+0x40+add);
	while(1)
	{
		if(*p == '\0')  break;
		write_data(*p);
		p++;
	}	
}


/***********************lcd1602上显示两位十进制数************************/
void write_sfm3(uchar hang,uchar add,uint date)
{
	if(hang==1)   
		write_com(0x80+add);
	else
		write_com(0x80+0x40+add);
	write_data(0x30+date/100%10);
	write_data(0x30+date/10%10);
	write_data(0x30+date%10);	
}


/***********************lcd1602初始化设置************************/
void init_1602()
{
	write_com(0x38);	//
	write_com(0x0c);
	write_com(0x06);
	delay_uint(1000);
	write_string(1,0,"   Heart Rate     ");	
	write_string(2,0,"     000/min       ");
}

/*************定时器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 pingjun_zhi(float *p)
{
	static float value;
	static uchar i,j;
	for(j=1;j<5;j++)		   //先对整个数组的5个值进行从小到大的排列
		for(i=0;i<5 - j;i++)
		{
			if(p[i] > p[i+1])
			{
				value = p[i];
				p[i] = p[i+1];
				p[i+1] = value;		
			}	
		}
}


uchar flag_value;

/****************主函数***************/
void main()
{	
	delay_1ms(150);
	P0 = P1 = P2 = P3 = 0xff;
	init_1602();                    //1602初始化
	time_init();                    //初始化定时器 
	init_int0();	  //外部中断0初始化程序
	while(1)
	{			
		if(displayOK==0)//如果显示关
		{
		 	rate = 0;
			flag_value = 0;
		}
		else//如果显示开
		{
			if(flag_en == 1)
			{
				flag_en = 0;
				flag_value ++;
				if(flag_value == 1)
					rate1[0]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
				if(flag_value == 2)
					rate1[1]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
				if(flag_value == 3)
					rate1[2]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
				if(flag_value == 4)
					rate1[3]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
				if(flag_value >= 5)
				{
					rate1[4]=60000/(time[1]/5+time[2]/5+time[3]/5+time[4]/5+time[5]/5);
			
					pingjun_zhi(rate1);
					flag_value = 0;
					rate = (rate1[1] / 3 + rate1[2] / 3 + rate1[3] / 3);
				}
			}
		}

		write_sfm3(2,5,rate);

		delay_1ms(300);
	}
}
/************外部0中断服务程序***************/
void int0() interrupt 0
{
	static uchar value;
		EX0=0;//暂时关外部中断
		if(timecount<8)   //当连续两次检测时间间隔小于8*50ms=400ms不处理
		{
			value ++;
			if(value >= 4)
			{
				value = 0;
			}	
			TR0=1;//开定时器
		}
		else if(timecount <= 18)
		{	
			value = 0;
			time[i]=timecount*50+TH0*0.256+TL0/1000;//算出间隔时间

			TH0 = 0x3c;
			TL0 = 0xb0;     // 50ms	 12M
			timecount=0;//50ms计数清零
			i++;
			flag_en = 1;
			if(i==6)//记录到超过等于6次时间
			{
				i=1;//计数从1开始
				displayOK=1;    //测得5次开始显示?
			}								
		} else 
		{
			flag_value = 0;
			timecount = 0;
		}
		EX0=1;
}
/*************定时器0中断服务程序***************/
void time0_int() interrupt 1
{	
	TH0 = 0x3c;
	TL0 = 0xb0;     // 50ms	 12M
	timecount++;//每50ms一次计数
	if(timecount>70)     //当超过25*50ms=1.5s没有检测到信号停止显示
	{
			i=0;//数据个数清零
			timecount=0;//50ms计数清零
			displayOK=0;//显示关
			TR0=0;//定时器关
			TH0 = 0x3c;
			TL0 = 0xb0;     // 50ms	 12M
	}
}

完整资料:

https://market.m.taobao.com/app/idleFish-F2e/widle-taobao-rax/page-detail?wh_weex=true&wx_navbar_transparent=true&id=614263901174&ut_sk=1.WUpxx7gpwUoDAMmnnrBIzAno_12431167_1585213694840.Copy.detail.614263901174.1828622527&forceFlush=1

发布了23 篇原创文章 · 获赞 7 · 访问量 327

猜你喜欢

转载自blog.csdn.net/weixin_41017942/article/details/105123659