C51单片机实现多功能电子时钟设计

4星 · 超过85%的资源 需积分: 33 74 下载量 174 浏览量 更新于2024-08-01 8 收藏 1.49MB DOC 举报
"这篇文档是关于基于C51单片机的多功能电子时钟的设计报告,作者通过这个项目学习了8051定时器的使用、按键扫描和LED数码管显示技术。报告详细阐述了实验目标、要求、基本原理以及设计分析。" 在这个基于C51单片机的多功能电子时钟设计中,学生需要掌握以下几个核心知识点: 1. C51单片机:C51是专门针对8051微控制器的C语言编译器,它允许程序员用高级语言编写单片机程序。AT89S51是8051系列的一个变种,具有4KB的闪存和兼容MCS-51指令集。它的低功耗和高性能特性使得它在电子时钟这样的应用中非常适用。 2. 定时器:8051单片机的定时器/计数器是实现电子时钟关键部分。定时器0被配置为中断模式,每隔0.01秒中断一次,每次中断时计数器减1,当计数器减到0时,表示1秒已过,秒变量递增。这种方法可以精确地计时。 3. LED数码管显示:动态显示法用于节省硬件资源,通过快速扫描每位数码管并发送相应字码来实现显示。尽管每位数码管只在短时间内点亮,但因人眼的视觉暂留效应,整个数码管看起来始终是亮的,显示时间和日期。 4. 按键扫描:通过单片机的I/O端口读取按键状态,实现对时间、闹钟设置以及功能切换的操作。例如,按键可以用来调整时间、启动闹钟、开启秒表或设置定时器。 5. 功能实现:电子时钟的基础功能包括显示“时时分分”格式的时间,LED秒闪,按键设置时间及闹钟,闹钟到时蜂鸣器提醒。扩展功能则包括日历(考虑平闰年和月份天数),音乐闹钟,定时器,倒计时和闹铃重响。 6. 日历功能:日历功能需要处理年、月、日、星期的显示,并能正确识别平年和闰年。设计时需考虑不同月份的天数,如2月的28天或29天。 7. 扩展功能实现:音乐闹钟允许用户选择不同的铃声,定时功能设定一段时间后会有提示,倒计时功能在时间到零时闪烁提示,而闹铃重响则在停止后按照可调的间隔再次响起。 8. 程序设计:使用分块设计方法,将程序分为多个模块,如时间处理模块、按键处理模块、显示模块等,便于代码管理和调试。 通过这个项目,学生不仅掌握了8051单片机的基本操作,还学会了如何结合硬件和软件设计一个实际的电子设备,这对深化理解和应用嵌入式系统原理至关重要。
1615 浏览量
准确延时,数码管显示!用于电子时钟 #include <reg51.h> //*** 函数定义 *** void long_delay(void); // 长延时 void short_delay(void); // 短延时 void delay10ms(unsigned char); // 延时10MS void write7279(unsigned char, unsigned char);// 写入到HD7279 unsigned char read7279(unsigned char);//从HD7279读入 void send_byte(unsigned char); // 发送一个字节 unsigned char receive_byte(void); //接收一个字节 void init_timer(); /*定时器T0初始化*/ void conv(); /*时、分、秒单元及走时单元转换*/ void dirve(); /*时间显示程序*/ void time_adj(); /*时间调整设置*/ unsigned char digit[6]; unsigned char j; unsigned int tmr; unsigned long wait_cnter; unsigned char hour=0,min=0,sec=0; /*时、分、秒单元清零*/ unsigned char deda=0; /*5mS计数单元清零*/ bit sign; //设置标志位 sbit cs=P1^5; // cs at P1.5 sbit clk=P1^4; // clk 连接于 P1.4 sbit dat=P1^3; // dat 连接于 P1.3 sbit set=P3^7; // key 连接于 P3.7 //****** HD7279A 指令 ****** #define CMD_RESET 0xa4 #define CMD_TEST 0xbf #define DECODE0 0x80 #define DECODE1 0xc8 #define CMD_READ 0x15 #define UNDECODE 0x90 #define RTL_CYCLE 0xa3 #define RTR_CYCLE 0xa2 #define RTL_UNCYL 0xa1 #define RTR_UNCYL 0xa0 #define ACTCTL 0x98 #define SEGON 0xe0 #define SEGOFF 0xc0 #define BLINKCTL 0x88 //*** 主函数 *** main() { for (tmr=0;tmr<0x2000;tmr++); // 上电延时 send_byte(CMD_RESET); // 复位HD7279A //****************************************** // 测试指令演示 //****************************************** send_byte(CMD_TEST); // 指令测试 for (j=0;j<3;j++) // 延时哟3秒? { delay10ms(100); } send_byte(CMD_RESET); // 清除显示 //********************************************** //时间显示 //********************************************** init_timer();/*定时器T0初始化*/ while(1) { if(set==0) time_adj(); conv(); /*时、分、秒单元及走时单元转换*/ dirve(); /*时、分、秒单元显示*/ } } /*定时器T0 5mS初始化*/ void init_timer() { TMOD=0x01; TH0=-(4800/256); TL0=-(4800%256); IE=0x82; TR0=1; } /*5mS定时中断服务子函数*/ void zd(void) interrupt 1 { TH0=-(4800/256); TL0=-(4800%256); deda++; } /*时、分、秒单元及走时单元转换*/ void conv() { if(deda>=200){sec++;deda=0;} if(sec==60){min++;sec=0;} if(min==60){hour++;min=0;} if(hour==24){hour=0;} } void dirve() { digit[0]=sec%10; //计数个位 write7279(DECODE0,digit[0]); //显示个位 digit[1]=0x80|(sec/10); //计数十位 write7279(DECODE0+1,digit[1]); //显示十位 digit[2]=0x80|(min%10); //计数百位 write7279(DECODE0+2,digit[2]); //显示百位 digit[3]=0x80|(min/10); //计数千位 write7279(DECODE0+3,digit[3]); //显示千位 digit[4]=0x80|(hour%10); //计数万位 write7279(DECODE0+4,digit[4]); //显示万位 digit[5]=hour/10; //计数十万位 write7279(DECODE0+5,digit[5]); } void write7279(unsigned char cmd, unsigned char dta) { send_byte (cmd); send_byte (dta); } unsigned char read7279(unsigned char command) { send_byte(command); return(receive_byte()); } void send_byte( unsigned char out_byte) { unsigned char i; cs=0; long_delay(); for (i=0;i<8;i++) { if (out_byte&0x80) { dat=1; } else { dat=0; } clk=1; short_delay(); clk=0; short_delay(); out_byte=out_byte*2; } dat=0; } unsigned char receive_byte(void) { unsigned char i, in_byte; dat=1; // 设置为输入状态 long_delay(); for (i=0;i<8;i++) { clk=1; short_delay(); in_byte=in_byte*2; if (dat) { in_byte=in_byte|0x01; } clk=0; short_delay(); } dat=0; return (in_byte); } void long_delay(void) { unsigned char i; for (i=0;i<0x30;i++); } void short_delay(void) { unsigned char i; for (i=0;i<8;i++); } // ********************* 延时 n*10ms ********************** void delay10ms(unsigned char time) { unsigned char i; unsigned int j; for (i=0;i<time;i++) { for(j=0;j<0x390;j++) { } } } /*时间调整程序*/ void time_adj() { if(set==0) //有键按下,判断按键时间 { delay10ms(200); //1s延时程序 if(set==0) //大于1s,进入时间设置 { ET0=0; TR0=0; //关定时器0 while(set==0) dirve(); //等键释放 // ET1=1;TR1=1; con=0xF3; //开定时器1,让调整位闪烁 write7279(BLINKCTL,0xF3); do { while(set!=0) dirve(); //等待按键 delay10ms(100); if(set!=0) //小于0.5s,进入分钟设置 { while(set==0) dirve(); //等待按键释放 sign=1; min++; if(min==60)min=0; //分钟加1 dirve(); } else sign=0; //大于0.5s,进入小时设置 }while(sign); while(set==0)dirve(); //等待按键释放 // con=0xCF; write7279(BLINKCTL,0xCF); do { while(set!=0) dirve(); //等待按键 delay10ms(100); if(set!=0) //小于0.5s,进入小时设置 { while(set==0) dirve(); //等待按键释放 sign=1; hour++; //小时加1 if(hour==24)hour=0; dirve(); } else sign=0; //大于0.5s,结束时间设置 }while(sign); // ET1=0;TR1=0; //关定时器1 ET0=1;TR0=1; //开定时器0 write7279(BLINKCTL,0xFF); } else //小于1s,进入省电模式 { ET0=1; TR0=1; //开定时器0 while(set!=0); //等待按键 do { dirve(); //有键按下,调显示程序消抖 }while(set!=0); //是干扰则继续循环 } while(set==0) dirve(); //等待按键释放 } else ; //无键按下,跳出按键扫描程序 }