stc89c52和LCD1602实现的秒表

功能描述

  1. 使用1602显示时间 分钟-秒-10毫秒 (256分钟以内,0.01秒精度,达到最大时间蜂鸣器警告)
  2. 记录20组数据
  3. 使用三个按键 K1开始/暂停 K2重置/计次 K3前一条记录 K4后一条记录(说明:运行时 K2添加一条记录)

效果如下图

stc89c52和LCD1602实现的秒表_第1张图片
Paste_Image.png

1602操作程序

#include 
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P2^5;
sbit BUSY = P0^7;
#define DATA P0

//读忙信号
void wait(void)
{
    P0 = 0xFF;
    do
    {
        RS = 0;
        RW = 1;
        EN = 0;
        EN = 1;
    }
    while (BUSY == 1);
    EN = 0;
}
//写命令到1602
void writeCMD(unsigned char cmd)
{
    wait();
    DATA = cmd;
    EN = 1;
    RS = 0;
    RW = 0;
    EN = 0;
}
//写数据到1602
void writeData(unsigned char dat)
{
    wait();
    DATA = dat;
    EN = 1;
    RS = 1;
    RW = 0;
    EN = 0;
}
//1602初始化
void init1602()
{
    writeCMD(0x38);
    writeCMD(0x08);
    writeCMD(0x01);
    writeCMD(0x06);
    writeCMD(0x0C);
    writeCMD(0x80);
}

秒表实现主程序

#include 
#include "1602.h"
#include 

#define noBtn               0
#define startOrPuaseBtn     1
#define resetOrCounterBtn   2
#define previousBtn         3
#define nextBtn             4
#define RE_NUM              20
#define FM_OFF              1
#define FM_ON               0
typedef struct{
    unsigned char minute;
    unsigned char second; 
    unsigned char msec;     
}time;

sbit K1 = P3^4;//开始、暂停按键
sbit K2 = P3^5;//重置、计次按键
sbit K3 = P3^6;//查看上一条记录按键
sbit K4 = P3^7;//查看下一条记录按键
sbit FM = P2^3;//蜂鸣器 0 开 1 关
unsigned char  msec = 0;
//bit runState = 0;
void Delay10ms()        //@11.0592MHz
{
    unsigned char i, j;

    i = 18;
    j = 235;
    do
    {
        while (--j);
    } while (--i);
}

//按键检测
unsigned char scanKey()
{
    P3 = 0xF0;
    if(P3!=0xF0)//有按键 延时10ms消抖
    {
        Delay10ms();
    }
    else
    {
        return noBtn;
    }
    if(K1==0) return startOrPuaseBtn;
    if(K2==0) return resetOrCounterBtn;
    if(K3==0) return previousBtn;
    if(K4==0) return nextBtn;
    return noBtn;
}
void Timer0Init(void)       //50毫秒@11.0592MHz
{
    //AUXR &= 0x7F;     //定时器时钟12T模式
    TMOD &= 0xF0;       //设置定时器模式
    TMOD |= 0x01;       //设置定时器模式
    TL0 = 0x00;     //设置定时初值
    TH0 = 0xDC;     //设置定时初值
    TF0 = 0;        //清除TF0标志
    TR0 = 0;        //定时器0开始计时  //开始时暂停的
    ET0 = 1;        //定时器0中断开启
    EA = 1;         //打开全局中断
}
//在1602的row行column列显示dat
//row 0 - 1
//column 0 - 15
void dis1602(unsigned char row, unsigned char column, char dat)//
{
    writeCMD(0x80+row*0x40+column);
    writeData(dat);
}
//在1602的row行column列显示字符串str
void disStr1602(unsigned char row, unsigned char column, char *str)//
{
    writeCMD(0x80+row*0x40+column);
    while(*str)
    {
        writeData(*str++);
    }
}
void main()
{
    unsigned char msecTemp = 0, keyValue = noBtn, keyTemp = noBtn;
    unsigned char recordTotal = 0, currentRecord = 0;
    unsigned char minute = 0, second = 0;
    char str[16] = "";
    time idata record[RE_NUM] = {0}; //记录存放
    init1602();
    Timer0Init();
    disStr1602(0,0, "stop   000:00:00");//初始化显示
    disStr1602(1,0, "00/00  000:00:00");
    //dis1602(0,10,':');
    //dis1602(0,13,':');
    while(1)
    {
        keyTemp = scanKey(); //当前key值
        if(keyValue!=keyTemp) //key状态发生变化则处理按键功能
        {
            keyValue = keyTemp;
            switch(keyValue)
            {
                case startOrPuaseBtn: //启动或暂停
                    TR0 = !TR0;
                    if(TR0)
                    {
                        disStr1602(0, 0, "start");
                    }
                    else
                    {
                        disStr1602(0, 0, "stop ");
                    }
                    break;
                case resetOrCounterBtn:
                    if(TR0)//运行状态 增加记录
                    {
                        if(recordTotal < RE_NUM)
                        {
                            record[recordTotal].minute = minute;
                            record[recordTotal].second = second;
                            record[recordTotal].msec = msec;
                            recordTotal++;
                            currentRecord = recordTotal;
                        }
                        sprintf(str,"%02d/%02d  %03d:%02d:%02d",
                                (int)currentRecord,(int)recordTotal,
                                (int)record[recordTotal-1].minute,
                                (int)record[recordTotal-1].second,
                                (int)record[recordTotal-1].msec);
                        disStr1602(1, 0, str);//显示 记录
                    }
                    else //暂停状态 重置
                    {
                        FM = FM_OFF;
                        minute = 0;
                        second = 0;
                        msec = 0;
                        recordTotal = 0;
                        currentRecord = 0;
                        disStr1602(0,0, "stop   000:00:00");//重置显示
                        disStr1602(1,0, "00/00  000:00:00");//重置显示
                    }
                    break;
                case previousBtn: //前一条记录
                    if(currentRecord > 1)
                    {
                        currentRecord--;
                        sprintf(str,"%02d/%02d  %03d:%02d:%02d",
                                (int)currentRecord,(int)recordTotal,
                                (int)record[currentRecord-1].minute,
                                (int)record[currentRecord-1].second,
                                (int)record[currentRecord-1].msec);
                        disStr1602(1, 0, str);//显示 记录
                    }
                    break;
                case nextBtn: //查看后一条记录
                    if(currentRecord < recordTotal)
                    {
                        currentRecord++;
                        sprintf(str,"%02d/%02d  %03d:%02d:%02d",
                                (int)currentRecord,(int)recordTotal,
                                (int)record[currentRecord-1].minute,
                                (int)record[currentRecord-1].second,
                                (int)record[currentRecord-1].msec);
                        disStr1602(1, 0, str);//显示 记录
                    }
                    break;  
            }
        }
        if(msecTemp!=msec)//每变一次10ms刷新
        {
            msecTemp = msec;
            if(msec>99)
            {
                if(++second>59)
                {
                    minute++;
                    second = 0;
                    dis1602(0, 7,'0'+minute/100);
                    dis1602(0, 8,'0'+minute/10%10);
                    dis1602(0, 9,'0'+minute%10);
                    if(minute==0xFF)//达到了秒表最大值 不能再继续 打开蜂鸣器提醒 并暂停秒表 等待重置
                    {
                        TR0 = 0;
                        FM = FM_ON;
                    }
                }
                else
                {
                    dis1602(0,11,'0'+second/10);
                    dis1602(0,12,'0'+second%10);
                }
                msec = 0;
            }
            dis1602(0,14,'0'+msec/10);
            dis1602(0,15,'0'+msec%10);
        }
    }
    
}

void T0_50ms() interrupt 1
{
    TL0 = 0x00;     //设置定时初值
    TH0 = 0xDC;     //设置定时初值
    //if(runState)
    {
        msec++;
    }
}

你可能感兴趣的:(stc89c52和LCD1602实现的秒表)