ds1302的12864液晶按键可调显示实时时钟程序(word文档良心出品)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一.绪言
1.在信息显示技术中,人们发现了信息数字化的重要作用和意义。
数字化的信息更加准确,同一性,更易传输和识别。
很多信息可以直接由数字表示,从而数字化信息显示又成为信息显示的又一个重要内容。
又从数字化显示发展到字符显示,它把人类特有的语言文字用于显示,这种显示与数字显示合在一起用途更广用量更大。
在这同时,人们还希望用图形和图像进行显示,且显示的内容为五彩缤纷,并且可以实时活动和具有三维立体效果。
这些在二十世纪尾声时都已经陆续实现。
LCD的计算机器,半导体发光数码管显示(LED)的汽车计价器,商场的大屏幕广告。
这零零总总的各类显示正为你做着各种各样的服务,相信在不久的将来显示技术的发展将会为人类做出更大的贡献。
Ds1302时钟芯片现在流行的串行时钟电路很多,如DS1302、 DS1307、PCF8485等。
这些电路的接口简单、价格低廉、使用方便,被广泛地采用。
本文介绍的实时时钟电路DS1302是DALLAS公司的一种具有涓细电流充电能力的电路,主要特点是采用串行数据传输,可为掉电保护电源提供可编程的充电功能,并且可以关闭充电功能。
采用普通3
2.768kHz晶振。
(一)设计任务
本课题采用ds1302的时钟芯片为主要的的设计来源,采用显示是1cd1602的图形点阵液晶显示。
,
(二)提出方案及方案论证
在设计中,我主要是考虑ds1302的时间显示问题,因为网上也有ds1302的读写和显示程序,但是至于怎样才能显示详细信息,我提出了两个方案,一个是LCD1602来显示,一个是LCD12864,其中1602是个字符型的点阵,而1CD12864是个图形的点阵,相比之下12864能够更好显示数据,而CPU都采用89C52的单片机
(三)原理说明:原理其实很简单,LCD12864的各种指令先进行宏定义和ds1302的读写指令也进行宏定义,从ds1302的读出数据显示在lcd上
(二)程序流程图
(三)C51程序设计,重要的代码要有注释。
#include <reg52.h>
#include <ABSACC.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
/********各种指令的宏定义********/
#define LLCD_CMD_WR PBYTE[0x10] // LCD左半部写的命令rs=0,wr=0 #define LLCD_CMD_RD PBYTE[0x11] // 读命令rs=0,wr=0
#define LLCD_DA TA_WR PBYTE[0x12] // 写数据rs=1,wr=0
#define LLCD_DA TA_RD PBYTE[0x13] // 读数据rs=1,wr=1
#define RLCD_CMD_WR PBYTE[0x20] // LCD右半部部分
#define RLCD_CMD_RD PBYTE[0x21] //
#define RLCD_DA TA_WR PBYTE[0x22] //
#define RLCD_DA TA_RD PBYTE[0x23] //
#define WRITE_SECOND 0x80
#define WRITE_MINUTE 0x82
#define WRITE_HOUR 0x84
#define WRITE_DAY 0x86
#define WRITE_MOUTH 0x88
#define WRITE_YEAR 0x8c
#define READ_SECOND 0x81
#define READ_MINUTE 0x83
#define READ_HOUR 0x85
#define READ_DAY 0x87
#define READ_MOUTH 0x89
#define READ_YEAR 0x8d
#define WRITE_PROTECT 0x8E
/*************************/
sbit SCK =P1^1;
sbit DIO =P1^0;
sbit CE =P1^2;
sbit K1 =P1^5;
sbit K2 =P1^6;
sbit K3 =P1^7;
sbit busy=P0^7;
uchar sec,min,hour,day,mouth,year,print;
uchar buffer[16];
code uchar shuzi1[] = {
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, //0 0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, //1 0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00, //2 0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00, //3 0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00, //4 0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, //5 0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00, //6 0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, //7 0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00, //8 0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00, //9 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//空};
code uchar hanzi1[] = {
0x00,0x50,0x4F,0x4A,0x48,0xFF,0x48,0x48,0x48,0x00,0xFC,0x00,0x00,0xFF,0x00,0x00,
0x00,0x00,0x3F,0x01,0x01,0xFF,0x21,0x61,0x3F,0x00,0x0F,0x40,0x80,0x7F,0x00,0x00,
0x80,0x40,0x20,0xF8,0x07,0x22,0x18,0x0C,0xFB,0x48,0x48,0x48,0x68,0x48,0x08,0x00,
0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0xFF,0x04,0x04,0x04,0x04,0x06,0x04,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x3F,0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x01,0x06,0x0C,0x18,0x30,0x60,0x20,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x08,0x28,0x49,0x8A,0x0C,0xC8,0x38,0x08,0x00,0xF8,0x00,0x00,0xFF,0x00,0x00, 0x40,0x20,0x10,0x08,0x04,0x03,0x06,0x38,0x10,0x00,0x07,0x20,0x40,0x3F,0x00,0x00,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xFE,0x60,0x90,0x08,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x10,0x21,0x40,0x78,0x00,
/*******姓名:刘飞***********/
};
code uchar shijian1[] = {
0x00,0xFC,0x44,0x44,0x44,0xFC,0x10,0x90,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x00, 0x00,0x07,0x04,0x04,0x04,0x07,0x00,0x00,0x03,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,
0x00,0xF8,0x01,0x06,0x00,0xF0,0x92,0x92,0x92,0x92,0xF2,0x02,0x02,0xFE,0x00,0x00, 0x00,0xFF,0x00,0x00,0x00,0x07,0x04,0x04,0x04,0x04,0x07,0x40,0x80,0x7F,0x00,0x00, };
code uchar riqi1[]={
0x00,0x00,0x00,0xFE,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0xFE,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x3F,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x3F,0x00,0x00,0x00,0x00,
0x00,0x04,0xFF,0x54,0x54,0x54,0xFF,0x04,0x00,0xFE,0x22,0x22,0x22,0xFE,0x00,0x00, 0x42,0x22,0x1B,0x02,0x02,0x0A,0x33,0x62,0x18,0x07,0x02,0x22,0x42,0x3F,0x00,0x00, };
code uchar hanzi2[]={
0x00,0x02,0x02,0xF2,0x12,0x12,0x12,0x12,0xF2,0x02,0x02,0x02,0xFE,0x02,0x02,0x00, 0x00,0x00,0x00,0x07,0x02,0x02,0x02,0x02,0x07,0x10,0x20,0x40,0x3F,0x00,0x00,0x00,
0x20,0x21,0xEE,0x04,0x00,0x00,0xFF,0x29,0xA9,0xBF,0xA9,0xA9,0x01,0xFF,0x00,0x00, 0x00,0x00,0x1F,0x88,0x44,0x30,0x0F,0x00,0x0F,0x04,0x04,0x4F,0x80,0x7F,0x00,0x00,
0x00,0x00,0xF8,0x48,0x48,0x48,0x48,0xFF,0x48,0x48,0x48,0x48,0xF8,0x00,0x00,0x00, 0x00,0x00,0x0F,0x04,0x04,0x04,0x04,0x3F,0x44,0x44,0x44,0x44,0x4F,0x40,0x70,0x00,
0x00,0x00,0x02,0x02,0x02,0x02,0x02,0xE2,0x12,0x0A,0x06,0x02,0x00,0x80,0x00,0x00, 0x01,0x01,0x01,0x01,0x01,0x41,0x81,0x7F,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,
0x00,0xFC,0x44,0x44,0x44,0xFC,0x10,0x90,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x00, 0x00,0x07,0x04,0x04,0x04,0x07,0x00,0x00,0x03,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,
0x40,0x30,0x2C,0xEB,0x28,0x28,0x00,0xF8,0x08,0x08,0xFF,0x08,0x08,0xF8,0x00,0x00, 0x01,0x01,0x01,0xFF,0x41,0x21,0x00,0x01,0x01,0x01,0xFF,0x01,0x01,0x01,0x00,0x00, };
/******检测LCD忙函数*********/
void lcd_busy_rd (uchar right)
{
if(right==1)
RLCD_CMD_RD;
else
LLCD_CMD_RD;
while (busy);
}
/**********写指令***********/
void lcd_comd_wr(uchar cmdcode, uchar right) //写指令{
lcd_busy_rd(right);
if(right==1)
RLCD_CMD_WR=cmdcode;
else
LLCD_CMD_WR=cmdcode;
}
/********对LCD进行读写***********/
void lcd_data_wr(uchar ldata ,uchar right) //
{
lcd_busy_rd(right);
if(right==1)
RLCD_DATA_WR=ldata;
else
LLCD_DATA_WR=ldata;
}
/********延时函数*******/
void delay(uint nms)
{
uint i;
while (nms--)
for (i=0;i<500;i++);
}
/****lcd初始化*******/
void lcd_init(void)
{
uint k;
lcd_comd_wr(0x3e+1,0); //左半部显示开
lcd_comd_wr(0xc0+0,0); //左半部顶行为第0行
lcd_comd_wr(0xb0+0,0); //设置左半部页的地址
lcd_comd_wr(0x40+0,0); //设置左列得地址
lcd_comd_wr(0x3e+1,1);
lcd_comd_wr(0xc0+0,1);
lcd_comd_wr(0x40+0,1);
lcd_comd_wr(0xb0+0,1);
for (k=0;k<256;k++)
{
lcd_data_wr(0x00,0);
lcd_data_wr(0x00,1);
}
lcd_comd_wr(0xb8+4,0);
lcd_comd_wr(0x40+0,0);
lcd_comd_wr(0xb8+4,1);
lcd_comd_wr(0x40+0,1);
for (k=0;k<256;k++) //这个for循环是为清楚不显示字的地方
{
lcd_data_wr(0x00,0);
lcd_data_wr(0x00,1);
}
}
/**********显示汉字****************/
/*********置入单个数字*********/
void lcd_shuzi_wr(uchar posx,uchar posy,uchar*shuzi)
{
uchar i1;
if(posy<8)
{
lcd_comd_wr(0xb8+2*posx,0); //左半部页的地址,相当于行扫描上半部分lcd_comd_wr(0x40+8*posy,0); //左半部列的地址
for (i1=0;i1<8;i1++)
{
lcd_data_wr(shuzi[i1],0);
}
lcd_comd_wr(0xb8+2*posx+1,0);//同上下部分的汉字
lcd_comd_wr(0x40+8*posy,0);
for (i1=8;i1<16;i1++)
{
lcd_data_wr(shuzi[i1],0);
}
}
else //否则右半部写
{
lcd_comd_wr(0xb8+2*posx,1);
lcd_comd_wr(0x40+8*(posy-8),1);
for (i1=0;i1<8;i1++)
{
lcd_data_wr(shuzi[i1],1);
}
lcd_comd_wr(0xb8+2*posx+1,1);
lcd_comd_wr(0x40+8*(posy-8),1);
for (i1=8;i1<16;i1++)
{
lcd_data_wr(shuzi[i1],1);
}
}
}
/**********输出方式**************/
/****row=写入的行,col=写入的字,*/
/****n=空几格的数************/
void lcd_num_wr(uchar row,uchar col,uchar n,uchar*str)
{
uchar i2;
for (i2=print;i2<n;i2++)
{
if (col>15)
{
row++;
col=col-16;
}
lcd_shuzi_wr(row,col,str+buffer[i2]*16); //i2=写入的数字
col++;
}
}
/**********显示汉字****************/
/*********置入单个汉字**********/
void lcd_hanzi_wr(uchar posx,uchar posy,uchar*hanzi)
{
uchar i1;
if(posy<4)
{
lcd_comd_wr(0xb8+2*posx,0); //左半部页的地址,相当于行扫描上半部分lcd_comd_wr(0x40+16*posy,0); //左半部列的地址
for (i1=0;i1<16;i1++)
{
lcd_data_wr(hanzi[i1],0);
}
lcd_comd_wr(0xb8+2*posx+1,0);//同上下部分的汉字
lcd_comd_wr(0x40+16*posy,0);
for (i1=16;i1<32;i1++)
{
lcd_data_wr(hanzi[i1],0);
}
}
else //否则右半部写{
lcd_comd_wr(0xb8+2*posx,1);
lcd_comd_wr(0x40+16*(posy-4),1);
for (i1=0;i1<16;i1++)
{
lcd_data_wr(hanzi[i1],1);
}
lcd_comd_wr(0xb8+2*posx+1,1);
lcd_comd_wr(0x40+16*(posy-4),1);
for (i1=16;i1<32;i1++)
{
lcd_data_wr(hanzi[i1],1);
}
}
}
/**********输出方式**************/
/****row=写入的行,col=写入的字,*/
/****n=空几格的数************/
void lcd_str_wr(uchar row,uchar col,uchar n,uchar*str) {
uchar i2;
for (i2=0;i2<n;i2++)
{
if (col>7)
{
row++;
col=col-8;
}
lcd_hanzi_wr(row,col,str+i2*32);
col++;
}
}
/***读出一个字节**********/
uchar Read1302_byte(uchar addr)
{
uchar i3,dat1,dat2;
CE=0;
_nop_();
SCK=0;
_nop_();
CE=1;
_nop_();
for (i3=0;i3<8;i3++) //写入要读的字节的地址{
SCK=0;
DIO=addr&0x01;
addr=addr>>1;
SCK=1;
}
for(i3=0;i3<8;i3++) //读数据
{
dat1=dat1>>1;
SCK=0;
if(DIO)
dat1=dat1 | 0x80;
SCK=1;
}
CE=0;
_nop_();
SCK=0;
_nop_();
SCK=1;
DIO=1;
dat2=dat1/16; //将16进制转化为10进制dat1=dat1%16;
dat1=dat2*10+dat1;
return(dat1);
}
/***x写入一个字节**********/
void write_ds1302(uchar addr,uchar dat)
{
uchar i2;
CE=0;
_nop_();
SCK=0; _nop_();
CE=1;
_nop_();
for (i2=0;i2<8;i2++) //写入要写的字节的地址{
SCK=0;
DIO=addr&0x01;
addr=addr>>1;
SCK=1;
}
for (i2=0;i2<8;i2++) //写数据
{
SCK=0;
DIO=dat&0x01;
dat=dat>>1;
SCK=1;
}
CE=0;
_nop_();
DIO=1;
SCK=1;
}
/*****将ds1302的数据分离**********/
void zh()
{
buffer[0]=year/10;
buffer[1]=year%10;
buffer[2]=11;
buffer[3]=mouth/10;
buffer[4]=mouth%10;
buffer[5]=11;
buffer[6]=day/10;
buffer[7]=day%10;
buffer[8]=hour/10;
buffer[9]=hour%10;
buffer[10]=10;
buffer[11]=min/10;
buffer[12]=min%10;
buffer[13]=10;
buffer[14]=sec/10;
buffer[15]=sec%10;
}
/**********读都ds1302的数据**********/
void read()
{
sec=Read1302_byte(READ_SECOND);
min=Read1302_byte(READ_MINUTE);
hour=Read1302_byte(READ_HOUR);
day=Read1302_byte(READ_DAY);
mouth=Read1302_byte(READ_MOUTH);
year=Read1302_byte(READ_YEAR);
}
/***********键盘扫描***********/
void key()
{
uchar w;
if (K1==0)
{
while (!K1);
write_ds1302(WRITE_PROTECT,0x00);
min++;
if(min>=60)
{
min=0;
hour++;
if(hour>=24)
{
hour=0;
write_ds1302(WRITE_HOUR ,hour);
}
}
w=min/10;
min=min%10;
min=min+w*16; //进制转换10进制转换16进制
write_ds1302(WRITE_MINUTE,min); //把调整后的时钟写入到时钟芯片中}
if(K2==0)
{
while(!K2);
write_ds1302(WRITE_PROTECT,0x00);
hour++;
if(hour>=24)
{
hour=0;
}
w=hour/10;
hour=hour%10;
hour=hour+w*16;
write_ds1302(WRITE_HOUR ,hour);
}
write_ds1302(WRITE_PROTECT ,0x80);
print=0;
lcd_num_wr(1,5,8,shuzi1); //写入到第几行,第几个开始,和写入的字数,写入的指针print=8;
lcd_num_wr(2,5,16,shuzi1);
}
/*******主程序*************/
void main()
{
lcd_init();
delay(100);
while(1)
{
key();
read();
zh();
print=0;
lcd_num_wr(1,5,8,shuzi1); //写入到第几行,第几个开始,和写入的字数,写入的指针print=8;
lcd_num_wr(2,5,16,shuzi1);
lcd_str_wr(0,1,6,hanzi2);
lcd_str_wr(3,0,6,hanzi1); //写入到第几行,第几个开始,和写入的字数,写入的指针
lcd_str_wr(2,0,2,shijian1);
lcd_str_wr(1,0,2,riqi1);
}
}
三、仿真验证
在程序和电路联合调试中我们出现这种或者是那种问题,比如说ds1302的读写程序问题,就是搞懂其中的读写的时序。
读和写一个字节的串行写入和读入。
二是遇到了数据转换,以为是读出的数据就直接十位和个位分离就行,其实还要数据转换!LCD显示倒不难网上有现成的程序可供参考,还有LCD12864汉字和数字还图形生成的数组的软件,LCD中液晶显示就是要搞懂其中内部指令,只有搞懂这些指令才能怎样显示数据在LCD上,最后就是按键、LCD、还有ds1302
的联合调试,我先调试出不带按键的程序,然后再加上按键,由于时间的关系没有加年月模式,只能调时和分。
再加按键时,碰到问题是最多的。
一个要判断数值是否超出60或者是24等,还要把调整后数值显示在LCD上和写入到DS1302的程序,所以加上按键估计是最难的一项任务!但经过我的细心和耐心终于调试出来!
四.总结
一个学期以来我从c51中从0开始,学了一些不少东西,对于一个系统设计来说,首先是要了解这个系统用来干什么,再对芯片进行选择,同时编制程序,然后联合调试,再后硬件和软件联合调试,不符合要求在分析具体原因!。