视屏效果在作者的博客上
http://hi.baidu.com/52%5Fdiy/blog/item/9b1b8009a8a610256b60fba8.html
/**************************************************************************
作品名:旋转LED时钟
作者:李景良
所用芯片:AT89C2051+DS1302
程序长度325行(加注释加空行)
请珍惜作者的劳动成果,此程序未经作者许可,禁止传播或作为商业用途。
**************************************************************************/
#include <REG2051.H> //定义头文件
#define uchar unsigned char //定义缩写字符
#define uint unsigned int
//以下定义DS1302时钟接口
sbit clock_clk=P3^4;
sbit clock_IO=P3^5;
sbit clock_Rst=P3^7;
//-----------------------------独立键盘定义
sbit Set1_Key= P3^0;//设定键
sbit Set2_Key= P3^1;//设定键进行调整
//-----------------------------定义累加器A中的各位
sbit a0=ACC^0;
sbit a1=ACC^1;
sbit a2=ACC^2;
sbit a3=ACC^3;
sbit a4=ACC^4;
sbit a5=ACC^5;
sbit a6=ACC^6;
sbit a7=ACC^7;
//以下定义全局变量
uchar sec,min,hour,k;
uint o;
//以下函数声明
uchar DSInputByte(void); //DS1302写入字节(底层协议)
void DSOutputByte(uchar dd); //DS1302读出字节(底层协议)
void write_clock(uchar ord,uchar dd); //向DS1302写入数据
uchar read_clock(uchar ord); //从DS1302读出数据
void read_clockS(void); //常用时钟读取
void Reset_DS1302(void); //初始日期时间
void Set_time(uchar sel); //设置时间日期
void delay(uchar a); //延时
void display_s(uchar z); //执行扫描
void display_sm(uchar m); //位扫描
void key(void); //检测按键调时
//以下定义扫描数字字符的二维数组
uchar dispLed[11][5]=
{
{0x82,0x7C,0x7C,0x7C,0x82}, //0
{0xFF,0xBC,0x00,0xFC,0xFF}, //1
{0xBC,0x78,0x74,0x6C,0x9C}, //2
{0x7A,0x7C,0x5C,0x2C,0x72}, //3
{0xE6,0xD6,0xB6,0x00,0xF6}, //4
{0x1A,0x5C,0x5C,0x5C,0x62}, //5
{0xC2,0xAC,0x6C,0x6C,0xF3}, //6
{0x3F,0x7F,0x71,0x6F,0x1F}, //7
{0x83,0x6D,0x6D,0x6D,0x83}, //8
{0x9B,0x6D,0x6D,0x6D,0x83}, //9
{0xFF,0xFF,0x92,0xFF,0xFF}, //显示小时、分、秒之间的:字符
};
uchar dispLed2[28]={0xFF,0x7D,0x00,0x7D,0xFF,0xC7,0x83,0xC1,0x83,0xC7,0xFF,0x03,0xFD,0xFD,0xFD,0x03,
0xFF,
0x00,0x6F,0x6F,0x6F,0x7F, //F
0xFF,
0x00,0xFD,0xFD,0xFD,0xF9, //L
};
//I心U图案
//===============================================主函数
void main(void) //主函数
{
write_clock(0x8e,0x00); //允许写操作
write_clock(0x90,0xa5); //打开充电二极管串联一个2K电阻
write_clock(0x8e,0x80); //禁止写操作
o=0;
k=0;
TCON|=0x01; //外部中断0下降沿触发
IE=0x81; //开中断
while(1) //死循环,此循环完成两项功能,1是等待中断,2是在没有中断时循环按键函数进行调时
{
key(); //调用调时函数
}
}
//************************************************以下对DS1320进行操作
void Reset_DS1302(void) //将恢复初始日期时间函数,调整初始日期为2006年05月01日12时00分00秒星期一
{
write_clock(0x8e,0x00); //允许写操作
write_clock(0x8c,0x06); //年
write_clock(0x8a,0x01); //星期
write_clock(0x88,0x05); //月
write_clock(0x86,0x01); //日
write_clock(0x84,0x12); //小时
write_clock(0x82,0x00); //分钟
write_clock(0x80,0x00); //秒
write_clock(0x8e,0x80); //禁止写操作
}
void DSOutputByte(uchar dd) //DS1302读出字节(底层协议)
{
ACC=dd;
clock_IO=a0; clock_clk=1; clock_clk=0;
clock_IO=a1; clock_clk=1; clock_clk=0;
clock_IO=a2; clock_clk=1; clock_clk=0;
clock_IO=a3; clock_clk=1; clock_clk=0;
clock_IO=a4; clock_clk=1; clock_clk=0;
clock_IO=a5; clock_clk=1; clock_clk=0;
clock_IO=a6; clock_clk=1; clock_clk=0;
clock_IO=a7; clock_clk=1; clock_clk=0;
}
uchar DSInputByte(void) //DS1302写入字节(底层协议)
{
clock_IO=1;
a0=clock_IO;
clock_clk=1; clock_clk=0; a1=clock_IO;
clock_clk=1; clock_clk=0; a2=clock_IO;
clock_clk=1; clock_clk=0; a3=clock_IO;
clock_clk=1; clock_clk=0; a4=clock_IO;
clock_clk=1; clock_clk=0; a5=clock_IO;
clock_clk=1; clock_clk=0; a6=clock_IO;
clock_clk=1; clock_clk=0; a7=clock_IO;
return(ACC);
}
uchar read_clock(uchar ord) //DS1302读数据(底层协议)
{
uchar dd=0;
clock_clk=0;
clock_Rst=0;
clock_Rst=1;
DSOutputByte(ord);
dd=DSInputByte();
clock_Rst=0;
clock_clk=1;
return(dd);
}
void write_clock(uchar ord, uchar dd) //DS1302写数据(底层协议)
{
clock_clk=0;
clock_Rst=0;
clock_Rst=1;
DSOutputByte(ord);
DSOutputByte(dd);
clock_Rst=0;
clock_clk=1;
}
void read_clockS(void) //常用时钟数据读取
{
sec=((read_clock(0x81))/16)*10 + (read_clock(0x81))%16; //秒
min=((read_clock(0x83))/16)*10 + (read_clock(0x83))%16; //分钟
hour=((read_clock(0x85))/16)*10+(read_clock(0x85))%16; //小时
}
//调时用加1程序
void Set_time(uchar sel) //根据选择调整的相应项目加1并写入DS1302
{
signed char add,item;
signed char max,mini;
if(sel==3) {add=0x80; max=0;mini=0;} //秒7
if(sel==2) {add=0x82; max=59;mini=0;} //分钟6
if(sel==1) {add=0x84; max=23;mini=0;} //小时5
//读取1302某地址上的数值转换成10进制赋给item
item=((read_clock(add+1))/16)*10 + (read_clock(add+1))%16;
item++;//数值加1
if(item>max) item=mini;//查看数值有效范围
if(item<mini) item=max;
write_clock(0x8e,0x00);//允许写操作
write_clock(add,(item/10)*16+item%10);//转换成16进制写入1302
write_clock(0x8e,0x80);//写保护,禁止写操作
}
//****************************************************以下扫描输出
void display(void) interrupt 0 //显示(中断处理)
{
uchar c;
k=0; //退出调时状态
o++;
if (o<80) //显示I心U
{
delay(15); //移位,使图案显示在中央位置
for (c=0;c<28;c++)
{
P1=dispLed2[c];
delay(2);
}
P1=0xFF;
}
else //显示时间
{
read_clockS(); //读出时间值
display_sm(hour); //将小时值作为入口参数进行小时显示
display_s(10); //显示小时与分之间的冒号符号
display_sm(min); //将分钟值作为入口参数进行分钟显示
display_s(10); //显示分钟与秒之间的冒号符号
display_sm(sec); //将秒值作为入口参数进行秒显示
}
if (o==500) //当o等于500时,将o清零,再次显示I心U图案
{
o=0;
}
}
void display_sm(uchar m) //位扫描
{
display_s(m/10); //十位显示
delay(2);
switch (m%10) //个位
{
case 0: //0
display_s(0);
break;
case 1: //1
display_s(1);
break;
case 2: //2
display_s(2);
break;
case 3: //3
display_s(3);
break;
case 4: //4
display_s(4);
break;
case 5: //5
display_s(5);
break;
case 6: //6
display_s(6);
break;
case 7: //7
display_s(7);
break;
case 8: //8
display_s(8);
break;
case 9: //9
display_s(9);
break;
}
}
void display_s(uchar z) //执行扫描
{
uchar i;
for (i=0;i<5;i++)
{
P1=dispLed[z]
;
delay(2);
}
P1=0xFF;
}
//************************************************其它函数
void key(void) //检测按键并调时
{
if(Set1_Key==0) //正常显示时同时按下Set1_Key、Set2_Key二个键则初始化时间
{
delay(2); //延时去抖动
if(Set1_Key==0&&Set2_Key==0)
{
Reset_DS1302(); //调用时间初始化函数
}
}
if(Set1_Key==0) //调时切换键按下切换调时的内容
{
delay(2); //去抖
if(Set1_Key==0)
{
k++;//切换累加变量
if(k>3) //切换值超出后清0
{
k=0;
}
while(Set1_Key==0)//等待键放开
{
}
}
}
if(Set2_Key==0) //位加1键(使小时、分、秒加1)
{
delay(2); //去抖
if(Set2_Key == 0)
{
switch(k) //根据Set1_Key的按键次数进行数据调整
{
case 1:
{
Set_time(1);//秒调整
}
break;
case 2:
{
Set_time(2);//小时调整
}
break;
case 3:
{
Set_time(3);//分钟调整
}
break;
}
while(Set2_Key==0 )//等待按键释放
{
}
}
}
}
void delay(uchar a) //延时函数
{
uchar i;
while(--a!=0)
{
for (i=0;i<80;i++);
}
}
[
本帖最后由 电火花 于 2008-1-8 21:25 编辑 ]