#include <STC15.H> // 該程序具有顯示日期、月份、日期和時間功能
#include <GPIO.H>
#include<stdio.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define sint signed int
#define disp_off 0x3e //顯示關
#define disp_on 0x3f //顯示開
#define disp_x 0xb8 //頁地址為0頁
#define disp_z 0xc0 //行地址為0行
#define disp_y 0x40 //列地址為0列
#define comm 0 //命令標志位
#define dat1 1 //數據標志位
//#define data_ora P0 //液晶12864的數據端與單片機的P0相連
sbit di =P2^0; //Data or Instrument Select,H:寫數據,L:寫指令
sbit rw =P2^1; //Write or Read,H:read,L:write
sbit e =P2^4; //讀寫使能
sbit cs1=P2^2; //cs1=H,選擇左半屏
sbit cs2=P2^3; //cs2=H,選擇右半屏
sbit clk=P1^0; //8563 clk
sbit dat=P1^1; //8563 data
sbit DS = P2^5; //SER 串行數據
sbit SHCP= P2^6; //SCK 串行時鐘信號
sbit STCP = P2^7; //ST 鎖存輸出信號
uchar fen=0x42,miao=0x38,shi=0x17,riqi=0x02,//設置時間用
yuefen=0x09,xingqi=0x00,nian=0x07,zhongduan;//設置時間用
uchar code tabma[10][16]=
//陰碼點陣格式、取模方式為列行式、逆向取模(低位在前),
//十六進制輸出,中文16*16,英文8*16 宋體
{
//0(0) 1(1) 2(2) 3(3) 4(4) 5(5) 6(6) 7(7) 8(8) 9(9)
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00}, /*"0",0*/
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00}, /*"1",1*/
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00}, /*"2",2*/
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00}, /*"3",3*/
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00}, /*"4",4*/
{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00}, /*"5",5*/
{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00}, /*"6",6*/
{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00}, /*"7",7*/
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00}, /*"8",8*/
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00}, /*"9",9*/
};
uchar code tab2ma[7][32]=
// 日(0) 一(1) 二(2) 三(3) 四(4) 五(5) 六(6)
{
{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}, /*"日",0*/
{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /*"一",1*/
{0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,
0x04,0x04,0x04,0x06,0x04,0x00,0x00,0x00,
0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x18,0x10,0x00}, /*"二",2*/
{0x00,0x04,0x84,0x84,0x84,0x84,0x84,0x84,
0x84,0x84,0x84,0x84,0x84,0x04,0x00,0x00,
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00}, /*"三",3*/
{0x00,0xFE,0x02,0x02,0x02,0xFE,0x02,0x02,
0xFE,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,
0x00,0x7F,0x28,0x24,0x23,0x20,0x20,0x20,
0x21,0x22,0x22,0x22,0x22,0x7F,0x00,0x00}, /*"四",4*/
{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}, /*"五",5*/
{0x10,0x10,0x10,0x10,0x10,0x91,0x12,0x1E,
0x94,0x10,0x10,0x10,0x10,0x10,0x10,0x00,
0x00,0x40,0x20,0x10,0x0C,0x03,0x01,0x00,
0x00,0x01,0x02,0x0C,0x78,0x30,0x00,0x00}, /*"六",6*/
};
uchar code nianma[]=
//年(0) 月(1) 日(2) 星(3) 期(4)
{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}; /*"年",0*/
uchar code yuema[]=
{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}; /*"月",1*/
uchar code rima[]=
{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}; /*"日",2*/
uchar code xingqima[]=
{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, /*"星",3*/
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}; /*"期",4*/
//時(0) 分(1) 秒(2)
uchar code shima[]=
{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}; /*"時",0*/
uchar code fenma[]=
{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}; /*"分",1*/
uchar code miaoma[]=
{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}; /*"秒",2*/
void delay(sint n); //延時程序
void xie_start(); //開始條件
void xie_stop(); //停止條件
bit xie1(uchar shu); //向8563中寫入1個字
uchar du1(); //從8563中讀出1個字
uchar du(); //從8563中讀出時間和日期
uchar xie(); //向8563中設置時間和日期
//uchar xie_dingshi(); //8563定時器設置
//uchar xie_fangbo_dingshi(); //8563的方波設置
void delay1 (uint ms); //延時
void wr_lcd (uchar dat_comm,uchar content); //向12864中寫命令
//uchar rd_lcd (); //讀12864數據
void chk_busy (); //忙閑檢測
void lat_disp (uchar data1,uchar data2); //寫點鐘
//void img_disp (uchar code *img) ; //顯示圖像
void chn_disp (uchar x,uchar y,uchar xl,uchar yl,uchar row_xl,uchar row_yl,uchar code *chn);
//顯示漢字
void init_lcd (); //12864初始化
void disp(); //128顯示程序
void hc595SendByte(unsigned char dat)
{
unsigned char i;
for(i=0; i<8; i++)
{
SHCP=0;
DS=dat&0x80;
_nop_();
dat=dat<<1;
_nop_();
SHCP=1;
_nop_();
}
SHCP=0;
}
void Out595(void)
{
STCP=1;
STCP=0;
}
//-------------主函數--------------------
void main()
{
uchar ml=0;
init_lcd (); //LCD初始化
lat_disp(0x00,0x00);
xie(); //預設時間用,設置好時間后可以屏蔽
for(;;)
{
du(); //讀8563的時間
lat_disp(0x00,0x00);
disp(); //顯示時間
delay1(100);
}
}
//-------------------延時---------------------------//
void delay(sint n)
{
for(n;n>0;n--);
}
/////////////////////以下是PCF8563讀寫/////////////////////以下是PCF8563讀寫
/* I2C的起始條件,在時鐘端SCK為高電平時,數據端SDA發生由高到低的變化,為起始條件,
啟動I2C總線。程序代碼如下。 */
void xie_start()
{
clk=1;
_nop_();
dat=1;
_nop_();
dat=0;
_nop_();
clk=0;
_nop_();
}
/* I2C的停止條件,在時鐘端SCL為高電平時,數據端SDA發生由低到高的變化,
為停止條件,停止I2C總線數據傳輸。 */
void xie_stop()
{
dat=0;
_nop_();
clk=1;
_nop_();
dat=1;
_nop_();
}
bit xie1(uchar shu) //向8563中寫入1個字
{
uchar i=8;
bit fan_w;
clk=0;
_nop_();
while(i--)
{
dat=(bit)(shu&0x80); //取字節的最高位
_nop_();
shu<<=1; //字節左移一位
clk=1; //上升沿鎖存數據
_nop_();
clk=0;
_nop_();
}
dat=1;
_nop_();
clk=1;
_nop_();
fan_w=dat; //讀應答信號
clk=0;
_nop_();
return(fan_w); //返回應答信號
}
uchar du1() //從8563中讀出1個字
{
uchar shu=0;
uchar data rdata;
uchar i=8;
while(i--)
{
rdata<<=1; //字節左移一位
dat=1;
clk=1;_nop_(); //上升沿鎖存數據
if(dat) rdata|=0x01; //數據線為1時 對應位存1
clk=0;_nop_();
}
shu=rdata; //讀到的數據存于SHU
return(shu); //返回讀到的數據
}
uchar du()
{
EA=0; //關總中斷
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//取器件地址 寫
if(xie1(0x02)!=0){xie_stop();return(0);}//取讀時間的首字節地址從秒開始讀
xie_start(); //起始條件
if(xie1(0xa3)!=0){xie_stop();return(0);}//取器件地址 讀
miao=du1()&0x7f; //讀秒 屏蔽最高位
xie_stop(); //停止條件
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//取器件地址 寫
if(xie1(0x03)!=0){xie_stop();return(0);}//取讀分鐘字節地址
xie_start(); //起始條件
if(xie1(0xa3)!=0){xie_stop();return(0);}//取器件地址 讀
fen=du1()&0x7f; //讀分 屏蔽最高位
xie_stop(); //停止條件
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//取器件地址 寫
if(xie1(0x04)!=0){xie_stop();return(0);}//取讀小時字節地址
xie_start(); //起始條件
if(xie1(0xa3)!=0){xie_stop();return(0);}//取器件地址 讀
shi=du1(); //讀時
shi&=0x3f; //屏蔽最高2位
xie_stop(); //停止條件
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//寫
if(xie1(0x05)!=0){xie_stop();return(0);}//取讀日期字節地址
xie_start(); //起始條件
if(xie1(0xa3)!=0){xie_stop();return(0);}//讀
riqi=du1(); //讀日期
riqi&=0x3f; //屏蔽最高2位
xie_stop(); //停止條件
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//寫
if(xie1(0x07)!=0){xie_stop();return(0);}//取讀月份字節地址
xie_start(); //起始條件
if(xie1(0xa3)!=0){xie_stop();return(0);}//讀
yuefen=du1(); //讀月份
yuefen&=0x1f; //屏蔽最高3位
xie_stop(); //停止條件
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//寫
if(xie1(0x06)!=0){xie_stop();return(0);}//星期字節地址
xie_start(); //起始條件
if(xie1(0xa3)!=0){xie_stop();return(0);}//讀
xingqi=du1(); //讀星期
xingqi&=0x07; //保留低3位
xie_stop(); //停止條件
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//寫
if(xie1(0x08)!=0){xie_stop();return(0);}//年份字節地址
xie_start(); //起始條件
if(xie1(0xa3)!=0){xie_stop();return(0);}//讀
nian=du1(); //讀年份
xie_stop(); //停止條件
EA=1; //開總中斷
return(1);
}
uchar xie()
{
EA=0;
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//取器件地址 寫
if(xie1(0x02)!=0){xie_stop();return(0);}//寫秒地址
if(xie1(miao)!=0){xie_stop();return(0);}//寫秒
xie_stop(); //停止條件
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//取器件地址 寫
if(xie1(0x03)!=0){xie_stop();return(0);}//寫分地址
if(xie1(fen)!=0){xie_stop();return(0);} //寫分
xie_stop();
xie_start(); //起始條件
if(xie1(0xa2)!=0){xie_stop();return(0);}//取器件地址 寫
if(xie1(0x04)!=0){xie_stop();return(0);}//寫小時地址
if(xie1(shi)!=0){xie_stop();return(0);} //寫時
xie_stop();
xie_start(); //寫日期
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x05)!=0){xie_stop();return(0);}
if(xie1(riqi)!=0){xie_stop();return(0);}
xie_stop();
xie_start(); //寫月份
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x07)!=0){xie_stop();return(0);}
if(xie1(yuefen)!=0){xie_stop();return(0);}
xie_stop();
xie_start(); //寫星期
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x06)!=0){xie_stop();return(0);}
if(xie1(xingqi)!=0){xie_stop();return(0);}
xie_stop();
xie_start(); //寫年份
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x08)!=0){xie_stop();return(0);}
if(xie1(nian)!=0){xie_stop();return(0);}
xie_stop();
EA=1;
return(1);
}
/* uchar xie_dingshi() //定時器
{
xie_start(); // 控制中斷開關
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x01)!=0){xie_stop();return(0);}
if(xie1(0x01)!=0){xie_stop();return(0);}
xie_start(); //定時器控制器
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x0e)!=0){xie_stop();return(0);}
if(xie1(0x82)!=0){xie_stop();return(0);}
xie_start(); //計數器
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x0f)!=0){xie_stop();return(0);}
if(xie1(5)!=0){xie_stop();return(0);}
xie_stop();
return(1);
} */
/* uchar xie_fangbo_dingshi()
{
xie_start(); //方波頻率
if(xie1(0xa2)!=0){xie_stop();return(0);}
if(xie1(0x0d)!=0){xie_stop();return(0);}
if(xie1(0x82)!=0){xie_stop();return(0);}
xie_stop();
return(1);
} */
/////////////////////以上是PCF8563讀寫/////////////////////以上是PCF8563讀寫
/*---------------延時子程序----------------*/
void delay1 (uint ms)
{
uint i,j;
for(i=0;i<ms;i++)
for(j=0;j<1000;j++);
}
/*------------寫數據或命令到LCD--------------*/
void wr_lcd (uchar dat_comm,uchar content)
{
chk_busy (); //
di=dat_comm; //命令標志
rw=0; //寫
hc595SendByte(content);
Out595(); //寫數據到LCD的數據端
e=1; //下降沿鎖定數據
e=0;
}
/*--------------讀LCD數據---------------*/
/* uchar rd_lcd ()
{
uchar rddata;
chk_busy ();
di=1;
rw=1; //讀
e=1;
rddata=data_ora; //讀數據
e=0; //下降沿鎖定數據
return rddata;
} */
void chk_busy()
{
hc595SendByte(1);
Out595(); //寫1到LCD的數據端
di=0;
rw=1; //讀
e=1;
//while(bf||res==1);
e=0;
}
/*--------------寫點陣------------------*/
void lat_disp (uchar data1,uchar data2)
{
uchar i,j;
cs1=1;cs2=1; //左右屏幕同時選中
wr_lcd (comm,disp_on); //寫命令字,顯示開
for(j=0;j<8;j++)
{
wr_lcd (comm,disp_x+j); //頁地址調整
wr_lcd (comm,disp_z); //指向對應頁的0行
wr_lcd (comm,disp_y); //指向對應頁的0列
for(i=0;i<32;i++) //寫64個數據
{
wr_lcd (dat1,data1);
wr_lcd (dat1,data2);
}
}
}
/*--------------顯示圖片----------------*/
/* void img_disp (uchar code *img)
{
uchar i,j;
for(j=0;j<8;j++)
{
cs1=0;cs2=1; //左半屏幕選中
wr_lcd (comm,disp_on); //寫命令字,顯示開
wr_lcd (comm,disp_x+j); //頁地址調整
wr_lcd (comm,disp_z); //指向對應頁的0行
wr_lcd (comm,disp_y); //指向對應頁的0列
for(i=0;i<64;i++) //寫64個數據
wr_lcd (dat1,img[j*128+i]);
cs1=1;cs2=0; //右半屏幕選中
wr_lcd (comm,disp_on); //寫命令字,顯示開
wr_lcd (comm,disp_x+j); //頁地址調整
wr_lcd (comm,disp_z); //指向對應頁的0行
wr_lcd (comm,disp_y); //指向對應頁的0列
for(i=64;i<128;i++) //寫64個數據
wr_lcd (dat1,img[j*128+i]);
}
} */
/*---指定位置(x,y)顯示row_xl行(每行row_yl個)漢字(大小8xl*yl)---*/
void chn_disp (uchar x,uchar y,uchar xl,uchar yl,uchar row_xl,uchar row_yl,uchar code *chn)
{
uchar i,j,k,l,a;
wr_lcd (comm,disp_on); //寫命令字,顯示開
for(l=0;l<row_xl;l++) //行數循環
{
for(k=0;k<row_yl;k++) //字數循環
{
for(j=0;j<xl;j++)
{
wr_lcd (comm,disp_x+x+l*xl+j); //行數調整
wr_lcd (comm,disp_z); //列數調整
wr_lcd (comm,disp_y+y+k*yl); //字數調整
a=l*xl*yl*row_yl+k*xl*yl+j*yl;
for(i=0;i<yl;i++) //寫數據
wr_lcd (dat1,chn[a+i]);
}
}
}
}
/*------------------初始化-----------------*/
void init_lcd ()
{
//rst=0;
delay(50);
//rst=1;
cs1=1;cs2=1; //左右屏幕同時選中
wr_lcd (comm,disp_off); //寫命令字,顯示關
wr_lcd (comm,disp_on); //寫命令字,顯示開
}
void disp()
{
cs1=0;cs2=1; //左半屏幕選中
chn_disp (0,8,2,8,1,1,tabma[2]); //固定顯示數字“2”
chn_disp (0,16,2,8,1,1,tabma[0]); //固定顯示數字“0”
chn_disp (0,24,2,8,1,1,tabma[nian/16]); //顯示年的數字十位
chn_disp (0,32,2,8,1,1,tabma[nian%16]); //顯示年的數字個位
chn_disp (0,40,2,16,1,1,nianma); //固定顯示漢字“年”
chn_disp (0,56,2,8,1,1,tabma[yuefen/16]); //顯示月份的數字十位
cs1=1;cs2=0; //右半屏幕選中
chn_disp (0,0,2,8,1,1,tabma[yuefen%16]); //顯示月份的數字個位
chn_disp (0,8,2,16,1,1,yuema); //固定顯示漢字“月”
chn_disp (0,24,2,8,1,1,tabma[riqi/16]); //顯示日期的數字十位
chn_disp (0,32,2,8,1,1,tabma[riqi%16]); //顯示日期的數字個位
chn_disp (0,40,2,16,1,1,rima); //固定顯示漢字“日”
cs1=0;cs2=1; //左半屏幕選中
chn_disp (3,8,2,16,1,2,xingqima); //固定顯示漢字“星期”
chn_disp (3,40,2,16,1,1,tab2ma[xingqi]); //顯示漢字星期幾
chn_disp (6,16,2,8,1,1,tabma[shi/16]); //顯示小時的數字十位
chn_disp (6,24,2,8,1,1,tabma[shi%16]); //顯示小時的數字個位
chn_disp (6,32,2,16,1,1,shima); //固定顯示漢字“時”
chn_disp (6,48,2,8,1,1,tabma[fen/16]); //顯示分鐘的數字十位
chn_disp (6,56,2,8,1,1,tabma[fen%16]); //顯示分鐘的數字個位
cs1=1;cs2=0; //右半屏幕選中
chn_disp (6,0,2,16,1,1,fenma); //固定顯示漢字“分”
chn_disp (6,16,2,8,1,1,tabma[miao/16]); //顯示秒的數字十位
chn_disp (6,24,2,8,1,1,tabma[miao%16]); //顯示秒的數字個位
chn_disp (6,32,2,16,1,1,miaoma); //固定顯示漢字“秒”
}
|