Arduino DS1302 时钟模块应用示例(带闹钟功能)

呃,说点什么呢?

没啥好说的,很基础的东西。也是多年前某宝买了来,一直丢在角落里。还能找点儿空闲,就想让它们也动一动。
免得怪我遗忘了它们。

时钟模块用的是 DS1302,蜂鸣器用的是有源蜂鸣器(无源的还要设置频率编个曲儿啥的,我比较懒,喜欢直接一点的,HIGH or LOW)。


就是上面这些东西。

没有加按钮,因为后续打算添加 LCD 显示屏和温湿度传感器,做成一个比较完整的系统。所以 Arduino 的 IO 接口,能省就省了。时间设置以及其他功能,可以通过串口输入命令配置。闹钟是在代码的常量定义里手动修改(图省事啊)。

还有就是,用到的库文件来自网络,作者我他么也不认识。剩下的代码几乎全是我个人完成,没系统地学过 C,所以应该还有很大的提升空间。

线路连接图如下:


运行效果如下:


上代码了啊

ds1302.ino(这个是我写的。。。)

/******************************************************************************
-------------------------1.开发环境:Arduino IDE-----------------------------------
-------------------------------2.作者:starky-----------------------------------------
******************************************************************************/
#include <Arduino.h>
#include "DS1302.h"

#define Buzz_Pin 5                 // 有源蜂鸣器引脚
unsigned char Alarm_Hour=6;          // 闹钟小时设置
unsigned char Alarm_Minute=30;        // 闹钟分钟设置
bool Always=false;                 //是否不间断地输出时间到串口(每隔 1 秒)

void setup()
{
  pinMode(Buzz_Pin,OUTPUT);
  DS1302_Init();
  Serial.begin(9600); 
  Serial.println("Welcome to use!");  
  DS1302_GetTime(&DS1302Buffer);
  Display_RTCC();
  Serial.println("Type \"help\" To Get The Help Information.");
}

//显示时间
void Display_RTCC()
{
  
  if(DS1302Buffer.Year < 10)
  {
    Serial.print("200");
  }
  else
  {
    Serial.print("20");
  }
  Serial.print(DS1302Buffer.Year);
  Serial.print('-');
  Serial.print(DS1302Buffer.Month);
  Serial.print('-');
  Serial.print(DS1302Buffer.Day);

  Serial.print("   ");

  switch(DS1302Buffer.Week)
  {
    case 1:
        Serial.println("Mon");         //显示星期一
        break;
    case 2:
        Serial.println("Tue");         //显示星期二
        break;
    case 3:
        Serial.println("Wed");         //显示星期三
        break;
    case 4:
        Serial.println("Thu");         //显示星期四
        break;
    case 5:
        Serial.println("Fri");         //显示星期五
        break;
    case 6:
        Serial.println("Sat");         //显示星期六
        break;
    case 7:
        Serial.println("Sun");         //显示星期日
        break;
    default : break;            
  }

  Serial.print(DS1302Buffer.Hour);
  Serial.print(':');
  Serial.print(DS1302Buffer.Minute);
  Serial.print(':');
  Serial.println(DS1302Buffer.Second);
}

// 获取串口输入
void Scan_Input()
{
  String comdata=""; 
  while (Serial.available() > 0)  
   {
     comdata += char(Serial.read());
     delay(2);
   }
  if(comdata.length()==20 && comdata.startsWith("set"))
    {
      Set_Time(comdata);
    }
  if(comdata=="show")
  {
    Serial.println("The Time Now Is:");
    Always=false;
    Display_RTCC();
  }

//是否不间断地将时间输出到串口
  if(comdata=="always")
  {
    Always=!Always;
  }

//显示闹钟
  if(comdata=="alarm")
  {
    Serial.print("Alarm Set to ");
    Serial.print(Alarm_Hour); 
    Serial.print(":");
    Serial.println(Alarm_Minute);   
  }
  if(comdata=="help")
  {
    help();
  }
}

//时间设置函数
void Set_Time(String &command)
{
  DS1302_ON_OFF(0);     //关闭振荡
  DS1302Buffer.Year=command.substring(4,6).toInt();
  DS1302Buffer.Month=command.substring(7,9).toInt();
  DS1302Buffer.Day=command.substring(10,12).toInt();
  DS1302Buffer.Week=command.substring(13,14).toInt();
  DS1302Buffer.Hour=command.substring(15,17).toInt();
  DS1302Buffer.Minute=command.substring(18).toInt();
  DS1302_SetTime( DS1302_YEAR , DS1302Buffer.Year );
  DS1302_SetTime( DS1302_MONTH , DS1302Buffer.Month );
  DS1302_SetTime( DS1302_DAY , DS1302Buffer.Day );
  DS1302_SetTime( DS1302_WEEK , DS1302Buffer.Week );
  DS1302_SetTime( DS1302_HOUR , DS1302Buffer.Hour );
  DS1302_SetTime( DS1302_MINUTE , DS1302Buffer.Minute );
  DS1302_ON_OFF(1);
  Always=false;
  Serial.println("Set Done");
  Display_RTCC();   
}

//蜂鸣器报警函数
void buzz(int &times)
{
  for(int i=0;i<times;i++){
    digitalWrite(Buzz_Pin,HIGH);
    delay(650);
    digitalWrite(Buzz_Pin,LOW);
    delay(250);
    }
}

//帮助内容
void help()
{
  Serial.println("************************************* HELP *****************************************");
  Serial.println("Edited By Starky");
  Serial.println("Type \"set YY MM DD WEEK HH MM\" To Set The Time!");
  Serial.println("Such As Type \"set 08 08 08 1 12 00\" To Set The Time As 2008-8-8 Monday 12:00");
  Serial.println("Type \"show\" To Display The Time Now!");
  Serial.println("Type \"always\" To Print The Time Every Second!");
  Serial.println("Type \"alarm\" To Check The Current Alarm");
  Serial.println("Welcome To Use!"); 
  Serial.println("************************************* HELP *****************************************");
}

void loop()
{
  Scan_Input();
  DS1302_GetTime(&DS1302Buffer);        //获取当前RTCC值
  if(Always)
  {
    if(Flag_Time_Refresh == 1)
      {
          Flag_Time_Refresh = 0;
          Display_RTCC();
      }
  }
  
  // 闹钟激活
  if(DS1302Buffer.Hour==Alarm_Hour && DS1302Buffer.Minute==Alarm_Minute && DS1302Buffer.Second==0)
  {
    int times=15;        // 报警次数
    buzz(times);
  }
}

以下是库文件内容

DS1302.cpp

/******************************************************************************
----------------1.开发环境:Arduino IDE-----------------------------------------
----------------2.测试使用开发板型号:Arduino UNO R3-------
----------------3.单片机使用晶振:16M------------------------------------------
----------------4.作者:神秘藏宝室---------------------------------------------
******************************************************************************/
#include "DS1302.h"

SYSTEMTIME DS1302Buffer;
bool Flag_Time_Refresh = 1;

//****************************************************
//实时时钟写入一字节(内部函数)
//****************************************************
void DS1302_InputByte(unsigned char dat)    
{ 
    unsigned char i;

    pinMode(DS1302_IO,OUTPUT);

    for(i=0; i<8; i++)
    {
        if((dat & 0x01) == 1)
        {
            DS1302_IO_1;
        }
        else
        {
            DS1302_IO_0;
        }
          
        
        DS1302_CLK_0;               //上升沿写入数据
        
        delayMicroseconds(2);
        
        DS1302_CLK_1;
        
        delayMicroseconds(2);
        dat >>= 1; 
    } 
}

//****************************************************
//实时时钟读取一字节(内部函数)
//****************************************************
unsigned char DS1302_OutputByte(void)   
{ 
    unsigned char i;
    unsigned char dat;
    pinMode(DS1302_IO,INPUT);
    for(i=0; i<8; i++)
    {
        DS1302_CLK_1;                   //下降沿读出数据
        delayMicroseconds(2);
        DS1302_CLK_0;
        delayMicroseconds(2);
        dat >>= 1;                  
        if( digitalRead(DS1302_IO) == HIGH )
            dat |= 0x80;                //最高位置一
        else
            dat &= 0x7F;                //最高位清零       
    } 
    return(dat); 
}

//****************************************************
//ucAddr: DS1302地址, ucData: 要写的数据
//****************************************************
void DS1302_Write(unsigned char ucAddr, unsigned char ucDa) 
{
    DS1302_RST_0;
    delayMicroseconds(2);
    DS1302_CLK_0;
    delayMicroseconds(2);
    DS1302_RST_1;
    delayMicroseconds(2);
    DS1302_InputByte(ucAddr);           // 地址,命令 
    DS1302_InputByte(ucDa);             // 写1Byte数据
    DS1302_CLK_1;
    delayMicroseconds(2);
    DS1302_RST_0;
    delayMicroseconds(2);
}

//****************************************************
//读取DS1302某地址的数据
//****************************************************
unsigned char DS1302_Read(unsigned char ucAddr) 
{
    unsigned char ucData;
    DS1302_RST_0;
    delayMicroseconds(2);
    DS1302_CLK_0;
    delayMicroseconds(2);
    DS1302_RST_1;
    delayMicroseconds(2);
    DS1302_InputByte(ucAddr|0x01);        // 地址,命令 
    ucData = DS1302_OutputByte();         // 读1Byte数据
    DS1302_CLK_1;
    delayMicroseconds(2);
    DS1302_RST_0;
    delayMicroseconds(2);
    return(ucData);
}

//****************************************************
//是否写保护
//****************************************************
void DS1302_SetProtect(unsigned char flag)       
{
    if(flag)
        DS1302_Write(0x8E,0x10);            //保护
    else
        DS1302_Write(0x8E,0x00);            //不保护
} 

//****************************************************
// 设置时间函数
//****************************************************
void DS1302_SetTime(unsigned char Address, unsigned char Value)        
{
    DS1302_SetProtect(0);
    DS1302_Write(Address, ((Value/10)<<4 | (Value%10))); 
}

//****************************************************
//获取实时时间
//****************************************************
void DS1302_GetTime(SYSTEMTIME *Time)
{
    unsigned char ReadValue;
    ReadValue = DS1302_Read(DS1302_SECOND);
    ReadValue = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);            //BCD码转换十进制
    if(ReadValue != DS1302Buffer.Second)                                //跟上一次状态不同,置位刷新标志位
        Flag_Time_Refresh = 1;
    Time->Second = ReadValue;

    ReadValue = DS1302_Read(DS1302_MINUTE);
    Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_Read(DS1302_HOUR);
    Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_Read(DS1302_DAY);
    Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);    
    ReadValue = DS1302_Read(DS1302_WEEK);
    Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_Read(DS1302_MONTH);
    Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_Read(DS1302_YEAR);
    Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);   
}

//****************************************************
//初始化
//****************************************************
void DS1302_Init(void)
{
    unsigned char Second;

    pinMode(DS1302_RST,OUTPUT);
    pinMode(DS1302_IO,OUTPUT);
    pinMode(DS1302_CLK,OUTPUT);

    Second = DS1302_Read(DS1302_SECOND);
    if(Second&0x80)       
        DS1302_SetTime(DS1302_SECOND,Second & 0x7f);    //开启振荡    
}
//****************************************************
//DS1302振荡器停止
//****************************************************
void DS1302_ON_OFF(bool FLAG_ON_OFF)
{
    unsigned char Second;
    Second = DS1302_Read(DS1302_SECOND);
    if(FLAG_ON_OFF == 0)
        DS1302_Write(DS1302_SECOND,Second | 0x80);              //关闭振荡
    else
        DS1302_Write(DS1302_SECOND,Second & 0x7f);              //开启振荡
}

DS1302.h

/******************************************************************************
----------------1.开发环境:Arduino IDE-----------------------------------------
----------------2.测试使用开发板型号:Arduino Leonardo or Arduino UNO R3-------
----------------3.单片机使用晶振:16M------------------------------------------
----------------4.作者:神秘藏宝室---------------------------------------------
******************************************************************************/
#ifndef __DS1302_H__
#define __DS1302_H__

#include <Arduino.h>

//DS1302 IO设置
#define DS1302_RST 2     //实时时钟复位线引脚
#define DS1302_IO 3      //实时时钟数据线引脚
#define DS1302_CLK 4     //实时时钟时钟线引脚


#define DS1302_RST_0 digitalWrite(DS1302_RST,LOW)
#define DS1302_RST_1 digitalWrite(DS1302_RST,HIGH)

#define DS1302_IO_0 digitalWrite(DS1302_IO,LOW)
#define DS1302_IO_1 digitalWrite(DS1302_IO,HIGH)

#define DS1302_CLK_0 digitalWrite(DS1302_CLK,LOW)
#define DS1302_CLK_1 digitalWrite(DS1302_CLK,HIGH)


//宏定义
#define DS1302_SECOND   0x80
#define DS1302_MINUTE   0x82
#define DS1302_HOUR     0x84 
#define DS1302_DAY      0x86
#define DS1302_MONTH    0x88
#define DS1302_WEEK     0x8a
#define DS1302_YEAR     0x8c 


typedef struct __SYSTEMTIME__
{
    unsigned char Second;
    unsigned char Minute;
    unsigned char Hour;
    unsigned char Week;
    unsigned char Day;
    unsigned char Month;
    unsigned char  Year;
}SYSTEMTIME;    //定义的时间类型


//函数或者变量声明
extern void DS1302_InputByte(unsigned char dat);
extern unsigned char DS1302_OutputByte(void) ;
extern void DS1302_Write(unsigned char ucAddr, unsigned char ucDa);
extern unsigned char DS1302_Read(unsigned char ucAddr);
extern void DS1302_SetProtect(unsigned char flag) ;
extern void DS1302_SetTime(unsigned char Address, unsigned char Value);
extern void DS1302_GetTime(SYSTEMTIME *Time);
extern void DS1302_Init(void);
extern void DS1302_ON_OFF(bool FLAG_ON_OFF);


extern SYSTEMTIME DS1302Buffer;
extern bool Flag_Time_Refresh;

#endif

三个文件放一起上传就好了。至于都是些什么东西,你看看代码就知道了。
那么多,实在懒得说。(又何况我也不太懂?)

All Done!

推荐阅读更多精彩内容