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