基于ds1302的51单片机简易实时时钟-1602显示-源程序
基于ds1302和LCD1602的日历时钟51单片机程序
#include <reg52.h>#include <intrins.h>#include <string.h>#define uint unsigned int#define uchar unsigned charsbit led = P2^3;//led代替闹铃sbit IO = P1^3; //定义1302管脚//6sbit SCLK = P1^4;//7sbit RST = P1^5; //5sbit RS = P2^2;//定义1602管脚sbit RW = P2^1;sbit EN = P2^0;sbit key1=P3^4;//选择//调时键盘sbit key2=P3^5;//加sbit key3=P3^6;//减sbit key4=P3^7;//确定sbit key11=P1^6;//选择//闹钟键盘sbit key22=P1^7;//加sbit key33=P3^0;//减sbit key44=P3^1;//确定uchar x1=0,x;int hour=8,minute=0;//闹钟的初始时间8:00uchar DateTime[9]; //秒,分,时,日,周,月,年 address,uchar lcd1[]={"DATE 00-00-00 "};uchar lcd2[]={"TIME 00:00:00 "};/***************延时*************/void delayms(uchar x)//延时毫秒程序{ uchar i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}void delayus(uchar x)//延时微秒程序{ uchar i;for(i=0;i<x;i++);}/********1302的驱动程序***********///写入数据,dat:要写入的数据void DS1302WriteByte(uchar dat){uchar i;SCLK=0;//初始时钟线置为0delayus(2);for(i=0;i<8;i++)//开始传输8个字节的数据{IO=dat&0x01;//取最低位,注意DS1302的数据和地址都是从最低位开始传输的delayus(2);SCLK=1;//时钟线拉高,制造上升沿,SDA的数据被传输delayus(2);SCLK=0;//时钟线拉低,为下一个上升沿做准备dat>>=1;//数据右移一位,准备传输下一位数据}}/********1302的驱动程序**********///功能: 读取数据,dat:读取的数据uchar DS1302ReadByte(){ uchar i;uchar dat;delayus(2);for(i=0;i<8;i++){dat>>=1;//要返回的数据左移一位if(IO==1)//当数据线为高时,证明该位数据为1dat|=0x80;//要传输数据的当前值置为1,若不是,则为0SCLK=1;//拉高时钟线delayus(2);SCLK=0;//制造下降沿delayus(2);}return dat;//返回读取出的数据/16*10+dat%16}/*********1302的驱动程序*********///从cmd相应地址中读取一个字节的数据uchar DS1302Read(uchar cmd)//cmd:要写入的控制字节,dat:读取的数据{uchar dat;RST=0;//初始CE线置为0SCLK=0;//初始时钟线置为0RST=1;//初始CE置为1,传输开始DS1302WriteByte(cmd);//传输命令字,要读取的时间/日历地址dat=DS1302ReadByte();//读取要得到的时间/日期SCLK=1;//时钟线拉高RST=0;//读取结束,CE置为0,结束数据的传输return dat;//返回得到的时间/日期}/**********1302的驱动程序*********///向cmd相应地址中写一个字节的数据void DS1302Write(uchar cmd, uint dat)//cmd:要写入的控制字,dat:要写入的数据{RST=0; //初始CE线置为0SCLK=0; //初始时钟线置为0RST=1; //初始CE置为1,传输开始DS1302WriteByte(cmd); //传输命令字,要写入的时间/日历地址DS1302WriteByte(dat); //写入要修改的时间/日期SCLK=1; //时钟线拉高RST=0; //读取结束,CE置为0,结束数据的传输}/*************初始化ds1302********///给1302写入日期和时钟的值void chushihuaDS1302(void){DS1302Write(0x8e,0x00);//写保护关DS1302Write(0x80,0x10); //初始秒DS1302Write(0x82,0x02);//初始分钟DS1302Write(0x84,0x15); //初始为24小时模式,初始时DS1302Write(0x86,0x01); //1日DS1302Write(0x88,0x08);//8月DS1302Write(0x8c,0x13);//2013年DS1302Write(0x8a,0x04);//星期4// DS1302Write(0x90,0x01); //充电//DS1302Write(0xc0,0xf0); //初始化一次标示//DS1302Write(0x8e,0x80);//写保护开}/************以下是1602的程序******************//******************************///向1602内写命令void write_order(uchar order){RS=0;P0=order;delayms(5);EN=1;delayms(5);EN=0;}/******************************///向1602内写数据void write_date(uchar date){RS=1;P0=date;delayms(5);EN=1;delayms(5);EN=0;}/******************************///lcd1602的初始化void chushihuaLCD1602(){ EN=0;write_order(0x38);write_order(0x0c);write_order(0x06);write_order(0x01);}/*************其他操作*****************/void gettime(){ uchar i,n;for(i=0,n=1;i<7,n<15;i++,n=n+2){ DateTime[i]=DS1302Read(0x80+n);delayus(1);}}void zhuanhuan(){ gettime();lcd1[5]=((DateTime[6]>>4)+0x30);lcd1[6]=((DateTime[6]&0x0f)+0x30);delayus(2);//年lcd1[14]=((DateTime[5]>>4)+0x30);lcd1[15]=((DateTime[5]&0x0f)+0x30);delayus(2);//周lcd1[11]=((DateTime[3]>>4)+0x30);lcd1[12]=((DateTime[3]&0x0f)+0x30);delayus(2);//日lcd1[8]=((DateTime[4]>>4)+0x30);lcd1[9]=((DateTime[4]&0x0f)+0x30);delayus(2);//月lcd2[5]=((DateTime[2]>>4)+0x30);lcd2[6]=((DateTime[2]&0x0f)+0x30);delayus(2);//时lcd2[8]=((DateTime[1]>>4)+0x30);lcd2[9]=((DateTime[1]&0x0f)+0x30);delayus(2);//分lcd2[11]=((DateTime[0]>>4)+0x30);lcd2[12]=((DateTime[0]&0x0f)+0x30);delayus(2);//秒if(DateTime[7]==DateTime[2] & DateTime[8]==DateTime[1]){led = 1;delayms(150);led = 0;}/**/}/***********************/void jianpan() //键盘调时{ uchar x2,address,max,min;int item;if(key1==0){ delayms(10);if(key1==0){ x1++;if(x1>=7) x1=1;switch(x1){ case 1: lcd2[15]='Y';x2=1;address=0x8c; max=99;min=0;break;//年case 2: lcd2[15]='M';x2=2;address=0x88; max=12;min=1;break;//月case 3: lcd2[15]='D';x2=3;address=0x86; max=31;min=1;break;//天case 4: lcd2[15]='H';x2=4;address=0x84; max=23;min=0;break;//时case 5: lcd2[15]='F';x2=5;address=0x82; max=59;min=0;break;//分case 6: lcd2[15]='W';x2=6;address=0x8A; max=7;min=1;break;//周}}while(!key1);}item=(DS1302Read(address+1)/16)*10 + (DS1302Read(address+1))%16;if(key2==0){ delayms(10);if(key2==0){ if(x2==1) {item++;}else if(x2==2) {item++;}else if(x2==3) {item++;}else if(x2==4) {item++;}else if(x2==5) {item++;}else if(x2==6) {item++;}}while(!key2);}if(key3==0){ delayms(10);if(key3==0){ if(x2==1) {item--;}else if(x2==2) {item--;}else if(x2==3) {item--;}else if(x2==4) {item--;}else if(x2==5) {item--;}else if(x2==6) {item--;}}while(!key3);}if(key4==0){ delayms(10);if(key4==0){ lcd2[15]=' ';x1=0;x2=0;}while(!key4);}//led=0;delayms(5000);led=1;if(item>max) item=min;if(item<min) item=max;DS1302Write(0x8e,0x00);//允许写操作delayms(10);DS1302Write(address,(item/10)*16+item%10); //写入DS1302 //转成BCD码delayms(20);DS1302Write(0x8e,0x80);//写保护,禁止写操作}void naozhong()//设定闹钟{ uchar da,xiao,i;if(key11==0){ delayms(10);if(key11==0){ x++;if(x>=4) x=1;switch(x){case 2: lcd2[13]='H';i=1;da=23;xiao=0;lcd2[14]=((hour>>4)+0x30);lcd2[15]=((hour&0x0f)+0x30);delayus(2);break;//时case 1: lcd2[13]='M';i=2;da=59;xiao=0;lcd2[14]=((minute>>4)+0x30);lcd2[15]=((minute&0x0f)+0x30);delayus(2);break;//分case 3: lcd2[13]=' ';lcd2[14]=' ';lcd2[15]=' ';x=0;i=0;break;}}while(!key11);}if(key22==0){ delayms(10);if(key22==0){ if(i==1){ hour=((hour/16)*10)+(hour%16);hour++;if(hour>da) hour=xiao;hour=(hour/10)*16+hour%10;lcd2[14]=((hour>>4)+0x30);lcd2[15]=((hour&0x0f)+0x30);delayus(2);}else if(i==2){ minute=((minute/16)*10)+(minute%16);minute++;if(minute>da) minute=xiao;minute=(minute/10)*16+minute%10;lcd2[14]=((minute>>4)+0x30);lcd2[15]=((minute&0x0f)+0x30);delayus(2);}}while(!key22);}if(key33==0){ delayms(10);if(key33==0){ if(i==1){ hour=((hour/16)*10)+(hour%16);hour--;if(hour<xiao) hour=da;hour=(hour/10)*16+hour%10;lcd2[14]=((hour>>4)+0x30);lcd2[15]=((hour&0x0f)+0x30);delayus(2);}else if(i==2){ minute=((minute/16)*10)+(minute%16);minute--;if(minute<xiao) minute=da;minute=(minute/10)*16+minute%10;lcd2[14]=((minute>>4)+0x30);lcd2[15]=((minute&0x0f)+0x30);delayus(2);}}while(!key33);}DateTime[7]=hour;DateTime[8]=minute;}/**/void wzd0() interrupt 0//外部中断0{jianpan();//}void wzd1() interrupt 2//外部中断1{naozhong();}void main(){uchar k;EA=1;EX0=1;IT0=1;PX0=1;EX1=1;IT1=1;PX1=0;RW=0;led=0;chushihuaLCD1602();if( (DS1302Read(0x81) & 0x80) ) chushihuaDS1302();//chushihuaDS1302();while(1){zhuanhuan();write_order(0x80);//lcd的第一行for(k=0;k<16;k++){ write_date(lcd1[k]);delayus(2);}write_order(0x80+0x40);//lcd的第二行for(k=0;k<16;k++){ write_date(lcd2[k]);delayus(2);}}}。
51单片机,DS1302时钟,1602显示,可调时钟剖析
基于proteus的51单片机仿真实例八十一、实时时钟芯片DS1302应用实例1、DS1302引脚排列:如下图引脚说明:1)Vcc1:后备电源,VCC2:主电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。
当Vcc2小于Vcc1时,DS1302由Vcc1供电。
2)X1、X2:振荡源,外接32.768kHz 晶振。
3)RST:复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。
上电运行时,在Vcc>2.0V之前,RST必须保持低电平。
只有在SCLK为低电平时,才能将RST置为高电平。
4)I/O为串行数据输入输出端(双向)。
5)SCLK为时钟输入端。
2、DS1302的控制字节DS1302 的控制字如下图所示。
控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。
3、数据输入输出(I/O)在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
DS1302的寄存器DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见数据手册。
DS1302实时时钟模块,1602显示
/******************* 说明:**************************将实时时钟数据通过LCD1602 显示基于51 单片机**************************************************/#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int uchar dis_time_buf[16]={0};//LCD1602 引脚定义// 采用8 位并行方式,DB0~DB7 连接至LCDDATA0~LCDDATA7sbit RS=P2A0;sbit RW=P2A1;sbit CS=P2A2;#define LCDDATA P0//DS1302 引脚定义sbit RST=P1A3;sbit IO=P1A2;sbit SCK=P1A1;//DS1302 地址定义#define ds1302_sec_add 0x80 // 秒数据地址#define ds1302_min_add 0x82 // 分数据地址#define ds1302_hr_add 0x84 // 时数据地址#define ds1302_date_add 0x86 // 日数据地址#define ds1302_month_add 0x88 // 月数据地址#define ds1302_day_add 0x8a // 星期数据地址#define ds1302_year_add 0x8c // 年数据地址#define ds1302_control_add 0x8e // 控制数据地址#define ds1302_charger_add 0x90#define ds1302_clkburst_add 0xbe// 初始时间定义uchar time_buf[8] = {0x20,0x10,0x06,0x01,0x23,0x59,0x55,0x02};// 初始时间2010年6月1号23 点59 分55 秒星期二// 功能:延时 1 毫秒// 入口参数:x// 出口参数:无//说明:当晶振为12M时,j<112 ;当晶振为11.0592M时,j<122void Delay_xms(uint x){uint i,j;for(i=0;i<x;i++)for(j=0;j<112;j++);// 功能:12us 延时//STC89C52为1T单片机,即1个时钟/机器周期,速度为AT89C52的12倍void Delay_xus(uint t){for(;t>0;t--){_nop_();}}//控制LCD写时序void LCD_en_write(void){CS=1;Delay_xus(20);CS=0;Delay_xus(20);}// 写指令函数void Write_Instruction(uchar command){RS=0;RW=0;CS=1;LCDDATA=command;LCD_en_write();// 写入指令数据}// 写数据函数void Write_Data(uchar Wdata){RS=1;RW=0;CS=1;LCDDATA=Wdata;LCD_en_write();// 写入数据}// 字符显示初始地址设置void LCD_SET_XY(uchar X,uchar Y){uchar address;if(Y==0) address=0x80+X;//Y=0, 表示在第一行显示,地址基数为0x80elseaddress=0xc0+X;//Y 非 0 时,表时在第二行显示,地址基数为 0xC0 Write_Instruction(address);// 写指令,设置显示初始地址}//在第X 行Y 列开始显示 Wdata 所对应的单个字符 void LCD_write_char(uchar X,uchar Y,uchar Wdata){LCD_SET_XY(X,Y)写 地址Write_Data(Wdata);// 写入当前字符并显示}// 清屏函数 void LCD_clear(void){Write_Instruction(0x01); Delay_xms(5);}// 显示屏初始化函数 void LCD_init(void){Write_Instruction(0x38); // 8bit interface,2line,5*7dotsDelay_xms(5);Write_Instruction(0x38); Delay_xms(5);Write_Instruction(0x38);Write_Instruction(0x08); //关显示,不显光标,光标不闪烁 Write_Instruction(0x01); //清屏 Delay_xms(5);//Write_Instruction(0x05); //Write_Instruction(0x06);//Write_Instruction(0x07);Delay_xms(5); // 写一字符,整屏右移 // 写一字符,整屏显示不移动// 写一字符,整屏左移//Write_Instruction(0x0B); Write_Instruction(0x0C);//Write_Instruction(0x0D); //Write_Instruction(0x0E); //Write_Instruction(0x0F); } //DS1302 初始化函数 void ds1302_init(void){Write_Instruction(0x04); // 写一字符,整屏显示不移动 // 关闭显示(不显示字符,只有背光亮) // 开显示,光标、闪烁都关闭// 开显示,不显示光标,但光标闪烁 // 开显示,显示光标,但光标不闪烁}//向DS1302写入一字节数据void ds1302_write_byte(uchar addr, uchar d){uchar i; RST=1;// 启动 DS1302 总线// 写入目标地址: addraddr = addr & 0xFE; // 最低位置零,寄存器 0 位为 0 时写,为 1 时读 for (i = 0; i < 8; i ++) {if (addr & 0x01) {IO=1;}else {IO=0;}SCK=1; //产生时钟 SCK=0;addr = addr >> 1;}// 写入数据: dfor (i = 0; i < 8; i ++) {if (d & 0x01) {IO=1;}else {IO=0;}SCK=1; // 产生时钟 SCK=0; d = d >> 1;}RST=O;〃停止 DS1302 总线}//从DS1302读出一字节数据uchar ds1302_read_byte(uchar addr) {uchar i,temp; RST=1;// 启动 DS1302 总线// 写入目标地址: addr addr = addr | 0x01;// 最低位置高,寄存器 0 位为 0 时写,为 1 时读for (i = 0; i < 8; i ++) {RST=0; SCK=0;//RST 脚置低 //SCK 脚置低if (addr & 0x01) { IO=1;}else { IO=0;}SCK=1;SCK=0;addr = addr >> 1;}// 输出数据:tempfor (i = 0; i < 8; i ++) { temp = temp >> 1; if (IO) {temp |= 0x80;}else {temp &= 0x7F; }SCK=1;SCK=0;}RST=0;//停止DS1302 总线return temp;}//向DS302写入时钟数据void ds1302_write_time(void) {ds1302_write_byte(ds1302_control_add,0x00); // 关闭写保护ds1302_write_byte(ds1302_sec_add,0x80); // 暂停时钟//ds1302_write_byte(ds1302_charger_add,0xa9); // 涓流充电ds1302_write_byte(ds1302_year_add,time_buf[1]); // 年ds1302_write_byte(ds1302_month_add,time_buf[2]); //月ds1302_write_byte(ds1302_date_add,time_buf[3]); // 日ds1302_write_byte(ds1302_hr_add,time_buf[4]); // 时ds1302_write_byte(ds1302_min_add,time_buf[5]); // 分ds1302_write_byte(ds1302_sec_add,time_buf[6]); // 秒ds1302_write_byte(ds1302_day_add,time_buf[7]); // 周ds1302_write_byte(ds1302_control_add,0x80); //打开写保护}//从DS302读出时钟数据void ds1302_read_time(void){time_buf[1]=ds1302_read_byte(ds1302_year_add); // 年time_buf[2]=ds1302_read_byte(ds1302_month_add); // 月time_buf[3]=ds1302_read_byte(ds1302_date_add); // 日time_buf[4]=ds1302_read_byte(ds1302_hr_add); // 时time_buf[5]=ds1302_read_byte(ds1302_min_add); // 分time_buf[6]=(ds1302_read_byte(ds1302_sec_add))&0x7f;// 秒,屏蔽秒的第7 位,避免超出59time_buf[7]=ds1302_read_byte(ds1302_day_add); // 周}void Display(void){LCD_write_char(3,0,dis_time_buf[0]+'0');LCD_write_char(4,0,dis_time_buf[1]+'0');LCD_write_char(5,0,dis_time_buf[2]+'0');LCD_write_char(6,0,dis_time_buf[3]+'0');LCD_write_char(7,0,'/');LCD_write_char(8,0,dis_time_buf[4]+'0');LCD_write_char(9,0,dis_time_buf[5]+'0');LCD_write_char(10,0,'/');LCD_write_char(11,0,dis_time_buf[6]+'0');LCD_write_char(12,0,dis_time_buf[7]+'0');LCD_write_char(15,0,dis_time_buf[14]+'0'); // 第 2 行显示LCD_write_char(3,1,dis_time_buf[8]+'0');LCD_write_char(4,1,dis_time_buf[9]+'0');LCD_write_char(5,1,':');LCD_write_char(6,1,dis_time_buf[10]+'0');LCD_write_char(7,1,dis_time_buf[11]+'0');LCD_write_char(8,1,':');LCD_write_char(9,1,dis_time_buf[12]+'0');LCD_write_char(10,1,dis_time_buf[13]+'0');}// 定时器中断函数void Timer2() interrupt 5// 定时器 2 是 5 号中断{static uchar t;TF2=0;t++;if(t==4) // 间隔200ms(50ms*4) 读取一次时间{t=0;ds1302_read_time(); // 读取时间dis_time_buf[0]=(time_buf[0]>>4); // 年dis_time_buf[1]=(time_buf[0]&0x0f);dis_time_buf[2]=(time_buf[1]>>4);dis_time_buf[3]=(time_buf[1]&0x0f);dis_time_buf[4]=(time_buf[2]>>4); // 月dis_time_buf[5]=(time_buf[2]&0x0f);dis_time_buf[6]=(time_buf[3]>>4); // 日dis_time_buf[7]=(time_buf[3]&0x0f);dis_time_buf[14]=(time_buf[7]&0x07); // 星期// 第 2 行显示dis_time_buf[8]=(time_buf[4]>>4); // 时dis_time_buf[9]=(time_buf[4]&0x0f);dis_time_buf[10]=(time_buf[5]>>4); // 分dis_time_buf[11]=(time_buf[5]&0x0f);dis_time_buf[12]=(time_buf[6]>>4); // 秒dis_time_buf[13]=(time_buf[6]&0x0f);}}// 定时器 2 初始化void Init_timer2(void){RCAP2H=0x3c;〃赋T2初始值0x3cb0,溢出20次为1秒,每次溢出时间为50ms RCAP2L=0xb0;TR2=1; //启动定时器 2ET2=1; // 打开定时器 2 中断EA=1; // 打开总中断}// 主函数void main(void){Delay_xms(50);// 等待系统稳定LCD_init(); //LCD 初始化LCD_clear(); // 清屏ds1302_init(); //DS1302 初始化Delay_xms(10);ds1302_write_time(); // 写入初始值Init_timer2(); // 定时器 2 初始化while(1){Display();}。
基于51单片机DS1302LCD1602数字时钟显示
#include <intrins.h>
#include <string.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]="I LIKE MCU!";
sbit RS=P2^0;
dispaly_string(0x00,lcd_buffer1);
dispaly_string(0x40,lcd_buffer2);
}
}
delay(5);
}
void write_a_byte_tods1302(uchar x)
{
uchar i;
for(i=0;i<8;i++)
{
IO=x&0x01;
sclk=1;
sclk=0;
x=x>>1;
}
}
uchar get_a_byte_fromds1302()
{
uchar i,b=0x00;
for(i=0;i<8;i++)
uchar lcd_buffer2[]={"TIME 00:00:00 "};
uchar datetime[7];
void delay(uchar ms)
{
uchar i;
while(ms--)
for(i=0;i<120;i++);
}
//忙检测
uchar busy()
{
uchar test;
RW=1;
{
51单片机实现基于DS1302_1602_18B20的多功能电子时钟_带测温功能
#include<reg51.h>#define uchar unsigned char#define uint unsigned int/*------------------寄存器地址定义------------*/#define WRITE_SECOND 0x80#define WRITE_MINUTE 0x82#define WRITE_HOUR 0x84#define WRITE_DAY 0x86#define WRITE_MONTH 0x88#define WRITE_YEAR 0x8C#define WRITE_PROTECT 0x8E#define WRITE_WEEK 0x8A#define WRITE_CURRENT 0x90#define READ_SECOND 0x81#define READ_MINUTE 0x83#define READ_HOUR 0x85#define READ_DAY 0x87#define READ_MONTH 0x89#define READ_WEEK 0x8B#define READ_YEAR 0x8Dsbit RST=P3^5; //DS1302片选sbit DIO=P3^4; //DS1302数据信号sbit SCLK=P3^6; //DS1302时钟信号sbit ACC7=ACC^7;sbit ACC0=ACC^0;unsigned char count;sbit beep=P1^4;void INITIAL_1302();unsigned char READ_1302(unsigned char addr);void WRITE_1302(unsigned char addr,unsigned char date); sbit LCD_E=P2^7; //液晶使能端sbit LCD_RS=P2^6; //液晶数据命令选择端sbit LCD_RW=P2^5; //液晶读写选择端sbit key0=P3^2; //功能键sbit key1=P3^3; //增大键sbit key2=P3^4; //减小键sbit DQ=P3^7; //18b20温度输入输出端char hour,minute,second,week,day,month,year,tem; unsigned char num,flag;unsigned char str1[]=" 20 - - ";unsigned char str2[]=" : : C";void delay(unsigned char z);void LCD_WRITE_COM(unsigned char com);void LCD_WRITE_DA TA(unsigned char date);void LCD_WRITE_SFM(unsigned char addr,unsigned char date);void LCD_WRITE_NYR(unsigned char addr,unsigned char date);void LCD_WRITE_WEEK(unsigned char week);void LCD_INITIAL();void LCD_WRITE_TEMP(uchar addr,uchar temp);void keyscan();void INITIAL_TEMER0();uchar TMPH ,TMPL;void w1602c(uchar com);void w1602d(uchar data01);void delay2(uint ms);void delay3(uint us);uchar resert(void);uchar read_byte();void write_byte(uchar val);uint get_temp();void display();void delay3(uint us); //18b20uchar resert(void); //18b20uchar read_byte(); //18b20void write_byte(uchar val); //18b20uint get_temp(); //18b20void main(){LCD_INITIAL(); //液晶初始化INITIAL_1302(); //DS1302初始化INITIAL_TEMER0(); //定时器初始化while(1){keyscan(); //按键扫描if(flag==0) //当标志位为0,允许读取DS1302数据,将数据送入液晶显示{second=READ_1302(0x81);LCD_WRITE_SFM(10,second);minute=READ_1302(0x83);LCD_WRITE_SFM(7,minute);hour=READ_1302(0x85);LCD_WRITE_SFM(4,hour);week=READ_1302(0x8b);LCD_WRITE_WEEK(week);day=READ_1302(0x87);LCD_WRITE_NYR(9,day);month=READ_1302(0x89);LCD_WRITE_NYR(6,month);year=READ_1302(0x8d);LCD_WRITE_NYR(3,year);tem=get_temp();LCD_WRITE_TEMP(13,tem);}}}/**********************1602BU份******************************************************/void delay(unsigned char z) //1602de延时函数{unsigned char x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void LCD_WRITE_COM(unsigned char com){LCD_RS=0;LCD_RW=0;LCD_E=1;P0=com;delay(5);LCD_E=0;}void LCD_WRITE_DA TA(unsigned char date){LCD_RS=1;LCD_RW=0;LCD_E=1;P0=date;delay(5);LCD_E=0;}void LCD_WRITE_SFM(unsigned char addr,unsigned char date) {unsigned char shi,ge;shi=date/10;ge=date%10;LCD_WRITE_COM(0x80+0x40+addr);LCD_WRITE_DATA(0x30+shi);LCD_WRITE_DATA(0x30+ge);}void LCD_WRITE_NYR(unsigned char addr,unsigned char date) {char shi,ge;shi=date/10;ge=date%10;LCD_WRITE_COM(0x80+addr);LCD_WRITE_DATA(0x30+shi);LCD_WRITE_DATA(0x30+ge);}void LCD_WRITE_WEEK(unsigned char week){LCD_WRITE_COM(0x80+12);switch(week){case 1: LCD_WRITE_DA TA('M');delay(5);LCD_WRITE_DATA('O');delay(5);;LCD_WRITE_DATA('N');break;case 2: LCD_WRITE_DA TA('T');delay(5);LCD_WRITE_DATA('U');delay(5);LCD_WRITE_DATA('E');break;case 3: LCD_WRITE_DA TA('W');delay(5);LCD_WRITE_DATA('E');delay(5);LCD_WRITE_DATA('D');break;case 4: LCD_WRITE_DA TA('T');delay(5);LCD_WRITE_DATA('H');delay(5);LCD_WRITE_DATA('U');break;case 5: LCD_WRITE_DA TA('F');delay(5);LCD_WRITE_DATA('R');delay(5);LCD_WRITE_DATA('I');break;case 6: LCD_WRITE_DA TA('S');delay(5);LCD_WRITE_DATA('A');delay(5);LCD_WRITE_DATA('T');break;case 7: LCD_WRITE_DA TA('S');delay(5);LCD_WRITE_DATA('U');delay(5);LCD_WRITE_DATA('N');break;}}void LCD_WRITE_TEMP(uchar addr,uchar temp){char shi,ge;shi=temp/10;ge=temp%10;LCD_WRITE_COM(0x80+0x40+addr);LCD_WRITE_DATA(0x30+shi);LCD_WRITE_DATA(0x30+ge);}void LCD_INITIAL(){unsigned char i;LCD_WRITE_COM(0x38);LCD_WRITE_COM(0x0c);LCD_WRITE_COM(0x06); //经本人试验证明1602初始化不清屏也可实现LCD_WRITE_COM(0x80);for(i=0;i<16;i++){LCD_WRITE_DATA(str1[i]);delay(5);}LCD_WRITE_COM(0x80+0x40);//液晶第二行显示for(i=0;i<16;i++){LCD_WRITE_DATA(str2[i]);delay(5);}}/***************************1302部分***************************************************/void WRITE_1302(unsigned char addr,unsigned char date) {unsigned char i;RST=0;SCLK=0;RST=1;for(i=8;i>0;i--){SCLK=0;ACC=addr;DIO=ACC0;addr>>=1;SCLK=1;}for(i=8;i>0;i--){SCLK=0;ACC=date;DIO=ACC0;date>>=1;SCLK=1;}RST=0;}unsigned char READ_1302(unsigned char addr){unsigned char i,date1,date2;RST=0;SCLK=0;RST=1;for(i=8;i>0;i--){SCLK=0;ACC=addr;DIO=ACC0;addr>>=1;SCLK=1;}for(i=8;i>0;i--){ACC7=DIO;SCLK=1;ACC>>=1;SCLK=0;}RST=0;date1=ACC;date2=date1/16;date1=date1%16;date1=date1+date2*10;return(date1) ;}void INITIAL_1302(){WRITE_1302(WRITE_SECOND,READ_1302(READ_SECOND)&0x7f); //启动DS1302}/**************************键盘扫描部分***************************************************/void keyscan(){if(key0==0)//确认功能键按下{delay(20);if(key0==0)//去抖{while(!key0);//释放num++;switch(num){case 1: flag=1; //修改时间,禁止从DS1302读数据TR0=0; //定时器关LCD_WRITE_COM(0x0f); //光标开始闪烁LCD_WRITE_COM(0x80+3);//第一次按下,光标定位到年位置break;case 2: LCD_WRITE_COM(0x80+6);//第二次按下,光标定位到月位置break;case 3: LCD_WRITE_COM(0x80+9);//第三次按下,光标定位到日位置break;case 4: LCD_WRITE_COM(0x80+12);//第四次按下,光标定位到星期位置break;case 5: LCD_WRITE_COM(0x80+0x40+4);//第五次按下,光标定位到时位置break;case 6: LCD_WRITE_COM(0x80+0x40+7);//第六次按下,光标定位到分位置break;case 7: LCD_WRITE_COM(0x80+0x40+10);//第七次按下,光标定位到秒位置break;case 8: num=0;//第八次按下,记录清零LCD_WRITE_COM(0x0c);//不显示光标WRITE_1302(WRITE_PROTECT,0x00); //允许写操作WRITE_1302(0x80,(second/10*16)+second%10);//将调节后的秒写入DS1302WRITE_1302(0x82,(minute/10*16)+minute%10);//将调节后的分写入DS1302WRITE_1302(0x84,(hour/10*16)+hour%10);//将调节后的时写入DS1302WRITE_1302(0x8a,(week/10*16)+week%10);//将调节后的星期写入DS1302WRITE_1302(0x86,(day/10*16)+day%10);//将调节后的日写入DS1302WRITE_1302(0x88,(month/10*16)+month%10);//将调节后的月写入DS1302WRITE_1302(0x8c,(year/10*16)+year%10);//将调节后的年写入DS1302WRITE_1302(WRITE_PROTECT,0x80); //开写保护flag=0; //时间修改完毕,允许液晶从DS1302读数据TR0=1;break;}}}if(num!=0){if(key1==0)//确认增大键按下{delay(20);if(key1==0)//增大键确实按下{while(!key1);switch(num){case 1: year++;//调节年if(year==100)year=0;LCD_WRITE_NYR(3,year);//将调节后的年送入液晶显示LCD_WRITE_COM(0x80+3);//光标回到指定处break;case 2: month++;//调节月if(month==13)month=0;LCD_WRITE_NYR(6,month);//将调节后的月送入液晶显示LCD_WRITE_COM(0x80+6);//光标回到指定处break;case 3: day++;//调节日if(day==32)day=0;LCD_WRITE_NYR(9,day);//将调节后的日送入液晶显示LCD_WRITE_COM(0x80+9);//光标回到指定处break;case 4: week++;if(week==8)week=0;LCD_WRITE_WEEK(week);//将调节后的星期送入液晶显示LCD_WRITE_COM(0x80+12);//光标回到指定处break;case 5: hour++;if(hour==24)hour=0;LCD_WRITE_SFM(4,hour);//将调节后的小时送入液晶显示LCD_WRITE_COM(0x80+0x40+4);//光标回到指定处break;case 6: minute++;if(minute==60)minute=0;LCD_WRITE_SFM(7,minute);//将调节后的分送入液晶显示LCD_WRITE_COM(0x80+0x40+7);//光标回到指定处break;case 7: second++;if(second==60)second=0;LCD_WRITE_SFM(10,second);//将调节后的秒送入液晶显示LCD_WRITE_COM(0x80+0x40+10);//光标回到指定处break;default:break;}}}if(key2==0)//确认减小键按下{delay(20);if(key2==0)//减小键确实按下{while(!key2);switch(num){case 1: year--;//调节年if(year==-1)year=99;LCD_WRITE_NYR(3,year);LCD_WRITE_COM(0x80+3);break;case 2: month--;//调节月if(month==-1)month=12;LCD_WRITE_NYR(6,month);LCD_WRITE_COM(0x80+6);break;case 3: day--;//调节日if(day==-1)day=31;LCD_WRITE_NYR(9,day);LCD_WRITE_COM(0x80+9);break;case 4: week--;//调节星期if(week==0)week=7;LCD_WRITE_WEEK(week);LCD_WRITE_COM(0x80+12);break;case 5: hour--;//调节时if(hour==-1)hour=23;LCD_WRITE_SFM(4,hour);LCD_WRITE_COM(0x80+0x40+4);break;case 6: minute--;//调节分if(minute==-1)minute=59;LCD_WRITE_SFM(7,minute);LCD_WRITE_COM(0x80+0x40+7);break;case 7: second--;//调节秒if(second==-1)second=59;LCD_WRITE_SFM(10,second);LCD_WRITE_COM(0x80+0x40+10);break;default:break;}}}}}/*******************************蜂鸣器部分******************************************//*-----------定时器0初始化-------------------------*/void INITIAL_TEMER0(){TMOD=0x01;TH0=(65536-20000)/256;TL0=(65536-20000)%256; //晶振频率12MHZ 定时20ms作右TR0=1;EA=1;ET0=1;}/*-------------------------------------------*/void timer0()interrupt 1{TH0=(65536-20000)/256;TL0=(65536-20000)%256; //重装count++;if(count==50) //1秒到{count=0;beep=0; //蜂鸣器响delay(5);beep=1; //蜂鸣器灭}if(tem>=30){beep=0;}}/*****************************18b20部分*********************************************888*/void delay3(uint us){uint s;for(s=0;s<us;s++);}uchar resert(void){uchar ready;DQ=0;delay3(32) ;DQ=1;delay3(3);ready=DQ;delay3(25);return ready;}uchar read_byte(){uchar i,j;uchar value=0;for(i=0;i<8;i++){DQ=0;DQ=1;for(j=0;j<3;j++);if(DQ){value|=0x01<<i;}delay3(6) ;}return value;}void write_byte(uchar val) {uchar i,temp;for(i=0;i<8;i++){temp=val>>i;temp=temp&0x01;DQ=0;if(temp==1)DQ=1;delay3(5);DQ=1;}DQ=1;}uint get_temp(){float f_temp;uint temp;P2=0x00;resert();delay3(50);write_byte(0xcc);write_byte(0x44);resert();write_byte(0xcc);write_byte(0xbe);TMPL = read_byte();TMPH = read_byte();temp = TMPH;temp <<= 8;TMPL=TMPL&0xf0;temp = temp | TMPL;f_temp=temp*0.0625;temp=f_temp;return temp;}。
DS1302时钟芯片与液晶1602程序
#include<reg52.h>#define wri_sec 0x80#define wri_min 0x82#define wri_hour 0x84#define wri_day 0x86#define wri_mon 0x88#define wri_week 0x8a#define wri_year 0x8c#define re_sec 0x81#define re_min 0x83#define re_hour 0x85#define re_day 0x87#define re_mon 0x89#define re_week 0x8b#define re_year 0x8d#define wri_pro 0x8e#define uchar unsigned char#define uint unsigned intsbit SCLK=P3^5;sbit DIO=P3^6;sbit CE=P3^7;sbit lcden=P1^0;sbit lcdrs=P1^2;sbit lcdrw=P1^1;uchar weeks[7][3]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"}; static uchar datatime[7]={0};void delay(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void write1302(uchar addr,dat){uchar i,temp;CE=0;SCLK=0;CE=1;for(i=0;i<8;i++){SCLK=0;temp=addr;DIO=(bit)(temp&0x01);addr>>=1;SCLK=1;}for(i=0;i<8;i++){SCLK=0;temp=dat;DIO=(bit)(temp&0x01);dat>>=1;SCLK=1;}CE=0;}uchar read1302(uchar addr){uchar i,temp, dat1,dat2;dat1=0;CE=0;SCLK=0;CE=1;for(i=8;i>0;i--){SCLK=0;temp=addr;DIO=(bit)(temp&0x01);addr>>=1;SCLK=1;}SCLK=0;for(i=8;i>0;i--){DIO=1;dat1>>=1;if(DIO) dat1|=0x80;SCLK=1;delay(5);SCLK=0;}dat2=dat1/16;dat1=dat1%16;dat1=dat2*10+dat1;return(dat1);}void init1302() //初始化{write1302(wri_pro,0x00); //允许写write1302(wri_sec,0x12);// write1302(wri_min,0x23);// write1302(wri_hour,0x16);// write1302(wri_day,0x17);// write1302(wri_mon,0x11);// write1302(wri_year,0x10);// write1302(wri_week,0x03);write1302(wri_pro,0x80); //禁止写}void write_com(uchar com) //lcd写命令{lcdrw=0;lcdrs=0;P0=com;delay(5);lcden=1;delay(5);lcden=0;}void write_data(uchar date) //lcd{lcdrw=0;lcdrs=1;P0=date;delay(5);lcden=1;delay(5);lcden=0;}void init_lcd() //lcd初始化{uint dat1,dat2;uint i;lcden=0;write_com(0x38);write_com(0x0f);write_com(0x06);write_com(0x01);write_com(0x81);write_data('2');delay(20);write_data('0');delay(20);write1302(wri_pro,0x00);datatime[6]=read1302(re_year);dat2=datatime[6]/10;dat1=datatime[6]%10;write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);write_data(45);delay(20);datatime[5]=read1302(re_mon);dat2=datatime[5]/10;dat1=datatime[5]%10;write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);write_data(45);delay(20);datatime[4]=read1302(re_day);dat2=datatime[4]/10;dat1=datatime[4]%10;write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);write_data(32);delay(20);datatime[3]=read1302(re_week);for (i=0;i<3;i++){write_data(weeks[datatime[3]-1][i]);delay(20);}write_com(0x80+0x43);datatime[2]=read1302(re_hour);dat2=datatime[2]/10;dat1=datatime[2]%10;write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);write_data(58);delay(20);datatime[1]=read1302(re_min);dat2=datatime[1]/10;dat1=datatime[1]%10;write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);write_data(39);delay(20);datatime[0]=read1302(re_sec);dat2=datatime[0]/10;dat1=datatime[0]%10;write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);write_data(34);delay(20);write1302(wri_pro,0x80);}void refresh() //更新时间{uchar sec,min,hou,day,mon,yea,wee,dat1,dat2;uint i;write1302(wri_pro,0x00);sec=read1302(re_sec);if(sec!=datatime[0]){datatime[0]=sec;dat2=datatime[0]/10;dat1=datatime[0]%10;write_com(0x80+0x49);delay(50);write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);if(!sec){min=read1302(re_min);datatime[1]=min;dat2=datatime[1]/10;dat1=datatime[1]%10;write_com(0x80+0x46);delay(5);write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);if(!min){hou=read1302(re_hour);datatime[2]=hou;dat2=datatime[2]/10;dat1=datatime[2]%10;write_com(0x80+0x43);delay(5);write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);if(!hou){wee=read1302(re_week);datatime[3]=wee;write_com(0x80+0x0c);delay(5);for (i=0;i<3;i++){write_data(weeks[datatime[3]-1][i]);delay(20);}day=read1302(re_day);datatime[4]=day;dat2=datatime[4]/10;dat1=datatime[4]%10;write_com(0x80+0x09);delay(5);write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);if(day==1){mon=read1302(re_mon);datatime[5]=mon;dat2=datatime[5]/10;dat1=datatime[5]%10;write_com(0x80+0x06);delay(5);write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);if(mon==1){yea=read1302(re_year);datatime[6]=yea;dat2=datatime[6]/10;dat1=datatime[6]%10;write_com(0x80+0x03);delay(5);write_data(48+dat2);delay(20);write_data(48+dat1);delay(20);}}}}}}write1302(wri_pro,0x80);}void readkey() //查键{uchar key,n,dat1,dat2;uint i;key=P2;delay(10);if(key==0xfe){key=P2;delay(20);n=1;while(1){if(n==1){n=0;write_com(0x83); //修改年write1302(wri_pro,0x00);dat1=read1302(re_year);dat2=dat1/10;dat1=dat1%10;key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd:if(dat2==9) dat2=0;else dat2++;write_data(48+dat2);delay(20);write_com(0x83);break;case 0xfb: if(dat2==0) dat2=9;else dat2--;write_data(48+dat2);delay(20);write_com(0x83);break;default: break;}key=P2;delay(10);}delay(200);write_com(0x84);key=P2;delay(20);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat1==9) dat1=0;else dat1++;write_data(48+dat1);delay(20);write_com(0x84);break;case 0xfb: if(dat1==0) dat1=9;else dat1--;write_data(48+dat1);delay(20);write_com(0x84);break;default: break;}key=P2;delay(10);}dat1=(dat2<<4)|dat1;write1302(wri_year,dat1);delay(200);write_com(0x86); //修改月dat1=read1302(re_mon);dat2=dat1/10;dat1=dat1%10;key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat2==1) dat2=0;else dat2++;write_data(48+dat2);delay(20);write_com(0x86);break;case 0xfb: if(dat2==0) dat2=1;else dat2--;write_data(48+dat2);delay(20);write_com(0x86);break;default: break;}key=P2;delay(10);}write_com(0x87);delay(200);key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat1==9) dat1=0;else dat1++;write_data(48+dat1);delay(20);write_com(0x87);break;case 0xfb: if(dat1==0) dat1=9;else dat1--;write_data(48+dat1);delay(20);write_com(0x87);break;default: break;}key=P2;delay(10);}dat1=(dat2<<4)|dat1;write1302(wri_mon,dat1);delay(200);write_com(0x89); //修改日dat1=read1302(re_day);dat2=dat1/10;dat1=dat1%10;key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat2==3) dat2=0;else dat2++;write_data(48+dat2);delay(20);write_com(0x89);break;case 0xfb: if(dat2==0) dat2=3;else dat2--;write_data(48+dat2);delay(20);write_com(0x89);break;default: break;}key=P2;delay(10);}write_com(0x8a);delay(200);key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat1==9) dat1=0;else dat1++;write_data(48+dat1);delay(20);write_com(0x8a);break;case 0xfb: if(dat1==0) dat1=9;else dat1--;write_data(48+dat1);delay(20);write_com(0x8a);break;default: break;}key=P2;delay(10);}dat1=(dat2<<4)|dat1;write1302(wri_day,dat1);delay(200);write_com(0x8c); //修改星期dat1=read1302(re_week);key=P2;delay(20);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat1==7) dat1=1;else dat1++;for(i=0;i<3;i++){write_data(weeks[dat1-1][i]);delay(20);}write_com(0x8c);break;case 0xfb: if(dat1==1) dat1=7;else dat1--;for(i=0;i<3;i++){write_data(weeks[dat1-1][i]);delay(20);}write_com(0x8c);break;}key=P2;delay(10);}write1302(wri_week,dat1);delay(200);write_com(0x80+0x43); //修改时dat1=read1302(re_hour);dat2=dat1/10;dat1=dat1%10;key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat2==2) dat2=0;else dat2++;write_data(48+dat2);delay(20);write_com(0x80+0x43);break;case 0xfb: if(dat2==0) dat2=2;else dat2--;write_data(48+dat2);delay(20);write_com(0x80+0x43);break;default: break;}key=P2;delay(10);}write_com(0x80+0x44);delay(200);key=P2;delay(20);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat1==9) dat1=0;else dat1++;write_data(48+dat1);delay(20);write_com(0x80+0x44);break;case 0xfb: if(dat1==0) dat1=9;else dat1--;write_data(48+dat1);delay(20);write_com(0x80+0x44);break;default: break;}key=P2;delay(10);}dat1=(dat2<<4)|dat1;write1302(wri_hour,dat1);delay(250);write_com(0x80+0x46); //修改分dat1=read1302(re_min);dat2=dat1/10;dat1=dat1%10;key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat2==5) dat2=0;else dat2++;write_data(48+dat2);delay(20);write_com(0x80+0x46);break;case 0xfb: if(dat2==0) dat2=5;else dat2--;write_data(48+dat2);delay(20);write_com(0x80+0x46);break;default: break;}key=P2;delay(10);}write_com(0x80+0x47);delay(200);key=P2;delay(20);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat1==9) dat1=0;else dat1++;write_data(48+dat1);delay(20);write_com(0x80+0x47);break;case 0xfb: if(dat1==0) dat1=9;else dat1--;write_data(48+dat1);delay(20);write_com(0x80+0x47);break;default: break;}key=P2;delay(10);}dat1=(dat2<<4)|dat1;write1302(wri_min,dat1);delay(250);write_com(0x80+0x49); //修改秒dat1=read1302(re_sec);dat2=dat1/10;dat1=dat1%10;key=P2;delay(10);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat2==5) dat2=0;else dat2++;write_data(48+dat2);delay(20);write_com(0x80+0x49);break;case 0xfb: if(dat2==0) dat2=5;else dat2--;write_data(48+dat2);delay(20);write_com(0x80+0x49);break;default: break;}key=P2;delay(10);}write_com(0x80+0x4a);delay(200);key=P2;delay(20);while(key!=0xf7){delay(200);switch(key){case 0xfd: if(dat1==9) dat1=0;else dat1++;write_data(48+dat1);delay(20);write_com(0x80+0x4a);break;case 0xfb: if(dat1==0) dat1=9;else dat1--;write_data(48+dat1);delay(20);write_com(0x80+0x4a);break;default: break;}key=P2;delay(10);}dat1=(dat2<<4)|dat1;write1302(wri_sec,dat1);write_com(0x80+0x4d);write1302(wri_pro,0x80);}break;}}}void main(){init1302();init_lcd();while(1){refresh();readkey();write_com(0x80+0x50);}}。
电子时钟程序DS1302时钟芯片lcd1602
date=Read1302();
SCLK=1;
REST=0;
return date;
}
void IntDS1302(void) //DS1302初始化
{
unsigned char flag;
flag= ReadSet1302(0x81);
/*液晶忙检测*/
bit BusyTest(void)
{
bit result;
RS=0;
RW=1;
E=1;
_nop_();
_nop_();
_nop_();
result=BF;
_nop_();
_nop_();
_nop_();
E=0;
return result;
delay1ms(1);
Write_com(0x0c);
delay1ms(1);
Write_com(0x01);
}
void displaymainpart(void)//显示液晶主要部分(不变化部分)
{
Write_Address(0x01);
delay1ms(1);
{
unsigned char i,j;
i=day/10;
j=day%10;
Write_Address(0x0E);
Write_Date(dit[j]);
delay1ms(1);
}
void display_Month(unsigned char month) //在液晶上显示月
_nop_();
E=1;
_nop_();
基于51单片机DS1302LCD1602数字时钟显示
dispaly_string(0x40,lcd_buffer2);
}
}
sbit RW=P2^1;
sbit EN=P2^2;
sbit IO=P1^0;
sbit sclk=P1^1;
sbit rst=P1^2;
uchar *week[]={"SUN","****","MON","TUS","WEN","THU","FRI","SAT"};
uchar lcd_buffer1[]={"DATE 00-00-00 "};
delay(5);
}
void write_a_byte_tods1302(uchar x)
{
uchar i;
for(i=0;i<8;i++)
{
IO=x&0x01;
sclk=1;
sclk=0;
x=x>>1;
}
}
uchar get_a_byte_fromds1302()
{
uchar i,b=0x00;
for(i=0;i<8;i++)
a[1]=d%10+'0';
}
void main()
{
init();
while(1)
{
gettime();
zhuanhuan(datetime[6],lcd_buffer1+5);
zhuanhuan(datetime[4],lcd_buffer1+8);
基于51单片机与DS1302时钟芯片和LCD1602液晶显示的数字时钟
PROTEUS仿真图:KEIL C程序:#include <REGX52.H>#include "LCD1602.h"#include "DS1302.h"void Delay1ms(unsigned int count) {unsigned int i,j;for(i=0;i<count;i++)for(j=0;j<120;j++);}main(){SYSTEMTIME CurrentTime;LCD_Initial();Initial_DS1302();GotoXY(0,0);Print(" tian ma dian zi");GotoXY(0,1);Print("Time: ");while(1){DS1302_GetTime(&CurrentTime);TimeToStr(&CurrentTime);GotoXY(6,1);Print(CurrentTime.TimeString);Delay1ms(400);}}#ifndef LCD_CHAR_1602_2005_4_9#define LCD_CHAR_1602_2005_4_9#include <intrins.h>//Port Definitions********************************************************** sbit LcdRs = P2^0;sbit LcdRw = P2^1;sbit LcdEn = P2^2;sfr DBPort = 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口//内部等待函数************************************************************************** unsigned char LCD_Wait(void){LcdRs=0;LcdRw=1; _nop_();LcdEn=1; _nop_();//while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用GotoXY()时,会进入死循环,//可能在写该控制字时,该模块没有返回写入完备命令,即DBPort&0x80==0x80//实际硬件时打开此语句LcdEn=0;return DBPort;}//向LCD写入命令或数据************************************************************#define LCD_COMMAND 0 // Command#define LCD_DATA 1 // Data#define LCD_CLEAR_SCREEN 0x01 // 清屏#define LCD_HOMING 0x02 // 光标返回原点void LCD_Write(bit style, unsigned char input){LcdEn=0;LcdRs=style;LcdRw=0; _nop_();DBPort=input; _nop_();//注意顺序LcdEn=1; _nop_();//注意顺序LcdEn=0; _nop_();LCD_Wait();}//设置显示模式************************************************************ #define LCD_SHOW 0x04 //显示开#define LCD_HIDE 0x00 //显示关#define LCD_CURSOR 0x02 //显示光标#define LCD_NO_CURSOR 0x00 //无光标#define LCD_FLASH 0x01 //光标闪动#define LCD_NO_FLASH 0x00 //光标不闪动void LCD_SetDisplay(unsigned char DisplayMode){LCD_Write(LCD_COMMAND, 0x08|DisplayMode);}//设置输入模式************************************************************ #define LCD_AC_UP 0x02#define LCD_AC_DOWN 0x00 // default#define LCD_MOVE 0x01 // 画面可平移#define LCD_NO_MOVE 0x00 //defaultvoid LCD_SetInput(unsigned char InputMode){LCD_Write(LCD_COMMAND, 0x04|InputMode);}//移动光标或屏幕************************************************************ /*#define LCD_CURSOR 0x02#define LCD_SCREEN 0x08#define LCD_LEFT 0x00#define LCD_RIGHT 0x04void LCD_Move(unsigned char object, unsigned char direction){if(object==LCD_CURSOR)LCD_Write(LCD_COMMAND,0x10|direction);if(object==LCD_SCREEN)LCD_Write(LCD_COMMAND,0x18|direction);}*///初始化LCD************************************************************ void LCD_Initial(){LcdEn=0;LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵LCD_Write(LCD_COMMAND,0x38);LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动}//************************************************************************ void GotoXY(unsigned char x, unsigned char y){if(y==0)LCD_Write(LCD_COMMAND,0x80|x);if(y==1)LCD_Write(LCD_COMMAND,0x80|(x-0x40));}void Print(unsigned char *str){while(*str!='\0'){LCD_Write(LCD_DATA,*str);str++;}}/*void LCD_LoadChar(unsigned char user[8], unsigned char place){unsigned char i;LCD_Write(LCD_COMMAND,0x40|(place*8));for(i=0; i<8; i++)LCD_Write(LCD_DATA,user[i]);}*///************************************************************************ #endif#ifndef _REAL_TIMER_DS1302_2003_7_21_#define _REAL_TIMER_DS1302_2003_7_21_sbit DS1302_CLK = P1^6; //实时时钟时钟线引脚sbit DS1302_IO = P1^7; //实时时钟数据线引脚sbit DS1302_RST = P1^5; //实时时钟复位线引脚sbit ACC0 = ACC^0;sbit ACC7 = ACC^7;typedef struct __SYSTEMTIME__{unsigned char Second;unsigned char Minute;unsigned char Hour;unsigned char Week;unsigned char Day;unsigned char Month;unsigned char Year;unsigned char DateString[9];unsigned char TimeString[9];}SYSTEMTIME; //定义的时间类型#define AM(X) X#define PM(X) (X+12) // 转成24小时制#define DS1302_SECOND 0x80#define DS1302_MINUTE 0x82#define DS1302_HOUR 0x84#define DS1302_WEEK 0x8A#define DS1302_DAY 0x86#define DS1302_MONTH 0x88#define DS1302_YEAR 0x8C#define DS1302_RAM(X) (0xC0+(X)*2) //用于计算 DS1302_RAM 地址的宏void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数) {unsigned char i;ACC = d;for(i=8; i>0; i--){DS1302_IO = ACC0; //相当于汇编中的 RRCDS1302_CLK = 1;DS1302_CLK = 0;ACC = ACC >> 1;}}unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数){unsigned char i;for(i=8; i>0; i--){ACC = ACC >>1; //相当于汇编中的 RRCACC7 = DS1302_IO;DS1302_CLK = 1;DS1302_CLK = 0;}return(ACC);}void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据{DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr); // 地址,命令DS1302InputByte(ucDa); // 写1Byte数据DS1302_CLK = 1;DS1302_RST = 0;}unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据{unsigned char ucData;DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr|0x01); // 地址,命令ucData = DS1302OutputByte(); // 读1Byte数据DS1302_CLK = 1;DS1302_RST = 0;return(ucData);}void DS1302_SetProtect(bit flag) //是否写保护{if(flag)Write1302(0x8E,0x10);elseWrite1302(0x8E,0x00);}void DS1302_SetTime(unsigned char Address, unsigned char Value) // 设置时间函数{DS1302_SetProtect(0);Write1302(Address, ((Value/10)<<4 | (Value%10)));}void DS1302_GetTime(SYSTEMTIME *Time){unsigned char ReadValue;ReadValue = Read1302(DS1302_SECOND);Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MINUTE);Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_HOUR);Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_DAY);Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_WEEK);Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MONTH);Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_YEAR);Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);}void DateToStr(SYSTEMTIME *Time){Time->DateString[0] = Time->Year/10 + '0';Time->DateString[1] = Time->Year%10 + '0';Time->DateString[2] = '-';Time->DateString[3] = Time->Month/10 + '0';Time->DateString[4] = Time->Month%10 + '0';Time->DateString[5] = '-';Time->DateString[6] = Time->Day/10 + '0';Time->DateString[7] = Time->Day%10 + '0';Time->DateString[8] = '\0';}void TimeToStr(SYSTEMTIME *Time){Time->TimeString[0] = Time->Hour/10 + '0';Time->TimeString[1] = Time->Hour%10 + '0';Time->TimeString[2] = ':';Time->TimeString[3] = Time->Minute/10 + '0';Time->TimeString[4] = Time->Minute%10 + '0';Time->TimeString[5] = ':';Time->TimeString[6] = Time->Second/10 + '0';Time->TimeString[7] = Time->Second%10 + '0';Time->DateString[8] = '\0';}void Initial_DS1302(void){unsigned char Second=Read1302(DS1302_SECOND);if(Second&0x80)DS1302_SetTime(DS1302_SECOND,0);}/****************************************************************************** **void BurstWrite1302(unsigned char *pWClock) //往DS1302写入时钟数据(多字节方式) {unsigned char i;Write1302(0x8e,0x00); // 控制命令,WP=0,写操作?DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(0xbe); // 0xbe:时钟多字节写命令for (i = 8; i>0; i--) //8Byte = 7Byte 时钟数据 + 1Byte 控制{DS1302InputByte(*pWClock); // 写1Byte数据pWClock++;}DS1302_CLK = 1;DS1302_RST = 0;}void BurstRead1302(unsigned char *pRClock) //读取DS1302时钟数据(时钟多字节方式){unsigned char i;DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(0xbf); // 0xbf:时钟多字节读命令for (i=8; i>0; i--){*pRClock = DS1302OutputByte(); // 读1Byte数据pRClock++;}DS1302_CLK = 1;DS1302_RST = 0;}void DS1302_TimeStop(bit flag) // 是否将时钟停止{unsigned char Data;Data=Read1302(DS1302_SECOND);DS1302_SetProtect(0);if(flag)Write1302(DS1302_SECOND, Data|0x80);elseWrite1302(DS1302_SECOND, Data&0x7F);}******************************************************************************* */#endif。
DS1302+1602时钟程序
//寄存器选择位,将 RS 位定义为 P2.0 引脚 //读写选择位,将 RW 位定义为 P2.1 引脚 //使能信号位,将 E 位定义为 P2.2 引脚 //忙碌标志位,,将 BF 位定义为 P0.7 引脚
/***************************************************** 函数功能:延时 1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒
***************************************************/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/***************************************************** 函数功能:延时若干毫秒
for(i=0;i<8;i++) //连续读 8 个二进制位数据
{ dat>>=1;
if(DATA==1) //如果读出的数据是 1
dat|=0x80; //将 1 取出,写在 dat 的最高位
SCLK=1;
//将 SCLK 置于高电平,为下降沿读出
delaynus(2); //稍微等待
SCLK=0;
WriteSet1302(0x90,0xa5);
//打开充电功能 选择 2K 电阻充电方式
WriteSet1302(0x8E,0x80);
//根据写状态寄存器命令字,写入保护指令
*/
基于ds1302的51单片机简易实时时钟-1602显示-源程序
==================主程序================= #include <reg51.h>。
#include "ds1302.h"#include "LCD1602.h"void change();uchar times[9];uchar date[9];main(){LCD_init();//LCD初始化init_1302(time_1302);gotoxy(1,1);LCD_display("Time:");gotoxy(1,2);LCD_display("Date:");times[8]='\0';//date[8]='\0';while(1){get_1302(time_1302);change();gotoxy(7,1);LCD_display(times);gotoxy(7,2);LCD_display(date);}}/*=========================== 转换子程序===========================*/void change(){// 时间的转换times[0]=time_1302[2]/10+'0';times[1]=time_1302[2]%10+'0';times[2]=':';times[3]=time_1302[1]/10+'0';times[4]=time_1302[1]%10+'0';times[5]=':';times[6]=time_1302[0]/10+'0';times[7]=time_1302[0]%10+'0';// 日期的转换date[0]=time_1302[6]/10+'0';date[1]=time_1302[6]%10+'0';date[2]='-';date[3]=time_1302[4]/10+'0';date[4]=time_1302[4]%10+'0';date[5]='-';date[6]=time_1302[3]/10+'0';date[7]=time_1302[3]%10+'0';}======================================================DS1302驱动程序=============#define uchar unsigned charuchar time_1302[7]={0x00,0x00,0x00,0x03,0x07,0x03,0x08};//设置时间初始值数组// 秒分时号月份星期年sbit T_IO=P1^0; //与硬件相关的连线clk为DS1302的时钟信号线sbit T_CLK=P1^1; //DAT为DS1302的I/O数据线sbit T_RST=P1^2; //RST为DS1302的RST信号线uchar bdata datbyte;sbit datbyte0=datbyte^0;sbit datbyte7=datbyte^7;void get_1302(uchar time[]);void write_ds1302(uchar dat);uchar r_1302(uchar add);void w_1302(uchar add,uchar dat);uchar read_ds1302(void);void init_1302(uchar *time);/*==========================================D S 1 3 0 2 初始化===========================================*/void init_1302(uchar *time){uchar i, add;//uchar time_bcd[7];add=0x80;//0写入,1读出w_1302(0x8e,0x00);for(i=0;i<7;i++){w_1302(add,*time);add+=2;time++;}w_1302(0x8e,0x80);}//===========================// 读取当前时间//===========================void get_1302(uchar time[]){uchar i;uchar add=0x81;w_1302(0x8e,0x00);for(i=0;i<7;i++){time[i]=r_1302(add);add+=2;}w_1302(0x8e,0x80);}/*================================= DS1302写入一个字节(上升沿有效)=================================*/void write_ds1302(uchar dat){uchar i;datbyte=dat;for(i=0;i<8;i++){T_IO=datbyte0;T_CLK=1;T_CLK=0;datbyte=datbyte>>1;}}/*======================================= DS1302读取一个字节(下降沿有效)=======================================*/uchar read_ds1302(void){uchar i;for(i=0;i<8;i++){datbyte=datbyte>>1;datbyte7=T_IO;T_CLK=1;T_CLK=0;}return(datbyte);}/*========================================= 指定位置读取数据=========================================*/uchar r_1302(uchar add){uchar temp,dat1,dat2;T_RST=0;T_CLK=0;T_RST=1;write_ds1302(add);temp=read_ds1302();T_CLK=1;T_RST=0;dat1=temp/16;dat2=temp%16;temp=dat1*10+dat2;return(temp);}/*========================================== 指定位置写入数据==========================================*/void w_1302(uchar add,uchar dat){T_RST=0;T_CLK=0;T_RST=1;write_ds1302(add);write_ds1302(dat/10<<4|dat%10);T_CLK=1;T_RST=0;}=========================================== =============LCD1602驱动程序================#define LCD_DB P0//定义LCD的数据端口sbit LCD_RS=P2^0;sbit LCD_RW=P2^1;sbit LCD_E=P2^2;#define uchar unsigned char#define uint unsigned int//===========延时子函数======================== void delay_lcd(uint x){uint i,j;for(i=x;i>0;i--)for(j=0;j<2;j++);}//==================写指令函数================= void LCD_write_command(uchar command){LCD_DB=command;LCD_RS=0;//指令LCD_RW=0;//写入LCD_E=1;LCD_E=0;delay_lcd(1);//等待执行完毕。
DS1302时钟LCD1602显示
/**************************************************************** ** DS1302时钟******************************************************************/ #include<reg51.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned int//--定义矩阵键盘使用的IO口--//#define GPIO_DIG P0#define GPIO_KEY P1//---定义lcd1602使用的IO口---//#define DB P0//--定义全局变量--//uchar error[]="Error!!!" ;//存放字符串“Error!!!”char KeyValue=-1;//用来存放读取到的键值uchar flag=0;//用来检测是否更改过时间uchar tt0=0;//中断里面的参数uchar beeflag=0;//看看有没有开闹钟//---定义蜂鸣器使用的IO口---//sbit bee=P2^3;//定义LCD1602使用的IO口//sbit LCDE=P2^7;sbit RS=P2^6;sbit RW=P2^5;//---定义ds1302使用的IO口---//sbit DSIO=P3^4; //数据传输口sbit RST=P3^5; //进行传输时,RST必须置高sbit SCLK=P3^6; //上沿读数据,下沿写数据//---DS1302写入和读取时分秒的地址命令---////---秒分时日月周年最低位读写位;-------//uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};//---键盘写入地址-------//uchar kyewrite[] = {0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8d,0xc0,0xc1,0xc3,0xc4,0xc6,0xc7};//用于判断增减//char addorm[]={0x01,0x10,-0x01,-0x10};//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。
1602液晶显示DS1302实时时钟程序要点
#include <reg51.h>#include <intrins.h>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;//设置状态计数标志、按键先前值、按键当前值bit alarm; //标识是否启用闹钟,1--启用,0--关闭sbit rs = P2^0; //LCD数据/命令选择端(H/L)sbit rw = P2^1; //LCD读/写选择端(H/L)sbit ep = P2^2; //LCD使能控制sbit PRE = P1^6; //调整键(k3)sbit SET = P1^7; //调整键(k4)sbit SPK = P3^7;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;}//写入指令到LCDvoid 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;}//写入数据到LCDvoid 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(0x0a); //"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;elseleap=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;elsec=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[4*week];dis_buf1[14]=dis_week[4*week+1];dis_buf1[15]=dis_week[4*week+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]=0x20; //空格if (alarm)dis_buf2[7]=0x01; //alarm=1,显示闹钟启用标致(第二个自定义字符)elsedis_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=0xdc; //Timer0置10ms定时初值dc00H(2^16=65536D,dc00H=56320D)TL0=0x00; //定时时间=(65536-56320)*(1/11.0592)*12=10ms (f0=11.0592Mhz)sec100++;if(sec100 >= 100) //1秒时间 (100*10ms=1000ms=1s){sec100 = 0;pro_timedate();//调用时间和日期处理程序}if(sec&0x01) / /"willar"闪一秒,停一秒update_disbuf(0x00," ",hour,min,sec); //0x0 0表示显示00位置的自定义字符elseupdate_disbuf(0x00,"willar",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;//禁止Timer0IE=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^0x0a){skey = scan_key(); //扫描按键状态if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体{ delay(10); //去按键抖动skey = scan_key(); //转回扫描按键状态if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体{ vkey=skey; //将skey的值付给vkeyif (skey==0x01) //PRE 键按下{ flag++; / /调整标志位加1switch (flag) //将光标置于相应调整位置{cas e 1: lcd_pos(0x49);break; //光标置小时报警设置位置cas e 2: lcd_pos(0x4c);break; //光标置分钟报警设置位置cas e 3: lcd_pos(0x4f);break; //光标置秒时报警设置位置cas e 4: update_disbuf(0x50,"time: ",hour,min,sec);pro_display();lcd_pos(0x05);break; //光标置年调整位置cas e 5: lcd_pos(0x08);break; //光标置月调整位置cas e 6: lcd_pos(0x0b);break; //光标置日调整位置cas e 7: lcd_pos(0x49);break; //光标置时调整位置cas e 8: lcd_pos(0x4c);break; //光标置分调整位置cas e 9: lcd_pos(0x4f);break; //光标置秒调整位置def ault: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(); //初始化LCDlcd_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,ar msec); //更新显示数据pro_display();//调用显示处理lcd_pos(0x47);break;//光标回到原调整位置case 1:armhour++;if (armhour>23) armhour=0;update_disbuf(0x50,"alarm:",armhour,armmin,ar msec); //更新显示数据pro_display();//调用显示处理lcd_pos(0x49);break;//光标回到原调整位置case 2:armmin++;if (armmin>59) armmin=0;update_disbuf(0x50,"alarm:",armhour,armmin,ar msec);pro_display();lcd_pos(0x4c);break;case 3:armsec++;if (armsec>59) armsec=0;update_disbuf(0x50,"alarm:",armhour,armmin,ar msec);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;}//DS1302时钟程序#include <stc89c52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int/******************************************************************** ///少占鱼制作河北正定欢迎您长沙航空职业技术学院//2010 年QQ:411656434//版权所有:#define LCD1602_RS P2_5 //定义引脚#define LCD1602_RW P2_6#define LCD1602_E P2_7#define LCD1602_IO P0#define Busy 0x80 //用于检测LCD1602状态字中的Busy标识const uchar num[]=" 3456789+";uchar code a[] = {" E N v"};void WriteData(uchar DAT);void WriteCommand(uchar command,BuysC);uchar ReadData(void);void Readbusy(void);void LCD1602_Init(void);void DisplayOneChar(uchar X, uchar Y, uchar DData);void Displaystring(uchar X, uchar Y, uchar *DData);void Delay5Ms(void);void Delay400Ms(void);void delayms(uint);void delays(uint m) ;void delayus(uchar x) ;sbit DS1302_CLK =P2^0;// P1^0;sbit DS1302_IO =P2^1;// P1^1;sbit DS1302_RST =P2^2;// P1^2;uchar shuju;unsigned char time[]={0x11,0x03,0x28,0x01,0x12,0x39,0x00};// 初始化时间年月日星期时分秒uchar Display_Buffer[12]={"12:25:00"};//时、分、秒的格式uchar riqi[12]={"11-03-28"};//年、月、日的格式uchar xingqi[5]="week";//星期unsigned char second,minute,hour,week,day,month,year;/******************1602函数********************************//******************************************************************** /void delays(uint m){uint i,j;for(i=0;i<m;i++){for(j=0;j<1000;j++){;}}}void Delay(void){unsigned char i;unsigned int j;for(i=0;i<200;i++)for(j=300;j>0;j--);/******************************************************************** *********函数功能:向DS1302送一字节数据子程序入口参数:出口参数:********************************************************************* ********/void InputByte(unsigned char BYTE){char i;for(i=8;i>0;i--){ //前面在read_ds1302()函数里已经把CLK清0了DS1302_CLK=0;//这里再清0一次,看着清楚。
(完整版)基于51系列单片机及DS1302时钟芯片的电子时钟_C语言毕业论文
实时时钟DS1302应用设计高也(陕西理工学院物理与电信工程学院电子信息工程专业,2011级3班,陕西汉中723000)指导教师:王文洋[摘要] 本设计主要为实现一款可正常显示时钟日历、带有定时闹铃的多功能电子时钟。
本文对当前电子钟开发手段进行了比较和分析,最终确定了采用单片机技术实现多功能电子时钟。
本设计应用AT89C52芯片作为核心,LM016L液晶屏显示,使用DS1302实时时钟日历芯片完成时钟日历的基本功能。
这种实现方法的优点是电路简单,性能可靠,实时性好,时间精确,操作简单,编程容易。
[关键词] AT89C52;DS1302;LM016L目录1、基于单片机的电子时钟硬件选择分析..............................................................................1.1主要IC芯片选择.......................................................................................................1.1.1微处理器选择.................................................................................................1.1.2 DS1302简介...................................................................................................2、电子时钟硬件电路设计......................................................................................................2.1.主控部分(单片机MCS-51).......................................................................................2.2时钟电路设计.............................................................................................................2.3整点报时功能.............................................................................................................2.4 LED显示电路.............................................................................................................3、proteus软件仿真及调试 (1)3.1电路板的仿真 (1)3.2软件调试....................................................................................................................4、硬件调试与功能说明 (1)4.1 硬盘调试 (1)4.2 系统性能测试与功能说明 (1)4.3 系统时钟误差分析 (1)5、课设心得 (1)参考文献 (1)附录A 硬件电路原理图 (1)附录B源程序 (1)附录C 元器件清单 (2)1、基于单片机的电子时钟硬件选择分析考虑单片机货源充足、价格低廉,可软硬件结合使用,能够较方便的实现系统的多功能性,故采用单片机作为本设计的硬件基础。
DS1302可调时钟1602显示
}
else
Set(id,1);
}
while(TimerUp==0);
}
if (TimerDown==0) //减少
{
Delay5Ms();
if(TimerDown==0)
if(id++==5) //1..5为年月日星期 exit
id=1;
}
id_case1_key(); //日期调整
Out_LCM(); //显示输出
}
}
//对相应的项目进行加、减调整。
void id_case1_key() //按键处理
if(model++==3)
model=1;
}
while(TimerDown==0);
}
b=1; //模式键是否动作标志。为1时不动作,为0时动作。
Modset(); //调用模式键处理程序判断按键是否按下。
}
while(TimerDown==0);
}
}
void timer_1(void) interrupt 1 //中断入口,闪烁
{
TH0=0x3c; //50ms定时
void timesetup(void); //时间设置
void datesetup(void); //日期设置
void delay1(int ms) //1ms的基准延时
{
unsigned char y ;
model=3;
}
while(TimerUp==0);
}
if (TimerDown==0) //设置项目右移
1602液晶显示DS1302实时时钟程序
#include <reg51.h>#include <intrins.h>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;//设置状态计数标志、按键先前值、按键当前值bit alarm; //标识是否启用闹钟,1--启用,0--关闭sbit rs = P2^0; //LCD数据/命令选择端(H/L)sbit rw = P2^1; //LCD读/写选择端(H/L)sbit ep = P2^2; //LCD使能控制sbit PRE = P1^6; //调整键(k3)sbit SET = P1^7; //调整键(k4)sbit SPK = P3^7;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;}//写入指令到LCDvoid 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;}//写入数据到LCDvoid 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(0x0a); //"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;elseleap=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;elsec=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[4*week];dis_buf1[14]=dis_week[4*week+1];dis_buf1[15]=dis_week[4*week+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]=0x20; //空格if (alarm)dis_buf2[7]=0x01; //alarm=1,显示闹钟启用标致(第二个自定义字符)elsedis_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=0xdc; //Timer0置10ms定时初值dc00H(2^16=65536D,dc00H=56320D)TL0=0x00; //定时时间=(65536-56320)*(1/11.0592)*12=10ms (f0=11.0592Mhz)sec100++;if(sec100 >= 100) //1秒时间 (100*10ms=1000ms=1s){sec100 = 0;pro_timedate();//调用时间和日期处理程序}if(sec&0x01) / /"willar"闪一秒,停一秒update_disbuf(0x00," ",hour,min,sec); //0x0 0表示显示00位置的自定义字符elseupdate_disbuf(0x00,"willar",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;//禁止Timer0IE=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^0x0a){skey = scan_key(); //扫描按键状态if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体{ delay(10); //去按键抖动skey = scan_key(); //转回扫描按键状态if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体{ vkey=skey; //将skey的值付给vkeyif (skey==0x01) //PRE 键按下{ flag++; / /调整标志位加1switch (flag) //将光标置于相应调整位置{cas e 1: lcd_pos(0x49);break; //光标置小时报警设置位置cas e 2: lcd_pos(0x4c);break; //光标置分钟报警设置位置cas e 3: lcd_pos(0x4f);break; //光标置秒时报警设置位置cas e 4: update_disbuf(0x50,"time: ",hour,min,sec);pro_display();lcd_pos(0x05);break; //光标置年调整位置cas e 5: lcd_pos(0x08);break; //光标置月调整位置cas e 6: lcd_pos(0x0b);break; //光标置日调整位置cas e 7: lcd_pos(0x49);break; //光标置时调整位置cas e 8: lcd_pos(0x4c);break; //光标置分调整位置cas e 9: lcd_pos(0x4f);break; //光标置秒调整位置def ault: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(); //初始化LCDlcd_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,ar msec); //更新显示数据pro_display();//调用显示处理lcd_pos(0x47);break;//光标回到原调整位置case 1:armhour++;if (armhour>23) armhour=0;update_disbuf(0x50,"alarm:",armhour,armmin,ar msec); //更新显示数据pro_display();//调用显示处理lcd_pos(0x49);break;//光标回到原调整位置case 2:armmin++;if (armmin>59) armmin=0;update_disbuf(0x50,"alarm:",armhour,armmin,ar msec);pro_display();lcd_pos(0x4c);break;case 3:armsec++;if (armsec>59) armsec=0;update_disbuf(0x50,"alarm:",armhour,armmin,ar msec);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;}//DS1302时钟程序#include <stc89c52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int/******************************************************************** ///少占鱼制作河北正定欢迎您长沙航空职业技术学院//2010 年QQ:411656434//版权所有:#define LCD1602_RS P2_5 //定义引脚#define LCD1602_RW P2_6#define LCD1602_E P2_7#define LCD1602_IO P0#define Busy 0x80 //用于检测LCD1602状态字中的Busy标识const uchar num[]=" 3456789+";uchar code a[] = {" E N v"};void WriteData(uchar DAT);void WriteCommand(uchar command,BuysC);uchar ReadData(void);void Readbusy(void);void LCD1602_Init(void);void DisplayOneChar(uchar X, uchar Y, uchar DData);void Displaystring(uchar X, uchar Y, uchar *DData);void Delay5Ms(void);void Delay400Ms(void);void delayms(uint);void delays(uint m) ;void delayus(uchar x) ;sbit DS1302_CLK =P2^0;// P1^0;sbit DS1302_IO =P2^1;// P1^1;sbit DS1302_RST =P2^2;// P1^2;uchar shuju;unsigned char time[]={0x11,0x03,0x28,0x01,0x12,0x39,0x00};// 初始化时间年月日星期时分秒uchar Display_Buffer[12]={"12:25:00"};//时、分、秒的格式uchar riqi[12]={"11-03-28"};//年、月、日的格式uchar xingqi[5]="week";//星期unsigned char second,minute,hour,week,day,month,year;/******************1602函数********************************//******************************************************************** /void delays(uint m){uint i,j;for(i=0;i<m;i++){for(j=0;j<1000;j++){;}}}void Delay(void){unsigned char i;unsigned int j;for(i=0;i<200;i++)for(j=300;j>0;j--);/******************************************************************** *********函数功能:向DS1302送一字节数据子程序入口参数:出口参数:********************************************************************* ********/void InputByte(unsigned char BYTE){char i;for(i=8;i>0;i--){ //前面在read_ds1302()函数里已经把CLK清0了DS1302_CLK=0;//这里再清0一次,看着清楚。
以DS1302实时时钟芯片和液晶显示屏CD1602为基础设计的电子钟
电子系统设计实验报告实验目的:1、能够以DS1302实时时钟芯片和液晶显示屏CD1602为基础设计一款电子钟2、熟悉DS1302芯片的工作过程3、熟悉CD1602芯片的工作过程4、可以进行必要的扩展,如用第三DS18B20新品进行温度采集和显示5、熟悉掌握51的c程序的编写6、掌握用Proteus进行系统设计仿真验证实验仪器、仪表目录1、DS1302实时时钟芯片1片2、LCD1602液晶显示屏1个,3、80C52芯片1片5、DS18B20芯片一片6、晶振、电容、电阻、开关各若干等7、proteus仿真软件8、Keil C51、PC机实验设计任务以DS1302实时时钟芯片和液晶显示屏LCD1602为基础设计一个电子钟,要求:时间和日期可调整,按键采用3个按键;至少在Proteus上调试通过。
扩展:闹钟和重要日期提醒功能(增加蜂鸣器),闹铃音乐功能实验步骤1、打开Keil软件,新建一个工程文件,选择好芯片,并记得在“Options for Target 1”的Output 选项中,将Create HEX Fil选项勾起来。
2、将编写的程序保存成“.C”的形式3、编译保存好的C文件,并根据提示修改程序中的错误,直到编译成功为止4、打开proteus软件,画出实验电路图5、在89C52中,载入原来已生成的HEX文档6、按下运行键,对Proteus进行软件仿真,观察运行结果原理、结果及分析一、设计方案原理与设计特点分析电子钟总的设计模块:各个模块电路原理分析:1、DS1302时钟采集模块:1.1电路原理图:1.2 DS1302分析:首先DS1302是DALLAS公司推出的涓流充电时钟芯片。
内含有一个实时时钟/日历和31字节静态RAM通过简单的串行接口与单片机进行通信实时时钟/日历电路提供秒分时日日期月年的信息每月的天数和闰年的天数可自动调整时钟操作。
DS1302芯片广脚介绍:X1、X2为32.768KHz晶振管脚。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
==================主程序================= #include <reg51.h>。
#include "ds1302.h"#include "LCD1602.h"void change();uchar times[9];uchar date[9];main(){LCD_init();//LCD初始化init_1302(time_1302);gotoxy(1,1);LCD_display("Time:");gotoxy(1,2);LCD_display("Date:");times[8]='\0';//date[8]='\0';while(1){get_1302(time_1302);change();gotoxy(7,1);LCD_display(times);gotoxy(7,2);LCD_display(date);}}/*=========================== 转换子程序===========================*/void change(){// 时间的转换times[0]=time_1302[2]/10+'0';times[1]=time_1302[2]%10+'0';times[2]=':';times[3]=time_1302[1]/10+'0';times[4]=time_1302[1]%10+'0';times[5]=':';times[6]=time_1302[0]/10+'0';times[7]=time_1302[0]%10+'0';// 日期的转换date[0]=time_1302[6]/10+'0';date[1]=time_1302[6]%10+'0';date[2]='-';date[3]=time_1302[4]/10+'0';date[4]=time_1302[4]%10+'0';date[5]='-';date[6]=time_1302[3]/10+'0';date[7]=time_1302[3]%10+'0';}======================================================DS1302驱动程序=============#define uchar unsigned charuchar time_1302[7]={0x00,0x00,0x00,0x03,0x07,0x03,0x08};//设置时间初始值数组// 秒分时号月份星期年sbit T_IO=P1^0; //与硬件相关的连线clk为DS1302的时钟信号线sbit T_CLK=P1^1; //DAT为DS1302的I/O数据线sbit T_RST=P1^2; //RST为DS1302的RST信号线uchar bdata datbyte;sbit datbyte0=datbyte^0;sbit datbyte7=datbyte^7;void get_1302(uchar time[]);void write_ds1302(uchar dat);uchar r_1302(uchar add);void w_1302(uchar add,uchar dat);uchar read_ds1302(void);void init_1302(uchar *time);/*==========================================D S 1 3 0 2 初始化===========================================*/void init_1302(uchar *time){uchar i, add;//uchar time_bcd[7];add=0x80;//0写入,1读出w_1302(0x8e,0x00);for(i=0;i<7;i++){w_1302(add,*time);add+=2;time++;}w_1302(0x8e,0x80);}//===========================// 读取当前时间//===========================void get_1302(uchar time[]){uchar i;uchar add=0x81;w_1302(0x8e,0x00);for(i=0;i<7;i++){time[i]=r_1302(add);add+=2;}w_1302(0x8e,0x80);}/*================================= DS1302写入一个字节(上升沿有效)=================================*/void write_ds1302(uchar dat){uchar i;datbyte=dat;for(i=0;i<8;i++){T_IO=datbyte0;T_CLK=1;T_CLK=0;datbyte=datbyte>>1;}}/*======================================= DS1302读取一个字节(下降沿有效)=======================================*/uchar read_ds1302(void){uchar i;for(i=0;i<8;i++){datbyte=datbyte>>1;datbyte7=T_IO;T_CLK=1;T_CLK=0;}return(datbyte);}/*========================================= 指定位置读取数据=========================================*/uchar r_1302(uchar add){uchar temp,dat1,dat2;T_RST=0;T_CLK=0;T_RST=1;write_ds1302(add);temp=read_ds1302();T_CLK=1;T_RST=0;dat1=temp/16;dat2=temp%16;temp=dat1*10+dat2;return(temp);}/*========================================== 指定位置写入数据==========================================*/void w_1302(uchar add,uchar dat){T_RST=0;T_CLK=0;T_RST=1;write_ds1302(add);write_ds1302(dat/10<<4|dat%10);T_CLK=1;T_RST=0;}=========================================== =============LCD1602驱动程序================#define LCD_DB P0//定义LCD的数据端口sbit LCD_RS=P2^0;sbit LCD_RW=P2^1;sbit LCD_E=P2^2;#define uchar unsigned char#define uint unsigned int//===========延时子函数======================== void delay_lcd(uint x){uint i,j;for(i=x;i>0;i--)for(j=0;j<2;j++);}//==================写指令函数================= void LCD_write_command(uchar command){LCD_DB=command;LCD_RS=0;//指令LCD_RW=0;//写入LCD_E=1;LCD_E=0;delay_lcd(1);//等待执行完毕。
}//===================写数据函数=================void LCD_write_data(uchar dat){LCD_DB=dat;LCD_RS=1;//数据寄存器LCD_RW=0;//写入数据LCD_E=1;LCD_E=0;delay_lcd(1);//等待程序执行完毕。
}/*============显示一个字符子函数=============== void LCD_disp_char(uchar x,uchar y, uchar dat){ uchar address;if(y==1)address=0x80+x;elseaddress=0xc0+x;LCD_write_command(address);LCD_write_data(dat);}===================================*///==========延时1==================== void delay1(uint x){uint i,j;for(j=0;j<x;j++)for(i=0;i<100;i++);}//===========初始化函数=============void LCD_init(void){LCD_write_command(0x38);//设置8位格式,2行,5*7LCD_write_command(0x0c);//整体显示,关光标,不闪烁LCD_write_command(0x06);//设定输入方式,增量不移位LCD_write_command(0x01);//清屏显示delay_lcd(200);}//==========光标定位======================= void gotoxy(uchar x,uchar y){uchar address;if(y==1)address=0x80+x;elseaddress=0xc0+x;LCD_write_command(address);}//=========显示一个字符串==================。
void LCD_display(uchar *dat){ while(*dat!='\0'){LCD_write_data(*dat);dat++;}}。