自学内容网 自学内容网

51单片机基础05 实时时钟-思路及代码参考2、3

目录

一、思路二

1、原理图

2、代码

二、思路三

1、原理图

2、代码


一、思路二

所有设定功能相关的操作均在矩阵键盘进行实现,并在定时器中扫描、计数等

1、原理图

2、代码

#include <AT89X52.h>       //调用51单片机的头文件
//---------------------------------------
#define uchar unsigned char
#define uint unsigned int         
//---------------------------------------
     
//---------------------------------------
//1602液晶相关I/O设置
sbit en=P2^3;               //1602液晶的E脚接在P2.3口上
sbit rw=P2^4;              //1602液晶的RW脚接在P2.4口上
sbit rs=P2^5;              //1602液晶的RS脚接在P2.5口上
#define dataPort P0 //P0口接1602的D0~D7
//---------------------------------------

//4×4矩阵式按键相关I/O设置
//分别为4行和4列的选择线。
sbit HAGN1=P1^0;           //第1行接在P1.0口上
sbit HANG2=P1^1;           //第2行接在P1.1口上
sbit HANB3=P1^2;           //第3行接在P1.2口上
sbit HANG4=P1^3;           //第4行接在P1.3口上
sbit LIE1=P1^4;            //第1列接在P1.4口上
sbit LIE2=P1^5;            //第2列接在P1.5口上
sbit LIE3=P1^6;            //第3列接在P1.6口上
sbit LIE4=P1^7;            //第4列接在P1.7口上
//---------------------------------------

//基本计时功能,具有时分秒
uchar code table[]="0123456789:."; //时间显示
uchar shi=0,fen=0,miao=0;
uchar TIME_FLAG=1;   //时间显示标志位,上电默认显示时间
uchar count=0; //定时器值
//---------------------------------------

//秒表功能,最大显示99.9秒
uchar code table1[]=" clock";
uchar code table2[]="ON ";
uchar code table3[]="OFF";
uint TIME_CLK=0;//秒表显示值
uchar CLK_FLAG=0;   //秒表显示标志位,上电不显示
uchar start_clk_flag=1;   //秒表开始与暂停标志位  默认不暂停
uchar clk=0;//定时器值
//---------------------------------------

//基本日历显示功能,自动计算闰年及各月对应的日期
uchar code table4[]="0123456789-"; //日期显示
uint nian=2019,yue=11,ri=5;
uchar Calendar_FLAG=0;   //日历显示标志位,上电不显示
//---------------------------------------

//基本闹钟功能与蜂鸣器I/O设置
sbit BEEP=P2^0; 
uchar beep_flag=0;   //闹钟标志位,置1后会五短一长
//---------------------------------------
void delay_ms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}

void lcd_wcom(unsigned char com) //1602写命令函数 
{
rs=0;//选择指令寄存器
rw=0;//选择写
dataPort=com;//把命令字送入P0
delay_ms(5);//延时一小会儿,让1602准备接收数据
en=1;//使能线电平变化,命令送入1602的8位数据口
en=0;
}

void lcd_wdat(unsigned char dat) //1602写数据函数
{
rs=1;//选择数据寄存器
rw=0;//选择写
dataPort=dat;//把要显示的数据送入P2
delay_ms(5);//延时一小会儿,让1602准备接收数据
en=1;//使能线电平变化,数据送入1602的8位数据口
en=0;
}

void lcd_init() //1602初始化函数 
{
lcd_wcom(0x34);//8位数据,双列,5*7字形 
//lcd_wcom(0x0c); //开显示屏,关光标,当前字符不闪烁
lcd_wcom(0x0f);//开启显示屏,开光标,当前字符闪烁
lcd_wcom(0x06);//显示地址递增,即写一个数据后,显示位置右移一位
lcd_wcom(0x01);//清屏
lcd_wcom(0x0C);//清屏
}


void lcd_clr()   //液晶屏清屏
{
lcd_wcom(0x01);//清屏
}

void TIME_display()
{
if(miao==60)
  {
miao=0;
fen++;
  }
  if(fen==60)
  {
  fen=0;
shi++;
  }
  if(shi==24)
 {
shi=0;
 } 
 if(shi!=0)
 if(fen==0)
 if(miao==0)
beep_flag=1;
lcd_wcom(0x80);   
lcd_wdat(table[shi/10]); 
lcd_wcom(0x81);  
lcd_wdat(table[shi%10]); 
lcd_wcom(0x82);  
lcd_wdat(table[10]); 

lcd_wcom(0x83);  
lcd_wdat(table[fen/10]); 
lcd_wcom(0x84);  
lcd_wdat(table[fen%10]); 
lcd_wcom(0x85);  
lcd_wdat(table[10]); 

lcd_wcom(0x86);  
lcd_wdat(table[miao/10]);
lcd_wcom(0x87);   
lcd_wdat(table[miao%10]); 
lcd_wcom(0x88);  
}

void Clock_display()
{
if(TIME_CLK==1000) //为1000*0.1故 100秒最大并清零
TIME_CLK=0;
if(start_clk_flag==1)
{
lcd_wcom(0x80);   
lcd_wdat(table2[0]);
lcd_wcom(0x81);   
lcd_wdat(table2[1]);
lcd_wcom(0x82);   
lcd_wdat(table2[2]);
}
else if(start_clk_flag==0)
{
lcd_wcom(0x80);   
lcd_wdat(table3[0]);
lcd_wcom(0x81);   
lcd_wdat(table3[1]);
lcd_wcom(0x82);   
lcd_wdat(table3[2]);
}
lcd_wcom(0x85);   
lcd_wdat(table[TIME_CLK/1000]); 
lcd_wcom(0x86);  
lcd_wdat(table[TIME_CLK/100%10]); 
lcd_wcom(0x87);  
lcd_wdat(table[TIME_CLK%100/10]); 
lcd_wcom(0x88);  
lcd_wdat(table[11]); 
 lcd_wcom(0x89);  
lcd_wdat(table[TIME_CLK%10]); 

}

void Calendar_display()
{
int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int b[12]={31,29,31,30,31,30,31,31,30,31,30,31};
if(nian%100==0)
{if(nian%4==0)
if(ri>b[yue])
{
ri=1;
yue+=1;
}
}
else if(nian%4==0)
{
if(ri>b[yue])
{
ri=1;
yue+=1;
}
}
else 
{
if(ri>a[yue])
{
ri=1;
yue+=1;
}
}
if(yue==13)
{
yue=1;
nian+=1;
}
lcd_wcom(0x80);   
lcd_wdat(table4[nian/1000]); 
lcd_wcom(0x81);  
lcd_wdat(table4[nian/100%10]); 
lcd_wcom(0x82);  
lcd_wdat(table4[nian%100/10]); 
lcd_wcom(0x83);  
lcd_wdat(table4[nian%10]); 
lcd_wcom(0x84);  
lcd_wdat(table4[10]); 

lcd_wcom(0x85);  
lcd_wdat(table4[yue/10]); 
lcd_wcom(0x86);  
lcd_wdat(table4[yue%10]); 
lcd_wcom(0x87);  
lcd_wdat(table4[10]); 

lcd_wcom(0x88);  
lcd_wdat(table4[ri/10]);
lcd_wcom(0x89);   
lcd_wdat(table4[ri%10]); 
lcd_wcom(0x8A); 
}

void keyscan()
{
P1=0xFE;                  //将第一行置零,以扫描K1-K4是否被按下
    if(LIE1==0)
{
while(LIE1==0);
 TIME_FLAG=1;     //时间显示打开,关闭秒表和日历
 shi=fen=miao=0;
 CLK_FLAG=Calendar_FLAG=0;
lcd_clr();   //先清屏
}                            
    else if(LIE2==0) {while(LIE2==0);shi++;} 
    else if(LIE3==0) {while(LIE3==0);fen++;}                           
    else if(LIE4==0) {while(LIE4==0);miao++;}                             

    P1=0xFD;                  //将第二行置零,以扫描K5-K8是否被按下
    if(LIE1==0) 
{
while(LIE1==0);
lcd_clr();   //先清屏
 TIME_CLK=0;
 CLK_FLAG=1;     //秒表打开,关闭时间和日历
 TIME_FLAG=Calendar_FLAG=0;
}
    else if(LIE2==0) {while(LIE2==0); start_clk_flag=1; }//开启计数  
    else if(LIE3==0) {while(LIE3==0); start_clk_flag=0;} //暂停计数
    else if(LIE4==0) 
{
 while(LIE4==0);
     lcd_clr();   //先清屏
 CLK_FLAG=TIME_FLAG=0;     //秒表关闭
 Calendar_FLAG=1;  //默认打开日历
 nian=2021;
 yue=11;
 ri=5;
}

    P1=0xFB;                  //将第三行置零,以扫描K9-K12是否被按下
    if(LIE1==0)
{
     lcd_clr();   //先清屏
 while(LIE1==0);
 CLK_FLAG=TIME_FLAG=0;     //关闭其他
 Calendar_FLAG=1;  //打开日历
 nian=2019;
 yue=11;
 ri=5;
}
    else if(LIE2==0) {while(LIE2==0);nian++; }//如果K10键按下,KEYbuf赋值写9
    else if(LIE3==0) {while(LIE3==0);yue++;}//如果K11键按下,KEYbuf赋值写10
    else if(LIE4==0) {while(LIE4==0);ri++;}//如果K12键按下,KEYbuf赋值写11

//        P1=0xF7;                  //将第四行置零,以扫描K13-K16是否被按下
//        if(LIE1==0) KEYbuf=12;    //如果K13键按下,KEYbuf赋值写12
//        else if(LIE2==0) KEYbuf=13;//如果K14键按下,KEYbuf赋值写13
//        else if(LIE3==0) KEYbuf=14;//如果K15键按下,KEYbuf赋值写14
//        else if(LIE4==0) KEYbuf=15;//如果K16键按下,KEYbuf赋值写15
}

uchar beep_on()
{
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(1000);
BEEP=1;
delay_ms(1000);
beep_flag=0;
return 1;
}
void time_init()
{
    TMOD  |=0x01;
IT0=1;     //INT0负跳变沿触发
EX0=1;     //外部中断0使能
    TH0=(65536-49000)/256;
    TL0=(65536-49000)%256; //50000us,50ms一次中断
    TR0=1;
    ET0=1;
    EA=1;
}

void api()
{
uchar i=0;
if(TIME_FLAG==1)
{
  TIME_display();
  if(beep_flag==1)
 beep_on();
  BEEP=1;
}
else if(CLK_FLAG==1)
{
  Clock_display();
}
else if(Calendar_FLAG==1) 
{
  Calendar_display();
}
}
void main(void)            //主函数,单片机开机后就是从这个函数开始运行
{

lcd_init(); //液晶初始化
 time_init(); //定时器与中断配置
while(1)
{
api();
}
}

void T0_ISR(void) interrupt 1
{
uchar i=0;
TH0=(65536-49000)/256;
TL0=(65536-49000)%256;
keyscan();
if(TIME_FLAG==1)
{
 count++;
 if(count==18)
  {
   count=0;
   miao++;
 }
}
else if((CLK_FLAG==1)&&(start_clk_flag==1))
{
 clk++;
 if(clk==2)
  {
   clk=0;
 TIME_CLK++;
 }
}

}

void INT0_ISR(void) interrupt 0
{
EX0=0;
delay_ms(1);
if(0==P3_2)
{
  beep_flag=0;   //外部中断高优先级控制蜂鸣器标志位
  BEEP=1;    //关闭蜂鸣器
}
IE0=0;
EX0=1;
}

二、思路三

通过数码管显示、矩阵键盘扫描按键功能。

1、原理图

2、代码

相对思路二而言,仅修改了显示的方式,其他都没有改变。

#include <AT89X52.h>       //调用51单片机的头文件
#define uint unsigned int
#define uchar unsigned char

//---------------------------------------

//4×4矩阵式按键相关I/O设置
//分别为4行和4列的选择线。
sbit HAGN1=P1^0;           //第1行接在P1.0口上
sbit HANG2=P1^1;           //第2行接在P1.1口上
sbit HANB3=P1^2;           //第3行接在P1.2口上
sbit HANG4=P1^3;           //第4行接在P1.3口上
sbit LIE1=P1^4;            //第1列接在P1.4口上
sbit LIE2=P1^5;            //第2列接在P1.5口上
sbit LIE3=P1^6;            //第3列接在P1.6口上
sbit LIE4=P1^7;            //第4列接在P1.7口上
//---------------------------------------

//基本计时功能,具有时分秒
uint shi=0,fen=0,miao=0;
uint TIME_FLAG=1;   //时间显示标志位,上电默认显示时间
uint count=0; //定时器值
//---------------------------------------

//秒表功能,最大显示99.9秒

uint TIME_CLK=0;//秒表显示值
uint CLK_FLAG=0;   //秒表显示标志位,上电不显示
uint start_clk_flag=1;   //秒表开始与暂停标志位  默认不暂停
uint clk=0;//定时器值
//---------------------------------------

//基本日历显示功能,自动计算闰年及各月对应的日期

uint nian=2019,yue=11,ri=5;
uint Calendar_FLAG=0;   //日历显示标志位,上电不显示
//---------------------------------------

//基本闹钟功能与蜂鸣器I/O设置
sbit BEEP=P3^7; 
uint beep_flag=0;   //闹钟标志位,置1后会五短一长
//---------------------------------------

//---------------------------------------
//8位数码管相关I/O设置
//P2.0-P2.2为3-8译码器U16的3个输入,P2=0x00 0x01 0x02 0x03最大为 0x07
//可以不用定义三个位,直接写P2=0X即可    
//数码管字形表,供显示时查询
unsigned char code LED1[12]=
{                          //定义表格一定要使用code,这样会做到程序存储区中
    0x3F,                  //"0"的字形表,0B00111111
    0x06,                  //"1"的字形表,0B00000110
    0x5B,                  //"2"的字形表,0B01011011
    0x4F,                  //"3"的字形表,0B01001111
    0x66,                  //"4"的字形表,0B01100110
    0x6D,                  //"5"的字形表,0B01101101
    0x7D,                  //"6"的字形表,0B01111101
    0x07,                  //"7"的字形表,0B00000111
    0x7F,                  //"8"的字形表,0B01111111
    0x6F,                  //"9"的字形表,0B01101111
0x40,   //"-"的字形表,0B01000000
0x80,   //"-"的字形表,0B01000000
};  
unsigned char code LED2[12]=
{                          //定义表格一定要使用code,这样会做到程序存储区中
    0xBF,                  //"0"的字形表,0B10111111
    0x86,                  //"1"的字形表,0B10000110
    0xDB,                  //"2"的字形表,0B11011011
    0xCF,                  //"3"的字形表,0B11001111
    0xE6,                  //"4"的字形表,0B11100110
    0xED,                  //"5"的字形表,0B11101101
    0xFD,                  //"6"的字形表,0B11111101
    0x87,                  //"7"的字形表,0B10000111
    0xFF,                  //"8"的字形表,0B11111111
    0xEF,                  //"9"的字形表,0B11101111
0xC0,   //"-"的字形表,0B11000000
}; 
  
//---------------------------------------
void delay_ms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}

//x为段选数据,y为位选0x00 0x01 0x02 0x03最大为 0x07
void tube_display(uint x,uint y,uint z)
{
 P2=y;
if(z==1)
P0=LED1[x];
else if(z==2)
P0=LED2[x];
}

//x为段选数据,y为位选0x00 0x01 0x02 0x03最大为 0x07
void TIME_display()
{
if(miao==60)
  {
miao=0;
fen++;
  }
  if(fen==60)
  {
  fen=0;
shi++;
  }
  if(shi==24)
 {
shi=0;
 } 
 if(shi!=0)
 if(fen==0)
 if(miao==0)
beep_flag=1; 
tube_display(shi/10,0,1); 
delay_ms(5);
tube_display(shi%10,1,1); 
delay_ms(5);
tube_display(10,2,1); 
delay_ms(5);

tube_display(fen/10,3,1); 
delay_ms(5);
tube_display(fen%10,4,1); 
delay_ms(5);
tube_display(10,5,1); 
delay_ms(5);

tube_display(miao/10,6,1); 
delay_ms(5);
tube_display(miao%10,7,1); 
delay_ms(5);

}
uchar beep_on()
{
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(50);
BEEP=1;
delay_ms(50);
if(beep_flag==0)
return 1;
BEEP=0;
delay_ms(1000);
BEEP=1;
delay_ms(1000);
beep_flag=0;
return 1;
}
void Clock_display()
{
if(TIME_CLK==1000) //为1000*0.1故 100秒最大并清零
TIME_CLK=0;

tube_display(TIME_CLK/1000,0,1); 
delay_ms(5);
tube_display(TIME_CLK/100%10,1,1); 
delay_ms(5);
tube_display(TIME_CLK%100/10,2,2); 
delay_ms(5);
tube_display(TIME_CLK%10,3,1); 
delay_ms(5);
}
void Calendar_display()
{
int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int b[12]={31,29,31,30,31,30,31,31,30,31,30,31};
if(nian%100==0)
{if(nian%4==0)
if(ri>b[yue])
{
ri=1;
yue+=1;
}
}
else if(nian%4==0)
{
if(ri>b[yue])
{
ri=1;
yue+=1;
}
}
else 
{
if(ri>a[yue])
{
ri=1;
yue+=1;
}
}
if(yue==13)
{
yue=1;
nian+=1;
}
tube_display(nian/1000,0,1); 
delay_ms(5);
tube_display(nian/100%10,1,1); 
delay_ms(5);
tube_display(nian%100/10,2,1); 
delay_ms(5);
tube_display(nian%10,3,2); 
delay_ms(5);

tube_display(yue/10,4,1); 
delay_ms(5);
tube_display(yue%10,5,2); 
delay_ms(5);

tube_display(ri/10,6,1); 
delay_ms(5);
tube_display(ri%10,7,1); 
delay_ms(5);  
}

void keyscan()
{
P1=0xFE;                  //将第一行置零,以扫描K1-K4是否被按下
    if(LIE1==0)
{
while(LIE1==0);
 TIME_FLAG=1;     //时间显示打开,关闭秒表和日历
 shi=fen=miao=0;
 CLK_FLAG=Calendar_FLAG=0;
}                            
    else if(LIE2==0) {while(LIE2==0);shi++;} 
    else if(LIE3==0) {while(LIE3==0);fen++;}                           
    else if(LIE4==0) {while(LIE4==0);miao++;}                             

    P1=0xFD;                  //将第二行置零,以扫描K5-K8是否被按下
    if(LIE1==0) 
{
while(LIE1==0);
 TIME_CLK=0;
 CLK_FLAG=1;     //秒表打开,关闭时间和日历
 TIME_FLAG=Calendar_FLAG=0;
}
    else if(LIE2==0) {while(LIE2==0); start_clk_flag=1; }//开启计数  
    else if(LIE3==0) {while(LIE3==0); start_clk_flag=0;} //暂停计数
    else if(LIE4==0) 
{
 while(LIE4==0);
 CLK_FLAG=TIME_FLAG=0;     //秒表关闭
 Calendar_FLAG=1;  //默认打开日历
 nian=2021;
 yue=11;
 ri=5;
}

    P1=0xFB;                  //将第三行置零,以扫描K9-K12是否被按下
    if(LIE1==0)
{
 while(LIE1==0);
 CLK_FLAG=TIME_FLAG=0;     //关闭其他
 Calendar_FLAG=1;  //打开日历
 nian=2019;
 yue=11;
 ri=5;
}
    else if(LIE2==0) {while(LIE2==0);nian++; }//如果K10键按下,KEYbuf赋值写9
    else if(LIE3==0) {while(LIE3==0);yue++;}//如果K11键按下,KEYbuf赋值写10
    else if(LIE4==0) {while(LIE4==0);ri++;}//如果K12键按下,KEYbuf赋值写11
}

void api()
{
if(TIME_FLAG==1)
{
  TIME_display();

  BEEP=1;
}
else if(CLK_FLAG==1)
{
  Clock_display();
}
else if(Calendar_FLAG==1) 
{
  Calendar_display();
}
}
void time_init()
{
    TMOD  |=0x01;
IT0=1;     //INT0负跳变沿触发
EX0=1;     //外部中断0使能
    TH0=(65536-49000)/256;
    TL0=(65536-49000)%256; //50000us,50ms一次中断
    TR0=1;
    ET0=1;
    EA=1;
}
void main(void)            //主函数,单片机开机后就是从这个函数开始运行
{
 time_init(); //定时器与中断配置
    while(1)               //死循环,单片机初始化后,将一直运行这个死循环
    {
        keyscan();
if(beep_flag==1)
 {
 beep_on();
     BEEP=1;    //关闭蜂鸣器
 }
    }
}

void T0_ISR(void) interrupt 1
{
uchar i=0;
TH0=(65536-49000)/256;
TL0=(65536-49000)%256;
if(TIME_FLAG==1)
{
 count++;
 if(count==20)
  {
   count=0;
   miao++;
 }
}
else if((CLK_FLAG==1)&&(start_clk_flag==1))
{
 clk++;
 if(clk==2)
  {
   clk=0;
 TIME_CLK++;
 }
}
api();
}

void INT0_ISR(void) interrupt 0
{
EX0=0;
delay_ms(1);
if(0==P3_2)
{
  beep_flag=0;   //外部中断高优先级控制蜂鸣器标志位
  BEEP=1;    //关闭蜂鸣器
}
IE0=0;
EX0=1;
}


原文地址:https://blog.csdn.net/qq_39376872/article/details/143827971

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!