原创 基于51单片机的时钟屏应用

2010-6-10 09:09 3259 8 8 分类: MCU/ 嵌入式

基于51单片机的时钟屏应用<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


    时钟屏简介


时钟屏是一块具有四位七段数码管(分别对应时、分)和秒点(有些还有上下午显示)的模块。本人使用的时钟屏上有30只发光二极管,如下图所示。


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />


点击看大图 


它是共阴的,其中:1A1G为第一位(可以为小时十位),2A2G为第二位(可以为小时个位),3A3G为第三位(可以为分钟十位),4A4G为第四位(可以为分钟个位),LC可以为秒点。


 


      硬件设计


时钟可以采用纯软件实现,也可以采用硬件时钟。软件时钟必须在每次上电时进行时间的初始化(包括校时);而硬件时钟一般使用专用的时钟芯片,它有自己的蓄电池,因此掉电后它还会继续走时,系统上电后时间仍然保证是正确的。


本应用采用PCF8563时钟芯片,51单片机采用AT89S52芯片,其详细的电原理图如下所示。



点击看大图 


    软件设计


每隔一分钟读取一次PCF8563中的日期时间值并屏蔽无效位,四位时间(小时和分钟)加秒点或日期(月和日), 显示子函数中的LED数码管采用动态显示,每位5ms,周期为2025ms。为了使看到的显示不闪烁,必须经常执行显示子函数。按键S2用于调整小时(或月)的值;按键S3用于调整分钟(或日)的值;按键S4用于使显示的时间改为日期。T0定时器用于产生25ms中断,在中断服务子函数中,使控制秒点闪烁的亮灭标志以一秒为周期变化;另外计时一分钟则使分钟标志为1。本应用详细的流程图如下所示。


点击看大图



 


基于51单片机的时钟屏应用详细C51程序如下所示。


 


/***************


PCF8563+时钟屏


****************/


#include "reg51.h"


#include<intrins.h>                //包含_nop_()函数定义的头文件


#define uint unsigned int


#define uchar unsigned char


uchar code ddata[]={


    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,


    };  //0,1,2,3....9的段码


sbit SS="P2"^0;                   //时十位       


sbit SG="P2"^1;                   //时个位


sbit FS="P2"^2;                   //分十位


sbit FG="P2"^3;                   //分个位


sbit M="P2"^4;                    //


sbit S2=P2^5;                   //时或月+1


sbit S3=P2^6;                   //分或日+1


sbit S4=P2^7;                   //日期键


uchar min,hour,date,month;         //分,时,日,月,


uchar int_c=0,sec_c=0,min_f,date_f;//中断计数,秒计数,分标志,日期标志


uchar time[7];                     //日期时间缓存


uchar light_wink;               //亮灭


uchar date_c=0;                 //日期显示计时器


 


void delay_1ms(uint x)             //延时xms


{


    uint j;


    uchar k;


    for(j=0;j<x;j++)


    {


       for(k=0;k<120;k++);


    }


}


 


/**********以下为8563的读写子函数*************/


sbit SDA="P1"^6;


sbit SCL="P1"^7;


bdata char com_data;


sbit mos_bit=com_data^7;


sbit low_bit=com_data^0;


 


void start()                    //启动读写时序


{


    SDA=1;SCL=1;_nop_();_nop_();


    SDA=0;_nop_();_nop_();


    SCL=0;


}


 


void stop()                        //停止操作


{


    SDA=0;SCL=1;


    _nop_();_nop_();


    SDA=1;_nop_();_nop_();


    SDA=0;SCL=0;


}


 


void ack()                         //应答


{


    SDA=0;SCL=1;


    _nop_();_nop_();


    SCL=0;


    SDA=1;


}


 


void shift8(char a)                    //8位移位输出


{


    data uchar i;


    com_data=a;


    for(i=0;i<8;i++)


    {


       SDA=mos_bit;


       SCL=1;_nop_();_nop_();


       SCL=0;SDA=0;


       com_data=com_data*2;


    }


}


 


rd_8563(char a)                 //8563a地址单元连续的5个数据


{


    data uchar i,j,command;


    SDA=1;SCL=0;_nop_();_nop_();


    start();


    command=162;


    shift8(command);


    ack();


    shift8(a);


    ack();


    start();


    command=163;


    shift8(command);


    ack();


    SDA=1;_nop_();_nop_();_nop_();_nop_();


    for(j=0;j<5;j++)


    {


       for(i=0;i<8;i++)


       {


           com_data=com_data*2;


           SDA=1;SCL=1;_nop_();_nop_();_nop_();_nop_();


           low_bit=SDA;


           SCL=0;_nop_();_nop_();


       }


       time[j]=com_data;


       ack();


    }


    stop();


}


 


void wr_8563(char a,char b)//b地址单元的数据写入8563a地址单元中


{


    data uchar command;


    start();


    command=162;


    shift8(command);


    ack();


    shift8(a);


    ack();


    shift8(b);


    ack();


    stop();


}


 


time_display(void)


{


    uchar i;


    for(i=1;i<6;i++)


    {


       switch(i)


       {


           case 1:{P2=0xfe;if(((hour&0xf0)>>4)==0)P0=0xff;


                  else P0=ddata[(hour&0xf0)>>4];break;}//显示小时十位


       case 2:P2=0xfd;P0=ddata[hour&0x0f];break; //显示小时个位


       case 3:P2=0xfb;P0=ddata[(min&0xf0)>>4];break; //显示分钟十位


       case 4:P2=0xf7;P0=ddata[min&0x0f];break;      //显示分钟个位


           case 5:if(light_wink)


           {


              P2=0xef;P0=0;


           };break;


       }


       delay_1ms(5);


       P2=0xff;


    }


}


 


date_display()


{


    uchar i;


    for(i=1;i<5;i++)


    {


       switch(i)


       {


           case 1:{P2=0xfe;if(((month&0xf0)>>4)==0)P0=0xff;


                                  else P0=ddata[(month&0xf0)>>4];break;}                                            //显示月十位


           case 2:P2=0xfd;P0=ddata[month&0x0f];break;                                                  //显示月个位


           case 3:P2=0xfb;P0=ddata[(date&0xf0)>>4];break;                                              //显示日十位


           case 4:P2=0xf7;P0=ddata[date&0x0f];break;                                                   //显示日个位


       }


       delay_1ms(5);


       P2=0xff;


    }


}


 


main()


{


    TMOD=0X01;


    TH0=0X9E;                   //25ms


    TL0=0X58;


    TR0=1;ET0=1;EA=1;


    rd_8563(0x03);                  //读日期时间


    min=time[0]&0x7f;           //屏蔽无效位


    hour=time[1]&0x3f;


    date=time[2]&0x3f;


    month=time[4]&0x1f;


    while(1)


    {


       if(date_f)


           date_display();          //显示日期


       else


           time_display();          //显示时间


       if(min_f)


       {             //每分钟读取一次日期时间并屏蔽无效位


           min_f=0;


           rd_8563(0x03);


           min=time[0]&0x7f;


           hour=time[1]&0x3f;


           date=time[2]&0x3f;


           month=time[4]&0x1f;


       }


       if (S2==0) 


      {                           //月或时+1


           time_display();             //延时25ms


           if(S2)


              goto loop;


           if(date_f)


           {                        //+1


              if(((month&0x0f)+1)>9)


                  month=(month&0xf0)+0x10;


              else


                  month=month+1;


              if(month>0x12)


                  month=0;


              wr_8563(0x07,month);     //写入月


              date_c=0;


           }


           else


           {


              if(((hour&0x0f)+1)>9)       //+1


                  hour=(hour&0xf0)+0x10;


              else


                  hour=hour+1;


              if(hour>0x23)


                  hour=0;


              wr_8563(0x04,hour);      //写入时


           }


           for(;;)


              if(S2)


                     goto loop;


                  if(date_f)


                  date_display();          //显示日期


              else


                  time_display();          //显示时间


       }


    loop:if(S3==0)


      {                           //日或分+1 


           time_display();             //延时25ms


           if(S3)


              goto loop;


           if(date_f)


           {                        //+1


              if(((date&0x0f)+1)>9)


                  date=(date&0xf0)+0x10;


              else


                  date=date+1;


              if(date>0x31)


                  date=0;


              wr_8563(0x05,date);      //写入月


              date_c=0;


           }


           else


           {


              if(((min&0x0f)+1)>9) //+1


                  min=(min&0xf0)+0x10;


              min=min+1;


              if(min>0x59)


                  min=0;


              wr_8563(0x03,min);       //写入分


           }


           for(;;)


              if(S3)


                  goto loop;


              if(date_f)


                  date_display();          //显示日期


              else


                  time_display();          //显示时间


       }


       if(S4==0)


       {                           //日期显示


           time_display();             //延时25ms


           if(S4)


              goto loop;


           date_display();


           date_c=0;


           date_f=1;


           for(;;)


              if(S4)


                  goto loop;


              if(date_f)


                  date_display();          //显示日期


              else


                  time_display();          //显示时间


       }


    } 


}


 


void T0_int(void) interrupt 1


{


    TH0=0X9E;TL0=0X58;


    int_c++;


    if(int_c==20)


       light_wink=1;


    if(int_c==40)


    {                    //一秒


       int_c=0x00;


       sec_c++;


       light_wink=0;


       date_c++;


           if(date_c==10)


           date_f=0;


       if(sec_c==60)


       {                 //一分钟


           sec_c=0;


           min_f=1;


       }


    }


}


 


以使用MedWin软件为例 ,启动MedWin V3.0,执行菜单命令“项目管理”“新建项目”创建项目(或利用原有项目),然后再执行菜单命令“项目管理”“新建文件”,在编辑窗口中输入上述源程序,经编译无误后,在构建窗口中将显示无错误。注意:需执行菜单命令“设置”“设置编译工具”点选“指定路径下的编译工具”(该软件默认的是汇编语言),将C51文件夹放在适当的路径(可利用Keil中的C51)。


 


    仿真调试


本人使用的硬件仿真器是万利公司的“ME-52HU”,将仿真头插入目标板中的CPU插座,连通仿真器与PCUSB线,先后接通目标板和仿真器的电源,点击快捷按钮“产生代码并装入”,将出现十几个调试的快捷按钮,此时可以点击某个快捷按钮进行仿真调试。当排除了程序中所有错误后,点击“全速运行”按钮时,将会在时钟屏上看到正确的显示,如下图所示。


0b6bbf24-5f21-4b87-98ad-88f973bd854b.jpg


 

    本人的邮箱:txxyc104@163.com,欢迎来信讨论.

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
8
关闭 站长推荐上一条 /3 下一条