📄 16字单绿点阵屏电子钟.c
字号:
/*****************************************************
16字LED点阵屏+DS1302电子钟 C 程序
******************************************************
声明:
本程序中DS1302读写部分是直接引用网上网友提供的共享程序,
本程序供大家学习之用,用勿用于商业用途。尊重作者版权。
编写:邓椿薪
时间:2006年2月6日 晚
邮箱:love2151@xinhuanet.com
*******************************************************
DS1302 接线图
Vcc2 CLK I/O /RST
| | | |
-------------------
| 8 7 6 5 |
| DS1302 |
| |
| 1 2 3 4 |
-------------------
| | | |
VCC1 GND
1 脚接+5V 2,3脚32768HZ晶振 4脚接地 5脚接S51的P02 6脚接S51的P01 7接S51的P00
8脚接后备电源,可以接老计算机主板上的3.6V电池,也可以通过二级管隔离接一个大容量电解电容
电压在2.5V以上即可维持
595连级输出数据,138行驱动。*/
#include <AT89x51.H>
#define uchar unsigned char
#define uint unsigned int
uchar code hanzi[18][32];
uchar code hanzi2[];
uchar code timer[12][16];
uchar code sw[];
void xs_out(); /*输出显示*/
void out_rxd(unsigned char *d); /*串口发送一行*/
/******************************************/
sbit resget=P1^3; //时钟复位
sbit key_moda=P1^0; //模式转换
sbit key_up=P1^1; //时钟加
sbit key_Down=P1^2; //时钟减
sbit T_CLK=P1^7; //DS1302引脚连接
sbit T_IO =P1^6;
sbit T_RST=P1^5;
sbit ACC0=ACC^0; //1bit数据存储位
sbit ACC7=ACC^7;
uchar inittime[7]={0x00,0x10,0x22,0x13,0x01,0x05,0x06}; //初始化后设置
uchar yid,i,e,id,miao,fen,shi,nian,yue,ri,xinqi; //时间变量
uint zimuo,ss;
uchar BUFF[10]; // 缓存
void RTInputByte(uchar); /* 输入 1Byte */
uchar RTOutputByte(void); /* 输出 1Byte */
void W1302(uchar, uchar); // 向DS1302写入一个字节
uchar R1302(uchar); // 从DS1302读出一个字节
void Set1302(uchar *); // 写DS1302时间
void du1302(); // 读时间
void DelayMs(void); // 延时
void Set(uchar,uchar ); // 变量调整
void in_data(); // 调整移动数据
void rxd_data(); // 串口发送移动数据
/*主函数*/
void main()
{
yid=0;
zimuo=0;
SCON=0; //初始化串口为工作方式0(同步通信方式,TxD输出同步脉冲)
while(1) //重复循环显示
{
while(yid<16) //数据移位。
{
for(e=0;e<8;e++) //移动速度
{
if(resget==0)
{DelayMs();
if(resget==0)
Set1302(inittime); //初始化
W1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/
W1302(0x90,0xa5); //打开充电二级管 一个二级管串联一个2K电阻
}
du1302(); //读取 秒 分 时 日 月 星期 年
if (key_moda==0) // 设置和选择项目键
{DelayMs();
if(key_moda==0)
{
id++;if(id==8) {id=0;yid=0;zimuo=0;}
while(key_moda==0){ xs_out();}
}
}
if (key_up==0) //增加
{
DelayMs();
if(key_up==0)
{
while(key_up==0)
{xs_out();}
ss=0;
Set(id,0);
}
}
if (key_Down==0) //减少
{
DelayMs();
if(key_Down==0)
{
while(key_Down==0)
{xs_out();}
ss=0;
Set(id,1);
}
}
xs_out(); /******调用显示****/
}
yid++; //移动一步
}
yid=0;
zimuo=zimuo+32; //后移一个字,
if(zimuo>=960) //总数减2个字。
zimuo=0;
}
}
/************************************************/
void xs_out() //串行输出显示
{
for(i=0;i<16;i++)
{
ss++; //ss为闪烁延时计数器
if (ss==1500) //定义SS的大小决定调整时闪烁的快慢,小于750时为亮,大于750时为黑
{ss=0;}
if(id==0) //当ID为零时显示移动的汉字。在时间设置时ID不为零
{ //显示年。
in_data(); //调整移动数据
rxd_data(); //串口发送移动数据
}
else //id不为零时,显示年。只有在时钟设置时ID才不为零。
{
out_rxd(&timer[11][i]); //不显示
if(id==1&&ss>750) //当ID为1和SS大于1000时年不显示。
{
out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]); //不显示
}
else
{ out_rxd(&timer[2][i]); //20年
out_rxd(&timer[0][i]);
out_rxd(&timer[nian/16][i]); //年
out_rxd(&timer[nian%16][i]);
}
out_rxd(&timer[11][i]); //不显示
out_rxd(&hanzi[0][i*2+1]); //年字符
out_rxd(&hanzi[0][i*2]);
}
if(id==2&&ss>750) //当ID为2和SS大于1000时月不显示。
{out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]);} //不显示
else
{if(yue/16==0)
out_rxd(&timer[11][i]); //当月十位为零时不显示
else
out_rxd(&timer[yue/16][i]);
out_rxd(&timer[yue%16][i]); //月
}
out_rxd(&hanzi[1][i*2+1]); //月字符
out_rxd(&hanzi[1][i*2]);
if(id==3&&ss>750) //当ID为3和SS大于1000时日不显示。
{out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]);} //不显示
else
{out_rxd(&timer[ri/16][i]);
out_rxd(&timer[ri%16][i]);} //日
out_rxd(&hanzi[17][i*2+1]); //日字符
out_rxd(&hanzi[17][i*2]);
out_rxd(&hanzi[2][i*2+1]); //星字符
out_rxd(&hanzi[2][i*2]);
out_rxd(&hanzi[3][i*2+1]); //期字符
out_rxd(&hanzi[3][i*2]);
out_rxd(&timer[11][i]); //不显示
if(id==4&&ss>750) //当ID为3和SS大于1000时星期不显示。
{out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]);} //不显示
else
{out_rxd(&hanzi[xinqi+10][i*2+1]);//星期值字符
out_rxd(&hanzi[xinqi+10][i*2]);}
out_rxd(&timer[11][i]); //不显示
if(id==5&&ss>750) //当ID为4和SS大于1000时时不显示。
{out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]);} //不显示
else
{
if(shi/16==0)
out_rxd(&timer[11][i]); //当时十位为零时不显示
else
out_rxd(&timer[shi/16][i]); //从串口输出时十位。
out_rxd(&timer[shi%16][i]); //从串口输出时个位。
}
out_rxd(&timer[10][i]); //从串口输出两点。
if(id==6&&ss>750) //当ID为6和SS大于1000时分不显示。
{out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]);} //不显示
else
{out_rxd(&timer[fen/16][i]); //输出分值
out_rxd(&timer[fen%16][i]);}
out_rxd(&timer[10][i]); //从串口输出两点。
if(id==7&&ss>750) //当ID为6和SS大于1000时秒不显示。
{out_rxd(&timer[11][i]); //不显示
out_rxd(&timer[11][i]);} //不显示
else
{out_rxd(&timer[miao/16][i]); //输出秒值
out_rxd(&timer[miao%16][i]);}
/*****************************************************************/
P2_7=1; //锁存为高,595锁存信号
P2=sw[i]; //输出行信号
DelayMs(); //延时,等待一段时间,让这列显示的内容在人眼内产生“视觉暂留”现象。*/
P2=0x7f; //关闭显示。
}
}
void in_data(void) //调整数据
{
char s;
for(s=4;s>=0;s--) //i为向后先择字节计数器,zimuoo为向后先字计数器
{
BUFF[2*s+1]=hanzi2[zimuo+32*s+2*i]; // 把第一个字模的第一个字节放入BUFF0中,第二个字模和第一个字节放入BUFF2中
BUFF[2*s]=hanzi2[zimuo+1+32*s+2*i]; // 把第一个字模的第二个字节放入BUFF1中,第二个字模的第二个字节放入BUFF3中
}
}
/***********************发送移动的数据****************************/
void rxd_data(void) //串行发送数据
{
uchar s;
uchar inc,tempyid,temp;
if(yid<8)
inc=0;
else
inc=1;
for(s=0+inc;s<8+inc;s++) //发送8字节数据
{
if(yid<8)
tempyid=yid;
else
tempyid=yid-8;
temp=(BUFF[s]>>tempyid)|(BUFF[s+1]<<(8-tempyid)); //h1左移tempyid位后和h2右移8-tempyid相或,取出移位后的数据。
SBUF=temp; //把BUFF中的字节从大到小移位相或后发送输出。
while(TI==0); //等待发送完毕
TI=0;
}
}
/*******************************************************/
void out_rxd(unsigned char *d) /*从串口发送数据*/
{
SBUF=*d;
while(TI==0); //等待发送完毕
TI=0;
}
//根据选择调整相应项目
void Set(uchar sel,uchar sel_1)
{
uchar address,item;
uchar max,mini;
if(sel==7) {address=0x80; max=0;mini=0;} //秒
if(sel==6) {address=0x82; max=59;mini=0;} //分钟
if(sel==5) {address=0x84; max=23;mini=0;} //小时
if(sel==4) {address=0x8a; max=7; mini=1;} //星期
if(sel==3) {address=0x86; max=31;mini=1;} //日
if(sel==2) {address=0x88; max=12;mini=1;} //月
if(sel==1) {address=0x8c; max=99;mini=0;} //年
item=R1302(address+1)/16*10+R1302(address+1)%16;
if (sel_1==0) item++; else item--;
if(item>max) item=mini;
if(item<mini) item=max;
W1302(0x8e,0x00);
W1302(address,item/10*16+item%10);
W1302(0x8e,0x80);
}
/**************************延时***********************/
void DelayMs(void)
{
uchar TempCyc;
for(TempCyc=100;TempCyc>1;TempCyc--)
{;}
}
//********DS1302读写程序***************//
/********************************************************************
函 数 名:RTInputByte()
功 能:实时时钟写入一字节
说 明:往DS1302写入1Byte数据 (内部函数)
入口参数:d 写入的数据
返 回 值:无
***********************************************************************/
void RTInputByte(uchar d)
{
uchar h;
ACC = d;
for(h=8; h>0; h--)
{
T_IO = ACC0; /*相当于汇编中的 RRC */
T_CLK = 1;
T_CLK = 0;
ACC = ACC >> 1;
}
}
/********************************************************************
函 数 名:RTOutputByte()
功 能:实时时钟读取一字节
说 明:从DS1302读取1Byte数据 (内部函数)
入口参数:无
返 回 值:ACC
设 计:zhaojunjie 日 期:2002-03-19
修 改: 日 期:
***********************************************************************/
uchar RTOutputByte(void)
{
uchar h;
for(h=8; h>0; h--)
{
ACC = ACC >>1; /*相当于汇编中的 RRC */
ACC7 = T_IO;
T_CLK = 1;
T_CLK = 0;
}
return(ACC);
}
/********************************************************************
函 数 名:W1302()
功 能:往DS1302写入数据
说 明:先写地址,后写命令/数据 (内部函数)
调 用:RTInputByte() , RTOutputByte()
入口参数:ucAddr: DS1302地址, ucData: 要写的数据
返 回 值:无
***********************************************************************/
void W1302(uchar ucAddr, uchar ucDa)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -