求教一个51单片机程序。。(LCD电子时钟)

求教一个51单片机程序。。(LCD电子时钟),第1张

#include<reg52h>

#define uint unsigned int

#define uchar unsigned char

uchar a,miao,shi,fen,ri,yue,nian,week,flag,key1n,temp;

#define yh 0x80

#define er 0x80+0x40//液晶屏的与 C51 之间的引脚连接定义

sbit rs=P2^5;

sbit en=P2^7;

sbit rw=P2^6;//如果硬件上 rw 接地,就不用写这句和后面的 rw=0

//DS1302 时钟芯片与 C51 之间的引脚连接定义

sbit IO=P3^6;

sbit SCLK=P3^5;

sbit RST=P3^7;

sbit ACC0=ACC^0;

sbit ACC7=ACC^7;//校时按键与 C51 的引脚连接定义

sbit key1=P3^2;//设置键

sbit key2=P3^3;//加键

sbit key3=P3^4;//减键

uchar code tab1[]={"20//////////"};//年显示的固定字符

uchar code tab2[]={"LOVE ::::::"};//时间显示的固定字符

//延时函数,后面经常调用

void delay(uint xms)//延时函数,有参函数

{

uint x,y;

for(x=xms;x>0;x--)

for(y=110;y>0;y--);

}

/液晶写入指令函数与写入数据函数,以后可调用/

write_1602com(uchar com) //液晶写入指令函数

{

rs=0; //数据/指令选择置为指令

rw=0; //读写选择 置为写

P0=com; //送入数据

delay(1);

en=1; //拉高使能端,为制造有效的下降沿做准备

delay(1);

en=0;

//en 由高变低,产生下降沿,液晶执行命令

}

write_1602dat(uchar dat) //液晶写入数据函数

{

rs=1; //数据/指令选择置为数据

rw=0; //读写选择置为写

P0=dat; //送入数据

delay(1);

en=1; //en 置高电平,为制造下降沿做准备

delay(1);

en=0; //en 由高变低,产生下降沿,液晶执行命令

}

lcd_init() //液晶初始化函数//

{

write_1602com(0x38); //设置液晶工作模式,意思:162 行显示,57 点阵,8 位数据

write_1602com(0x0c); //开显示不显示光标

write_1602com(0x06); //整屏不移动,光标自动右移

write_1602com(0x01); //清显示

write_1602com(yh+1); //日历显示固定符号从第一行第 1 个位置之后开始显示

for(a=0;a<14;a++)

{

write_1602dat(tab1[a]); //向液晶屏写日历显示的固定符号部分

}

write_1602com(er+1);//时间显示固定符号写入位置,从第 2 个位置后开始显示

for(a=0;a<12;a++)

{

write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号

}

}

/DS1302 有关子函数/

void write_byte(uchar dat)//写一个字节

{

ACC=dat;

RST=1;

for(a=8;a>0;a--)

{

IO=ACC0;//相当于汇编中的 RRC

SCLK=0;

SCLK=1;

ACC=ACC>>1;

}

}

uchar read_byte() //读一个字节

{

RST=1;

for(a=8;a>0;a--)

{

ACC7=IO;

SCLK=1;

SCLK=0;

ACC=ACC>>1;

}

return (ACC);

}

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

void write_1302(uchar add,uchar dat) //向 1302 芯片写函数,指定写入地址,数据

{

RST=0;

SCLK=0;

RST=1;

write_byte(add);

write_byte(dat);

SCLK=1;

RST=0;

}

uchar read_1302(uchar add) //从 1302 读数据函数,指定读取数据来源地址

{

uchar temp;

RST=0;

SCLK=0;

RST=1;

write_byte(add);

temp=read_byte();

SCLK=1;

RST=0;

return(temp);

}

uchar BCD_Decimal(uchar bcd)//BCD 码转十进制函数,输入 BCD,返回十进制

{

uchar Decimal;

Decimal=bcd>>4;

return(Decimal=Decimal10+(bcd&=0x0F));

}

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

void ds1302_init()//1302 芯片初始化子函数(2010-01-07,12:00:00,week4)

{

RST=0;

SCLK=0;

write_1302(0x8e,0x00);//允许写,禁止写保护

write_1302(0x8e,0x80);//打开写保护

}

//时分秒显示子函数

void write_sfm(uchar add,uchar dat)//向 LCD 写时分秒,有显示位置加、现示数据,两个参数

{

uchar gw,sw;

gw=dat%10;//取得个位数字

sw=dat/10;//取得十位数字

write_1602com(er+add);//er 是头文件规定的值 0x80+0x40

write_1602dat(0x30+sw);//数字+30 得到该数字的 LCD1602 显示码

write_1602dat(0x30+gw);//数字+30 得到该数字的 LCD1602 显示码

}

//年月日显示子函数

void write_nyr(uchar add,uchar dat)//向 LCD 写年月日,有显示位置加数、显示数据,两个参数

{

uchar gw,sw;

gw=dat%10;//取得个位数字

sw=dat/10;//取得十位数字

write_1602com(yh+add);//设定显示位置为第一个位置+add

write_1602dat(0x30+sw);//数字+30 得到该数字的 LCD1602 显示码

write_1602dat(0x30+gw);//数字+30 得到该数字的 LCD1602 显示码

}

void write_week(uchar week)//写星期函数

{

write_1602com(yh+0x0c);//星期字符的显示位置

switch(week)

{

case 1:write_1602dat('M');//星期数为一时,显示

write_1602dat('o');

write_1602dat('n');break;

case 2:write_1602dat('T');//星期数据为二时显示

write_1602dat('u');

write_1602dat('e');break;

case 3:write_1602dat('W');//星期数据为三时显示

write_1602dat('e');

write_1602dat('d');break;

case 4:write_1602dat('T');//星期数据为四是显示

write_1602dat('h');

write_1602dat('u');break;

case 5:write_1602dat('F');//星期数据为五时显示

write_1602dat('r');

write_1602dat('i');break;

case 6:write_1602dat('S');//星期数据为六时显示

write_1602dat('t');

write_1602dat('a');break;

case 7:write_1602dat('S');//星期数据为日时显示

write_1602dat('u');

write_1602dat('n');break;

}

}

//键盘扫描有关函数

void keyscan()

{

if(key1==0)//key1 为功能键(设置键)

{

delay(9);//延时,用于消抖动

if(key1==0)//延时后再次确认按键按下

{

delay(20);

while(!key1);

key1n++;

if(key1n==9)

key1n=1;//设置按键共有秒、分、时、星期、日、月、年、返回,8 个功能循环

switch(key1n)

{

case 1:TR0=0;//关闭定时器

write_1602com(er+0x0E);//设置按键按动一次,秒位置显示光标

write_1602com(0x0f);//设置光标为闪烁

temp=(miao)/1016+(miao)%10;//秒数据写入 DS1302

write_1302(0x8e,0x00);

write_1302(0x80,0x80|temp);//miao

write_1302(0x8e,0x80);break;

case 2:write_1602com(er+11);//按 2 次 fen 位置显示光标

break;

case 3:write_1602com(er+8);//按动 3 次,shi

break;

case 4:write_1602com(yh+0x0e);//按动 4 次,week

break;

case 5:write_1602com(yh+0);//按动 5 次,ri

break;

case 6:write_1602com(yh+0x07);//按动 6 次,yue

break;

case 7:write_1602com(yh+0x04);//按动 7 次,nian

break;

case 8:write_1602com(0x0c);//按动到第 8 次,设置光标不闪烁

TR0=1;//打开定时器

TR0=1;

temp=(miao)/1016+(miao)%10;

write_1302(0x8e,0x00);

write_1302(0x80,0x00|temp);//miao 数据写入 DS1302

write_1302(0x8e,0x80);break;

}

}

}

//------------------------------加键 key2----------------------------//

if(key1n!=0)//当 key1 按下以下。再按以下键才有效(按键次数不等于零)

{

if(key2==0)//上调键

{

delay(10);

if(key2==0)

{

delay(20);

while(!key2);

switch(key1n)

{

case 1:miao++;//设置键按动 1 次,调秒

if(miao==60)

miao=0;

write_sfm(0x0D,miao);

temp=(miao)/1016+(miao)%10;

write_1302(0x8e,0x00);

write_1302(0x80,temp);

write_1302(0x8e,0x80);

write_1602com(er+0x0E);

break;

case 2:fen++;

if(fen==60)

fen=0;

write_sfm(0x0A,fen);

temp=(fen)/1016+(fen)%10;

write_1302(0x8e,0x00);

write_1302(0x82,temp);

write_1302(0x8e,0x80);

write_1602com(er+11);

break;

case 3:shi++;

if(shi==24)

shi=0;

write_sfm(7,shi);

temp=(shi)/1016+(shi)%10;

write_1302(0x8e,0x00);

write_1302(0x84,temp);

write_1302(0x8e,0x80);

write_1602com(er+8);

break;

case 4:week++;

if(week==8)

week=1;

write_1602com(yh+0x0C) ;

write_week(week);

temp=(week)/1016+(week)%10;

write_1302(0x8e,0x00);

write_1302(0x8a,temp);

write_1302(0x8e,0x80);

write_1602com(yh+0x0e);

break;

case 5:ri++;

if(ri==32)

ri=1;

write_nyr(9,ri);

temp=(ri)/1016+(ri)%10;

write_1302(0x8e,0x00);

write_1302(0x86,temp);

write_1302(0x8e,0x80);

write_1602com(yh+10);

break;

case 6:yue++;

if(yue==13)

yue=1;

write_nyr(6,yue);

temp=(yue)/1016+(yue)%10;

write_1302(0x8e,0x00);

write_1302(0x88,temp);

write_1302(0x8e,0x80);

write_1602com(yh+7);

break;

case 7:nian++;

if(nian==100)

nian=0;

write_nyr(3,nian);

temp=(nian)/1016+(nian)%10;

write_1302(0x8e,0x00);

write_1302(0x8c,temp);

write_1302(0x8e,0x80);

write_1602com(yh+4);

break;

}

}

}

//------------------减键 key3,各句功能参照'加键'注释---------------

if(key3==0)

{

delay(10);

//调延时,消抖动

if(key3==0)

{

delay(20);

while(!key3);

switch(key1n)

{

case 1:miao--;

if(miao==-1)

miao=59;

write_sfm(0x0D,miao);

temp=(miao)/1016+(miao)%10;

write_1302(0x8e,0x00);

write_1302(0x80,temp);

write_1302(0x8e,0x80);

write_1602com(er+0x0E);

break;

case 2:fen--;

if(fen==-1)

fen=59;

write_sfm(10,fen);

temp=(fen)/1016+(fen)%10;

write_1302(0x8e,0x00);

write_1302(0x82,temp);

write_1302(0x8e,0x80);

write_1602com(er+11);

break;

case 3:shi--;

if(shi==-1)

shi=23;

write_sfm(7,shi);

temp=(shi)/1016+(shi)%10;

write_1302(0x8e,0x00);

write_1302(0x84,temp);

write_1302(0x8e,0x80);

write_1602com(er+8);

break;

case 4:week--;

if(week==0)

week=7;

write_1602com(yh+0x0C);

write_week(week);

temp=(week)/1016+(week)%10;

write_1302(0x8e,0x00);

write_1302(0x8a,temp);

write_1302(0x8e,0x80);

write_1602com(yh+0x0e);

break;

case 5:ri--;

if(ri==0)

ri=31;

write_nyr(9,ri);

temp=(ri)/1016+(ri)%10;//十进制转换成 DS1302 要求的 DCB 码

write_1302(0x8e,0x00);//允许写,禁止写保护

write_1302(0x86,temp);//向 DS1302 内写日期寄存器 86H 写入调整后的日期数据 BCD 码

write_1302(0x8e,0x80);//打开写保护

write_1602com(yh+10);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

break;

case 6:yue--;

if(yue==0)

yue=12;

write_nyr(6,yue);

temp=(yue)/1016+(yue)%10; //十进制转换成 DS1302 要求的 DCB 码

write_1302(0x8e,0x00); //允许写,禁止写保护

write_1302(0x88,temp); //向 DS1302 内写月份寄存器 88H 写入调整后的月份数据 BCD 码

write_1302(0x8e,0x80); //打开写保护

write_1602com(yh+7); //因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

break;

case 7:nian--;

if(nian==-1)

nian=99;

write_nyr(3,nian);

temp=(nian)/1016+(nian)%10; //十进制转换成 DS1302 要求的 DCB 码

write_1302(0x8e,0x00); //允许写,禁止写保护

write_1302(0x8c,temp); //向 DS1302 内写年份寄存器 8cH 写入调整后的年份数据 BCD 码

write_1302(0x8e,0x80); //打开写保护

write_1602com(yh+4); //因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

break;

}

}

}

}

}

void init()

//定时器、计数器设置函数

{

TMOD=0x11;

//指定定时/计数器的工作方式为 3

TH0=0;

//定时器 T0 的高四位=0

TL0=0;

//定时器 T0 的低四位=0

EA=1;

//系统允许有开放的中断

ET0=1;

//允许 T0 中断

TR0=1;

//开启中断,启动定时器

}

//主函数

void main()

{

lcd_init(); //调用液晶屏初始化子函数

ds1302_init(); //调用 DS1302 时钟的初始化子函数

init(); //调用定时计数器的设置子函数

delay(80);

while(1)

//无限循环下面的语句:

{

keyscan();

//调用键盘扫描子函数

}

}

void timer0() interrupt 1 //取得并显示日历和时间

{ //读取秒时分周日月年七个数据(DS1302 的读寄存器与写寄存器不一样)

miao = BCD_Decimal(read_1302(0x81));

fen = BCD_Decimal(read_1302(0x83));

shi = BCD_Decimal(read_1302(0x85));

ri = BCD_Decimal(read_1302(0x87));

yue = BCD_Decimal(read_1302(0x89));

nian=BCD_Decimal(read_1302(0x8d));

week=BCD_Decimal(read_1302(0x8b));

//显示秒、时、分数据:

write_sfm(13,miao); //秒,从第二行第 8 个字后开始显示(调用时分秒显示子函数)

write_sfm(10,fen); //分,从第二行第 5 个字符后开始显示

write_sfm(7,shi); //小时,从第二行第 2 个字符后开始显示

//显示日、月、年数据:

write_nyr(9,ri); //日期,从第二行第 9 个字符后开始显示

write_nyr(6,yue); //月份,从第二行第 6 个字符后开始显示

write_nyr(3,nian); //年,从第二行第 3 个字符后开始显示

write_week(week);

}

#include <reg52h>

#include<stddefh>

#define uchar unsigned char

#define uint unsigned int

#define LCD1602_FLAG

#define LCD1602_PORT P0

sbit lcd1602_rs=P2^0;

sbit lcd1602_e=P2^2;

sbit lcd1602_rw=P2^1;

sbit lcd1602_busy=P0^7;

sbit key_ch=P3^5;

sbit key_add=P3^6;

sbit key_minus=P3^7;

uchar i,sec,min,h,date,month,flag;

uint year;

uchar chgstr[7]={"  ","sec","min","hour","date","min","year"};

uchar j,k,m,n,o,p;

uchar code table[]={

0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71};

uchar timestr[10],datestr[10];

void init();

void delay(uint);

void time_display();

void date_display();

void control();

void time();

/

  函数名称:lcd1602_CheckBusy()

  函数功能:状态查询

/

void lcd1602_CheckBusy()

{

    do

    {

    lcd1602_busy=1;

    lcd1602_rs=0;

    lcd1602_rw=1;

    lcd1602_e=0;

    lcd1602_e=1;

    }

while(lcd1602_busy);

}

/

  函数名称: lcd1602_WriteCmd()

  函数功能:写命令

  入口参数:命令字

  出口参数:无

/

void lcd1602_WriteCmd(const uchar cmd)

{

    lcd1602_CheckBusy();

lcd1602_rs=0;

lcd1602_rw=0;

lcd1602_e=1;

LCD1602_PORT=cmd;

lcd1602_e=0;

}

/

  函数名称:lcd1602_WriteData()

  函数功能:写数据

  入口参数:c--待写数据

  出口参数:无

/

void lcd1602_WriteData(const uchar c)

{

    lcd1602_CheckBusy();

lcd1602_rs=1;

lcd1602_rw=0;

lcd1602_e=1;

LCD1602_PORT=c;

lcd1602_e=0;

}

/

  函数名称:lcd1602_Init()

  函数功能:初始化LCD

  入口参数:无

  出口参数:无

/

void lcd1602_Init()

{

    lcd1602_WriteCmd(0x38); //显示模式为8位2行57点阵

    lcd1602_WriteCmd(0x0c); //display enable,flag enable,flash enable,

    lcd1602_WriteCmd(0x06); //flag move to right,screen don't move

    lcd1602_WriteCmd(0x01); //clear screen

}

/

  函数名称:lcd1602_Display()

  函数功能: 字符显示

  入口参数:ptr--字符或字符串指针

  出口参数:无

  说    明:用户可通过以下方式来调用:

            1)lcd1602_Display("Hello,world!");

            2) INT8U 存储类型 txt[]="要显示的字符串";

               或者 INT8U 存储类型 txt[]={'t','x','t',,'\0'};

               INT8U ptr;

               ptr=&txt;

               lcd1602_Display(ptr);

               或 lcd1602_Display(txt);

               或 lcd1602_Display(&txt);

/

void lcd1602_Display(const uchar ptr,uchar line,uchar xaddr)

{

    uchar data i=0;

uchar data q;

q=ptr;

switch(line)

{

case 0:

lcd1602_WriteCmd(0x80+xaddr);

while(q!=NULL && (q!='\0') && i<16)

     {

lcd1602_WriteData(q);

q++;

i++;

     }

break;

case 1:

lcd1602_WriteCmd(0xc0+xaddr);

while(q!=NULL && (q!='\0') && i<16)

     {

lcd1602_WriteData(q);

q++;

i++;

}

break;

}

}

void main()

{

lcd1602_Init();

init();

while(1)

{

time_display();

date_display();

control();

}

}

void init()

{

i=0;

sec=0;

min=30;

h=7;

date=17;

month=10;

year=2017;

flag=0;

EA=1;

ET0=1;

TMOD=0x01;

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

TR0=1;

}

void delay(uint z)

{

uint x,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--);

}

void time_display()

{

timestr[7]=0x30+sec%10;

timestr[6]=0x30+sec/10;

timestr[5]=':';

timestr[4]=0x30+min%10;

timestr[3]=0x30+min/10;

timestr[2]=':';

timestr[1]=0x30+h%10;

timestr[0]=0x30+h/10;

timestr[8]=0;

lcd1602_Display(timestr,1,3);

}

void date_display()

{

datestr[9]=0x30+date%10;

datestr[8]=0x30+date/10;

datestr[7]=':';

datestr[6]=0x30+month%10;

datestr[5]=0x30+month/10;

datestr[4]=':';

datestr[3]=0x30+year%10;

datestr[2]=0x30+year/10%10;

datestr[1]=0x30+year/100%10;

datestr[0]=0x30+year/1000;

lcd1602_Display(datestr,0,2);

}

void control()

{

if(!key_ch)

{

delay(5);

if(!key_ch)

{

flag++;

TR0=0;

if(flag==7)

{flag=0;TR0=1;lcd1602_Init();}

lcd1602_Display(chgstr[flag],1,12);

}

}

while(!key_ch);

if(flag==1&&key_add==0)

{

while(!key_add);

sec++;

if(sec==60)

sec=0;

}

if(flag==1&&key_minus==0)

{

while(!key_minus);

sec--;

if(sec==-1)

sec=59;

}

if(flag==2&&key_add==0)

{

while(!key_add);

min++;

if(min==60)

min=0;

}

if(flag==2&&key_minus==0)

{

while(!key_minus);

min--;

if(min==-1)

min=59;

}

if(flag==3&&key_add==0)

{

while(!key_add);

h++;

if(h==24)

h=0;

}

if(flag==3&&key_minus==0)

{

while(!key_minus);

h--;

if(h==-1)

h=23;

}

if(flag==4&&key_add==0)

{

while(!key_add);

date++;

if(date==29)

if((year%4!=0)&&(month==2))

date=1;

if(date==30)

if((year%4==0)&&(month==2))

date=1;

if(date==31)

if((month==4)||(month==6)||(month==9)||(month==11))

date=1;

if(date==32)

if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))

date=1;

}

if(flag==4&&key_minus==0)

{

while(!key_minus);

if(date>1)date--;

}

if(flag==5&&key_add==0)

{

while(!key_add);

month++;

if(month==13)

month=1;

}

if(flag==5&&key_minus==0)

{

while(!key_minus);

month--;

if(month==0)

month=12;

}

if(flag==6&&key_add==0)

{

while(!key_add);

year++;

if(year==99)

year=1;

}

if(flag==6&&key_minus==0)

{

while(!key_minus);

year--;

if(year==0)

year=99;

}

}

void T0_rpt() interrupt 1

{

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

i++;

time();

}

void time()

{

if(i==20)

{

i=0;

sec++;

if(sec==60)

{

sec=0;

min++;

if(min==60)

{

min=0;

h++;

if(h==24)

{

h=0;

min=0;

sec=0;

date++;

if(date==29)

if((year%4!=0)&&(month==2))

{

date=1;

month++;

if(month==13)

{

month=1;

year++;

}

}

if(date==30)

if((year%4==0)&&(month==2))

{

date=1;

month++;

if(month==13)

{

month=1;

year++;

}

}

if(date==31)

if((month==4)||(month==6)||(month==9)||(month==11))

{

date=1;

month++;

if(month==13)

{

month=1;

year++;

}

}

if(date==32)

if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))

{

date=1;

month++;

if(month==13)

{

month=1;

year++;

}

}

}

}

}

}

}

这个就是在你的数码管显示语句中,任意加入一个即可

像你说的在小时和分钟之间加一个小数点,那么就加一个小时个位数显示的语句

只是这个增加的语句不是显示数字,是单独显示那个小点而已

循环中,不断的依次点亮四个数字和一个小数点,人眼是分不出来的,就可以达到效果了

另外,你需要一个LED闪烁,代表秒的显示,可以利用定时器来完成

观察你的程序,实在是不敢恭维,尤其是数码管的显示部分太乱了

程序中好像还没有自动加时的部分,并且按键处理还没有消抖措施

不多说了,上程序,俺刚刚为你编写的,测试的时候使用的端口和你的不一样

在我的开发板上测试成功后,按照你的板子端口做了修改

如果你直接复制到你的程序中不能使用,检查及更改一下端口即可

如果满意记得采纳哦,若有疑问可以随时向我提问

//

//#include<stdioh>

#include<reg51h>

sbit p20=P2^0; sbit p21=P2^1; sbit led=P2^7;

char dis_2[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数码管显示编码

unsigned int h,m,s,t,n;

//

void delay(char hs)//延时函数

{char hk;for(;hs>0;hs--){for(hk=100;hk>0;hk--);}}

//

void XS(unsigned int xh,unsigned int xs) //显示子函数

{

char d1,d2,d3,d4;

d1=(xs/1)%10; d2=(xs/10)%10;

d3=(xh/1)%10; d4=(xh/10)%10;

P0=dis_2[d1]; P1=0x08; delay(10); P1=0x00;//秒个位

P0=dis_2[d2]; P1=0x04; delay(10); P1=0x00;//秒十位

P0=0x7f; P1=0x04; delay(10); P1=0x00;//小数点

P0=dis_2[d3]; P1=0x02; delay(10); P1=0x00;//时个位

P0=dis_2[d4]; P1=0x01; delay(10); P1=0x00;//时十位

}

//

void main(void)

{

TH0=(65536-1000)/256; TL0=(65536-1000)%256;

TMOD=0x01; EA=1; ET0=1; TR0=1;//定时器初始化

while(1)//主循环

{

if(p20==0){delay(10);if(p20==0){h++;if(h>23){h=0;}}while(!p20){XS(h,m);}}

if(p21==0){delay(10);if(p21==0){m++;if(m>59){m=0;}}while(!p21){XS(h,m);}}

XS(h,m);//调用数码管显示函数

}

}

//

void int1() interrupt 1 //定时器中断

{

TH0=(65536-1000)/256; TL0=(65536-1000)%256; n++;t++;

if(t>500){t=0;led=~led;}//LED闪烁

if(n>1000){n=0;s++;}//如果达到一秒,秒加一

if(s>59){s=0;m++;}//如果达到一分,分加一

if(m>59){m=0;h++;}//如果达到一小时,小时加一

if(h>23){h=0;}//如果达到24小时,小时清零

}

//

#include <reg51h>

#include <intrinsh>

unsigned char code dis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};

unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5};//星期月参变数

unsigned char data dis_buf1[16];//lcd上排显示缓冲区

unsigned char data dis_buf2[16];//lcd下排显示缓冲区

unsigned char data year,month,date,week;//年、月、日、星期

unsigned char data armhour,armmin,armsec;//闹钟时、分、秒

unsigned char data hour,min,sec,sec100;//时、分、秒、百分之一秒

unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值

bitalarm;//标识是否启用闹钟,1--启用,0--关闭

sbit rs = P2^0;//LCD数据/命令选择端(H/L)

sbit rw = P2^1;//LCD读/写选择端(H/L)

sbit ep = P2^2;//LCD使能控制

sbitPRE = P3^3;//调整键(AN3)

sbitSET = P3^4;//调整键(AN4)

sbitSPK = P3^6;

void delayms(unsigned char ms);//延时程序

bit lcd_busy();//测试LCD忙碌状态程序

void lcd_wcmd(char cmd);//写入指令到LCD程序

void lcd_wdat(char dat);//写入数据到LCD程序

void lcd_pos(char pos);//LCD数据指针位置程序

void lcd_init();//LCD初始化设定程序

void pro_timedate();//时间日期处理程序

void pro_display();//显示处理程序

void pro_key();//按键处理程序

void time_alarm();//定时报警功能(闹钟)

unsigned char scan_key();//按键扫描程序

unsigned char week_proc();//星期自动计算与显示函数

bit leap_year();//判断是否为闰年

void lcd_sef_chr();//LCD自定义字符程序

void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s);

//更新显示缓冲区函数

// 延时程序

void delay(unsigned char ms)

{while(ms--)

{unsigned char i;

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

{

_nop_(); //执行一条_nop_()指令为一个机器周期

_nop_();

_nop_();

_nop_();

}

}

}

//测试LCD忙碌状态

bit lcd_busy()

{

bit result;

rs = 0;

rw = 1;

ep = 1;

_nop_();

_nop_();

_nop_();

_nop_();

result =(bit)(P0&0x80);//LCD的D0--D7中,D7=1为忙碌,D7=0为空闲

ep = 0;

return result;

}

//写入指令到LCD

void lcd_wcmd(char cmd)

{

while(lcd_busy());//当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令

rs = 0;

rw = 0;

ep = 0;

_nop_();

_nop_();

P0 = cmd;

_nop_();

_nop_();

_nop_();

_nop_();

ep = 1;

_nop_();

_nop_();

_nop_();

_nop_();

ep = 0;

}

//写入数据到LCD

void lcd_wdat(char dat)

{

while(lcd_busy());//当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据

rs = 1;

rw = 0;

ep = 0;

P0 = dat;

_nop_();

_nop_();

_nop_();

_nop_();

ep = 1;

_nop_();

_nop_();

_nop_();

_nop_();

ep = 0;

}

//LCD数据指针位置程序

void lcd_pos(char pos)

{

lcd_wcmd(pos|0x80);//数据指针=80+地址码(00H~27H,40H~67H)

}

//设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符)

//这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)

void lcd_sef_chr()

{//第一个自定义字符

lcd_wcmd(0x40);//"01 000 000" 第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))

lcd_wdat(0x1f);//"XXX 11111"第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)

lcd_wcmd(0x41);//"01 000 001" 第2行地址

lcd_wdat(0x11);//"XXX 10001"第2行数据

lcd_wcmd(0x42);//"01 000 010" 第3行地址

lcd_wdat(0x15);//"XXX 10101"第3行数据

lcd_wcmd(0x43);//"01 000 011" 第4行地址

lcd_wdat(0x11);//"XXX 10001"第4行数据

lcd_wcmd(0x44);//"01 000 100" 第5行地址

lcd_wdat(0x1f);//"XXX 11111"第5行数据

lcd_wcmd(0x45);//"01 000 101" 第6行地址

lcd_wdat(0);//"XXX 01010"第6行数据

lcd_wcmd(0x46);//"01 000 110" 第7行地址

lcd_wdat(0x1f);//"XXX 11111"第7行数据

lcd_wcmd(0x47);//"01 000 111" 第8行地址

lcd_wdat(0x00);//"XXX 00000"第8行数据

//第二个自定义字符

lcd_wcmd(0x48);//"01 001 000" 第1行地址

lcd_wdat(0x01);//"XXX 00001"第1行数据

lcd_wcmd(0x49);//"01 001 001" 第2行地址

lcd_wdat(0x1b);//"XXX 11011"第2行数据

lcd_wcmd(0x4a);//"01 001 010" 第3行地址

lcd_wdat(0x1d);//"XXX 11101"第3行数据

lcd_wcmd(0x4b);//"01 001 011" 第4行地址

lcd_wdat(0x19);//"XXX 11001"第4行数据

lcd_wcmd(0x4c);//"01 001 100" 第5行地址

lcd_wdat(0x1d);//"XXX 11101"第5行数据

lcd_wcmd(0x4d);//"01 001 101" 第6行地址

lcd_wdat(0x1b);//"XXX 11011"第6行数据

lcd_wcmd(0x4e);//"01 001 110" 第7行地址

lcd_wdat(0x01);//"XXX 00001"第7行数据

lcd_wcmd(0x4f);//"01 001 111" 第8行地址

lcd_wdat(0x00);//"XXX 00000"第8行数据

}

//LCD初始化设定

void lcd_init()

{

lcd_wcmd(0x38);//设置LCD为16X2显示,5X7点阵,八位数据借口

delay(1);

lcd_wcmd(0x0c);//LCD开显示及光标设置(光标不闪烁,不显示"-")

delay(1);

lcd_wcmd(0x06);//LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)

delay(1);

lcd_wcmd(0x01);//清除LCD的显示内容

delay(1);

}

//闰年的计算

bit leap_year()

{

bit leap;

if((year%4==0&&year%100!=0)||year%400==0)//闰年的条件

leap=1;

else

leap=0;

return leap;

}

//星期的自动运算和处理

unsigned char week_proc()

{unsigned char num_leap;

unsigned char c;

num_leap=year/4-year/100+year/400;//自00年起到year所经历的闰年数

if( leap_year()&& month<=2 ) //既是闰年且是1月和2月

c=5;

else

c=6;

week=(year+para_month[month]+date+num_leap+c)%7;//计算对应的星期

return week;

}

//更新显示缓冲区

void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s)

{dis_buf1[0]=t1; //

dis_buf1[1]=0x20; //空格

dis_buf1[2]=50; //'2'

dis_buf1[3]=48; //'0'

dis_buf1[4]=year/10+48;

dis_buf1[5]=year%10+48;

dis_buf1[6]=0x2d;

dis_buf1[7]=month/10+48;

dis_buf1[8]=month%10+48;

dis_buf1[9]=0x2d; //'-'

dis_buf1[10]=date/10+48;

dis_buf1[11]=date%10+48;

dis_buf1[12]=0x20;

dis_buf1[13]=dis_week[4week];

dis_buf1[14]=dis_week[4week+1];

dis_buf1[15]=dis_week[4week+2];

dis_buf2[0]=t2[0];

dis_buf2[1]=t2[1];

dis_buf2[2]=t2[2];

dis_buf2[3]=t2[3];

dis_buf2[4]=t2[4];

dis_buf2[5]=t2[5];

dis_buf2[6]=t2[6];//空格

if (alarm)

dis_buf2[7]=0x01;//alarm=1,显示闹钟启用标致(第二个自定义字符)

else

dis_buf2[7]=0x20;//alarm=0,不显示闹钟启用标致

dis_buf2[8]=dis_h/10+48;

dis_buf2[9]=dis_h%10+48;

dis_buf2[10]=0x3a;//':'

dis_buf2[11]=dis_m/10+48;

dis_buf2[12]=dis_m%10+48;

dis_buf2[13]=0x3a;

dis_buf2[14]=dis_s/10+48;

dis_buf2[15]=dis_s%10+48;

}

//时间和日期处理程序

void pro_timedate()

{

sec++;

if(sec > 59)

{sec = 0;

min++;

if(min>59)

{min=0;

hour++;

if(hour>23)

{hour=0;

date++;

if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)

if (date>31) {date=1;month++;}//大月31天

if (month==4||month==6||month==9||month==11)

if (date>30) {date=1;month++;}//小月30天

if (month==2)

{if( leap_year())//闰年的条件

{if (date>29) {date=1;month++;}}//闰年2月为29天

else

{if (date>28) {date=1;month++;}}//平年2月为28天

}

if (month>12) {month=1;year++;}

if (year>99) year=0;

}

}

}

week_proc();

if (sec==armsec && min==armmin && hour==armhour)

{if (alarm)

TR1=1;//闹钟启用时,报警时间到,启动Timer1

}

}

//显示处理程序

void pro_display()

{unsigned char i;

lcd_pos(0x00);

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

{lcd_wdat(dis_buf1[i]);}

lcd_pos(0x40);

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

{lcd_wdat(dis_buf2[i]);}

}

//Timer0中断处理程序,秒的产生

void timer0() interrupt 1

{

TH0=0xD8;

TL0=0xF0;

sec100++;

if(sec100 >= 100)//1秒时间 (10010ms=1000ms=1s)

{sec100 = 0;

pro_timedate();//调用时间和日期处理程序

}

if (sec&0x01)//"RICHMCU"闪一秒,停一秒

update_disbuf(0x00," ",hour,min,sec); //0x00表示显示00位置的自定义字符

else

update_disbuf(0x00,"RICHMCU",hour,min,sec);

pro_display(); //调用显示处理函数

}

//按键扫描程序

unsigned char scan_key()

{

skey=0x00;//给变量vkey置初值

skey|=PRE;//读取PRE键的状态

skey=skey<<1;//将PRE键的状态存于skey的B1位

skey|=SET;//读取SET键的状态,并存于skey的B0位

return skey;//返回skey的键值(即PRE,SET的状态)

}

//外部中断INT0中断处理程序

void int0() interrupt 0

{

TR0=0;//禁止Timer0

IE=0;//禁止中断

lcd_wcmd(0x0e);//显示光标"_",整个光标不闪烁

alarm=1;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);//更新显示数据,0x50表示要显示"P"

pro_display();//调用显示处理程序

lcd_pos(0x47); //使光标位于第一个调整项下

flag=0;

vkey=0x03;

while(flag^0)

{skey = scan_key();//扫描按键状态

if (skey^vkey)//若skey与vkey相同,跳出循环,相异执行循环体

{delay(10);//去按键抖动

skey = scan_key();//转回扫描按键状态

if (skey^vkey)//若skey与vkey相同,跳出循环,相异执行循环体

{vkey=skey;//将skey的值付给vkey

if (skey==0x01)//PRE键按下

{ flag++;//调整标志位加1

switch (flag)//将光标置于相应调整位置

{

case 1: lcd_pos(0x49);break;//光标置小时报警设置位置

case 2:lcd_pos(0x4c);break;//光标置分钟报警设置位置

case 3:lcd_pos(0x4f);break;//光标置秒时报警设置位置

case 4:update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();

lcd_pos(0x05);break;//光标置年调整位置

case 5:lcd_pos(0x08);break;//光标置月调整位置

case 6:lcd_pos(0x0b);break;//光标置日调整位置

case 7: lcd_pos(0x49);break;//光标置时调整位置

case 8:lcd_pos(0x4c);break;//光标置分调整位置

case 9:lcd_pos(0x4f);break;//光标置秒调整位置

default:break;

}

}

if (skey==0x02) //SET键按下

{pro_key();//转设置按键处理程序

}

}

}

}

lcd_wcmd(0x0c);//设置LCD开显示及光标不闪烁,不显示"-"

lcd_wcmd(0x01); //清除LCD的显示内容

IE=0x8f; //CPU开中断,INT0,INT1,开中断

TR0=1;//Timer0启动

}

//主程序,初始化及初值设定

void main()

{

lcd_init(); //初始化LCD

lcd_sef_chr();//写入自定义字符号

hour=0;min=0;sec=0; //开机时的时,分,秒显示

armhour=0;armmin=0;armsec=0;//开机时的时,分,秒报警初值

year= 5; month=1;date=1; //开机时的年,月,日,星期显示

week_proc();

alarm=1;//初始开机,启用闹钟

IE = 0x8f;//CPU开中断,INT0,INT1,Timer0,Timer1开中断

IP = 0x04;//设置INT0为中断最高优先级

IT0=0;IT1=0;//外部INT0,INT1设置为电平触发方式(注意,触发不要选边沿方式,易误动)

TMOD = 0x11;//Timer0,Timer1工作于模式1, 16位定时方式

TH0 = 0xdc;TL0 = 0x00;//Timer0置10ms定时初值

TH1 = 0xff;TL1 = 0x00;//Timer1置初值

TR0 = 1;//Timer0启动

TR1 = 0;

while(1);

}

//设置按键处理程序

void pro_key()

{

switch (flag)

{

case 0:alarm=!alarm;//启用或关闭闹钟(alarm=1:启用,alarm=0:关闭)

update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据

pro_display();//调用显示处理

lcd_pos(0x47);break;//光标回到原调整位置

case 1:armhour++;

if (armhour>23) armhour=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据

pro_display();//调用显示处理

lcd_pos(0x49);break;//光标回到原调整位置

case 2:armmin++;

if (armmin>59) armmin=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);

pro_display();

lcd_pos(0x4c);break;

case 3:armsec++;

if (armsec>59) armsec=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);

pro_display();

lcd_pos(0x4f);break;

case 4:year++;

if(year> 99) year= 0;

week_proc(); //星期自动运算

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();

lcd_pos(0x05);break;

case 5:month++;

if (month>12) month=1;

week_proc();//星期自动运算

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();

lcd_pos(0x08);break;

case 6:date++;

if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)

if (date>31) date=1;//大月31天

if (month==4||month==6||month==9||month==11)

if (date>30) date=1;//小月30天

if (month==2)

{if(leap_year())//闰年的条件

{if (date>29) date=1;}//闰年2月为29天

else

{if (date>28) date=1;}}//平年2月为28天

week_proc(); //星期自动运算

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();

lcd_pos(0x0b);break;

case 7:hour++;

if (hour>23) hour=0;

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();

lcd_pos(0x49);break;

case 8:min++;

if (min>59) min=0;

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();

lcd_pos(0x4c);break;

case 9:sec++;

if (sec>59) sec=0;

update_disbuf(0x50,"time: ",hour,min,sec);

pro_display();

lcd_pos(0x4f);break;

default: break ;

}

}

//Timer1中断处理程序,产生报警的声音

void timer1() interrupt 3

{

TH1=0xff;

TL1=0x00;

SPK=~SPK;

}

//外部中断INT1中断处理程序,停止报警声音

void int1() interrupt 2

{

if(TR1)

TR1=0;

}

实验说明:

按K1按键进入设定状态

按K2,依次进入闹钟功能是否启用,闹钟时,分秒,年,月,日及时间时,分,秒的设置,直到退出设置状态

按K3,调整是否起用闹钟和调节闹钟时,分,秒,年,月,日,时间的时,分,秒的数字

LCD第二排中间显示小喇叭,表示启用闹钟功能,无则禁止闹钟功能(可在调整状态进行设置)

正常状态,LCD上排最前面显示自定义字符,LCD下排最前面闪动"RICHMCU"

设置状态,LCD上排最前面显示"P",下排最前面在设置闹钟时间时显示"alarm:",其它状态显示"time"

年代变化2000--2099,星期自动转换

望采纳,谢谢~~

我这写了一个!使用数码管显示的!可以用键盘校对时间!你参考下。还写了一个液晶显示的!你要的话也可以发给你!

#include<reg52h>

#define uchar unsigned char

#define uint unsigned int

sbit K1=P3^0;

sbit K2=P3^1;

sbit K3=P3^2;

uchar table[]={

0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f};

uchar table1[]={0x5b,0x66,0x6d,0x6f,0x6d,0x6f};

uchar table2[]={0,1,0,0,0,0};

int shi=1,fen=0,miao=0;

uchar a,i,j,temp=-2,temp1;

void sfm(uchar dz,uchar shu);//将计的数的十位和个位分开

void display();//将时间显示出来

void display1(uchar dz);//只显示要校对的数

void init();//初始化

void jiaoshi();//定义一个校时函数

void delay(uchar z)//定义一个延时函数

{

uchar x,y;

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

for(y=0;y<z;y++);

}

void main()

{

init();

while(1)

{

jiaoshi();

}

}

void init()

{

EA=1;

ET0=1;

ET1=1;

TR1=1;

TR0=0;

TMOD=0x11;

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

TH1=(65536-50000)/256;

TL1=(65536-50000)%256;

K1=K2=1;

temp1=0;

while(TR1)

{

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

{

delay(3);

P1=i;

P2=table1[i];

delay(3);

}

}

}

void sfm(uchar dz,uchar shu)

{

if(shu==60&dz!=0) shu=0;

table2[dz]=shu/10;

table2[dz+1]=shu%10;

}

void display()

{

uchar j;

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

{

delay(3);

P1=j;

P2=table[table2[j]];

delay(3);

}

}

void display1(uchar dz)

{

uchar j;

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

{

delay(3);

P1=dz+j;

P2=table[table2[dz+j]];

delay(3);

}

}

void jiaoshi()

{

uchar a;

if(K1==0)

{

delay(5);

if(K1==0)

{

TR0=0;

a++;

temp+=2;

if(a==4|temp==6)

{

a=0;

temp=-2;

TR0=1;

}

}

}

while(!K1)

{

delay(5);

display1(temp);

}

while(!K1);

display1(temp);

if(K2==0)

{

delay(5);

if(K2==0)

{

if(a==1)

{

temp=0;

if(shi==24)

shi=0;

shi++;

sfm(0,shi);

}

if(a==2)

{

temp=2;

if(fen==59)

fen=-1;

fen++;

sfm(2,fen);

}

if(a==3)

{

temp=4;

if(miao==59)

miao=-1;

miao++;

sfm(4,miao);

}

}

}

while(!K2)

{

delay(5);

display1(temp);

}

while(!K2);

if(K3==0)

{

delay(5);

if(K3==0)

{

if(a==1)

{

shi--;

if(shi==0)

shi=24;

sfm(0,shi);

}

if(a==2)

{

fen--;

if(fen==-1)

fen=59;

sfm(2,fen);

}

if(a==3)

{

miao--;

if(miao==-1)

miao=59;

sfm(4,miao);

}

}

}

while(!K3)

{

delay(5);

display1(temp);

}

while(!K3);

}

void timer0() interrupt 1

{

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

a++;

if(a==16)

{

a=0;

miao++;

sfm(4,miao);

if(miao==60)

{

miao=0;

display();

fen++;

sfm(2,fen);

if(fen==60)

{

fen=0;

shi++;

sfm(0,shi);

if(shi==25)

{

shi=1;

sfm(0,shi);

}

}

}

}

display();

}

void timer1() interrupt 3

{

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

j++;

if(j==20)

{

TR0=1;

TR1=0;

}

}

以上就是关于求教一个51单片机程序。。(LCD电子时钟)全部的内容,包括:求教一个51单片机程序。。(LCD电子时钟)、51单片机简单电子时钟程序,通过按键设置时间,有图,有解析!、关于用51单片机做一个电子时钟的问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/9504981.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-29
下一篇 2023-04-29

发表评论

登录后才能评论

评论列表(0条)

保存