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

embedded/2024/11/24 10:07:23/

目录

一、思路二

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;//把命令字送入P0delay_ms(5);//延时一小会儿,让1602准备接收数据en=1;			//使能线电平变化,命令送入1602的8位数据口en=0;
}void lcd_wdat(unsigned char dat) //1602写数据函数
{rs=1;//选择数据寄存器rw=0;//选择写dataPort=dat;//把要显示的数据送入P2delay_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赋值写9else if(LIE3==0) {while(LIE3==0);yue++;}//如果K11键按下,KEYbuf赋值写10else 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"的字形表,0B001111110x06,                  //"1"的字形表,0B000001100x5B,                  //"2"的字形表,0B010110110x4F,                  //"3"的字形表,0B010011110x66,                  //"4"的字形表,0B011001100x6D,                  //"5"的字形表,0B011011010x7D,                  //"6"的字形表,0B011111010x07,                  //"7"的字形表,0B000001110x7F,                  //"8"的字形表,0B011111110x6F,                  //"9"的字形表,0B011011110x40,				   //"-"的字形表,0B010000000x80,				   //"-"的字形表,0B01000000
};  
unsigned char code LED2[12]=
{                          //定义表格一定要使用code,这样会做到程序存储区中0xBF,                  //"0"的字形表,0B101111110x86,                  //"1"的字形表,0B100001100xDB,                  //"2"的字形表,0B110110110xCF,                  //"3"的字形表,0B110011110xE6,                  //"4"的字形表,0B111001100xED,                  //"5"的字形表,0B111011010xFD,                  //"6"的字形表,0B111111010x87,                  //"7"的字形表,0B100001110xFF,                  //"8"的字形表,0B111111110xEF,                  //"9"的字形表,0B111011110xC0,				   //"-"的字形表,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赋值写9else if(LIE3==0) {while(LIE3==0);yue++;}//如果K11键按下,KEYbuf赋值写10else 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;
}


http://www.ppmy.cn/embedded/139337.html

相关文章

多传感器融合感知算法-后融合

1.传感器 需求分析 超声波 camera radar-多普勒效应 径向速度 车远离人&#xff0c;频率下降&#xff1b;车接近人&#xff0c;频率上升。速度变化会引起频率变化。 幅值不变&#xff0c;频率变化。 毫米波雷达为何那么多误检&#xff1f; 在频域中的阈值选取有关。取频域的峰…

AI Large Language Model

AI 的 Large Language model LLM , 大语言模型&#xff1a; 是AI的模型&#xff0c;专门设计用来处理自然语言相关任务。它们通过深度学习和庞大的训练数据集&#xff0c;在理解和生成自然语言文本方面表现出色。常见的 LLM 包括 OpenAI 的 GPT 系列、Google 的 PaLM 和 Meta…

uniapp vue3小程序报错Cannot read property ‘__route__‘ of undefined

在App.vue里有监听应用的生命周期 <script>// 只能在App.vue里监听应用的生命周期export default {onError: function(err) {console.log(AppOnError:, err); // 当 uni-app 报错时触发}} </script>在控制台打印里无意发现 Cannot read property ‘__route__‘ of …

Android开发实战班 - 网络编程 - WebSocket 实时通信

在现代应用开发中&#xff0c;实时通信是许多应用的核心功能之一&#xff0c;例如聊天应用、实时通知、在线游戏等。WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议&#xff0c;能够实现服务器与客户端之间的实时双向数据交换。相比于传统的 HTTP 请求&#xff0c;Web…

【iOS】iOS的轻量级数据库——FMDB

文章目录 前言FMDB一、特点二、关于SQLite什么是 SQLite&#xff1f; 三、FMDB库的导入四、FMDB库的使用1. 核心类2.使用步骤 总结 前言 在完成知乎日报仿写项目时&#xff0c;在文章详情页进行点赞和收藏&#xff0c;在个人账号页面的收藏里需要展现出来&#xff0c;这里使用到…

机器学习-02HMM模型学习

首先可以从视频有一个直观的理解&#xff0c;直接上公式会让人云里雾里&#xff0c;看完如下视频后&#xff0c;对于隐马尔可夫模型有直观理解&#xff0c;再理解机器学习的应用有个感觉 盒子模型来解释隐马尔可夫模型 - 简介 盒子模型来解释隐马尔可夫模型 - 前向算法 盒子模型…

引擎启动:Spring Boot汽车资讯新纪元

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理汽车资讯网站的相关信息成为必然。开发合适…

k8s 学习笔记之 k8s 存储管理

文章目录 概述卷卷的常用类型emptyDir边车容器 HostPathnfsPV/PVC静态供给 PV 和 PVC创建静态 PV创建 pvc创建 pod 应用 pvc 动态供给 PV 和 PVC创建 StorageClass创建 pvc创建 pod 使用 pvc PV 的生命周期 内置存储对象ConfigMapSecret 配置文件自动重新加载方案**1. 应用内动…