#include <stc12c5a60s2.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD_data P0 //数据口
#define LIE 0xf0
#define HANG 0x0f
sbit LCD_RS = P3^5; //寄存器选择输入
sbit LCD_RW = P3^6; //液晶读/写控制
sbit LCD_EN = P3^4; //液晶使能控制
sbit LCD_PSB = P3^7;
sbit sclk=P2^0; //时钟模块
sbit io=P2^1;
sbit ce=P2^2;
sbit beep=P2^3; //蜂鸣器
uchar code dis1[] = {"星期"};
uchar code dis2[] = {"公历:"};
uchar code dis3[] = {"闹钟"};
uchar code dis5[] = {"ON"};
uchar code dis6[] = {"OFF"};
uchar dis4[] = {"零一二8三990123456789四五六七"};
uchar time_data[]={15,6,4,17,23,59,55};//年 周 月 日 时 分 秒
uchar write_add[]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80};
uchar read_add[]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};
uchar disp[13];
uchar num,knum1,knum3;shi=21,fen,miao;
/*定义数字ascii编码*/
unsigned char mun_char_table[]={"0123456789abcdef"};
void lcd_pos(uchar X,uchar Y); //确定显示位置
void delay1ms(uint ms) //延时程序1ms
{
uint i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
/*******************************************************************/
/* */
/* 延时函数 */
/* */
/*******************************************************************/
void delay(int ms)
{
while(ms--)
{
uchar i;
for(i=0;i<250;i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
/*******************************************************************/
/* */
/*检查LCD忙状态 */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。 */
/* */
/*******************************************************************/
bit lcd_busy()
{
bit result;
P0=0X00; //关掉数码管的信号。阻止数码管受到P0口信号的影响
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delay(1);
result = (bit)(P0&0x80);
LCD_EN = 0;
return(result);
}
/*******************************************************************/
/* */
/*写指令数据到LCD */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。 */
/* */
/*******************************************************************/
void lcd_wcmd(uchar cmd)
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
delay(1);
LCD_EN = 1;
delay(1);
LCD_EN = 0;
}
/*******************************************************************/
/* */
/*写显示数据到LCD */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。 */
/* */
/*******************************************************************/
void lcd_wdat(uchar dat)
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
delay(1);
LCD_EN = 1;
delay(1);
LCD_EN = 0;
}
/*******************************************************************/
/* */
/* LCD初始化设定 */
/* */
/*******************************************************************/
void lcd_init()
{
LCD_PSB = 1; //并口方式
lcd_wcmd(0x34); //扩充指令操作
delay(5);
lcd_wcmd(0x30); //基本指令操作
delay(5);
lcd_wcmd(0x0c); //显示开,关光标
delay(5);
//lcd_wcmd(0x06);//光标设置
//delay(5);
lcd_wcmd(0x01);//清除LCD的显示内容
delay(5);
}
/***********************************************************************
以上是lcd显示
***********************************************************************/
/**********************************************************************
写地址
***********************************************************************/
void write_ds1302_byte(uchar add)
{
uchar i;
for(i=0;i<8;i++)
{
sclk=0;
io=add&0x01;
add=add>>1;
sclk=1;
}
}
/**********************************************************************
写一个字节
***********************************************************************/
void write_ds1302(uchar add,uchar dat)
{
ce=0;
sclk=0;
ce=1;
_nop_();
write_ds1302_byte(add);
write_ds1302_byte(dat);
ce=0;
_nop_();
io=1;
sclk=1;
}
/**********************************************************************
读单字节
***********************************************************************/
uchar read_ds1302(uchar add)
{
uchar i,value;
ce=0;
sclk=0;
ce=1;
_nop_();
write_ds1302_byte(add);
for(i=0;i<8;i++)
{
value=value>>1;
sclk=0;
if(io)
{
value=value|0x80;
}
sclk=1;
}
ce=0;
_nop_();
sclk=0;
_nop_();
sclk=1;
io=1;
return value;
}
/**********************************************************************
写数据
***********************************************************************/
void set_rtc()
{
uchar i,j,k;
for(i=0;i<7;i++)
{
j=time_data[i]/10;
k=time_data[i]%10;
time_data[i]=k+j*16;
}
write_ds1302(0x8e,0x00);//去除写保护
for(i=0;i<7;i++)
{
write_ds1302(write_add[i],time_data[i]);
}
write_ds1302(0x8e,0x80);//加写保护
}
/**********************************************************************
读时间
***********************************************************************/
void read_rtc()
{
uchar i;
for(i=0;i<7;i++)
{
time_data[i]=read_ds1302(read_add[i]);
}
}
/**********************************************************************
bcd码转换
***********************************************************************/
void time_pros()
{
disp[0]=time_data[0]/16;//算出年
disp[1]=time_data[0]%16;
disp[2]=time_data[1]%16;//算出周
disp[3]=time_data[2]/16;//算出月
disp[4]=time_data[2]%16;
disp[5]=time_data[3]/16;//算出日
disp[6]=time_data[3]%16;
disp[7]=time_data[4]/16;//算出小时
disp[8]=time_data[4]%16;
disp[9]=time_data[5]/16;//算出分
disp[10]=time_data[5]%16;
disp[11]=time_data[6]/16;//算出秒
disp[12]=time_data[6]%16;
}
/**********************************蜂鸣器************************/
void beepplay()
{
beep=0;
delay1ms(500);
beep=1;
}
/**************整点报时*********************************/
void zhengdian()
{
uchar hour;
hour=disp[7]*10+disp[8];
if(disp[11]==0&&disp[12]==0)
{
if(disp[9]==0&&disp[10]==0)
{
beepplay();
}
}
}
/*************************************按键*********************/
void Matrixkeyscan()
{
uchar key_lie; //按键扫描函数里用来存储列的变量
uchar key_hang; //存储行的变量
uchar key; //具体按下的键值的编码
P1=LIE; //行为低电平,列为高电平
key_lie=P1; //读取IO的数值
key_lie=key_lie&LIE; //与,将低四位屏蔽
if(key_lie!=LIE) //如果不等,说明有按键按下
{
delay(25); //去抖动
if(key_lie!=LIE) //说明确实有按键被按下
{
key_lie=P1; //读取最新的P3值
key_lie=key_lie&LIE; //得到最新的列的信息
//假如第一列的某个按键按下,例如4*4键盘key_lie为1110 0000
P1=HANG; //列为低电平,行为高电平
key_hang=P1; //读取P3口
key_hang=key_hang&HANG; //将高四位屏蔽掉,得到具体的行的信息,假如4×4第一行的某个按键被按下
//则key_hang为0000 1110
key=key_hang|key_lie; //将行和列的信息相或,1110 0000 |0000 1110=1110 1110,
//可知第一行,第一列的按键被按下
}
while(P1!=HANG); //等待按键被释放
}
switch(key) //根据按键的数值进行判断
{
case 0xee: knum1++;break; //0xee=1110 1110 说明第一个按键被按下,则num的值为0;
case 0xde: num=2;break;
case 0xbe: knum3++;break;
case 0x7e: num=4;break;
case 0xed: num=5;break;
case 0xdd: num=6;break;
case 0xbd: num=7;break;
case 0x7d: num=8;break;
case 0xeb: num=9;break;
case 0xdb: num=10;break;
case 0xbb: num=11;break;
case 0x7b: num=12;break;
case 0xe7: num=13;break;
case 0xd7: num=14;break;
case 0xb7: num=15;break;
case 0x77: num=16;break;
case 0xff: num=17;break;
}
key=0xff;
}
/*************************闹钟设置**************************/
void keys()
{
if(knum3==4)
{
knum3=0;
}
if(knum3!=0)
{
if(num==2)
{
switch(knum3)
{
case 1 :
miao++;
if(miao==60)
{miao=0;}
num=17;
break;
case 2 :
fen++;
if(fen==60)
{fen=0;}
num=17;
break;
case 3 :
shi++;
if(shi==24)
shi=0;
num=17;
break;
}
}
}
}
void main()
{
uchar i;
lcd_init(); //初始化LCD
set_rtc();
lcd_pos(0,4); //设置显示位置为第一行的第1个字符
i = 0;
while(dis1[i] != '\0')
{ //显示星期
lcd_wdat(dis1[i]);
i++;
}
lcd_pos(1,0); //设置显示位置为第二行的第1个字符
i = 0;
while(dis2[i] != '\0')
{ //显示日期
lcd_wdat(dis2[i]);
i++;
}
lcd_pos(2,0); //设置显示位置为第三行的第1个字符
i = 0;
while(dis3[i] != '\0')
{ //显示闹铃
lcd_wdat(dis3[i]);
i++;
}
while(1)
{
read_rtc();
time_pros();
Matrixkeyscan();
keys();
zhengdian();
lcd_pos(0,0); //第一行显示时间
lcd_wdat(mun_char_table[disp[7]]);
lcd_wdat(mun_char_table[disp[8]]);
lcd_wdat(':');
lcd_wdat(mun_char_table[disp[9]]);
lcd_wdat(mun_char_table[disp[10]]);
lcd_wdat(':');
lcd_wdat(mun_char_table[disp[11]]);
lcd_wdat(mun_char_table[disp[12]]);
delay(10);
lcd_pos(0,6); //显示星期
lcd_wdat(0xb6);
lcd_wdat(0xfe);
lcd_pos(1,3); //第二行显示实时日期
lcd_wdat(mun_char_table[2]);
lcd_wdat(mun_char_table[0]);
lcd_wdat(mun_char_table[disp[0]]);
lcd_wdat(mun_char_table[disp[1]]);
lcd_wdat('-');
lcd_wdat(mun_char_table[disp[3]]);
lcd_wdat(mun_char_table[disp[4]]);
lcd_wdat('-');
lcd_wdat(mun_char_table[disp[5]]);
lcd_wdat(mun_char_table[disp[6]]);
delay(10);
lcd_pos(2,2);
lcd_wdat(':');
if(knum1==0)
{
i = 0;
while(dis5[i] != '\0')
{ //显示on
lcd_wdat(dis5[i]);
i++;
}
}
if(knum1==1||knum1==2||knum1==3)
{
i = 0;
while(dis6[i] != '\0')
{ //显示off
lcd_wdat(dis6[i]);
i++;
}
}
lcd_pos(2,4);
lcd_wdat(mun_char_table[shi/10]);
lcd_wdat(mun_char_table[shi%10]);
lcd_wdat(':');
lcd_wdat(mun_char_table[fen/10]);
lcd_wdat(mun_char_table[fen%10]);
lcd_wdat(':');
lcd_wdat(mun_char_table[miao/10]);
lcd_wdat(mun_char_table[miao%10]);
}
}
void lcd_pos(uchar X,uchar Y)
{
uchar pos;
if (X==0)
{X=0x80;}
else if (X==1)
{X=0x90;}
else if (X==2)
{X=0x88;}
else if (X==3)
{X=0x98;}
pos = X+Y ;
lcd_wcmd(pos); //显示地址
}
|