刚刚开始学编程,暑假期间闲来无事,用stc89c52通过ds1302做了一个电子时钟。我对ds1302的时钟代码理解也不是太深,自己在网上搜了一下相关代码,以及自己琢磨了一下,做了一个简陋的电子时钟。废话不多直接上代码。
在这里插入代码片
#ifndef __DS1302_H_
#define __DS1302_H_
//---包含头文件---//
#include<reg52.h>
#include<intrins.h>
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;
//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();
//---加入全局变量--//
extern uchar TIME[7]; //加入全局变量
#endif
接着是ds1302.c
#include"ds1302.h"
char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
sbit k1=P3^1;
//---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
char TIME[7] = {0, 0x12, 0x12, 0x07, 0x05, 0x06, 0x16};
void Ds1302Write(char addr, char dat)
{
char n;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for (n=0; n<8; n++)//开始传送八位地址命令
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++)//写入8位数据
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
uchar Ds1302Read(uchar addr)
{
uchar n,dat,dat1;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1;//然后将RST(CE)置高电平。
_nop_();
for(n=0; n<8; n++)//开始传送八位地址命令
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
_nop_();
for(n=0; n<8; n++)//读取8位数据
{
dat1 = DSIO;//从最低位开始接收
dat = (dat>>1) | (dat1<<7);
SCLK = 1;
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
RST = 0;
_nop_(); //以下为DS1302复位的稳定时间,必须的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
void Ds1302Init()
{
uchar n,temp;
Ds1302Write(0x8E,0X00); //禁止写保护,就是关闭写保护功能
for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
{
Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
}
Ds1302Write(0x8E,0x80); //打开写保护功能
}
void Ds1302ReadTime()
{
uchar n;
for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
{
TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
}
}
ds1302是电子时钟的计时器,是关键。
然后是数码管显示函数smguan.h汉语拼的,勿怪,哈哈哈。很low。
#ifndef _SMGUAN_H_
#define _SMGUAN_H_
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include"ds1302.h"
#include"key.h"
#include"smguan.h"
void datapros();
void datayears();
void DigDisplay();
void clockyears();
void clockpros();
unsigned char BCD_shi(unsigned char bcd);
unsigned char shi_BCD(unsigned char shi);
#endif
接下来是smguan.c
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include"ds1302.h"
#include"key.h"
#include"smguan.h"
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 DisplayData[8];
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void datapros()
{
Ds1302ReadTime();
DisplayData[0] = smgduan[TIME[2]/16]; //时
DisplayData[1] = smgduan[TIME[2]&0x0f];
DisplayData[2] = 0x40;
DisplayData[3] = smgduan[TIME[1]/16]; //分
DisplayData[4] = smgduan[TIME[1]&0x0f];
DisplayData[5] = 0x40;
DisplayData[6] = smgduan[TIME[0]/16]; //秒
DisplayData[7] = smgduan[TIME[0]&0x0f];
}
void datayears()
{
Ds1302ReadTime();
DisplayData[0] = smgduan[TIME[6]/16]; //年
DisplayData[1] = smgduan[TIME[6]&0x0f];
DisplayData[2] = 0x40;
DisplayData[3] = smgduan[TIME[4]/16]; //月
DisplayData[4] = smgduan[TIME[4]&0x0f];
DisplayData[5] = 0x40;
DisplayData[6] = smgduan[TIME[3]/16]; //日
DisplayData[7] = smgduan[TIME[3]&0x0f];
}
void clockpros()
{
DisplayData[0] = smgduan[clock_display[2]/16]; //时
DisplayData[1] = smgduan[clock_display[2]&0x0f];
DisplayData[2] = 0x40;
DisplayData[3] = smgduan[clock_display[1]/16]; //分
DisplayData[4] = smgduan[clock_display[1]&0x0f];
DisplayData[5] = 0x40;
DisplayData[6] = smgduan[clock_display[0]/16]; //秒
DisplayData[7] = smgduan[clock_display[0]&0x0f];
}
void clockyears()
{
DisplayData[0] = smgduan[clock_display[6]/16]; //年
DisplayData[1] = smgduan[clock_display[6]&0x0f];
DisplayData[2] = 0x40;
DisplayData[3] = smgduan[clock_display[4]/16]; //月
DisplayData[4] = smgduan[clock_display[4]&0x0f];
DisplayData[5] = 0x40;
DisplayData[6] = smgduan[clock_display[3]/16]; //日
DisplayData[7] = smgduan[clock_display[3]&0x0f];
}
void DigDisplay()
{
u8 i;
for(i=0;i<8;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=0;LSB=0;LSC=0; break;//显示第0位
case(1):
LSA=1;LSB=0;LSC=0; break;//显示第1位
case(2):
LSA=0;LSB=1;LSC=0; break;//显示第2位
case(3):
LSA=1;LSB=1;LSC=0; break;//显示第3位
case(4):
LSA=0;LSB=0;LSC=1; break;//显示第4位
case(5):
LSA=1;LSB=0;LSC=1; break;//显示第5位
case(6):
LSA=0;LSB=1;LSC=1; break;//显示第6位
case(7):
LSA=1;LSB=1;LSC=1; break;//显示第7位
}
P0=DisplayData[7-i];//发送数据
delay(100); //间隔一段时间扫描
P0=0x00;//消隐
}
}
unsigned char BCD_shi(unsigned char bcd) //BCD码转换成十进制
{
unsigned char Z;
Z=(bcd/16)*10 +bcd%16;
return Z;
}
unsigned char shi_BCD(unsigned char shi) //十进制转换成BCD码
{
return ((shi/10)*16+(shi%10));
}
我的所有时钟控制和模式选择都在key.c里面,通过按键进行选择。
接下来是按键函数。key.h
#ifndef _KEY_H_
#define _KEY_H_
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include"ds1302.h"
#include"key.h"
#include"smguan.h"
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
void delay(u16 i);
void KEY1_time();
void KEY1_date();
void Start();
void key_just();
void song_time();
void key_clock_just();
void clock_just();
void clock_date();
void clock_time();
extern uchar clock_display[7];
#endif
然后key.c
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include"ds1302.h"
#include"key.h"
#include"smguan.h"
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
sbit led1=P2^5;
sbit led2=P2^6;
sbit led3=P2^7;
sbit led4=P2^0;
sbit led5=P2^1;
sbit beep=P1^5;
bit flag,flag1=0,flag2=0;
unsigned char last_miao=0;
unsigned char miao;
extern unsigned char last_miao;
extern unsigned char miao;
uchar clock_display[7]={0x10, 0x12, 0x12, 0x07, 0x05, 0x06, 0x16};
void DigDisplay();
void datapros();
void datayears();
void delay(u16 i)
{
while(i--);
}
void KEY1_time()
{
static u16 count_2=0;
static u16 count_3_4=0;
static u16 count_4=0;
datapros();
DigDisplay();
if(k2==0)
{
delay(1000);
if(k2==0)
{
count_2++;
if(count_2==4)
count_2=1;//循环选择
while(!k2)//按键检测是否松开
{
led1=1;
led2=1;
led3=1;
}
}
}
if(k3==0)
{
delay(1000);
if(k3==0)
{
count_3_4++;
while(!k3);
}
}
if(k4==0)
{
delay(1000);
if(k4==0)
{
count_3_4--;
while(!k4);
}
}
if(count_2==3)//修改时
{
led3=0;
TIME[2]+=count_3_4;
}
if(count_2==2)//修改分
{
led2=0;
TIME[1]+=count_3_4;
}
if(count_2==1)//修改秒
{
led1=0;
TIME[0]+=count_3_4;
}
count_3_4=0;
if((TIME[0]&0x0f)>9) //换成BCD码。
{
TIME[0]=TIME[0]+6;
}
if((TIME[1]&0x0f)>9) //换成BCD码。
{
TIME[1]=TIME[1]+6;
}
if((TIME[2]&0x0f)>9) //换成BCD码。
{
TIME[2]=TIME[2]+6;
}
if(TIME[0]>=0x60) //分秒只能到59
{
TIME[0]=0;
}
if(TIME[1]>=0x60) //分秒只能到59
{
TIME[1]=0;
}
if(TIME[2]>=0x24) //小时只能到23
{
TIME[2]=0;
}
}
void KEY1_date()
{
static u16 count_2=0;
static u16 count_3_4=0;
datayears();
DigDisplay();
if(k2==0)
{
delay(1000);
if(k2==0)
{
count_2++;
if(count_2==4)
count_2=1;//循环选择
while(!k2)//按键检测是否松开
{
led1=1;
led2=1;
led3=1;
}
}
}
if(k3==0)
{
delay(1000);
if(k3==0)
{
count_3_4++;
while(!k3);
}
}
if(k4==0)
{
delay(1000);
if(k4==0)
{
count_3_4--;
while(!k4);
}
}
if(count_2==3)//修改年
{
led3=0;
TIME[6]+=count_3_4;
}
if(count_2==2)//修改月
{
led2=0;
TIME[4]+=count_3_4;
}
if(count_2==1)//修改日
{
led1=0;
TIME[3]+=count_3_4;
}
count_3_4=0;
if((TIME[3]&0x0f)>9) //换成BCD码。
{
TIME[3]=TIME[3]+6;
}
if((TIME[4]&0x0f)>9)
{
TIME[4]=TIME[4]+6;
}
if((TIME[6]&0x0f)>9)
{
TIME[6]=TIME[6]+6;
}
if(TIME[3]>=0x32) //日只能到31
{
TIME[3]=0;
}
if(TIME[4]>=0x13) //月只能到12
{
TIME[4]=0;
}
}
void Start()
{
miao=BCD_shi(TIME[0]);
if(miao-last_miao>=5)
{
flag=~flag;
last_miao=miao;
}
if(flag!=0)
{
datayears();
}
else
{
datapros(); //数据处理函数
}
}
void key_just()
{
static u16 count_1=0;
if(k2==0)
{
flag1=~flag1;
led4=~led4;
}
f(flag1==0)
Start();
else
{
if(k1==0)
{
delay(1000);
if(k1==0)
{
count_1++;
if(count_1==3)
count_1=0;
while(!k1);
}
}
if(count_1==1)
{
KEY1_time();
Ds1302Init();
}
if(count_1==2)
{
KEY1_date();
Ds1302Init();
}
else
datapros();
}
}
void clock_time()
{
static u16 count_2=0;
static u16 count_3_4=0;
static u16 count_4=0;
clockpros();;
DigDisplay();
if(k2==0)
{
delay(1000);
if(k2==0)
{
count_2++;
if(count_2==4)
count_2=1;//循环选择
while(!k2)//按键检测是否松开
{
led1=1;
led2=1;
led3=1;
}
}
}
if(k3==0)
{
delay(1000);
if(k3==0)
{
count_3_4++;
while(!k3);
}
}
if(k4==0)
{
delay(1000);
if(k4==0)
{
count_3_4--;
while(!k4);
}
}
if(count_2==3)//修改时
{
led3=0;
clock_display[2]+=count_3_4;
}
if(count_2==2)//修改分
{
led2=0;
clock_display[1]+=count_3_4;
}
if(count_2==1)//修改秒
{
led1=0;
clock_display[0]+=count_3_4;
}
count_3_4=0;
if((clock_display[0]&0x0f)>9) //换成BCD码。
{
clock_display[0]=clock_display[0]+6;
}
if((clock_display[1]&0x0f)>9) //换成BCD码。
{
clock_display[1]=clock_display[1]+6;
}
if((clock_display[2]&0x0f)>9) //换成BCD码。
{
clock_display[2]=clock_display[2]+6;
}
if(clock_display[0]>=0x60) //分秒只能到59
{
clock_display[0]=0;
}
if(clock_display[1]>=0x60) //分秒只能到59
{
clock_display[1]=0;
}
if(clock_display[2]>=0x24) //小时只能到23
{
clock_display[2]=0;
}
}
void clock_date()
{
static u16 count_2=0;
static u16 count_3_4=0;
clockyears();
DigDisplay();
if(k2==0)
{
delay(1000);
if(k2==0)
{
count_2++;
if(count_2==4)
count_2=1;//循环选择
while(!k2)//按键检测是否松开
{
led1=1;
led2=1;
led3=1;
}
}
}
if(k3==0)
{
delay(1000);
if(k3==0)
{
count_3_4++;
while(!k3);
}
}
if(k4==0)
{
delay(1000);
if(k4==0)
{
count_3_4--;
while(!k4);
}
}
if(count_2==3)//修改年
{
led3=0;
clock_display[6]+=count_3_4;
}
if(count_2==2)//修改月
{
led2=0;
clock_display[4]+=count_3_4;
}
if(count_2==1)//修改日
{
led1=0;
clock_display[3]+=count_3_4;
}
count_3_4=0;
if((clock_display[3]&0x0f)>9) //换成BCD码。
{
clock_display[3]=clock_display[3]+6;
}
if((clock_display[4]&0x0f)>9)
{
clock_display[4]=clock_display[4]+6;
}
if((clock_display[6]&0x0f)>9)
{
clock_display[6]=clock_display[6]+6;
}
if(clock_display[3]>=0x32) //日只能到31
{
clock_display[3]=0;
}
if(clock_display[4]>=0x13) //月只能到12
{
clock_display[4]=0;
}
}
void clock_just()
{
static u16 count_1=0;
if(k1==0)
{
delay(1000);
if(k1==0)
{
count_1++;
if(count_1==3)
count_1=0;
while(!k1);
}
}
if(count_1==1)
{
clock_time();
// Ds1302Init();
}
if(count_1==2)
{
clock_date();
// Ds1302Init();
}
// else
// datapros();
}
void key_clock_just()
{
if(k4==0)
{
delay(1000);
if(k4==0)
{
flag2=~flag2;
led5=~led5;
while(!k4);
}
}
if(flag2==0)
key_just();
else
clock_just();
}
void song_time()
{ u16 i;
if(TIME[0]==clock_display[0]&&TIME[1]==clock_display[1]&&TIME[2]==clock_display[2]&&TIME[3]==clock_display[3]&&TIME[4]==clock_display[4]&&TIME[6]==clock_display[6])
{
for(i=0;i<=100;i++)
beep=~beep;
}
}
主要代码就这些,比较繁琐,下面是主函数main.c
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include"ds1302.h"
#include"key.h"
#include"smguan.h"
void main()
{
Ds1302Init();
while(1)
{
key_clock_just();
DigDisplay();//数码管显示函数
song_time();
}
}
代码就这些,很多很繁琐,当时在网上找代码找了好久,也不是特别全,搜了一些代码,从网上借鉴了一些,本文章中是通过按键++直接对TIME数组的控制时分秒进行++;整个代码的功能分三个,按键用来调换模式,第一个是按键不按下时,每五秒切换一次时间和日期,交替来。第二个功能通过按键来对时间,对日期来加减,调时间和日期,第三个是闹铃。
不足:按键控制的功能太多导致时钟和闹铃转换的时候进行加加或者减减的时候容易跳模式。如果去掉闹钟功能剩下的其他功能都正常的。
因为部分代码是直接复制过来的,第一次写,也不是太懂会不会侵权啥的,哈哈如果有哪里侵权请告诉我。谢谢。