51单片机实时时间显示及调节


程序代码由3个文件组成,main.c,DS1302.c,DS1302.h。

1. main.c

/*************************************************************************************
* 实验现象: 实时时间显示及调节
* 接线说明: 动态数码管段选接P0,位选接P2^2,3,4口,k1、k2、k3、k4接P3^1、0、2、3,beep接P1^5
**************************************************************************************

*/

#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include "ds1302.h"

typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;

sbit LSA = P2 ^ 2;
sbit LSB = P2 ^ 3;
sbit LSC = P2 ^ 4;

sbit k1 = P3 ^ 1;
sbit k2 = P3 ^ 0;
sbit k3 = P3 ^ 2;
sbit k4 = P3 ^ 3;

sbit beep = P1 ^ 5;

char num = 0;
u8 DisplayData[8];
u8 code smgduan[20] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f,
                       0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x00, 0x40}; //显示0~F,无,'-'的值

u8 clocks, minutes, seconds;
u8 stopSwitch = 0;
u8 beepSwitch = 0;

/*******************************************************************************
* 函 数 名         : delay()
* 函数功能           : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
    while (i--)
        ;
}

/*******************************************************************************
* 函 数 名         : DS1302WriteTime()
* 函数功能           : 时分秒写入函数
* 输    入         : 时、分、秒
* 输    出         : 无
*******************************************************************************/
void DS1302WriteTime(u8 clocks, u8 minutes, u8 seconds)
{
    u8 clocks_16, minutes_16, seconds_16;

    clocks_16 = (clocks / 10 * 16) | (clocks % 10);
    minutes_16 = (minutes / 10 * 16) | (minutes % 10);
    seconds_16 = (seconds / 10 * 16) | (seconds % 10);

    Ds1302Write(0x8E, 0X00); //禁止写保护,就是关闭写保护功能

    Ds1302Write(WRITE_RTC_ADDR[2], clocks_16);
    Ds1302Write(WRITE_RTC_ADDR[1], minutes_16);
    Ds1302Write(WRITE_RTC_ADDR[0], seconds_16);

    Ds1302Write(0x8E, 0x80); //打开写保护功能
}

/*******************************************************************************
* 函 数 名         : getTime()
* 函数功能           : 时间读取处理转换函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void getTime()
{
    if (stopSwitch)
    {
        DS1302WriteTime(clocks, minutes, seconds);
    }
    else
    {
        Ds1302ReadTime();
        clocks = (TIME[2] / 16 * 10) + (TIME[2] % 16);
        minutes = (TIME[1] / 16 * 10) + (TIME[1] % 16);
        seconds = (TIME[0] / 16 * 10) + (TIME[0] % 16);
    }
}

/*******************************************************************************
* 函 数 名         : DigDisplay
* 函数功能           : 数码管显示函数
* 参数               : ord为数码管次序,ch为该数码管显示符号
*******************************************************************************/
void DigDisplay(u8 ord, u8 ch)
{
    switch (ord) //位选,选择点亮的数码管,
    {
    case (0):
        LSA = 1;
        LSB = 1;
        LSC = 1;
        break; //显示第0位
    case (1):
        LSA = 0;
        LSB = 1;
        LSC = 1;
        break; //显示第1位
    case (2):
        LSA = 1;
        LSB = 0;
        LSC = 1;
        break; //显示第2位
    case (3):
        LSA = 0;
        LSB = 0;
        LSC = 1;
        break; //显示第3位
    case (4):
        LSA = 1;
        LSB = 1;
        LSC = 0;
        break; //显示第4位
    case (5):
        LSA = 0;
        LSB = 1;
        LSC = 0;
        break; //显示第5位
    case (6):
        LSA = 1;
        LSB = 0;
        LSC = 0;
        break; //显示第6位
    case (7):
        LSA = 0;
        LSB = 0;
        LSC = 0;
        break; //显示第7位
    }
    P0 = smgduan[ch]; //发送段码
    if (beepSwitch)
        beep = ~beep;
}

/*******************************************************************************
* 函 数 名       : timeDisplay
* 函数功能         : 将时分秒显示在数码管上
* 输    入       : 无
* 输    出         : 无
*******************************************************************************/
void timeDisplay()
{
    u8 n = 0;
    u8 dig[10];
    getTime();

    dig[0] = clocks / 10;
    dig[1] = clocks % 10;
    dig[2] = 17;
    dig[3] = minutes / 10;
    dig[4] = minutes % 10;
    dig[5] = 17;
    dig[6] = seconds / 10;
    dig[7] = seconds % 10;
    for (n = 0; n < 8; n++)
    {
        DigDisplay(n, dig[n]);
        delay(10);
        DigDisplay(n, 16);
    }
}

/*******************************************************************************
* 函 数 名       : keypros
* 函数功能         : 按键处理
* 输    入       : 无
* 输    出         : 无
*******************************************************************************/
void keypros()
{
    u16 delayTimes = 10;
    //按键K1
    if (k1 == 0) //检测按键K1是否按下
    {
        while (delayTimes--)
            timeDisplay(); //消除抖动 一般大约10ms
        if (k1 == 0)       //再次判断按键是否按下
        {
            if (++clocks == 24)
            {
                clocks = 0;
            }
            DS1302WriteTime(clocks, minutes, seconds);
        }
        while (!k1)
            timeDisplay(); //检测按键是否松开
    }
    //按键K2
    if (k2 == 0) //检测按键是否按下
    {
        while (delayTimes--)
            timeDisplay(); //消除抖动 一般大约10ms
        if (k2 == 0)       //再次判断按键是否按下
        {
            if (++minutes == 60)
            {
                minutes = 0;
            }
            DS1302WriteTime(clocks, minutes, seconds);
        }
        while (!k2)
            timeDisplay(); //检测按键是否松开
    }
    //按键K3
    if (k3 == 0) //检测按键是否按下
    {
        while (delayTimes--)
            timeDisplay(); //消除抖动 一般大约10ms
        if (k3 == 0)       //再次判断按键是否按下
        {
            if (++seconds == 60)
            {
                seconds = 0;
            }
            DS1302WriteTime(clocks, minutes, seconds);
        }
        while (!k3)
            timeDisplay(); //检测按键是否松开
    }
    //按键K4
    if (k4 == 0) //检测按键是否按下
    {
        while (delayTimes--)
            timeDisplay(); //消除抖动 一般大约10ms
        if (k4 == 0)       //再次判断按键是否按下
        {
            stopSwitch = (stopSwitch + 1) % 2;
        }
        while (!k4)
            timeDisplay(); //检测按键是否松开
    }
}
/*******************************************************************************
* 函 数 名       : main
* 函数功能         : 主函数
* 输    入       : 无
* 输    出         : 无
*******************************************************************************/
void main()
{
    Ds1302Init(); //初始化
    while (1)
    {
        keypros();       //按键处理
        timeDisplay(); //显示时间
        //蜂鸣器整点响应
        if (minutes == 59 && seconds == 59)
        {
            beepSwitch = 1;
        }
        if (beepSwitch == 1)
        {
            if (minutes == 0 && seconds == 3)
            {
                beepSwitch = 0;
            }
        }
    }
}

2. ds1302.h

#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];    //加入全局变量
extern uchar code WRITE_RTC_ADDR[7];
#endif

3. ds1302.c

#include"ds1302.h"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0, 0, 0x12, 0x07, 0x05, 0x06, 0x16};

/*******************************************************************************
* 函 数 名         : Ds1302Write
* 函数功能           : 向DS1302命令(地址+数据)
* 输    入         : addr,dat
* 输    出         : 无
*******************************************************************************/

void Ds1302Write(uchar addr, uchar dat)
{
    uchar 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_();
    }

    RST = 0;//传送数据结束
    _nop_();
}

/*******************************************************************************
* 函 数 名         : Ds1302Read
* 函数功能           : 读取一个地址的数据
* 输    入         : addr
* 输    出         : dat
*******************************************************************************/

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;
}

/*******************************************************************************
* 函 数 名         : Ds1302Init
* 函数功能           : 初始化DS1302.
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds1302Init()
{
    uchar n;
    Ds1302Write(0x8E,0X00);         //禁止写保护,就是关闭写保护功能
    for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
    {
        Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
    }
    Ds1302Write(0x8E,0x80);         //打开写保护功能
}

/*******************************************************************************
* 函 数 名         : Ds1302ReadTime
* 函数功能           : 读取时钟信息
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds1302ReadTime()
{
    uchar n;
    for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
    {
        TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
    }

}

按键k1增加时钟,k2增加分钟,k3增加秒钟,k4暂停或继续。

具有整点响应功能,时间为3秒。  

代码中值得注意的是,ds1302.h中相对于原始文件另将ds1302.c中的写地址数组声明为全局变量,在main.c中调用有调用。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM