用51单片机做一个电子钟

发布者:知者如渊最新更新时间:2020-04-19 来源: eefocus关键字:51单片机  电子钟  数码管  动态显示 手机看文章 扫描二维码
随时随地手机看文章

学了一个多月51了,终于整了个电子钟出来,个人感觉还是比较有趣的。


需要注意的是我用的是普中的板子,板子类型不同,io口的功能可能会有所差异。然后我这个k1开关和k2开关是接反了的,原本k1应该是接P3^0,k2接P3^1的,结果我一测试才知道k1接到了P3^1,k2接到P3^0了,不过这不要紧,用sbit定义位变量时注意换一下就可以了。然后大概讲讲功能,用8个数码管显示目前时间和闹铃时间,然后用4个独立按键对目前时间和闹铃时间进行调整(k2是加,k3是减 ,k4是用来停止闹铃的),第一次按k1是对目前时间秒数调整,第2次按k1是对目前时间分钟数调整,第三次按k1是对目前时间小时数调整,第4次按k1是对闹铃秒数调整,第5次按k1是对闹铃时间分钟数调整,第6次按k1是对闹铃秒数调整,第7次按k1是调整完毕,进去非调整状态即实时显示目前时间(不过有点差异,时间走的快了一点)。主要用到了数码管动态显示,独立按键,定时器中断这些。


代码如下:

#include

typedef unsigned int u16;

typedef unsigned char u8;

sbit led=P2^0;

sbit lsa=P2^2;

sbit lsb=P2^3;

sbit lsc=P2^4;

sbit beep=P1^5;

sbit k1=P3^1;

sbit k2=P3^0;

sbit k3=P3^2;

sbit k4=P3^3;

sbit dian=P0^7;

 

u8 keyvalue,alarmexist=0;

u8 smgduan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x00};//段选码,分别对应0到无

u16 cnt=0,i=0,j=0,flag=0,time[]={0,0,0,0,0,0,0,0};//只用数码管0,1 3,4 6,7

u16 alarm[]={0,0,0,0,0,0,1,0};

u16*p;

 

 

void delay(u16 mmp);

void t0andt1init();

void addproct(int x);     

void addproca(int x);

void reduceproct(int x);

void reduceproca(int x);

void keyscan();

void jia();

void jian();

 

void main()

{

  led=0;

    t0andt1init();

P0=0x00;

while(1)

{   

    

if(time[0]==alarm[0]&&time[1]==alarm[1]&&time[3]==alarm[3]&&time[4]==alarm[4]&&time[6]==alarm[6]&&time[7]==alarm[7])//满足条件 蜂鸣器以一定的时间间隔响,只到K4按键并松开,此时数码管任然正常显示当前时间

{   

alarmexist=0;

while(k4)

{

beep=~beep;

delay(25);

beep=~beep;

delay(25);

}

}

keyscan();

}

}

void delay(u16 mmp)

{

while(mmp--);

}

void t0andt1init()

{

TMOD=0x11;

TH0=0xfc;

TL0=0x67;//赋定时器初始值,定时1ms

TH1=0xfc;

TL1=0x67;

TR0=1;//T0定时器开始定时

EA=1;

ET0=1;

ET1=1;

}

void addproct(int x)   //对非调整状态和调整状态的加1处理(仅用于对当前时间)

{

if(x==0||x==3||x==6)

if(time[x]==10)

{

time[x]=0;

time[x+1]=time[x+1]+1;

addproct(x+1);

}

   

    if(x==1||x==4)

    if(time[x]==6)

{

time[x]=0;

time[x+2]=time[x+2]+1;

addproct(x+2);

}

if(time[6]==4&&time[7]==2)

time[6]=time[7]=0;

}

void addproca(int x)   //对调整状态的加1处理(仅用于对闹钟时间)

{

if(x==0||x==3||x==6)

if(alarm[x]==10)

{

alarm[x]=0;

alarm[x+1]=alarm[x+1]+1;

addproca(x+1);

}

   

    if(x==1||x==4)

    if(alarm[x]==6)

{

alarm[x]=0;

alarm[x+2]=alarm[x+2]+1;

addproca(x+2);

}

if(alarm[6]==4&&alarm[7]==2)

alarm[6]=alarm[7]=0;

}

void reduceproct(int x) // 对调整状态的减1处理(仅用于对当前时间)

{

if(time[0]==0&&time[1]==0&&time[3]==0&&time[4]==0&&time[6]==0&&time[7]==0)

{

time[0]=time[3]=9;

time[1]=time[4]=5;

time[6]=3;

time[7]=2;

return ;

}

if(x==0||x==3||x==6)

{

if(time[x]>=1)

time[x]=time[x]-1;

else

{   

if(time[7]==0&&x==6)

{

time[6]=3;

time[7]=2;

}

else

{

time[x]=9;

reduceproct(x+1);

}

}

}

else

{

if(time[x]>=1)

time[x]=time[x]-1;

else

{

time[x]=5;

if(x!=7)

reduceproct(x+2);

else

time[x]=1;

}

}

}

void reduceproca(int x) // 对调整状态的减1处理(仅用于对闹钟时间)

{

if(alarm[0]==0&&alarm[1]==0&&alarm[3]==0&&alarm[4]==0&&alarm[6]==0&&alarm[7]==0)

{

alarm[0]=alarm[3]=9;

alarm[1]=alarm[4]=5;

alarm[6]=3;

alarm[7]=2;

return ;

}

if(x==0||x==3||x==6)

{

if(alarm[x]>=1)

alarm[x]=alarm[x]-1;

else

{   

if(alarm[7]==0&&x==6)

{

alarm[6]=3;

alarm[7]=2;

}

else

{

alarm[x]=9;

reduceproca(x+1);

}

}

}

else

{

if(alarm[x]>=1)

alarm[x]=alarm[x]-1;

else

{

alarm[x]=5;

if(x!=7)

reduceproca(x+2);

else

alarm[x]=1;

}

}

}

void keyscan()

{   

flag=0;

keyvalue=0;

    if(k1==0)

{   

    TR0=0;//不在显示当前时间

TR1=1;

    delay(1000);

if(k1==0)

{   

while(!k1) ;

delay(1000);

led=~led;

    keyvalue++;

}

else

return ;

while(keyvalue!=7)

{

if(k1==0)

{   

    delay(1000);

if(k1==0)

{

while(!k1) ;

led=~led;

            keyvalue++;

if(keyvalue==4)

flag=1;

}

if(k2==0)

{

delay(1000);

if(k2==0)

{

while(!k2) ;

led=~led;

jia();

}

}

if(k3==0)

{

delay(1000);

if(k3==0)

{

while(!k3) ;

    led=~led;

jian();

}

}

}

TR0=1;

TR1=0;

if(((alarm[6]+alarm[7]*10)*60+alarm[3]+alarm[4]*10)>((time[6]+time[7]*10)*60+time[3]+time[4]*10))//判断闹钟时间是否大于当前时间,

alarmexist=1;

else

alarmexist=0;

}

}

void jia()

{

switch(keyvalue)

{

case 1:time[0]=time[0]+1;addproct(0);break;

case 2:time[3]=time[3]+1;addproct(3);break;

case 3:time[6]=time[6]+1;addproct(6);break;

case 4:alarm[0]=alarm[0]+1;addproca(0);break;

case 5:alarm[3]=alarm[3]+1;addproca(3);break;

case 6:alarm[6]=alarm[6]+1;addproca(6);break;

 

}

}

void jian()

{

switch(keyvalue)

{

case 1:reduceproct(0);break;

case 2:reduceproct(3);break;

case 3:reduceproct(6);break;

case 4:reduceproca(0);break;

case 5:reduceproca(3);break;

case 6:reduceproca(6);break;

 

}

}

void Timer0() interrupt 1//非调整时,执行的中断服务程序

{

TH0=0xfc;

TL0=0x67;//赋定时器初始值,定时1ms

cnt++;

if(1000==cnt)

{   

cnt=0;

time[0]=time[0]+1;

addproct(0);

}

P0=0X00;

switch(i)

{

    case 0:lsa=0;lsb=0;lsc=0;P0=smgduan[time[0]];dian=(alarmexist==1)?1:0;i++;break;

case 1:lsa=1;lsb=0;lsc=0;P0=smgduan[time[1]];i++;i++;break;

case 3:lsa=1;lsb=1;lsc=0;P0=smgduan[time[3]];i++;break;

case 4:lsa=0;lsb=0;lsc=1;P0=smgduan[time[4]];i++;i++;break;

case 6:lsa=0;lsb=1;lsc=1;P0=smgduan[time[6]];i++;break;

case 7:lsa=1;lsb=1;lsc=1;P0=smgduan[time[7]];i=0;break;

}

}

void Timer1() interrupt 3 //调整时,执行的中断服务程序  ,flag=0显示正在调整的time,为1显示正在调整的alarm

{

    

TH1=0xfc;

TL1=0x67;//赋定时器初始值,定时1ms

    if(flag==0)

p=time;

else

p=alarm;

P0=0X00;

switch(j)

{

    case 0:lsa=0;lsb=0;lsc=0;P0=smgduan[p[0]];j++;break;

case 1:lsa=1;lsb=0;lsc=0;P0=smgduan[p[1]];j++;j++;break;

case 3:lsa=1;lsb=1;lsc=0;P0=smgduan[p[3]];j++;break;

case 4:lsa=0;lsb=0;lsc=1;P0=smgduan[p[4]];j++;j++;break;

case 6:lsa=0;lsb=1;lsc=1;P0=smgduan[p[6]];j++;break;

case 7:lsa=1;lsb=1;lsc=1;P0=smgduan[p[7]];j=0;break;

}

}

关键字:51单片机  电子钟  数码管  动态显示 引用地址:用51单片机做一个电子钟

上一篇:单片机之时钟工作原理
下一篇:51单片机外围模块——A/D模数转换

推荐阅读最新更新时间:2024-11-11 12:24

51单片机——定时器
1、定时器和计数器 时钟周期:单片机时序中的最小单位,集体计算的放法就是时钟源分之一 机器周期:单片机完成一个操作的最短时间,=12个时钟周期 定时器:打开定时器后,定时器“存储寄存器”的值经过一个机器周期自动加1,也就是说,机器周期是定时器的计数周期。 2、定时器的寄存器 TMOD —— 工作模式选择寄存器——常用模式1和模式2. TCON —— 控制寄存器(TRn定时器开关) TH/TL —— 定时计数器 3、定时器应用 第一步:设置特殊功能寄存器 TMOD,配置好工作模式。 第二步:设置计数寄存器TH0和TL0的初值。 第三步:设置TCON,通过TR0置 1来让定时器开始计数。 第四步:判断TCON 寄存
[单片机]
<font color='red'>51单片机</font>——定时器
51单片机实现按住一个独立按键不松手的连续步进触发
一、使用proteus绘制简单的电路图,用于后续仿真 二、编写程序 /******************************************************************************************************************** ---- @Project: Independent-KEY ---- @File: main.c ---- @Edit: ZHQ ---- @Version: V1.0 ---- @CreationTime: 20200507 ---- @ModifiedTime: 2020
[单片机]
<font color='red'>51单片机</font>实现按住一个独立按键不松手的连续步进触发
51单片机——数码管动态显示
1、静态与动态不同的显示 在静态显示时所有数码管显示的是一样的,动态显示时可以单独决定每个数码管显示什么; 静态显示时,数码管是常亮的。动态显示时每时刻只有一个数码管在亮; 2、按原理图找对应控制端口 数码管的显示由P0口控制 可以用P1口选择哪个数码管亮 3、程序部分 程序如下: #include reg52.h sbit ADDR0=P1^0; sbit ADDR1=P1^1; sbit ADDR2=P1^2; sbit ADDR3=P1^3; sbit ENLED=P1^4; void delay(unsigned char x); unsigned char code
[单片机]
<font color='red'>51单片机</font>——<font color='red'>数码管</font><font color='red'>动态显示</font>
51单片机简单计时器
#include reg52.h #define uint8 unsigned char #define uint16 unsigned short int //数码管段码显示:0~f,不亮 uint8 code LED_Disp = {0xC0,0xF9,0xA4,0xB0, //这一组编码当中不包含小数点 0x99,0x92,0x82,0xF8, 0x80,0x90}; //十个分别显示 0 1 2 3 4 5 6 7 8 9 uint8 code LED_Disp1 = {0x40,0x79,0x24,0x30, //这一个数组的编码中包含小数点 0x19,
[单片机]
51单片机定时器中断_51单片机中断系统_51单片机扩展中断的四种方法
  中断是为使单片机具有对外部或内部随机发生的事件进行处理而设置的。51单片机有5种中断源,即有5种对应的情况发生时会使单片机去处理中断程序(中断函数)。   此篇主要整理定时器中断笔记。采用定时器中断会涉及中断寄存器,定时器/计数器相关寄存器(TCON,TMOD),中断函数等知识点。   其中,中断寄存器,定时器/计数器相关寄存器本身或者相关位用来做初始化,中断函数的内容主要是体现发生中断后所需要的操作(在中断函数内写代码)。   1.中断允许寄存器IE      图1.中断寄存器IE   中断寄存器用来设定各个中断源的打开和关闭,IE在特殊功能寄存器中,字节地址为A8H,位地址(由低位到高位)分别是A8H~AFH
[单片机]
<font color='red'>51单片机</font>定时器中断_<font color='red'>51单片机</font>中断系统_<font color='red'>51单片机</font>扩展中断的四种方法
基于51单片机控制的以太网通讯实现
  摘要:介绍以太网的帧协议和以太网控制芯片RTL8019AS的结构特性;介绍51单片机控制RTL8019AS实现以太网通讯的硬件设计方案;采用C51语言实现ARP协议(地址解析协议),并进行了系统的调试与验证。   互联网络硬件、软件的迅猛发展,使得网络用户呈指数增长,在使用计算机进行网络互联的同时,各种家电设备、仪器仪表以及工业生产中的数据采集与控制设备在逐步地走向网络化,以便共享网络中庞大的信息资源。在电子设备日趋网络化的背景下,利用廉价的51单片机来控制RTL8019AS实现以太网通讯具有十分重要的意义。   1 以太网(Ethernet)协议   一个标准的以太网物理传输帧由七部分组成(如表1所示,单位:字节
[单片机]
基于<font color='red'>51单片机</font>控制的以太网通讯实现
51单片机—DAC0832(详细介绍)—06—①
DAC0832~相信大家都不陌生,想整理整理这个,三种方法吗~~所以这个也得两三篇吧~~慢慢来~~ 这一篇还是比较简单的介绍,不过也有注意的~~ 1、DAC0832的简介 1)DAC0832的引脚 当然第一就得是引脚,由于网上的这个东西比较多,那我就粘贴了~~ 2)DAC0832的内部结构(这个对于理解1还是很重要的~~ ,呵呵,这个应该放在1处) 这里一定注意了: 8位输入寄存器用于存放CPU送来的数字量,使得输入的数字量得到缓冲和锁存,由/LE1来控制。 8位DAC寄存器用于存放待转换的数字量,由/LE2控制 都是低电平有效啊~~ (当他们所对应的引脚都有效的时候,它们俩是高电平~~
[单片机]
<font color='red'>51单片机</font>—DAC0832(详细介绍)—06—①
89C51单片机定时/计数器0
89C51单片机的定时计数功能由特殊功能寄存器TMOD和TCON共同控制。 TMOD没有位地址,不能进行位操作,其每位的名称和功能如下: TMOD:GATE C/T1 M1 M0 GATE C/T1 M1 M0 D7 D6 D5 D4 D3 D2 D1 D0 GATE C/T1 M1 M0 控制定时计时器1; GATE C/T0 M1 M0 控制定时计时器0; GATE=0时,定时计数信号是T0脚状态(P3.4)或机器周期(C/T=0计机器周期,即定时,C/T=1,计T0脚的状态,即计数),计数开始开关是TR0(0关闭计数
[单片机]
89C<font color='red'>51单片机</font>定时/计数器0
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved