单片机简易数字时钟

#include
#include

unsigned char data dis_digit;
unsigned char key_s, key_v;

unsigned char code dis_code[11]={0xc0,0xf9,0xa4,0xb0,    // 0, 1, 2, 3
                0x99,0x92,0x82,0xf8,0x80,0x90, 0xff};// 4, 5, 6, 7, 8, 9, off
unsigned char data dis_buf[8];
unsigned char data dis_bufY[8];//存储年月日的缓冲区
unsigned char data dis_bufC[8];//存储闹钟的缓冲区
unsigned char data dis_index;
unsigned char hour,min,sec;
unsigned char hourC,minC,enable;//存储闹钟的时间和使能变量    ,0为不使能,1为使能
unsigned char sec100;
unsigned char year,month,date;
unsigned char flag;            //显示年月日与时分秒的标志;1为显示时间,2为显示年份,3为设定闹钟
unsigned char monthflag;    //月份不同的标志,用以显示日期

sbit    K1 = P1^4;            //小时或年份调整
sbit    K2 = P1^5;            //分钟或月份调整
sbit    K3 = P1^6;            //日期调整
sbit    K4 = P1^7;            //显示内容切换按键
sbit    bell = P3^7;        //闹钟控制,0为响,1为不响

bit scan_key();
void proc_key();
void inc_sec();
void inc_min();
void inc_hour();
void inc_year();
void inc_month();
void inc_date();
void display();
void delayms(unsigned char ms);

void main(void)
{
    P0 = 0xff;
    P2 = 0xff;
    TMOD = 0x11;        // 定时器0, 1工作模式1, 16位定时方式
    TH1 = 0xdc;         //定时器1,10ms中断一次,这样100次正好是1秒钟的时间
    TL1 = 0;

    TH0 = 0xFC;
    TL0 = 0x17;
    hour = 12;
    min = 30;
    sec = 0;

    hourC = 12;
    minC = 31;
    enable=1;

    year =9;
    month = 12;
    date =9;
    monthflag=31;    //09年12月有31天

    flag = 1;

    sec100 = 0;
    dis_buf[0] = dis_code[hour / 10];        // 时十位
    dis_buf[1] = dis_code[hour % 10];        // 时个位
    dis_buf[3] = dis_code[min / 10];        // 分十位
    dis_buf[4] = dis_code[min % 10];        // 分个位
    dis_buf[6] = dis_code[sec / 10];        // 秒十位
    dis_buf[7] = dis_code[sec % 10];        // 秒个位
    dis_buf[2] = 0xbf;                        // 显示"-"
    dis_buf[5] = 0xbf;                        // 显示"-"

    dis_bufC[0] = dis_code[hourC/ 10];        // 以下是闹钟的设定,时间十位
    dis_bufC[1] = dis_code[hourC % 10];        // 闹钟的时间个位
    dis_bufC[3] = dis_code[minC / 10];        // 分十位
    dis_bufC[4] = dis_code[minC % 10];        // 分个位
    dis_bufC[6] = dis_code[enable];            //使能端显示,0为闹钟关,1为闹钟开
    dis_bufC[7] = dis_code[10];                // 该位不显示
    dis_bufC[2] = 0xbf;                        // 显示"-"
    dis_bufC[5] = 0xbf;                        // 显示"-"

    dis_bufY[0] = dis_code[year / 10];        // 年十位
    dis_bufY[1] = dis_code[year % 10];        // 年个位
    dis_bufY[3] = dis_code[month / 10];        // 月份十位
    dis_bufY[4] = dis_code[month % 10];        // 月份个位
    dis_bufY[6] = dis_code[date / 10];        // 日期十位
    dis_bufY[7] = dis_code[date % 10];        // 日期个位
    dis_bufY[2] = 0xbf;                        // 显示"-"
    dis_bufY[5] = 0xbf;                        // 显示"-"

    dis_digit = 0xfe;
    dis_index = 0;
    TCON = 0x01;
    IE = 0x8a;                // 使能timer0,1 中断
    TR0 = 1;
    TR1 = 1;

    key_v = 0x0f;          //检测键盘用

    while(1)
    {
        if(scan_key())
        {
            delayms(10);
            if(scan_key())
            {
                key_v = key_s;
                proc_key();
            }
        }
        if(hour == hourC && min == minC && enable == 1)         //注意必须在显示正常时间时,按k3键即P16才能关闭    
        {
            bell = 0;//闹钟响,按下k3停止响
        }
    }
}

bit scan_key()
{
    key_s = 0x00;
    key_s |= K4;
    key_s <<= 1;
    key_s |= K3;
    key_s <<= 1;
    key_s |= K2;
    key_s <<= 1;
    key_s |= K1;
    return(key_s ^ key_v);   
}

void proc_key()
{
    EA = 0;
    if((key_v & 0x01) == 0)        // K1键被按下
    {
        if(flag == 1)
        {
            inc_hour();
        }
        else if(flag ==2)
        {
            inc_year();
        }
        else
        {   
            inc_hour();
        }
    }
    else if((key_v & 0x02) == 0)    // K2 键被按下
    {
        if(flag == 1)
        {
            min++;
            if(min > 59)
            {
                min = 0;
            }
            dis_buf[3] = dis_code[min / 10];        // 分十位
            dis_buf[4] = dis_code[min % 10];        // 分个位
        }
        else if(flag ==2)
        {
            inc_month();
        }
        else
        {
            inc_min();
        }
    }
    else if((key_v & 0x04) == 0)    //k3  键被按下
    {
        if(flag ==3)
        {
            if(enable == 1)
            {
                enable = 0;
            }
            else
            {
                enable = 1;
            }
            dis_bufC[6] = dis_code[enable%10];   

        }
        else if(flag == 2)
        {
            inc_date();
        }
        else        //闹钟关闭,必须在显示正常时间下按k3才能关闭     
        {
            bell = 1;
            enable = 0;
        }
    }
    else if((key_v & 0x08) == 0)    //k4  键被按下
    {
        if(flag == 1)
            flag++ ;
        else if(flag == 2)
            flag++;
        else
            flag=1;
    }

    EA = 1;
}

void timer0() interrupt 1
// 定时器0中断服务程序, 用于数码管的动态扫描
// dis_index --- 显示索引, 用于标识当前显示的数码管和缓冲区的偏移量
// dis_digit --- 位选通值, 传送到P2口用于选通当前数码管的数值, 如等于0xfe时,
//                选通P2.0口数码管
// dis_buf   --- 显于缓冲区基地址   
{
    TH0 = 0xFC;
    TL0 = 0x17;
    P2 = 0xff;                            // 先关闭所有数码管
    if(flag == 1)
    {
        P0 = dis_buf[dis_index];            // 显示代码传送到P0口
    }
    else if(flag == 2)                        //送年月份的显示代码
    {   
        P0 = dis_bufY[dis_index];
    }
    else                                  //送闹钟的显示代码
    {
        P0 = dis_bufC[dis_index];
    }
    P2 = dis_digit;                        //

    dis_digit = _crol_(dis_digit,1);    // 位选通值左移, 下次中断时选通下一位数码管
    dis_index++;                        //
    dis_index &= 0x07;            // 8个数码管全部扫描完一遍之后,再回到第一个开始下一次扫描
}

void timer1() interrupt 3
{
    TH1 = 0xdc;
    sec100++;
    if(sec100 >= 100)
    {
        sec100 = 0;
        inc_sec();
    }
}

void inc_sec()
{
    sec++;
    if(sec > 59)
    {
        sec = 0;
        inc_min();
    }
    dis_buf[6] = dis_code[sec / 10];        // 秒十位
    dis_buf[7] = dis_code[sec % 10];        // 秒个位   
}

void inc_min()
{
    if(flag ==3)
    {
        minC++;
        if(minC > 59)
        {
            minC = 0;
        }
        dis_bufC[3] = dis_code[minC / 10];        // 闹钟分十位
        dis_bufC[4] = dis_code[minC % 10];        // 闹钟分个位
    }
    else
    {
        min++;
        if(min > 59)
        {
            min = 0;
            if(flag ==1)
            {
                inc_hour();
            }
        }
        dis_buf[3] = dis_code[min / 10];        // 分十位
        dis_buf[4] = dis_code[min % 10];        // 分个位
    }
}

void inc_hour()
{
    if(flag == 3)
    {
        hourC++;
        if(hourC > 23)
        {
            hourC = 0;
        }
        if(hourC > 9)
            dis_bufC[0] = dis_code[hourC / 10];        // 时十位
        else
            dis_bufC[0] = 0xff;                    // 当小时的十位为0时不显示
        dis_bufC[1] = dis_code[hourC % 10];        // 时个位
    }
    else
    {
        hour++;
        if(hour > 23)
        {
            hour = 0;
            if(flag == 1)
            {
                inc_date();
            }
        }
        if(hour > 9)
            dis_buf[0] = dis_code[hour / 10];        // 时十位
        else
            dis_buf[0] = 0xff;                    // 当小时的十位为0时不显示
        dis_buf[1] = dis_code[hour % 10];        // 时个位
    }
}

void inc_year()
{
    year++;
    if(year>99)
    {
        year = 0;
    }
    if(year > 9)
    {
        dis_bufY[0]=dis_code[year / 10];
    }
    else
        dis_bufY[0] = 0xff;                    // 当年份的十位为0时不显示
    dis_bufY[1] = dis_code[year % 10];        // 年份的个位
}
void inc_month()
{
    month++;
    if(month > 12)
    {
        month = 1;
        if(flag == 1)
        {
            inc_year();
        }
    }
    dis_bufY[3] = dis_code[month / 10];        // 月份十位
    dis_bufY[4] = dis_code[month % 10];        // 月份个位
    if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12)
    {
        monthflag = 31;  //月份标志31表示,日期有31天
    }
    else if ( month==4 || month==6 || month==9 || month==11)
    {
        monthflag = 30; //月份标志30表示,日期有30天
    }
    else
    {
        monthflag = 28; //2月有28天;
    }
}

void inc_date()
{
    date++;
    if(date > monthflag)                    //日期需要进位了
    {
        date = 1;
        if(flag == 1)
        {
            inc_month();
        }
    }
    dis_bufY[6] = dis_code[date / 10];        // 日期十位
    dis_bufY[7] = dis_code[date % 10];        // 日期个位
}

void delayms(unsigned char ms)   
// 延时子程序
{                       
    unsigned char i;
    while(ms--)
    {
        for(i = 0; i < 120; i++);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值