这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 基于AT89S52的简易电子脉搏测量仪

共1条 1/1 1 跳转至

基于AT89S52的简易电子脉搏测量仪

高工
2014-06-16 08:10:05     打赏
光电脉搏检测的基本原理是:随着心脏的搏动,人体组织半透明度随之改变。当血液送到人体组织时,组织的半透明度减小;当血液流回心脏,组织的半透明度增大,这种现象在人体组织较薄的手指尖、耳垂等部位最为明显。利用波长600-1000nm的红光或红外发光二极管产生的光线照射到人体的手指尖、耳垂等部位,用装在该部位另一侧或同侧旁边的光电接收管来检测机体组织的透明程度,即可将搏动信息转换成电信号。




                        





因为最小系统都是那几样东西就没上这个图了,主要就是AT89S52+DS1302+24C02,还有就是用红外对管做的传感器模块。






系统板+传感模块,用的是开关电源。这个是完成后在做极限测试。
..




模块测试时用到的开发板,界面还没改成中文。对管用油性笔盖做了红外光屏蔽,手指插入即可测量,效果很好。
..


开关电源测试0.06A的电流。示波器显示脉搏波形,因为人的正常脉搏基本都在1Hz左右,所以示波器不能成连续图像。
..






传感器用的MX494做信号放大与调整,图中为LM324,实测效果没有MAX494好。
..










便携式脉搏测量仪与本作品进行误差对比,实测误差在正负3以内。
..






奋战了几天的地方,前面兄弟太累睡着了。






【功能介绍】


本作品共用到3个按键:    KEY1=手动测试按键、KEY2=退出按键KEY3=查询测量数据按键


作品上电开机时为自己测量模式,能在光电探头达到合适测试部位时自动启动测量,[font='Times New Roman', serif]测量时间为30秒,完成测量后自动待机,直至撤离探头并再次达到测试部位时自动启动下一次测量。




预置了脉搏次数上下告警门限,当脉搏次数测量值超出告警限时,测试仪告警。所有界面都带时钟显示,所有测量的数据都被存储然后可以进行查询,且带测量时间,存储次数可在程序上更改。








【main.c源程序】



#include<AT89X52.h>
#include "LCD12864.h"
#include "math.h"
#include "DS1302.h"
#include "AT24C02.H"
//#include "Draw_Sin.h"
//#include "System_Init.h"
#define uchar unsigned char
#define uint  unsigned int
unsigned char chuzhi;


unsigned char flang1=0;
unsigned char DATA1;


/*============ 外部控制引脚定义 ==============*/ 
#define     Key_Start    P1_0
#define     Key_Return    P1_1
#define        Key_Find    P1_2    //查询按键
#define        Key_Sin        P1_3    //查询按键
#define     Bee        P3_3
#define     Inter        P3_5
#define     LED            P1_4
/*============ 关键变量定义 ==============*/ 
sfr  WDTRST  =0xA6;


unsigned int k;           //定义定时器中间变量 
unsigned char Face=0;    //界面变量 
bit KeyStart_Switch;    //定义开关允许位  为0时开关有效     
bit Check_flag;            //检测标志位 检测到脉搏时为1,否则为0
unsigned char H,L;
unsigned int Temp_fan,DATA;
bit Save_falg;
unsigned char Write_add;        //量测完成后,24C0X写操作指向地址
unsigned char jayt;          //进度条变量
unsigned char Num[4];    //显示缓存
bit Sleep_mode;            //睡眠模式开启标志位,为1时为开启状态
bit alarm;                //上下限报警标志位
unsigned char time[3];       //从24C0X取出的时间显示缓存


void read_24c02();
void Display_LCD12864_Face3();
void cunchu_24c02();
void Display_Auto_Mode(); 




/**************************声明文件************************/
/**********************************************************/
void Timer0NCounterT1_Init();
void Rst_Watchdog(void);         //看门狗拿来复位
void Cotrl_Key();                 //按键控制
void Display_LCD12864_Face0();     //界面一
void Display_LCD12864_Face1();   //界面二
void Display_LCD12864_Face2();     //界面三
void Display_LCD12864_Face3();   //界面四
void Display_LCD12864_Face4();   //界面五
void Display_Auto_Mode();        //睡眠模式界面
/*************************************************/


/*************************************************
*函数作用:定时和计数器初始化配置         *
**************************************************/
void Timer0NCounterT1_Init()
{
    EA=1;    
    TMOD=0X51;
    TH0=0xd8;
    TL0=0xf0;
     ET0=1;
    TH1=0X00;TL1=0X00;
    ET1=1;            
    TR0=0;
    TR1=1;
}
void Bee_Speak(unsigned int t)
{
    Bee=0;LED=0;
    delay_ms(t);
    Bee=1;LED=1;
    delay_ms(t);
}
/*************************************************
*函数作用:看门狗函数                 *
**************************************************/
void Rst_Watchdog(void)        //看门狗拿来复位
{
    WDTRST = 0x1E;             //先赋值1E 然后赋值E1
    WDTRST = 0xE1;
}
/*************************************************
*函数作用:按键控制                 *
**************************************************/
void Cotrl_Key()
{
    if(Key_Start==0)
    {
        delay_ms(10);

        if(Key_Start==0)
        {  
            if(KeyStart_Switch==0)
            {
                TR1=0;
                TH1=0X00;           //
                TL1=0X00;           //计数器清零
                TR0=1;              //
                TR1=1;              //
                Face=1;                  //切换到界面一
                LcdWcom(0x01);
                Bee_Speak(50);
                KeyStart_Switch=1;    
            }
            while(Key_Start==0);             
        }
    }
    if(Key_Return==0)
    {
        delay_ms(10);
        if(Key_Return==0)
        {
            Rst_Watchdog();         // 复位
            Bee_Speak(50);
        }
    }
    if(Key_Find==0)               //查询按键
    {
        delay_ms(50);
        if(Key_Find==0)
        {
            if(Face==0||Face==2||Face==3||Face==4)       //待机状态下
            {
                TL1=0;
                TR1=0;
                  Face=3;                    //查询界面
                Check_flag=1;            //关闭自动模式
                Display_LCD12864_Face3();
                Bee_Speak(50);
            }
            while(Key_Find==0);
        }
    }
/*    if(Key_Sin==0)               //查询按键
    {
        delay_ms(50);
        if(Key_Sin==0)
        {
            if(TR0==0)       //待机状态下
            {
                Face=5;            //进入画图界面
                LcdWcom(0x01);
                delay_ms(50);
                Draw_Heart(1);
                 Draw_Heart(2);
            }
            while(Key_Find==0);
        }
    }      */
}
/*************************************************
*函数作用:界面一    检测脉搏界面        *
**************************************************/
void Display_LCD12864_Face0()
{
    if(Check_flag==0)
    {
        if(TL1==1){Display_HZ_Line(0,0,">>");}
        if(TL1==2){Display_HZ_Line(0,0,">>> ");}
        if(TL1==3){Display_HZ_Line(0,0,">>>>");}
        if(TL1==4){Display_HZ_Line(0,0,">>>>> ");}
    }
    Display_HZ_Line(1,1,"尝试检测脉搏");
    Display_HZ_Line(2,2,"请您放好");
    time_display();
    delay_ms(80);    
    Check_flag=0;
    Display_Auto_Mode();
}
/*************************************************
*函数作用:界面二        测量中界面    *
**************************************************/
void Display_LCD12864_Face1()
{
    unsigned char i;
    unsigned char Num[3];    //显示缓存
    unsigned char Temp;
    Display_HZ_Line(0,0,"测量中....");
    delay_ms(80);


    if(jayt==0){Display_HZ_Line(2,0,"10%>> ");}
    if(jayt==1){Display_HZ_Line(2,0,"29%>>>");}
    if(jayt==2){Display_HZ_Line(2,0,"42%>>>>>");}
    if(jayt==3){Display_HZ_Line(2,0,"57%>>>>>>>");}
    if(jayt==4){Display_HZ_Line(2,0,"77%>>>>>>>>>");}
    if(jayt==5){Display_HZ_Line(2,0,"95%>>>>>>>>>>>");}
    delay_ms(20);


    H=TH1;                 //读取计数值高位
    L=TL1;                   //读取计数值低位
    Temp=H*256+L;          //合成总数       16位


    Num[0]= Temp/100;  
    Num[1]= Temp%100/10;
    Num[2]= Temp%10;
    LcdWcom(0x90+0x05);              //显示计数值
    for(i=0;i<3;i++)
    {
        LcdWdata(Num+'0');
    }
    delay_ms(20);


    time_display();
    delay_ms(20);
}
/*************************************************
*函数作用:界面三      量测结果界面        *
**************************************************/
void Display_LCD12864_Face2()
{
    unsigned char i;
    jayt=0;                    //清除进度条殘影
    if(flang1==1)      //清除第二行留下的殘影
    {
        LcdWcom(0x01);
        delay_ms(50);
        flang1=0;    
    }




    if(Save_falg==1)          //写入24C0X标志位为1,数据写入24C0X
    {    
        for(i=5;i>1;i--)
        {
            write_AT24C02_ADD(20+i,read_AT24C02_ADD(20+i-1));             //存储数据
            delay_ms(50); //AT24C02_init();
              write_AT24C02_ADD(70+i,read_AT24C02_ADD(70+i-1));             //存储时间
            delay_ms(50); //AT24C02_init();
            write_AT24C02_ADD(80+i,read_AT24C02_ADD(80+i-1));             //
            delay_ms(50);//AT24C02_init();
            write_AT24C02_ADD(90+i,read_AT24C02_ADD(90+i-1));             //
            delay_ms(50); // AT24C02_init();
            write_AT24C02_ADD(50,i);                 //存入地址变量,防止乱写
            delay_ms(50); // AT24C02_init();
            Save_falg=0;                                    //写入标志位清0
        }
            write_AT24C02_ADD(20+1,DATA);             //存储数据
            delay_ms(50);// AT24C02_init();
              write_AT24C02_ADD(70+1,shi);             //存储时间
            delay_ms(50); //AT24C02_init();
            write_AT24C02_ADD(80+1,fen);             //
            delay_ms(50);//AT24C02_init();
            write_AT24C02_ADD(90+1,miao);             //
            delay_ms(50); // AT24C02_init();
            write_AT24C02_ADD(50,1);                 //存入地址变量,防止乱写
            delay_ms(50); // AT24C02_init();
            Save_falg=0;
    }


    if(alarm==1){Display_HZ(1,2,"异");Display_HZ(1,3,"常");Display_HZ(1,4,"!");} //上下限报警
    else {Display_HZ(1,2,"无");Display_HZ(1,3,"异");Display_HZ(1,4,"常");}


    delay_ms(70);
    Display_HZ_Line(0,0,"您的量测结果是: ");
    delay_ms(70);


    LcdWcom(0x88+0x02);                //显示最终结果
    for(i=0;i<3;i++)
    {
        LcdWdata(Num+'0');
        delay_ms(10);
    }
    Display_HZ_Line(2,4,"次/ 分钟");
    delay_ms(70);


    time_display();            //显示时间
}
/*************************************************
*函数作用:界面四          查询模式界面     *
**************************************************/
void Display_LCD12864_Face3()
{
    unsigned char Read_add;                //查询模式下,24C0X读操作指向地址  
    LcdWcom(0x01);      //清屏
    delay_ms(20);

    Read_add++;    
    if(Read_add==6)Read_add=1;    
    DATA1=read_AT24C02_ADD(20+Read_add);    //取出数据
    delay_ms(50);
    time[0]=read_AT24C02_ADD(70+Read_add);    //取出时间
    delay_ms(50);
    time[1]=read_AT24C02_ADD(80+Read_add);
    delay_ms(50);
    time[2]=read_AT24C02_ADD(90+Read_add);
    delay_ms(50);




    Display_HZ(0,1,"第");
    delay_ms(5);
    LcdWcom(0x80+0x02);
    LcdWdata(Read_add+'0');
    delay_ms(1);
    Display_HZ(0,3,"次");
    delay_ms(1);
    Display_HZ(0,4,"量");
    delay_ms(1);
    Display_HZ(0,5,"测");
    delay_ms(1);
    Display_HZ(0,6,"结");
    delay_ms(1);
    Display_HZ(0,7,"果");



    LcdWcom(0x89);
    LcdWdata(DATA1/100+'0');
    LcdWdata(DATA1%100/10+'0');
    LcdWdata(DATA1%10+'0'); 


    Display_HZ(2,3,"次");            
    LcdWcom(0x88+0x04);                
    LcdWdata('/');
    Display_HZ(2,5,"分");
    Display_HZ(2,6,"钟");
    delay_ms(1);


    LcdWcom(0x98);             //显示读取出来的时间
    LcdWdata(time[0]/10+'0');
    LcdWdata(time[0]%10+'0');
    LcdWdata(':');
    LcdWdata(time[1]/10+'0');
    LcdWdata(time[1]%10+'0');
    LcdWdata(':');
    LcdWdata(time[2]/10+'0');
    LcdWdata(time[2]%10+'0');


}
/*************************************************
*函数作用:界面五          睡眠模式界面     *
**************************************************/
/*void Display_LCD12864_Face4()
{
    Display_HZ(1,3,"休");
    Display_HZ(1,4,"眠");

/*************************************************
*函数作用:睡眠模式界面                *
**************************************************/   
void Display_Auto_Mode()
{
    if(Check_flag==0)           //自动启动模式
    {
        if(TL1>2)                //判断
        {    
            if(TL1>4)            //再次判断
            {
                delay_ms(50);
                if(TL1>5)          //再再次判断
                {
                    TR1=0;
                     TH1=0X00;           //
                    TL1=0X00;           //计数器清零
                    TR0=1;              // 
                    TR1=1;              //


                    Bee_Speak(200);
                    Check_flag=1;
                    Face=1;    
                    LcdWcom(0x01);
                }
            }
        }
    }
}




/*************************************************
*函数作用:Main函数                 *
**************************************************/
void main()
{
    unsigned char i;
    Timer0NCounterT1_Init();
    AT24C02_init();
    reset_1302();
    Display_Init();                   
    sheshi();
    Write_add=read_AT24C02_ADD(50);
//    Display_Welcom1();                                            
    GUI_Fill_GDRAM(0x00);            
    Bee_Speak(70);
    while(1)
    {

        Cotrl_Key();
        if(Face==0){Display_LCD12864_Face0();}
        if(Face==1){Display_LCD12864_Face1();}
        if(Face==2)
        {
            Display_LCD12864_Face2();
            i++;
            if(i==10)
            {
                Sleep_mode=1;
                TR1=1;
                Face=4;
                chuzhi=1;
            }
        }
        if(Face==4){time_display();}
    }      
}
/*************************************************
*函数作用:定时中断入口函数             *
**************************************************/
void Timer0(void) interrupt 1
{
    uchar i,j,Temp;
    uchar Temp_Data[3];
    uchar H1,L1;
    TH0=0xd8;
    TL0=0xf0;
    k++;
    if(k==500||k==1000)jayt++;     //进度条取样


    if(Sleep_mode==0)                 //正常测量模式
    {
        if(k==1000)                        //1000=10s定时 
        {        
            k=0;
            j++;
            H1=TH1;                         //读取计数值高位
            L1=TL1;                           //读取计数值低位
            Temp_Data=H1*256+L1;     //采样3次,取出数据
            if(j==3)                    //j=3,为采集3次,每次采集10s,共30s        
            {
            //    TR1=0;                       //关闭计数  
            //    TR0=0;                      //关闭定时 
                j=0;

                DATA=(Temp_Data[0]+Temp_Data[1]+Temp_Data[2])/3;    //求平均值
                DATA=DATA*6;                                       //*6推算得到60S时的值

                if((DATA>120)||(DATA<50)){alarm=1;Bee_Speak(50);Bee_Speak(50);Bee_Speak(50);}//上下限报警
                else alarm=0;

                Num[0]= DATA/100;  
                Num[1]= DATA%100/10;
                Num[2]= DATA%10;

                Bee_Speak(50);

                Face=2;                          //进入界面二
                Save_falg=1;                //数据写入24C0X允许标志位,为1时允许写入,写完后清0

                flang1=1;                    //某标志位,用于清屏
            }
        }
    }
    else if(Sleep_mode==1)                 //正常测量模式
    {
        if(k==500)
        {
            k=0;

            TR1=1;                
            TR0=1;

            L1=TL1;                       
            Temp=L1;             
            if((chuzhi==1)&&(Temp==0))          //判断手指是否拿出
            {    
                chuzhi=0;
                LED=0;
            }

            if((chuzhi==0)&&(Temp>2))         //判断手指是否放入
            {    
                LED=0;
                Rst_Watchdog();
            }
            TL1=0; TH1=0;
        }
    }

}

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]