51单片机控制DS1302,时间显示在数码管上。

2024-11-20 22:24:35
推荐回答(1个)
回答1:

1302.c

#include

#include

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

#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 

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