极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 13318|回复: 3

数码管显示的多功能时钟

[复制链接]
发表于 2017-9-26 22:59:44 | 显示全部楼层 |阅读模式
本多功能时钟的功能有:1、时钟显示(交替显示月、日和时、分、秒);
2、倒计时(计时阶段有场效应管电子开关,计时结束时有蜂鸣器提示。最长计时100小时-1秒);
3、秒表计时(计时时长99小时59分59秒,在计时阶段,每秒钟蜂鸣器会响0.1秒可关闭)。
主要元器件:(利用电信早期用的显示来电号码的外壳)
ATMEGA328P、一个四位数码管和一个三位数码管(可用两个四位数码管,本人把第二个第四位数码管用一个LED灯替代)、两个74HC595、DS1307模块。其它元件略。
电路图:
  


   


   
   
上传DS1307和MsTimer2的库文件失败,提示说不能传输零字节的文件,明明都是好几K的文件。
啃萝卜 - Make it easy!
复制代码
//VCC -- 5V
//GND -- GND
//DS -- A0
//ST_CP -- A1
//SH_CP -- A2
#include <Wire.h>
#include "DS1307.h"
#include <MsTimer2.h>
#define SJ 11   //时间设置键接口
#define SK  10  //秒表键接口
#define DK1 9   //定时键接口
#define ZK 5    //增加键接口
#define JK 6   //减少键接口
#define BZ 7   //蜂鸣器接口
#define LED 8  //LED接口
int szl,val,dsl,dnian,dyue,dri,dxiaos,dfenz,dmiaoz,dmiaob,dsjs;     //秒表、定时分辨变量;定时小时、定时分钟、定时秒钟
// 定义记录按键当前状态的变量
int S1,D1,Z1,J1,SZ,pmkg,fmkg;
// 定义记录按键最近一次状态变化的变量,并初始化状态为LOW。
int BS1=LOW;  //秒表键最近一次状态变化的变量
int BD1=LOW;  //定时键最近一次状态变化的变量
  int BZ1=LOW;  //增加键最近一次状态变化的变量
int BJ1=LOW;  //减少键最近一次状态变化的变量
int SZ1=LOW; //设置键最近一次状态变化的变量
// 定义记录最近一次抖动的时间变量,并初始化时间为0毫秒。
long STime = 0; //秒表键最近一次抖动的时间变量
long DTime=0;  //定时键最近一次抖动的时间变量
  long ZTime=0;  //增加键最近一次抖动的时间变量
long JTime=0;  //减少键最近一次抖动的时间变量
long SZTime=0; //设置键最近一次抖动的时间变量
// 定义延迟抖动的时间变量
long debouncdDelay = 60;
int dataPin = A0; //DS 74hc595的14脚。
int latchPin = A1;//ST_CP  74hc595的12脚。
int clockPin = A2;//SH_CP 74hc595的11脚。
int x=0; //定义点显示与否,0为不显示,1为显示。
int y=0;  //交替显示月日和小时分秒
//int s=0;//s为秒计时器
//这里定义了74HC595的那三个脚

DS1307 clock;//define a object of DS1307 class
void init_click(uint16_t _year, uint8_t _month, uint8_t _date, uint8_t _hour, uint8_t _minite, uint8_t _second, uint8_t _week)
{
    // clock.begin();
    clock.fillByYMD(_year, _month, _date, 1); //年、月、日
    clock.fillByHMS(_hour, _minite, _second); //时、分、秒
    clock.fillDayOfWeek(_week);   //1=MON 2=TUE 3=WED 4=THU 5=FRI 6=SAT 7=SUN
    clock.setTime();//write time to the RTC chip
}
void setup ()
{
  //让74HC595的三个脚都是输出状态
  pinMode(latchPin,OUTPUT);
   pinMode(clockPin,OUTPUT);
    pinMode(dataPin,OUTPUT);
   pinMode(BZ,OUTPUT);
  pinMode(LED,OUTPUT);
    digitalWrite(BZ,HIGH);
      digitalWrite(LED,LOW);
   //配置10,9,5,6号引脚为输入引脚 如果是自己连接普通按键 pinMode(SK,INPUT_PULLUP),弱上拉
   pinMode(SK,INPUT);//10号引脚
     pinMode(DK1,INPUT);//9号引脚
     pinMode(ZK,INPUT);//5号引脚
      pinMode(JK,INPUT);//6号引脚
     pinMode(SJ,INPUT);//11号引脚   
//  pinMode(dianya,INPUT);//A3号引脚  
   szl=0;
    val=0;
     dsl=0;
     dxiaos=0;
      dfenz=0;
     dmiaoz=0;
    pmkg=0;// 屏幕开关
   fmkg=0; //蜂鸣器开关
    clock.begin();
    //init_click(2017, 8, 26, 20, 44, 55,6);
//  clock.fillByYMD(2017, 8, 26, 1); //年、月、日
//   clock.fillByHMS(20, 58, 10); //时、分、秒
//   clock.fillDayOfWeek(_week);   //1=MON 2=TUE 3=WED 4=THU 5=FRI 6=SAT 7=SUN
//   clock.setTime();//write time to the RTC chip  
    //调用中断,中断时间为10ms
   MsTimer2::set(10, flash); // 10ms period
   MsTimer2::start();
}
//定时器工作计数器
void flash()
{
  static int xshi=0; //小时
   static int s=0; //计数器
    static int hao=0; //0.1秒
   static int fen=0;  //分
  static int miao=0;  //秒
  s++;
  if(dsjs==1){
    dmiaoz++;
    if(dmiaoz%2==0)  digitalWrite(BZ,HIGH);
     else  digitalWrite(BZ,LOW);
     if(dmiaoz>500){
      dmiaoz=0;
      dsjs=0;
       digitalWrite(BZ,HIGH);
     }
    }
  //秒表工作条件
if(val>1)
{
  if(val==2) //秒表开始工作
  {
   hao++;
   if(hao==86) hao+=12;//修正秒表计时
   if(fmkg==1){
    if(hao>85)     digitalWrite(BZ,LOW);//在最后0.15秒内蜂鸣器发声
      else     digitalWrite(BZ,HIGH);}
    if(hao==100)
    {
      hao=0;
      miao++;
      if(miao==60)
       {
        miao=0;
        fen++;
        if(fen==60)
         {
          fen=0;
          xshi++;
          if(xshi==100) xshi=0;
          }
        }
      }
    if(xshi/10==0)   disNum(11,1,0);
    else     disNum(xshi/10,1,0);
     if(xshi/10==0 and xshi%10==0)  disNum(11,2,0);
      else   disNum(xshi%10,2,0);
     if (xshi/10==0 and xshi%10==0 and fen/10==0) disNum(11,3,0);
        else   disNum(fen/10,3,0);
        if(xshi/10==0 and xshi%10==0 and fen/10==0 and fen%10==0) disNum(11,4,0);
        else   disNum(fen%10,4,0);
       if(xshi/10==0 and xshi%10==0 and fen/10==0 and fen%10==0 and miao/10==0) disNum(11,5,0);
        else   disNum(miao/10,5,0);
      disNum(miao%10,6,1);
     disNum(hao/10,7,0);
    disNum(11,8,0);

    }
   if(val==3)  //秒表暂停
    {
    if(xshi/10==0)   disNum(11,1,0);
    else     disNum(xshi/10,1,0);
     if(xshi/10==0 and xshi%10==0)  disNum(11,2,0);
      else   disNum(xshi%10,2,0);
     if (xshi/10==0 and xshi%10==0 and fen/10==0) disNum(11,3,0);
        else   disNum(fen/10,3,0);
        if(xshi/10==0 and xshi%10==0 and fen/10==0 and fen%10==0) disNum(11,4,0);
        else   disNum(fen%10,4,0);
       if(xshi/10==0 and xshi%10==0 and fen/10==0 and fen%10==0 and miao/10==0) disNum(11,5,0);
        else   disNum(miao/10,5,0);
      disNum(miao%10,6,1);
     disNum(hao/10,7,0);
    disNum(11,8,0);
     digitalWrite(BZ,HIGH);
     }
    if(val==4)  //秒表停止工作
     {
       val=1;
        xshi=0;
         fen=0;
         miao=0;
        hao=0;   
      }
}
  //时间设定
  if(szl>1)
  {
    if(szl==2)
    {
       disNum(dnian/1000,1,0);  
       disNum(dnian%1000/100,2,0);
       disNum(dnian%100/10,3,0);
       if(s>50) disNum(10,4,0);
       else  disNum(dnian%10,4,0);
      }
     if(szl==3)
     {
      disNum(dyue/10,1,0);
       if(s>50) disNum(10,2,0);
       else  disNum(dyue%10,2,0);      
      }
     if(szl==4)
     {
      disNum(dri/10,3,0);
       if(s>50) disNum(10,4,0);
       else  disNum(dri%10,4,0);      
      }
     if(szl==5)
     {
      disNum(dxiaos/10,1,0);
       if(s>50) disNum(10,2,0);
       else  disNum(dxiaos%10,2,0);         
      }
     if(szl==6)
     {
      disNum(dfenz/10,3,0);
       if(s>50) disNum(10,4,0);
       else  disNum(dfenz%10,4,0);      
      }
     if(szl==7)
     {
      disNum(dmiaoz/10,5,0);
       if(s>50) disNum(10,6,0);
       else  disNum(dmiaoz%10,6,0);      
      }
    }
  //定时器工作
  if(dsl>1)
  {
    if(dsl==2) //调整定时的小时数
    {
      if(dxiaos/10==0) disNum(11,1,0);
       else disNum(dxiaos/10,1,0);
      if(s>50) disNum(10,2,0);
       else disNum(dxiaos%10,2,0);  
       disNum(11,3,0);   
        disNum(11,4,0);  
         disNum(11,5,0);  
         disNum(11,6,0);  
        disNum(dsl,7,0);
       disNum(11,8,0);   
      }
    if(dsl==3)   //调整定时的分钟数
    {
      if(dxiaos/10==0) disNum(11,1,0);
       else disNum(dxiaos/10,1,0);
        if(dxiaos%10==0) disNum(11,2,0);
         else disNum(dxiaos%10,2,0);
          if(dfenz/10==0) disNum(11,3,0);
           else disNum(dfenz/10,3,0);
          if(s>50) disNum(10,4,0);
           else disNum(dfenz%10,4,0);  
          disNum(11,5,0);  
         disNum(11,6,0);  
        disNum(dsl,7,0);
       disNum(11,8,0);        
      }
    if(dsl==4)  //调整定时的秒数
    {
      if(dxiaos/10==0) disNum(11,1,0);
       else disNum(dxiaos/10,1,0);
        if(dxiaos%10==0) disNum(11,2,0);
         else disNum(dxiaos%10,2,0);
          if(dfenz/10==0) disNum(11,3,0);
           else disNum(dfenz/10,3,0);
           if(dfenz%10==0) disNum(11,4,0);
            else disNum(dfenz%10,4,0);
           if(dmiaoz/10==0) disNum(11,5,0);
            else disNum(dmiaoz/10,5,0);  
           if(s>50) disNum(10,6,0);
           else disNum(dmiaoz%10,6,0);
         disNum(dsl,7,0);
        disNum(11,8,0);      
       }
    }
  if(s<50)x=1;  //秒点显示与否开关,1开,0关。
   else x=0;
   if(s==100)
   {
     s=0;
     y++;
   if(y==8) y=1;
  }
  
}

void printTime()
{
  int dNum [8];//定义数组,显示年月日时分秒
  //int nian,yue,ri,shi,fen,miao; //定义年月日时分秒
   int i;
    clock.getTime();
   // nian=clock.year;
        if(dsl==5)  //定时器开始工作,定时器指示灯亮,第八个虚拟数码管输入数字5
      {
        digitalWrite(LED,HIGH);//定时继电器工作
      //  clock.getTime();
        if(dmiaob!=clock.second)
         {
          dmiaob=clock.second;
          if(dmiaoz==0)
           {
            if(dfenz==0)
             {
              if(dxiaos!=0)
               {
                dxiaos--;
                dfenz=59;
                dmiaoz=59;
                }
                else //定时结束
                {
                  val=1;
                  dsl=1;
                  dsjs=1;
                  dmiaoz=0;
                  //关闭定时指示灯
               digitalWrite(LED,LOW); //关闭定时继电器
                  }
              }
             else {
              dfenz--;
              dmiaoz=59;
              }
            }
          else dmiaoz--;
          }
       if(dxiaos/10==0) disNum(11,1,0);
       else disNum(dxiaos/10,1,0);
        if(dxiaos/10==0 and dxiaos%10==0) disNum(11,2,0);
         else disNum(dxiaos%10,2,0);
          if(dxiaos/10==0 and dxiaos%10==0 and dfenz/10==0) disNum(11,3,0);
           else disNum(dfenz/10,3,0);
           if(dxiaos/10==0 and dxiaos%10==0 and dfenz/10==0 and dfenz%10==0) disNum(11,4,1);
            else disNum(dfenz%10,4,1);
           if(dxiaos/10==0 and dxiaos%10==0 and dfenz/10==0 and dfenz%10==0 and dmiaoz/10==0) disNum(11,5,0);
            else disNum(dmiaoz/10,5,0);  
          disNum(dmiaoz%10,6,0);
         disNum(dsl,7,0);
        disNum(10,8,0);            
        }
        else{
    if(y<3){
     if(clock.month/10==0)dNum [1]=11;
     else  dNum [1]=clock.month/10;
    dNum [2]=clock.month%10;
    if(clock.dayOfMonth/10==0) dNum [3]=11;
     else  dNum [3]=clock.dayOfMonth/10 ;
    dNum [4]=clock.dayOfMonth%10;
     disNum(dNum[1], 1,0);
      disNum(dNum[2], 2,0);
       disNum(dNum[3], 3,0);
        disNum(dNum[4], 4,0);
        disNum(11, 5,0);
       disNum(11, 6,0);
      disNum(val, 7,0);
     disNum(11, 8,0);
   }
   if(y>2)
   {
    if(clock.hour/10==0)  dNum [1]=11;
     else  dNum [1]=clock.hour/10;
    dNum [2]=clock.hour%10;
     dNum [3]=clock.minute/10;
      dNum [4]=clock.minute%10;
       dNum [5]=clock.second/10;     
      dNum [6]=clock.second%10;
    dNum [7]=11;
   // int t=dNum[8];
    disNum(dNum[1], 1,0);
     disNum(dNum[2], 2,x);
      disNum(dNum[3], 3,0);
       disNum(dNum[4], 4,0);
       disNum(dNum[5], 5,0);
      disNum(dNum[6], 6,1);
     disNum(pmkg, 7,0);
    disNum(11, 8,0);
   }
  }   
}
//这个函数是显示一个数用的disNum(显示的数,显示的位)
void disNum(int Num_Qua, int Num_Pos, int Num_Dec)
{
    int Num_Qua_B = 0;
    int Num_Pos_B = 0;
    switch (Num_Qua)
    {
                case 0:Num_Qua_B = 192;break;
                 case 1:Num_Qua_B = 249;break;
                  case 2:Num_Qua_B = 164;break;
                   case 3:Num_Qua_B = 176;break;
                    case 4:Num_Qua_B = 153;break;
                     case 5:Num_Qua_B = 146;break;
                    case 6:Num_Qua_B = 130;break;
                   case 7:Num_Qua_B = 248;break;
                 case 8:Num_Qua_B = 128;break;
                case 9:Num_Qua_B = 144;break;
                case 10:Num_Qua_B = 247;break;  //数码管显示"_"
               default: Num_Qua_B = 255;break;  //0-9以外的整数表示该位的数不显示
    };
        //这个值转换为2进制 为一个数abcdefg的需要亮的针脚。增加的绿灯数字为1,最后一个位。
        switch (Num_Pos)
    {
                case 1:Num_Pos_B = 1;break;
                 case 2:Num_Pos_B = 2;break;
                  case 3:Num_Pos_B = 4;break;
                   case 4:Num_Pos_B = 8;break;
                    case 5:Num_Pos_B = 16;break;
                     case 6:Num_Pos_B = 32;break;
                    case 7:Num_Pos_B = 64;break;
                  case 8:Num_Pos_B = 128;break;
                default: Num_Pos_B = 0;break;
    };
        //这个值转换为2进制 为当前点亮的位数。
    if (Num_Dec == 1)
    {
        Num_Qua_B = Num_Qua_B + 128;
    }
    if(pmkg==1) Num_Pos_B = 0;
        //128是Q7端口2进制值转换为10进制的结果。
    digitalWrite(latchPin,LOW); //将ST_CP口上面加低电平让芯片准备好接收数据
     int L = Num_Qua_B; int R = Num_Pos_B;
      shiftOut(dataPin,clockPin,MSBFIRST,R);
     shiftOut(dataPin,clockPin,MSBFIRST,L);
    digitalWrite(latchPin,HIGH); //将ST_CP这个针脚恢复到高电平
        //上面是74HC595的输出方式 每个74HC595能接受一个8位的2进制数值来电灯 第一个74HC595再次输入一个8位的数值他会把他现在的数值传给第二个串联的74HC595。
        delayMicroseconds(100);
   
}

void loop()
{
       //时间设置键
   int SJ1 = digitalRead(SJ);//读取当前时间设置按键状态  SJ1->buttonState
  if(SJ1 != SZ1)
  {
     //如果按键发生了变化  则重新设置最近一次抖动的时间
     //方法millis()可以获取当前时间,单位统一为毫秒。
     SZTime = millis();  
   }
  // 判断按键按下状态时间间隔是否大于延迟抖动的时间长度。
  if(millis()-SZTime>debouncdDelay)
  {
    // 判断当前的按键状态是否和之前有所变化
    if(SJ1 != SZ){
       // 如果发生了变化,
       // 则更新按键状态变量。
       SZ =SJ1;
       if(SZ == HIGH){
        //再次确认是否真的按下了按键,是的话就执行以下命令
        szl++;
        if(szl==2){
              clock.getTime();
               dnian=clock.year;
                dyue=clock.month;
                  dri=clock.dayOfMonth;
                 dxiaos=clock.hour;
               dfenz=clock.minute;
              dmiaoz=clock.second;
          }
          if(szl==8){
               clock.fillByYMD(dnian,dyue,dri, 1); //年、月、日
                  clock.fillByHMS(dxiaos, dfenz, dmiaoz); //时、分、秒
                clock.setTime();//write time to the RTC chip  
                szl=1;         
            }
       }
    }
  }
  // 更新按键最近一次状态变化的变量
     SZ1 = SJ1;
   
    //秒表键
   int DS1 = digitalRead(SK);
  if(DS1 != BS1)
  {
     STime = millis();  
   }

  if(millis()-STime>debouncdDelay)
  {
    if(DS1 != S1){
       S1 = DS1;
       if(S1 == HIGH){
        val++;
       }
    }
  }
     BS1 = DS1;
     
     //定时键
  int ss1=digitalRead(DK1);
  if(ss1 != BD1)
  {
     DTime = millis();  
  }
  if(millis()-DTime>debouncdDelay){
    if(ss1 != D1)
    {
       D1 = ss1;
       if(D1 == HIGH)
       {
        dsl++;
        if(dsl==6) //取消定时
         {
          val=1;
          dsl=1;
          }
       }
    }
  }
     BD1 = ss1;
     
     //增键
    int DZ1 = digitalRead(ZK);
    if(DZ1 != BZ1)
    {
     ZTime = millis();  
     }
  if(millis()-ZTime>debouncdDelay)
  {
    if(DZ1 != Z1)
    {
       Z1 = DZ1;
       if(Z1 == HIGH)
       {
        if(val*dsl*szl==1) fmkg=!fmkg;
        if(szl>1)
        {
          if(szl==2)
          {
            dnian++;
            }
           if(szl==3)
           {
            dyue++;
            if(dyue==13) dyue=1;
            }
           if(szl==4)
           {
              dri++;
              if(dri==32) dri=1;
            }
            if(szl==5)
            {
              dxiaos++;
              if(dxiaos==24) dxiaos=1;
              }
             if(szl==6)
             {
               dfenz++;
               if(dfenz==60) dfenz=1;
              }
              if(szl==7)
              {
                dmiaoz++;
                if(dmiaoz==60) dmiaoz=1;
                }
                  
          }
        if(dsl>1)
       {
        if(dsl==2)
        {
          dxiaos++;
          if(dxiaos==100) dxiaos=0;
          }
         if(dsl==3)
         {
          dfenz++;
          if(dfenz==60) dfenz=0;
          }
         if(dsl==4)
         {
          dmiaoz++;
          if(dmiaoz==60) dmiaoz=0;
          }
       }
      }
    }
  }
     BZ1 = DZ1;
     
     //减键
     int DJ1 = digitalRead(JK);
   if(DJ1 != BJ1)
   {
     JTime = millis();  
   }
  if(millis()-JTime>debouncdDelay)
  {
    if(DJ1 != J1)
    {
       J1 = DJ1;
       if(J1 == HIGH)
       {
        if(val*dsl*szl==1) pmkg=!pmkg;
        if(dsl>1){
        if(dsl==2)
        {
          dxiaos--;
          if(dxiaos==-1) dxiaos=99;
          }
         if(dsl==3)
         {
          dfenz--;
          if(dfenz==-1) dfenz=59;
          }
         if(dsl==4)
         {
          dmiaoz--;
          if(dmiaoz==-1) dmiaoz=59;
          }
       }
         if(szl>1)
        {
          if(szl==2)
          {
            dnian--;
            }
           if(szl==3)
           {
            dyue--;
            if(dyue==-1) dyue=12;
            }
           if(szl==4)
           {
              dri--;
              if(dri==-1) dri=31;
            }
            if(szl==5)
            {
              dxiaos--;
              if(dxiaos==-1) dxiaos=23;
              }
             if(szl==6)
             {
               dfenz--;
               if(dfenz==-1) dfenz=59;
              }
              if(szl==7)
              {
                dmiaoz--;
                if(dmiaoz==-1) dmiaoz=59;
                }
                  
          }
     }
    }
  }
     BJ1 = DJ1;
     
    if(val*dsl*szl==1 or dsl==5)
    {
      printTime();
    }
   
   }


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2017-9-27 10:12:28 | 显示全部楼层
這個得好好學習學習~~給樓主個讚
回复 支持 反对

使用道具 举报

发表于 2017-9-28 14:36:00 | 显示全部楼层
占个位,收藏学习
回复 支持 反对

使用道具 举报

发表于 2017-9-29 10:29:52 | 显示全部楼层
谢谢分享   学习一下  没有完整程序
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-19 21:42 , Processed in 0.040460 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表