LCD1602液晶屏显示的万年历,DS1307还有很多功能可以添加小白一个
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- /****************************************************
- 电路图说明:
- 将单片机P2.7和P1.0分别与RTC(实时时钟)的时钟信号SCL端
- 和数据信号SDA端相连, RTC的sout引脚与单片机P3.2相连,RTC的
- 地址是11010000.独立键盘k0~K3接P1.1~P1.3
- 程序功能:
- 使用时钟芯片ds1307制作一个实时时钟
- ******************************************************/
- #include <reg52.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- //实时时钟两信号线
- sbit scl=P2^7;
- sbit sda=P1^0;
- //独立键盘扫描位
- sbit k0=P1^1;
- sbit k1=P1^2;
- sbit k2=P1^3;
- //液晶显示器控制位
- sbit lcd_rs=P3^4;
- sbit lcd_e=P3^5;
- //数码管和led锁存器选通位
- sbit duan=P2^0;
- sbit wei=P2^1;
- sbit led=P2^2;
- void init();//初始化IIC总线,使总线处于备用状态,
- //初始化lcd并显示上面table1和table2的值,初始化定时器0,初始化变量时分秒
- /****************IIC总线控制函数***************************/
- void IIC_start();//IIC通信开始信号
- void IIC_stop();//IIC通信停止信号
- void IIC_un_ack();//单片机发送非应答位
- //void IIC_ack();//单片机发送应答位
- void IIC_check_ack();//单片机检查应答位
- void IIC_write_byte(uchar);//发送一字节数据
- uchar IIC_read_byte();//接收一字节数据
- void nop();//5us空操作延迟
- /**********************************/
- /**********ds1307读写函数*******************/
- void ds1307_write_date(uchar ,uchar ,uchar);//向指定器件写一字节数据
- //参数1器件地址,参数2要存的数据存放位置8位地址
- //参数3要写的数据
- uchar ds1307_read_date(uchar ,uchar );//从指定器件读一字节数据,
- //参数1被通信器件地址,参数2要读的数据存放位置8位地址
- //函数返回读取的数据。
- void delay(uint);//基数1ms延迟程序
- /***********************************/
- /**************LCD操作函数**************************/
- uchar hour,minute,second,k0_num;//时分秒变量,菜单键k0第几次按下计数,ds1307跟新标志
- //时钟初显示
- uchar code table1[]="2017-11-16 THUR";
- uchar code table2[]=" 23:59:55 ";
- void lcd_write_com(uchar);//向液晶显示器写指令设置其显示的格式
- void lcd_write_date(uchar);//向液晶显示器写显示的数据
- /**********************************************/
- /**************时钟函数*******************/
- void lcd_write_second(uchar);//向lcd写秒
- void lcd_write_minute(uchar);//向lcd写分
- void lcd_write_hour(uchar);//向lcd写时
- void run_time();//时钟走动显示
- void keyscan();//菜单键扫描
- /****************************************/
- /*********十进值与BCD码之间互换**********/
- uchar b_second,b_minute,b_hour;
- uchar dectobcd(uchar);//十进值转bcd码
- uchar bcdtodec(uchar);//bcd码转十进值
- /****************************************/
- void main()
- {
- init();
- while(1)
- {
- keyscan();
- }
- }
- void nop()
- {
- _nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();
- }
- void init()
- {
- uchar i;
- //将数据线和时钟线拉高,处于备用状态即非忙
- sda=1;
- nop();
- scl=1;
- nop();
-
- //关数码管显示和8个LED显示
- duan=0;
- wei=0;
- led=0;
- lcd_e=0;
-
- //初始化写入LCD的时分秒
- second=55;
- minute=59;
- hour=23;
- //初始化ds1307
- ds1307_write_date(0xd0,0x07,0x10);//初始化1307的控制字,使其SOUT引脚输出1Hz的方波。
- //初始化1307的时间
- ds1307_write_date(0xd0,6,0x14);
- ds1307_write_date(0xd0,5,0x06);
- ds1307_write_date(0xd0,4,0x09);
- ds1307_write_date(0xd0,3,0x00);
- ds1307_write_date(0xd0,2,0x23);
- ds1307_write_date(0xd0,1,0x59);
- ds1307_write_date(0xd0,0,0x55);
- //初始化液晶显示器
- lcd_write_com(0x38);//设置16*2行,5*7点阵,8位数据接口
- lcd_write_com(0x06);//写字符指针和光标自动向右移动
- lcd_write_com(0x0c);//开显示,不显示光标,光标不闪烁
- lcd_write_com(0x01);//显示清屏
- for(i=0;i<15;i++)
- {
- lcd_write_date(table1[i]);
- }
- lcd_write_com(0x80+0x40);
- for(i=0;i<10;i++)
- {
- lcd_write_date(table2[i]);
- }
-
- //开启外部中断0
- EA=1;
- EX0=1;
- IT0=1;
- }
- void IIC_start()
- {
- //在时钟信号有效scl=1时,数据线负跳变
- sda=1;
- nop();
- scl=1;
- nop();
- sda=0;
- nop();
- scl=0;//拉低为下个时钟数据作准备
- nop();
- }
- void IIC_stop()
- {
- //在时钟信号有效scl=1时,数据线正跳变,释放总线,使总线处于备用状态即非忙
- sda=0;
- nop();
- scl=1;
- nop();
- sda=1;
- nop();
- nop();
- nop();
- }
- void IIC_un_ack()
- {
- //时钟信号有效时,sda给1,给出非应答
- sda=1;
- nop();
- scl=1;
- nop();
- scl=0;//拉低为下个时钟数据作准备
- nop();
- }
- /*
- void IIC_ack()
- {
- //时钟信号有效时,sda给0,给出应答
- sda=0;
- nop();
- scl=1;
- nop();
- scl=0;//拉低为下个时钟数据作准备
- nop();
- }
- */
- void IIC_check_ack()
- {
- //uchar i;
- //时钟信号有效时,检测数据信号sda是否为0,给0说明有应答信号
- scl=1;
- //while((sda==1)&&(i<255)) i++;
- nop();
- scl=0;//拉低为下个时钟数据作准备
- nop();
- }
- uchar IIC_read_byte( )
- {
- uchar i,temp;//temp用于存放从数据线读到的数据
- for(i=0;i<8;i++)//从数据线读取一个字节(8位)
- {
- scl=1;
- nop();
- temp=(temp<<1)|sda;//temp左移,腾出第0位,然后将数据线上的一位数用或
- //运算存放到temp的第0位
- scl=0;//拉低为下个时钟数据作准备
- nop();
- }
- return temp;
- }
- void IIC_write_byte(uchar byte)
- {
- uchar i;
- for(i=0;i<8;i++)//向数据线写一个字节(8位)
- {
- byte=byte<<1;//左移位,将byte第7位移到PSW中的进位标志位CY中
- sda=CY;
- nop();
- scl=1;
- nop();
- scl=0;//拉低为下个时钟数据作准备
- nop();
- }
- sda=1;//释放总线,准备接收被控设备应答信号
- nop();
- }
- void ds1307_write_date(uchar d_address,uchar r_address,uchar date)
- {
- IIC_start();
- IIC_write_byte(d_address & (~0x01));//写器件地址,方向是写,所以或上0x00
- IIC_check_ack();//等待应答
- IIC_write_byte(r_address);//写存储器数据存放的8位地址
- IIC_check_ack();//等待应答
- IIC_write_byte(date);//写一字节数据
- IIC_check_ack();//等待应答
- IIC_stop();
- }
- uchar ds1307_read_date(uchar d_address,uchar r_address)
- {
- uchar r;
- IIC_start();
- IIC_write_byte(d_address & (~0x01));//写器件地址,方向是写
- IIC_check_ack();//等待应答
- IIC_write_byte(r_address);//写存储器数据存放的8位地址
- IIC_check_ack();//等待应答
- //换方向
- IIC_start();
- IIC_write_byte(d_address|0x01);//写器件地址,方向是读,所以或上1
- IIC_check_ack();
- r=IIC_read_byte();//读取一个字节数据
- IIC_un_ack();
- IIC_stop();
- return r;//将读到的数据返回
- }
- void delay(uint z)//晶振频率12MHz时,z=1时延迟1ms
- {
- uint a,b;
- for(a=z;a>0;a--)
- for(b=110;b>0;b--);
- }
- void lcd_write_com(uchar com)//lcd写指令函数定义
- {
- lcd_rs=0;
- P0=com;
- delay(1);
- lcd_e=1;
- lcd_e=0;
- delay(2);
- }
- void lcd_write_date(uchar date)//lcd写数据函数定义
- {
- lcd_rs=1;
- P0=date;
- delay(1);
- lcd_e=1;
- lcd_e=0;
- delay(2);
- }
- void lcd_write_second(uchar sec)//向lcd写秒
- {
- uchar h,l;
- h=sec/10;
- l=sec%10;
- lcd_write_com(0x80+0x40+10);
- lcd_write_date(0x30+h);
- lcd_write_date(0x30+l);
- }
- void lcd_write_minute(uchar min)//向lcd写分
- {
- uchar h,l;
- h=min/10;
- l=min%10;
- lcd_write_com(0x80+0x40+7);
- lcd_write_date(0x30+h);
- lcd_write_date(0x30+l);
- }
- void lcd_write_hour(uchar hou)//向lcd写时
- {
- uchar h,l;
- h=hou/10;
- l=hou%10;
- lcd_write_com(0x80+0x40+4);
- lcd_write_date(0x30+h);
- lcd_write_date(0x30+l);
- }
- void inter0()interrupt 0
- {
- run_time();
- }
- void run_time()//时钟走动函数定义
- {
- //从1307中读出时间
- b_second=ds1307_read_date(0xd0,0);//返回函数r值秒
- b_minute=ds1307_read_date(0xd0,1);
- b_hour=ds1307_read_date(0xd0,2);
- //将读出的时间转换成十进值
- second=bcdtodec(b_second);
- minute=bcdtodec(b_minute);
- hour=bcdtodec(b_hour);
- //更新lcd显示时间
- lcd_write_second(second);
- lcd_write_minute(minute);
- lcd_write_hour(hour);
- }
- uchar dectobcd(uchar dec)//十进值到BCD码
- {
- uchar x,y;
- x=dec/10;//得到bcd的十位数
- y=dec%10;//得到bcd的个位数
- y=(x<<4)|y;
- return y;
- }
- uchar bcdtodec(uchar bcd)//bcd码转十进值
- {
- uchar x,y;
- y=bcd/16;//得到十进制的十位数
- x=bcd%16;//得到十进制的个位数
- y=y*10+x;
- return y;
- }
- void keyscan()//菜单键按下扫描函数定义
- {
- k0=1;
- k1=1;
- k2=1;
- //判断菜单键k0是否按下
- if(k0==0)
- {
- delay(5);
- if(k0==0)
- {
- while(!k0);//松手检测
- k0_num++;//记录菜单键k0是第几次按下,而判断是调节秒、分还是时。
- if(k0_num==1)//指示调节秒
- {
- EX0=0;//关闭外部中断0,使时间走动停止,准备调时间
- ds1307_write_date(0xd0,0,0x80|b_second);
- lcd_write_com(0x80+0x40+11);//数据指针和光标移动秒出
- lcd_write_com(0x0f);//使光标显示,并光标处字符格符闪烁,用来提示用户此时可以调节
- //什么?是秒,是分还是时。
- }
- if(k0_num==2)//指示调节分
- {
- lcd_write_com(0x80+0x40+8);//数据指针和光标移动分出
- }
- if(k0_num==3)//指示调节时
- {
- lcd_write_com(0x80+0x40+5);//数据指针和光标移动时出
- }
- if(k0_num==4)//退出时间调节菜单
- {
- k0_num=0;//菜单键k0按下清零
- lcd_write_com(0x0c);//恢复到时钟走动状态,即光标不显示,不闪烁
- //将所调的时间转换成bcd码
- b_second=dectobcd(second);
- b_minute=dectobcd(minute);
- b_hour=dectobcd(hour);
- //将所调的时间向时钟写入
- ds1307_write_date(0xd0,2,b_hour);
- ds1307_write_date(0xd0,1,b_minute);
- ds1307_write_date(0xd0,0,b_second);
- EX0=1;//开外部中断0,时间开始继续走动
- }
-
- }
- }
- //判断是否按下过时间调节菜单键k0,而处于需要调节时间状态
- if(k0_num)
- {
- //判断是否是上调键k1按下
- if(k1==0)
- {
- delay(5);
- if(k1==0)
- {
- while(!k1);//松手检测
- if(k0_num==1)//上调秒
- {
- second++;
- if(second==60)
- second=0;
- lcd_write_second(second);//向lcd写入被修改的时间
- lcd_write_com(0x80+0x40+11);//光标位置重定位到所要调的时间处
-
- }
- if(k0_num==2)//上调分
- {
- minute++;
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
DS1307实时时钟应用.rar
(56.62 KB, 下载次数: 415)
|