12864LCD万年历
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
12864LCD+DS1302万年历设计proteus仿真
(2011-05-18 23:09:40)
标签:
it
原理图
程序代码
//DS1302与12864设计的可调式电子日历与时钟//
#include<reg51.h>
#include<intrins.h>
#include<string.h>
#define uchar unsigned char
#define uint unsigned int
extern void LCD_Initialize();
extern void Display_A_Char_8x16(ucharP,ucharL,uchar *M)reentrant; extern void Display_A_WORD(ucharP,ucharL,uchar *M)reentrant;
//在调整日期时间时,用该位决定是否反白显示//
extern bit Reverse_Display;
sbit SDA =P1^0; //DS1302数据线
sbit CLK =P1^1; //DS1302时钟线
sbit RST =P1^2; //DS1302复位线
sbit K1 =P3^4; //选择
sbit K2 =P3^5; //加
sbit K3 =P3^6; //减
sbit K4 =P3^7; //确定
uchartCount =0;
//一年中每月的天数,2月的天数由年份决定
ucharMonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31};
//所读取的日期时间
ucharDateTime[7];
//当前调整的时间对象:秒,分,时,日,月,年(0,1,2,3,4,6)
//5对应星期,星期调节由年月日调整自动完成
char Adjust_Index=-1;
//水平与垂直偏移
ucharH_Offset=10,V_Page_Offset=0;
//年月日,星期,时分秒汉字点阵(16*16)------
uchar code DATE_TIME_WORDS[]=
{/
/
0x40,0x20,0x10,0x0C,0xE3,0x22,0x22,0x22,0xFE,0x22,0x22,0x22,0x22,0x02,0x00,0x00, 0x04,0x04,0x04,0x04,0x07,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x04,0x04,0x00, /
/
0x00,0x00,0x00,0x00,0x00,0xFF,0x11,0x11,0x11,0x11,0x11,0xFF,0x00,0x00,0x00,0x00,
0x00,0x40,0x20,0x10,0x0C,0x03,0x01,0x01,0x01,0x21,0x41,0x3F,0x00,0x00,0x00,0x00,
/
/
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,0x00,0x00,0xBE,0x2A,0x2A,0x2A,0xEA,0x2A,0x2A,0x2A,0x2A,0x3E,0x00,0x00,0x00, 0x00,0x48,0x46,0x41,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0x49,0x49,0x41,0x40,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,
/
/
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,
/
/
0x80,0x40,0x20,0x98,0x87,0x82,0x80,0x80,0x83,0x84,0x98,0x30,0x60,0xC0,0x40,0x00,
0x00,0x80,0x40,0x20,0x10,0x0F,0x00,0x00,0x20,0x40,0x3F,0x00,0x00,0x00,0x00,0x00,
/
/
0x12,0x12,0xD2,0xFE,0x91,0x11,0xC0,0x38,0x10,0x00,0xFF,0x00,0x08,0x10,0x60,0x00,
0x04,0x03,0x00,0xFF,0x00,0x83,0x80,0x40,0x40,0x20,0x23,0x10,0x08,0x04,0x03,0x00,
/
/
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,0x02,0x02,0x02,0x02,0x82,0x7E,0x22,0x22,0x22,0x22,0xF2,0x22,0x02,0x02,0x00,
0x00,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x20,0x60,0x20,0x1F,0x00,0x00,0x00,0x00,
/
/
0x00,0x00,0xFE,0x02,0x22,0x22,0x22,0x22,0xFA,0x22,0x22,0x22,0xE2,0x02,0x02,0x00, 0x40,0x30,0x0F,0x00,0x40,0x20,0x18,0x06,0x01,0x00,0x20,0x60,0x3F,0x00,0x00,0x00,
/
/
0x00,0x02,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0xC2,0x82,0x02,0x00,0x00,0x00, 0x20,0x20,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x20,0x3F,0x20,0x20,0x30,0x20,0x00,
/
/
0x42,0x42,0xFE,0x42,0x42,0xE0,0x00,0xFF,0x00,0x42,0x42,0xFE,0x42,0x42,0x42,0x00, 0x10,0x10,0x0F,0x88,0x49,0x20,0x18,0x07,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x00,
/
/
0x00,0xFE,0x22,0x52,0x8E,0x00,0xC4,0xB4,0x8C,0xE7,0x84,0x84,0x84,0x84,0x04,0x00, 0x00,0xFF,0x02,0x04,0x23,0x10,0x0C,0x40,0x80,0x7F,0x00,0x02,0x04,0x18,0x30,0x00,
/
0x00,0x10,0x10,0x92,0x72,0xA2,0xA2,0xF2,0xAA,0xAA,0x66,0xA2,0x12,0x18,0x00,0x00, 0x10,0x08,0x06,0x01,0x04,0x44,0x84,0x7F,0x04,0x04,0x04,0x01,0x06,0x18,0x08,0x00,
};
//星期几的汉字点阵(16*16)
uchar code WEEKDAY[]=
{/
/
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,
/
//
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
/
//
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,
/
/
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,
/
//
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,
//
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,
/
/
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,
};
//半角数字点阵(8*16)
uchar code DIGITS[]={//
//
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,
/
//
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
/
//
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,
/
/
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,
/
//
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,
//
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,
/
/
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,
/
/
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,
/
/
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,
/
/
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00, };
//向DS1302写、读一字节--------
//向DS1302写入一字节
void Write_A_Byte_TO_DS1302(uchar x)
{uchar i;
for (i=0;i<8;i++)
{SDA=x&1;CLK=1;CLK=0;x>>=1;}
}
//从DS1302读取一字节
uchar Get_A_Byte_FROM_DS1302()
{uchari,b,t;
for(i=0;i<8;i++)
{b>>=1;t=SDA;b|=t<<7;CLK=1;CLK=0;}
//BCD码转换
return b/16*10+b;}
//DS1302指定位置读数据
ucharRead_Data(ucharaddr)
{uchardat;
RST=0;CLK=0;RST=1;
Write_A_Byte_TO_DS1302(addr);
dat=Get_A_Byte_FROM_DS1302();
CLK=1;RST=0;
return dat;}
//向DS1302某地址写入数据
void Write_DS1302(ucharaddr,uchardat)
{CLK=0;RST=1;
Write_A_Byte_TO_DS1302(addr);
Write_A_Byte_TO_DS1302(dat);
CLK=0;RST=0;}
//设置时间
void SET_DS1302()
{uchar i;
Write_DS1302(0x8E,0x00);
//秒分时日月年依次写入
for(i=0;i<7;i++)
{//秒的起始地址10000000(0x80),
//后续依次是分,时,日,月,周,年,写入地址每次递增2 Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i])); }
Write_DS1302(0x8E,0x80);
}
//读取当前日期时间
void GetTime()
{uchar i;
for(i=0;i<7;i++)
{DateTime[i]=Read_Data(0x81+2*i);
}
}
//判断是否为闰年
ucharisLeapYear(uint y)
{return(y%4==0&&y0!=0)||(y@0==0);}
//----------------------------------------
void RefreshWeekDay()
{uinti,d,w=5;
for(i=2000;i<2000+DateTime[6];i++)
{d=isLeapYear(i)?366:365;
w=(w+d)%7;}
d=0;
for (i=1;i<DateTime[4];i++)
d+=MonthsDays[i];
d+=DateTime[3];
DateTime[5]=(w+d)%7+1;}
//年月日时分秒++--
void DateTime_Adjust(char x)
{switch(Adjust_Index)
{case 6://年00-99
if(x==1&&DateTime[6]<99) DateTime[6]++;
if(x==-1&&DateTime[6]>0)DateTime[6]--;
//获取2月天数
MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28; //如果年份变化后当前月份的天数大于上限则设为上限
if(DateTime[3]>MonthsDays[DateTime[4]])
DateTime[3]=MonthsDays[DateTime[4]];
RefreshWeekDay();//刷新星期
break;
case 4://月01-12
if(x==1&&DateTime[4]<12)DateTime[4]++;
if(x==-1&&DateTime[4]>1)DateTime[4]--;
//获取2月天数
MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;
//如果年份变化后当前月份的天数大于上限则设为上限
if(DateTime[3]>MonthsDays[DateTime[4]])
DateTime[3]=MonthsDays[DateTime[4]];
RefreshWeekDay();//刷新星期
break;
case 3://日00-28/29/30/31;调节前首先根据年份得出该年中2月的天数MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;
//根据当前月份决定调节日期的上限
if(x==1&&DateTime[3]<MonthsDays[DateTime[4]])DateTime[3]++;
if(x==-1&&DateTime[3]>0)DateTime[3]--;
RefreshWeekDay();//刷新星期
break;
case 2://时
if(x==1&&DateTime[2]<23)DateTime[2]++;
if(x==-1&&DateTime[2]>0)DateTime[2]--;
break;
case 1://分
if(x==1&&DateTime[1]<59)DateTime[1]++;
if(x==-1&&DateTime[1]>0)DateTime[1]--;
break;
case 0://秒
if(x==1&&DateTime[0] <59) DateTime[0]++;
if(x==-1&&DateTime[0] >0) DateTime[0]--;
break;}}
//定时器0每秒刷新LCD显示
void T0_INT() interrupt 1
{TH0=-50000/256;
TL0=-50000%6;
if(++tCount!=2)return;
tCount=0;
//年(后两位)
Reverse_Display=Adjust_Index==6;
Display_A_Char_8x16(V_Page_Offset,16+H_Offset,DIGITS+DateTime[6]/10*16); Display_A_Char_8x16(V_Page_Offset,24+H_Offset,DIGITS+DateTime[6]*16);
//月
Reverse_Display=Adjust_Index==4;
Display_A_Char_8x16(V_Page_Offset,48+H_Offset,DIGITS+DateTime[4]/10*16); Display_A_Char_8x16(V_Page_Offset,56+H_Offset,DIGITS+DateTime[4]*16);
//日
Reverse_Display=Adjust_Index==3;
Display_A_Char_8x16(V_Page_Offset,80+H_Offset,DIGITS+DateTime[3]/10*16); Display_A_Char_8x16(V_Page_Offset,88+H_Offset,DIGITS+DateTime[3]*16);
//星期
Reverse_Display=Adjust_Index==5;
Display_A_Char_8x16(V_Page_Offset+3,104+H_Offset, WEEKDAY+DateTime[5]*16-16);
//时
Reverse_Display=Adjust_Index==2;
Display_A_Char_8x16(V_Page_Offset+6,16+H_Offset,DIGITS+DateTime[2]/10*16); Display_A_Char_8x16(V_Page_Offset+6,24+H_Offset,DIGITS+DateTime[2]*16);
//分
Reverse_Display=Adjust_Index==1;
Display_A_Char_8x16(V_Page_Offset+6,48+H_Offset,DIGITS+DateTime[1]/10*16); Display_A_Char_8x16(V_Page_Offset+6,56+H_Offset,DIGITS+DateTime[1]*16);
//秒
Reverse_Display=Adjust_Index==0;
Display_A_Char_8x16(V_Page_Offset+6,80+H_Offset,DIGITS+DateTime[0]/10*16); Display_A_Char_8x16(V_Page_Offset+6,88+H_Offset,DIGITS+DateTime[0]*16);} //键盘中断(INT0)
void EX_INT0() interrupt 0
{
if (K1 == 0) //选择调整对象
{
if (Adjust_Index == -1 || Adjust_Index == 0) Adjust_Index = 7;
Adjust_Index--;
if (Adjust_Index == 5) Adjust_Index = 4; //跳过对星期的调整
}
else
if (K2 == 0)
DateTime_Adjust( 1); //加
else
if (K3 == 0)
DateTime_Adjust( -1 ); //减
else
if (K4 == 0) //确定
{
SET_DS1302();
Adjust_Index = -1;
}
}
void main()
{
//液晶初始化
LCD_Initialize();
//显示年的固定前两位
Display_A_Char_8x16(V_Page_Offset,0+H_Offset,DIGITS+2*16);
Display_A_Char_8x16(V_Page_Offset,8+H_Offset,DIGITS);
//显示固定汉字:年月日,星期,时分秒
Display_A_WORD(V_Page_Offset,32+H_Offset,DATE_TIME_WORDS+0*32); Display_A_WORD(V_Page_Offset,64+H_Offset,DATE_TIME_WORDS+1*32); Display_A_WORD(V_Page_Offset,96+H_Offset,DATE_TIME_WORDS+2*32); Display_A_WORD(V_Page_Offset+3,72+H_Offset,DATE_TIME_WORDS+3*32); Display_A_WORD(V_Page_Offset+3,88+H_Offset,DATE_TIME_WORDS+4*32); Display_A_WORD(V_Page_Offset+6,32+H_Offset,DATE_TIME_WORDS+5*32); Display_A_WORD(V_Page_Offset+6,64+H_Offset,DATE_TIME_WORDS+6*32); Display_A_WORD(V_Page_Offset+6,96+H_Offset,DATE_TIME_WORDS+7*32); Display_A_WORD(V_Page_Offset+2,0+H_Offset,DATE_TIME_WORDS+8*32); Display_A_WORD(V_Page_Offset+2,16+H_Offset,DATE_TIME_WORDS+9*32); Display_A_WORD(V_Page_Offset+2,32+H_Offset,DATE_TIME_WORDS+10*32); Display_A_WORD(V_Page_Offset+2,48+H_Offset,DATE_TIME_WORDS+11*32); Display_A_WORD(V_Page_Offset+4,0+H_Offset,DATE_TIME_WORDS+12*32); Display_A_WORD(V_Page_Offset+4,16+H_Offset,DATE_TIME_WORDS+13*32); Display_A_WORD(V_Page_Offset+4,32+H_Offset,DATE_TIME_WORDS+14*32); Display_A_WORD(V_Page_Offset+4,48+H_Offset,DATE_TIME_WORDS+15*32);
//允许INT0,T0中断
IE=0x83;
IP=0x01;
IT0=0x01;
TH0=-50000/256;
TL0=-50000/256;
TR0=1;
while(1)
{
//如果未执行调整操作则正常读取当前时间
if(Adjust_Index==-1)GetTime();
}
}
// 名称:12864LCD显示驱动程序(不带字库)//------------------------------------------------------------- #include <reg51.h>
#include <intrins.h>
#define unchar unsigned char
#define uint unsigned int
#define LCD_DB_PORT P0 //液晶DB0-DB7 #define LCD_START_ROW 0xC0 //起始行
#define LCD_PAGE 0xB8 //页指令
#define LCD_COL 0x40 //列指令
//液晶引脚定义
sbit DI =P2^0 ;
sbit RW =P2^1 ;
sbit E =P2^2 ;
sbit CS1 =P2^3 ;
sbit CS2 =P2^4 ;
sbit rst =P2^5 ;
bit Reverse_Display =0;
//----------------------------------------------------------- //检查LCD是否忙
//-----------------------------------------------------------
bit LCD_Check_Busy ()
{
LCD_DB_PORT =0xFF;
RW =1; _nop_(); DI =0;
E =1;_nop_(); E =0;
return (bit) (P0 & 0x80);
}
//-----------------------------------------------------------
// 向LCD发送命令
//-----------------------------------------------------------
void LCD_Write_Command( unchar c)
{
while (LCD_Check_Busy ());
LCD_DB_PORT =0xFF; RW =0; _nop_();DI =0;
LCD_DB_PORT = c; E =1; _nop_();E =0;
}
//-----------------------------------------------------------
//向LCD发送数据
//-----------------------------------------------------------
//向LCD发送数据
void LCD_Write_Data(uchar d )
{
while(LCD_Check_Busy());
LCD_DB_PORT = 0xFF;
RW = 0; _nop_();DI = 1;
//根据Reverse_Display决定是否反相显示
if (! Reverse_Display) LCD_DB_PORT = d; else LCD_DB_PORT = ~d;
E = 1 ;_nop_(); E = 0;
}
//初始化LCD
void LCD_Initialize()
{
CS1 = 1; CS2 = 1;
LCD_Write_Command(0x38);
LCD_Write_Command(0x0F);
LCD_Write_Command(0x01);
LCD_Write_Command(0x06);
LCD_Write_Command(LCD_START_ROW);}
void Common_Show(ucharP,ucharL,ucharW,uchar *r)reentrant {
uchar i;
if(L<64)//显示在左半屏或左右半屏
{
CS1=1; CS2=0;
LCD_Write_Command( LCD_PAGE+P);
LCD_Write_Command(LCD_COL + L);
if(L+W<64)
{
for(i=0;i<W;i++) LCD_Write_Data(r[i]);
}
else//如果月结则跨越左右半屏显示
{
for(i=0;i<64-L;i++) LCD_Write_Data(r[i]);
CS1=0;CS2=1;
LCD_Write_Command(LCD_PAGE+P);
LCD_Write_Command(LCD_COL);
for(i=64-L;i<W;i++) LCD_Write_Data(r[i]);
}
}
else // 全屏显示在右半屏
{
CS1=0;CS2=1;
LCD_Write_Command(LCD_PAGE + P);
LCD_Write_Command(LCD_COL+L-64);
for (i=0;i<W;i++)
LCD_Write_Data(r[i]);
}
}
//显示一个8X16点阵字符
//
void Display_A_Char_8X16(ucharP,ucharL,uchar *M) reentrant {
Common_Show( P, L, 8, M );
Common_Show( P +1,L,8,M+8 );
}
//显示一个16x16点阵汉字
void Display_A_WORD(ucharP,ucharL,uchar *M) reentrant {
Common_Show( P, L, 16, M); //显示汉字上半部分
Common_Show( P + 1,L, 16, M +16); //显示汉字下半部分}。