功能介绍:
0.本系统采用STC89C52作为单片机
1.系统可检测心率脉搏值,通过LCD1602液晶实时显示测量值
2.心率脉搏超过设定阈值,蜂鸣器将报警
3.四个功能按键可修改心率脉搏上下限阈值
4.采用DC002作为电源接口可直接输入5V给整个系统供电
5.实物中采用两个红外对管模拟心率,可以方便演示心率脉搏的高低变化
原理图:
PCB :
主程序:
#include <reg52.h>
#include <intrins.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 HEART = P1^0; //脉搏检测输入端定义
sbit BUZZER = P2^4; //蜂鸣器引脚定义
void Delay5ms(void);
void LCD_WriteData(uchar LCD_1602_DATA); /********LCD1602数据写入***********/
void LCD_WriteCom(uchar LCD_1602_COM); /********LCD1602命令写入***********/
void LCD_DispWord(uchar Adress_Com, uchar Num_Adat, uchar *Adress_Data); /*1602字符显示函数,变量依次为字符显示首地址,显示字符长度,所显示的字符*/
void LCD_Init(); //初始化LCD
void TIM_Init(); //初始化定时器
uchar heartChange = 0;
uint heartCnt;
uchar stopFlag;
uchar View_Data[3];
uchar View_L[3];
uchar View_H[3];
uchar heartH = 100; //脉搏上限
uchar heartL = 40; //脉搏下限
uchar keyFlag;
uchar keyValue; //按键键值
uchar dispIndex; //设置的位(0正常工作,1设置上限,2设置下限)
uchar dispFlag;
void main() //主函数
{
LCD_Init();
TIM_Init();
LCD_DispWord(0x80, 16, "Heart Rate: "); //初始化显示
TR0 = 1;
TR1 = 1; //打开定时器
while (1) //进入循环
{
if (dispFlag) //开始显示变量
{
dispFlag = 0; //变量清零
if (stopFlag == 0) //心率正常时
{
if (View_Data[0] == '0') //最高位为0时不显示
View_Data[0] = ' ';
}
else //持续未检测到(计数超过5000,也就是两次信号时间超过5s)不显示数据
{
View_Data[0] = ' ';
View_Data[1] = ' ';
View_Data[2] = ' ';
}
switch (dispIndex)
{
case 0: //正常显示
{
LCD_DispWord(0x80, 16, "Heart Rate: "); //显示一行数据
LCD_DispWord(0xc0, 16, " "); //显示第二行数据
LCD_DispWord(0xcd, 3, View_Data); //第二行显示心率
break;
}
case 1: //设置下限时显示
{
LCD_DispWord(0x80, 16, "Heart Rate: "); //第一行显示心率
LCD_DispWord(0x8d, 3, View_Data);
View_L[0] = heartL / 100 + '0'; //将下限数据拆字
View_L[1] = heartL % 100 / 10 + '0';
View_L[2] = heartL % 10 + '0';
if (View_L[0] == '0') //最高位为0时,不显示
View_L[0] = ' ';
LCD_DispWord(0xC0, 16, "Warning L : "); //第二行显示下限数据
LCD_DispWord(0xCd, 3, View_L);
break;
}
case 2: //设置上限时显示(同上)
{
LCD_DispWord(0x80, 16, "Heart Rate: ");
LCD_DispWord(0x8d, 3, View_Data);
View_H[0] = heartH / 100 + '0';
View_H[1] = heartH % 100 / 10 + '0';
View_H[2] = heartH % 10 + '0';
if (View_H[0] == '0')
View_H[0] = ' ';
LCD_DispWord(0xC0, 16, "Warning H : ");
LCD_DispWord(0xCd, 3, View_H);
break;
}
}
}
if (keyFlag) //有按键按下并已经得出键值
{
keyFlag = 0; //将按键使能变量清零,等待下次按键按下
dispFlag = 1;
switch (keyValue) //判断键值
{
case 1: //设置键按下
{
dispIndex++; //设置的位加
if (dispIndex == 3) //都设置好后将此变量清零
dispIndex = 0;
break; //跳出,下同
}
case 2: //加键按下
{
if (dispIndex == 2) //判断是设置上限
{
if (heartH < 150) //上限数值小于150
heartH++; //上限+
}
if (dispIndex == 1) //如果是设置下限
{
if (heartL < heartH - 1) //下限值小于上限-1(下限值不能超过上限)
heartL++; //下限值加
}
break;
}
case 3: //减键按下
{
if (dispIndex == 2) //设置上限
{
if (heartH > heartL + 1) //上限数据大于下限+1(同样上限值不能小于下限)
heartH--; //上限数据减
}
if (dispIndex == 1) //设置下限
{
if (heartL > 30) //下限数据大于30时
heartL--; //下限数据减
}
break;
}
}
}
}
}
void Time1() interrupt 3 //定时器1服务函数
{
static uchar keyCon, heartDelay;
TH1 = 0xDC; //设置定时初始值
TL1 = 0x00; //设置定时初始值 10ms
switch (keyCon) //无按键按下时此值为0
{
case 0: //每10ms扫描此处
{
if ((P3 & 0x07) != 0x07) //扫描按键是否有按下
{
keyCon++; //有按下此值加1,值为1
}
break;
}
case 1: // 10ms后二次进入中断后扫描此处(keyCon为1)
{
if ((P3 & 0x07) != 0x07) //第二次进入中断时,按键仍然是按下(起到按键延时去抖的作用)
{
keyCon++; //变量加1,值为2
switch (P3 & 0x07) //判断是哪个按键按下
{
case 0x06:
keyValue = 1;
break; //判断好按键后将键值赋值给变量Key_Value
case 0x05:
keyValue = 2;
break;
case 0x03:
keyValue = 3;
break;
}
}
else //如果10ms时没有检测到按键按下(按下时间过短)
{
keyCon = 0; //变量清零,重新检测按键
}
break;
}
case 2: // 20ms后检测按键
{
if ((P3 & 0x07) == 0x07) //检测按键是否还是按下状态
{
keyFlag = 1; //有按键按下使能变量,(此变量为1时才会处理键值数据)
keyCon = 0; //变量清零,等待下次有按键按下
}
break;
}
}
switch (heartDelay) //此处与上面按键的检测类似
{
case 0: //默认heartDelay是为0的
{
if (!HEART) //每10ms(上面的定时器)检测一次脉搏是否有信号
{
heartDelay++; //如果有信号,变量加一,程序就会往下走了
}
break;
}
case 1:
{
if (!HEART) //每过10ms检测一下信号是否还存在
{
heartDelay++; //存在就加一
}
else
{
heartDelay = 0; //如果不存在了,检测时间很短,说明检测到的不是脉搏信号,可能是其他干扰,将变量清零,跳出此次检测
}
break;
}
case 2:
{
if (!HEART)
{
heartDelay++; //存在就加一
}
else
{
heartDelay = 0; //如果不存在了,检测时间很短,说明检测到的不是脉搏信号,可能是其他干扰,将变量清零,跳出此次检测
}
break;
}
case 3:
{
if (!HEART)
{
heartDelay++; //存在就加一
}
else
{
heartDelay = 0; //如果不存在了,检测时间很短,说明检测到的不是脉搏信号,可能是其他干扰,将变量清零,跳出此次检测
}
break;
}
case 4:
{
if (HEART) //超过30ms一直有信号,判定此次是脉搏信号,执行以下程序
{
if (heartChange == 1) //心率计原理为检测两次脉冲间隔时间计算心率,变量heartChange第一次脉冲时为0的,所有走下面的else,第二次走这里
{
View_Data[0] = (60000 / heartCnt) / 100 + '0';
View_Data[1] = (60000 / heartCnt) % 100 / 10 + '0';
View_Data[2] = (60000 / heartCnt) % 10 + '0';
if (((60000 / heartCnt) >= heartH) || ((60000 / heartCnt) <= heartL)) //心率不在范围内报警
BUZZER = 0; //蜂鸣器响
else
BUZZER = 1; //不响
dispFlag = 1; //计算出心率后启动显示
heartCnt = 0; //心跳计数清零
heartChange = 0; //计算出心率后该变量清零,准备下次检测心率
stopFlag = 0; //计算出心率后stop清零
}
else //第一次脉冲时heartChange为0
{
heartCnt = 0; //脉冲计时变量清零,开始计时
heartChange = 1; // heartChange置1,准备第二次检测到脉冲时计算心率
}
heartDelay = 0; //清零,准备检测下一次脉冲
break;
}
}
}
}