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