×
单片机 > 单片机程序设计 > 详情

一个51单片机实现数字时钟(1602显示)

发布时间:2020-06-09 发布时间:
|
     用单片机实现数字时钟,关于时间显示,是用的1602液晶,C51单片机,然后再加一个定时器,每到一秒就动态的更新一下液晶的时间显示,在更新的时候也要计算相应的分针和时针的变化,还要注意边界问题.为了能够达到一个最好的效果,我还加了一个键盘扫描,用到了3个键,分别为功能键,增1,减1来实现用户自定义时间. 

     在实现过程中,用到了单片机的中断系统的相关知识,还有定时器,液晶显示,键盘的动态扫描,都是以前的知识,没什么难度. 
    程序如下,可以正常运行.

C代码 
#i nclude    
#define uint unsigned int   
#define uchar unsigned char   
  
sbit lcdrs = P1^0;   
sbit lcdrw = P1^1;   
sbit lcden = P1^2;   
  
sbit key0 = P2^0;//功能键,选择时分秒   
sbit key1 = P2^1;//加1键   
sbit key2 = P2^2;//减1键   
sbit key4 = P2^4;   
  
uchar key0_count;//按键0被按的次数(0~3)   
  
char hour,minute,second; //时分秒   
uint timer_count;  //定时器中断计数   
  
uchar table_date[] = "2009-4-12  Mon";   
uchar table_time[] = "00:00:00";   
  
/****** 函数申明 ********/  
void write_cmd_1602(uchar cmd);   
void write_data_1602(uchar dat);   
void write_add(uchar add,uchar dat);   
void init1602();   
void delay(uint z);   
uchar reverse(uchar c);   
void keyscan();   
void init();   
/****** 主函数 ********/  
void main()   
{   
    init();   
    //init1602();   
    //while(1);   
    while(1)   
    {   
        keyscan();   
        delay(5);   
    }   
}   
//1602液晶初始化   
void init1602()   
{   
    lcdrw = 0;             //本程序只读不写,故将其置低   
    lcden = 0;             //关闭1602   
    delay(5);   
    write_cmd_1602(0x01);  //清屏   
    write_cmd_1602(0x38);  //显示模式   
    write_cmd_1602(0x0c);  //开显示,不显示光标,不闪烁   
    write_cmd_1602(0x06);  //地址指针自动加1   
    write_cmd_1602(0x80+1);//将光标指向第一行第二个位置   
    delay(5);   
}   
void delay(uint z)   
{   
    uint x,y;   
    for(x=z;x>0;x--)   
        for(y=110;y>0;y--);   
}   
/** 将发送的数据进行翻转,高位到低位,低位转到高位 **/      
uchar reverse(uchar c)      
{      
   uchar chbuff=0;      
   if (c&0x01) chbuff=chbuff|0x80;      
   if (c&0x02) chbuff=chbuff|0x40;      
   if (c&0x04) chbuff=chbuff|0x20;      
   if (c&0x08) chbuff=chbuff|0x10;      
   if (c&0x10) chbuff=chbuff|0x08;      
   if (c&0x20) chbuff=chbuff|0x04;      
   if (c&0x40) chbuff=chbuff|0x02;      
   if (c&0x80) chbuff=chbuff|0x01;      
   return chbuff;      
}   
//向液晶写命令   
void write_cmd_1602(uchar cmd)   
{   
    lcdrs = 0; //低表示写命令,高表示写数据   
    delay(5);   
    P0 = reverse(cmd);   
    delay(5);   
    lcden = 1; //给一个高脉冲   
    delay(5);      
    lcden = 0;   
    delay(5);   
}   
//向液晶写数据   
void write_data_1602(uchar dat)   
{   
    lcdrs = 1; //低表示写命令,高表示写数据   
    delay(5);   
    P0 = reverse(dat);   
    delay(5);   
    lcden = 1; //给一个高脉冲   
    delay(5);      
    lcden = 0;   
    delay(5);   
}    
//根据地址向液晶写数据   
void write_add(uchar add,uchar dat)   
{   
    uchar shi,ge;   
    shi = dat/10;   
    ge = dat%10;   
    delay(5);   
    write_cmd_1602(0x80+add);   
    write_data_1602(shi+0x30);   
    delay(5);   
    write_data_1602(ge+0x30);   
}   
//键盘扫描函数   
void keyscan()   
{   
    key4 = 0;   
    if(0==key0) //第一个键被按下   
    {   
        delay(5); //消抖   
        if(0==key0)   
        {   
            key0_count ++;   
            if(4==key0_count)   
                key0_count = 0;   
            while(!key0); //松手检测   
            if(0==key0_count)   
            {   
                TR0 = 1;  //重新开始计时   
                write_cmd_1602(0x0c);  //禁止显示光标并不让其闪烁      
            }   
            if(1==key0_count)   
            {   
                TR0 = 0;  //暂停计时   
                write_cmd_1602(0x80+0x40+11);//将地址指针指向秒的位置   
                write_cmd_1602(0x0f);  //显示光标并闪烁   
                delay(5);      
            }   
            if(2==key0_count)   
            {   
                TR0 = 0;  //暂停计时   
                write_cmd_1602(0x80+0x40+8);//将地址指针指向分的位置   
                write_cmd_1602(0x0f);  //显示光标并闪烁   
                delay(5);   
            }   
            if(3==key0_count)   
            {   
                TR0 = 0;  //暂停计时   
                write_cmd_1602(0x80+0x40+5);//将地址指针指向小时的位置   
                write_cmd_1602(0x0f);  //显示光标并闪烁       
                delay(5);   
            }   
        }   
    }   
    if(0==key1) //第二个键被按下   
    {   
        delay(5); //消抖   
        if(0==key1)   
        {   
            while(!key1); //松手检测   
            if(key0_count==1)   
            {   
                second ++;   
                if(60==second)     
                    second = 0;   
                 write_add(0x40+10,second);   
            }   
            if(key0_count==2)   
            {   
                minute ++;   
                if(60==minute)     
                    minute = 0;   
                 write_add(0x40+7,minute);   
            }   
            if(key0_count==3)   
            {   
                hour ++;   
                if(24==hour)       
                    hour = 0;   
                 write_add(0x40+4,hour);   
            }   
        }   
    }   
    if(0==key2) //第三个键被按下   
    {   
        delay(5); //消抖   
        if(0==key2)   
        {   
            while(!key2); //松手检测   
            if(key0_count==1)   
            {   
                second --;   
                if(-1==second)     
                    second = 59;   
                write_add(0x40+10,second);     
            }   
            if(key0_count==2)   
            {   
                minute --;   
                if(-1==minute)     
                    minute = 59;   
                write_add(0x40+7,minute);      
            }   
            if(key0_count==3)   
            {   
                hour --;   
                if(-1==hour)       
                    hour = 23;   
                write_add(0x40+4,hour);    
            }   
        }   
    }   
  
}   
//程序初始化函数   
void init()   
{   
    uchar i;   
    hour = 0;   
    minute = 0;   
    second = 0;   
    key0_count = 0;   
    init1602();   
    delay(20);  //延长时间,确保液晶处于非忙状态   
    for(i=0;i<14;i++)   
    {   
        write_data_1602(table_date[i]);   
        delay(5);      
    }   
    write_cmd_1602(0x80+0x40+4);  //调整地址指针   
    for(i=0;i<8;i++)   
    {   
        write_data_1602(table_time[i]);   
        delay(5);      
    }   
    //初始化定时器   
    TMOD = 0x01;   //定时器模式   
    TH0 = (65536-50000)/256;  //装初值   
    TL0 = (65536-50000)%256;   
    EA = 1;//开总中断   
    ET0 = 1;//开定时器0中断   
    TR0 = 1; //启动定时器,此时开始计时   
}   
void timer0() interrupt 1  //定时器0的中断处理函数   
{   
    TH0 = (65536-50000)/256;  //装初值   
    TL0 = (65536-50000)%256;   
    timer_count ++;   
    if(20==timer_count)        //到了1秒更新时分秒的显示   
    {   
        timer_count = 0; //中断次数清0,重新计数   
        second ++;   //秒针加1   
        if(second==60)   
        {   
            second = 0;   
            minute ++;   //分针加1   
            if(60==minute)   
            {   
                minute = 0;   
                hour ++;  //小时加1   
                if(24==hour)   
                {   
                    hour = 0;   
                }   
                write_add(0x40+4,hour);   
            }   
            write_add(0x40+7,minute);  //更新分针的显示   
        }   
        write_add(0x40+10,second);  //更新秒针   
    }   
}  

关键字:51单片机  数字时钟  1602显示 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
实验八 交通灯控制(80C51单片机汇编语言编程)