51单片机控制DS1302,时间显示在数码管上。
我QQ:434836340,邮箱:lzxadw@qq.com,小弟正处在模块化程序设计的初级阶段,谢谢各位大侠的指点。 展开
1302.c
#include<DS1302.h>
#include<key.h>
uchar bit_ser[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
uchar seven_seg[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/***********************时间显示*****************/
void timer0_init(void) //T0初始化函数,用于时间的动态显示
{
TMOD = 0x21;
TL0 = (65536-5000) % 256;
TH0 = (65536-5000) / 256;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void timer0_isr(void) interrupt 1 //T0中断处理函数
{
char flag; //flag用于表示调整时闪烁的亮或灭
TR0 = 0;
TL0 = (65536-5000) % 256;
TH0 = (65536-5000) / 256;
TR0 = 1;
flag = x / 100 * 0xff; //设置闪烁标志,如果x大于100则flag为0xff,小于100则为0x00
x++;
if(x > 200)
x = 0;
switch(i)
{
case 0:
P2 = bit_ser[0];
if(setflag == 3) //根据setflag的值判断当前位是否需要闪烁
P0 = flag | seven_seg[dis_buffer[0]];
else
P0 = seven_seg[dis_buffer[0]];
break;
case 1:
P2 = bit_ser[1];
if(setflag == 3)
P0 =flag | seven_seg[dis_buffer[1]];
else
P0 =seven_seg[dis_buffer[1]];
break;
case 2:
P2 = bit_ser[2];
if(setflag == 2)
P0 =flag | seven_seg[dis_buffer[2]];
else
P0 =seven_seg[dis_buffer[2]];
break;
case 3:
P2 = bit_ser[3];
if(setflag == 2)
P0 =flag | seven_seg[dis_buffer[3]];
else
P0 =seven_seg[dis_buffer[3]];
break;
case 4:
P2 = bit_ser[4];
if(setflag == 1)
P0 =flag | seven_seg[dis_buffer[4]];
else
P0 =seven_seg[dis_buffer[4]];
break;
case 5:
P2 = bit_ser[5];
if(setflag == 1)
P0 =flag | seven_seg[dis_buffer[5]];
else
P0 =seven_seg[dis_buffer[5]];
break;
}
i++;
if(i >= 6)
{
i = 0;
if(j == 10)
{
j = 0;
if(setflag == 0)
DS1302_GetTime(&Time); //如果setflag是0,就从1302中读出时间,因为setflag不是0时,说明处于调整状态,不需要读时间
dis_buffer[5] = Time.Second % 10; //把当前时间放入显示缓冲区
dis_buffer[4] = Time.Second / 10;
dis_buffer[3] = Time.Minute % 10;
dis_buffer[2] = Time.Minute / 10;
dis_buffer[1] = Time.Hour % 10;
dis_buffer[0] = Time.Hour / 10;
}
j++;
}
}
void main()
{
Initial_DS1302(Time);
timer0_init();
while(1)
{
set_down();
timer_down();
up_down();
down_down();
beepflag_down();
if(setflag == 0 && Time.Hour == romhour && Time.Minute == romminute && Beepflag == 1) //判断蜂鸣器是否要响
Beep = !Beep;
}
}
//key.c
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar i = 0,j = 0,x = 0,setflag,flag_set,flag_timer; //setflag用来表示调整的位置,flag_set和flag_timer分别表示当前处于调整状态还是定时状态
SYSTEMTIME Time={0,20,15,3,30,6,10}; //系统时间的初始值2010年6月30日星期三,15时20分0秒
char dis_buffer[6]; //存放显示数据的缓冲区
sbit Beep_flag = P3^2; //蜂鸣器的接口
sbit key_timer = P3^4; //定时按钮
sbit key_set = P3^5; //调整按钮
sbit key_up = P3^6; //增加按钮
sbit key_down = P3^7; //减小按钮
char romhour,romminute,romsec; //分别存放定时的时,分,秒
bit Beepflag; //标记闹钟是否开启
//延时函数
void delays(uchar x)
{
while(x) x--;
}
//设置键的处理函数
void set()
{
setflag ++;
flag_set = 1;
if(setflag >= 4)
{
setflag = 0;
flag_set = 0;
Initial_DS1302(Time);
}
}
//定时间的处理函数
void timer()
{
setflag ++;
flag_timer = 1;
if(setflag == 1)
{
Time.Hour = romhour;
Time.Minute = romminute;
Time.Second = romsec;
}
else if(setflag >= 4)
{
setflag = 0;
flag_timer = 0;
romhour = Time.Hour;
romminute = Time.Minute;
romsec = Time.Second;
}
}
//增加键的处理函数
void up()
{
switch(setflag)
{
case 0:
break;
case 1:
Time.Second ++;
if(Time.Second >= 60)
Time.Second = 0;
break;
case 2:
Time.Minute ++;
if(Time.Minute >= 60)
Time.Minute = 0;
break;
case 3:
Time.Hour ++;
if(Time.Hour >= 24)
Time.Hour = 0;
break;
}
}
//减小键的处理函数
void down()
{
switch(setflag)
{
case 0:
break;
case 1:
Time.Second --;
if(Time.Second < 0)
Time.Second = 59;
break;
case 2:
Time.Minute --;
if(Time.Minute < 0)
Time.Minute = 59;
break;
case 3:
Time.Hour --;
if(Time.Hour < 0)
Time.Hour = 23;
break;
}
}
//设置键的扫描函数
void set_down()
{
if(key_set == 0 && flag_timer == 0)
{
delays(100);
if(key_set == 0)
{
set();
}
while(!key_set);
}
}
//定时键的扫描函数
void timer_down()
{
if(key_timer == 0 && flag_set == 0)
{
delays(100);
if(key_timer == 0)
{
timer();
}
while(!key_timer);
}
}
//增加键的扫描函数
void up_down()
{
if(key_up == 0 && setflag != 0)
{
delays(100);
if(key_up == 0)
{
up();
while(!key_up);
}
}
}
//减少键的处理函数
void down_down()
{
if(key_down == 0 && setflag != 0)
{
delays(100);
if(key_down == 0)
{
down();
while(!key_down);
}
}
}
//定时开关的扫描处理函数
void beepflag_down()
{
if(Beep_flag == 0)
{
delays(100);
{
Beepflag = !Beepflag;
while(!Beep_flag);
}
}
}
//ds1302.h
#ifndef _REAL_TIMER_DS1302
#define _REAL_TIMER_DS1302
#include <REG51.h>
sbit DS1302_CLK = P1^1; //实时时钟时钟线引脚
sbit DS1302_IO = P1^2; //实时时钟数据线引脚
sbit DS1302_RST = P1^3; //实时时钟复位线引脚
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
sbit Beep = P2^7;
typedef struct __SYSTEMTIME__
{ char Second;
char Minute;
char Hour;
char Week;
char Day;
char Month;
char Year;
}SYSTEMTIME; //定义的时间类型
#define AM(X) X
#define PM(X) (X+12) // 转成24小时制
#define DS1302_SECOND 0x80 //秒寄存器
#define DS1302_MINUTE 0x82 //分寄存器
#define DS1302_HOUR 0x84
#define DS1302_WEEK 0x8A
#define DS1302_DAY 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C
#define DS1302_RAM(X) (0xC0+(X)*2) //用于计算 DS1302_RAM 地址的宏
void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数)
{ unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{ DS1302_IO = ACC0; //相当于汇编中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0; //发一个高跳变到低的脉冲
ACC = ACC >> 1;
}
}
unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数)
{ unsigned char i;
for(i=8; i>0; i--)
{ ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0; //发一个高跳变到低的脉冲
}
return(ACC);
}
void Write1302(unsigned char ucAddr, unsigned char ucDa)//ucAddr: DS1302地址, ucData: 要写的数据
{ DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 写1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0; //RST 0->1->0,CLK 0->1
}
unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据
{ unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1; //enable
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 读1Byte数据
DS1302_CLK = 1; //RST 0->1->0,CLK 0->1
DS1302_RST = 0;
return(ucData);
}
void DS1302_SetProtect(bit flag) //是否写保护
{ if(flag)
Write1302(0x8E,0x80); //WP=1,不能写入
else
Write1302(0x8E,0x00);//WP=0,可以写入
}
void DS1302_SetTime(unsigned char Address, unsigned char Value) // 设置时间函数
{ DS1302_SetProtect(0);
Write1302(Address, ((Value/10)<<4 | (Value%10))); //高4位为十位,低4位为个位
DS1302_SetProtect(1);
}
//获取时间函数,从DS1302内读取时间然后存入Time内
void DS1302_GetTime(SYSTEMTIME *Time)
{ unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//转换成10进制的秒
ReadValue = Read1302(DS1302_MINUTE);
Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
}
//利用STime初始化DS1302
void Initial_DS1302(SYSTEMTIME STime)
{ unsigned char Second=Read1302(DS1302_SECOND);
if(Second&0x80) DS1302_SetTime(DS1302_SECOND,0); //如果第七为1(表明没有启动), 则启动时钟
DS1302_SetTime(DS1302_SECOND,STime.Second); //设定起始时间
DS1302_SetTime(DS1302_MINUTE,STime.Minute);
DS1302_SetTime(DS1302_HOUR,STime.Hour);
DS1302_SetTime(DS1302_DAY,STime.Day);
DS1302_SetTime(DS1302_MONTH,STime.Month);
DS1302_SetTime(DS1302_YEAR,STime.Year);
DS1302_SetTime(DS1302_WEEK,STime.Week);
}
#endif