基于51单片机的跑步机心率计速度测量系统proteus仿真原理图PCB

功能介绍:
0.本系统采用STC89C52作为单片机
1.系统实现监测跑步者心率和跑步机速度并显示
2.可以设置跑步速度
3.当心率低于设定下限阈值时跑步机升高速度档位
4.当心率超过设定上限阈值时跑步机降低速度档位,同时蜂鸣器发出警报
5.采用DC002作为电源接口可直接输入5V给整个系统供电

原理图:
在这里插入图片描述

PCB :
在这里插入图片描述

主程序:

#include <reg52.h> //调用单片机头文件
#include <intrins.h>
#include <stdio.h>
#include "lcd1602.h"
#include "main.h"

#define DIAMETER 20 //直径mm

bit rekey; //按键标志
bit startFlag = 0; //启动标志
bit setFlag = 0; //设置标志

unsigned char setIndex = 0;
unsigned char datIndex = 0;
unsigned int heartRateBuf[6] = {0}; //暂存心率值
unsigned int heartRate = 0;
unsigned int heartRateH = 120;
unsigned int heartRateL = 60;
unsigned char tab0[16]; //显示内容缓存
unsigned char motorPWM = 1; //设定速度档位
unsigned char realMotorPWM = 1; //真实速度档位
unsigned int xdata pulseCnt = 0;
unsigned int timeCnt = 0;
bit dispFlag = 0; //更新显示标志
bit updateFlag = 0; //更新心率标志
bit refreshFlag = 0;

/****************主函数***************/
void main()
{
    LED_GREEN = OFF;
    LED_RED = ON;
    BUZZER = OFF;
    EA = 0;
    Timer0_Init(); //初始化定时器
    Timer1_Init();
    Ext0_1_Init(); //外部中断0初始化程序
    
    LCD_Init();  //初始化液晶
    DelayMs(20); //延时有助于稳定
    LCD_Clear(); //清屏
    DelayMs(10);
    MOTOR_INA = 1;
    MOTOR_INB = 1;
    EA = 1;
    while (1)
    {
        if (refreshFlag == 1) //刷新心率
        {
            EX0 = 0;
            TR0 = 0;
            refreshFlag = 0;
            heartRateBuf[datIndex] = timeCnt * 5; //算出间隔时间
            TH0 = 0xEE; //(65536 - 0.005*11059200/12 + 200) / 256
            TL0 = 0xC8; //(65536 - 0.005*11059200/12 + 200) % 256  5ms
            timeCnt = 0; //50ms计数清零
            datIndex++;
            if (datIndex > 3) //记录到超过等于2次时间
            {
                datIndex = 1;   //计数从1开始
                updateFlag = 1; //测得4次开始显示
            }
            EX0 = 1;
            TR0 = 1;
        }
        
        if (dispFlag == 1) //更新显示标志置位
        {
            dispFlag = 0; //更新显示标志清零
            if (setFlag == 0)
            {
                if (updateFlag == 0) //如果显示关  检测心率是否真实
                {
                    heartRate = 0;
                }
                else //如果显示开
                {
                    heartRate = 60000 / ((heartRateBuf[1]>>1) + (heartRateBuf[2]>>1)); //心率计算 2次求平均值
                }

                if (startFlag == 1) //跑步机启动情况下
                {
                    if (heartRate > heartRateH) //心率超过阈值
                    {
                        realMotorPWM = motorPWM - 1; //速度档位降低1档
                        //BUZZER = ON;                 //蜂鸣器报警
                    }
                    else if (heartRate < heartRateL)
                    {
                        realMotorPWM = motorPWM + 1; //速度档位升高1档
                        BUZZER = OFF;
                    }
                    else
                    {
                        realMotorPWM = motorPWM; //速度档位等于设定档位
                        BUZZER = OFF;
                    }
                }
                else
                {
                    realMotorPWM = motorPWM; //速度档位等于设定档位
                    BUZZER = OFF;
                }
                
                
                DelayMs(20);
                DispNormal();
            }
        }

        KeyProcess();

    }
}

/************************* 正常显示 *************************/
void DispNormal(void)
{
    sprintf(tab0, "H:%3dbpm S%2d A%2d", heartRate, (int)motorPWM, (int)realMotorPWM); //显示心率和速度档位
    EA = 0;
    LCD_DispStr(0, 0, tab0); //显示心率
    EA = 1;

    sprintf(tab0, "Speed:%5.1fkm/h", (float)pulseCnt*3.6*3.14*DIAMETER/1000); //显示速度
    pulseCnt = 0;
    EA = 0;
    LCD_DispStr(0, 1, tab0); //显示转速
    EA = 1;
}

/************************* 显示设定心率上下限 *************************/
void DispSetLimit(unsigned char setIndex)
{
    LCD_DispStr(0, 0, "   Set Limit    ");
    sprintf(tab0, "  L:%3d  H:%3d  ", heartRateL, heartRateH); //显示心率上下限
    LCD_DispStr(0, 1, tab0); //显示心率

    switch (setIndex)
    {
        case 1: LCD_SetCursor(6, 1, 1); break;
        case 2: LCD_SetCursor(13, 1, 1); break;
        default:;
    } 

}

/************************* 按键处理 *************************/
void KeyProcess()
{
    
    if (KEY_SET == 0) //设置键按下
    {
        DelayMs(20);
        if (KEY_SET == 0) //设置键按下
        {
            if (setFlag == 0)
            {
                setFlag = 1; //进入设置
                setIndex = 1;
                DispSetLimit(setIndex);
            }
            else
            {
                setIndex++; //切换设置位置
                DispSetLimit(setIndex);
                if (setIndex > 2)
                {
                    setFlag = 0;
                    setIndex = 0;
                    LCD_WriteCommand(0x0C, 0); //关闭闪烁
                }
                
            }
        }
        while (KEY_SET == 0);
    }
    
    if (KEY_ADD == 0) //加键按下
    {
        DelayMs(200);
        if (KEY_ADD == 0) //加键按下
        {
            if (setFlag == 0)
            {
                if (motorPWM < 10)
                {
                    motorPWM++;
                }
            }
            else
            {
                if (setIndex == 1)
                {
                    heartRateL++;
                    if (heartRateL >= heartRateH)
                    {
                        heartRateL = 60;
                    }
                }
                else if (setIndex == 2)
                {
                    heartRateH++;
                    if (heartRateH > 140)
                    {
                        heartRateH = heartRateL + 1;
                    }
                }
                DispSetLimit(setIndex);
            }
        }
        
    }
    
    if (KEY_SUB == 0) //减键按下
    {
        DelayMs(200);
        if (KEY_SUB == 0) //减键按下
        {
            if (setFlag == 0)
            {
                if (motorPWM > 1)
                {
                    motorPWM--;
                }
            }
            else
            {
                if (setIndex == 1)
                {
                    heartRateL--;
                    if (heartRateL < 60)
                    {
                        heartRateL = heartRateH - 1;
                    }
                }
                else if (setIndex == 2)
                {
                    heartRateH--;
                    if (heartRateH <= heartRateL)
                    {
                        heartRateH = 140;
                    }
                }
                DispSetLimit(setIndex);
            }
        }
        
    }
    if (KEY_SWITCH == 0) //启停
    {
        DelayMs(20);
        if (KEY_SWITCH == 0) //启停
        {
            startFlag = ~startFlag;
            if (startFlag == 1)
            {
                LED_GREEN = ON;
                LED_RED = OFF;  
            }
            else
            {
                LED_GREEN = OFF;
                LED_RED = ON;  
            }
        }
        while (KEY_SWITCH == 0);
        
    }
}


/*************定时器初始化程序***************/
void Timer0_Init()
{
    TMOD &= 0xF0;
    TMOD |= 0x01; //定时器0工作方式1
    TH0 = 0xB8; //(65536 - 0.02*11059200/12) / 256
    TL0 = 0x00; //(65536 - 0.02*11059200/12) % 256  20ms
    //PT0 = 1;    //设置高优先级
    ET0 = 1;    //开定时器0中断
    TR0 = 1;    //允许定时器0定时
}

void Timer1_Init() //定时器1初始化
{
    TMOD &= 0x0F;
    TMOD |= 0x10;
	TL1 = 0x00;		//设置定时初始值
	TH1 = 0xEE;		//设置定时初始值 5ms
    PT1 = 1;    //设置高优先级
    ET1 = 1;
    TR1 = 1;
}

/***********外部中断0初始化程序****************/
void Ext0_1_Init() //外部中断0和1初始化程序
{
    IT0 = 1; //外部中断0负跳变中断
    IT1 = 1; //外部中断1负跳变中断
    PX0 = 1; //设置高优先级
    EX0 = 1; //允许外部中断0中断
    EX1 = 1; //允许外部中断0中断
}

void Ext0_Interrupt() interrupt 0
{
    if (timeCnt < 80) //当连续两次检测时间间隔小于80*5ms=400ms不处理
    {
        TR0 = 1; //开定时器
    }
    else
    {
        refreshFlag = 1;
    }
}

/*************定时器0中断服务程序***************/
void Timer0_Interrupt() interrupt 1
{
    TH0 = 0xEE; //(65536 - 0.005*11059200/12 + 200) / 256
    TL0 = 0xC8; //(65536 - 0.005*11059200/12 + 200) % 256  5ms
    timeCnt++; //每5ms一次计数

    if (timeCnt > 250) //当超过25*50ms=1.5s没有检测到信号停止显示
    {
        datIndex = 0;   //数据个数清零
        timeCnt = 0;  //50ms计数清零
        updateFlag = 0; //显示关
        TR0 = 0;      //定时器关
    }
}

void Ext1_Interrupt() interrupt 2
{
    pulseCnt++;
}

void Timer1_Interrupt(void) interrupt 3
{
    static unsigned int time5ms = 0;
    static unsigned char IN1Count = 0;
    
	TL1 = 0x00;		//设置定时初始值
	TH1 = 0xEE;		//设置定时初始值 5ms
    
    time5ms++;
    
    if (time5ms > 200) //定时1秒
    {
        time5ms = 0;
        dispFlag = 1; //更新数据标志置位
    }

    /************************* 电机PWM控制 *************************/
    if (startFlag == 1) //跑步机启动情况下
    {
        IN1Count++;
        if (IN1Count > realMotorPWM+15) //关闭时间段
        {
            MOTOR_INA = 1; //关闭
        }
        else if (IN1Count <= realMotorPWM+15) //占空比调节
        {
            MOTOR_INA = 0; //开启
        }
        
        if (IN1Count > 10+15)
        {
            IN1Count = 0; //一个周期结束
        }
    }
    else
    {
        MOTOR_INA = 1;
    }

}

仿真演示视频:
https://www.bilibili.com/video/BV1qB4y1j7Ki/

实物演示视频:
https://www.bilibili.com/video/BV1aP411J7uW/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值