huchunhb 发表于 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 SK10//秒表键接口
#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_CP74hc595的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);
   elsedigitalWrite(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);
       elsedisNum(dnian%10,4,0);
      }
   if(szl==3)
   {
      disNum(dyue/10,1,0);
       if(s>50) disNum(10,2,0);
       elsedisNum(dyue%10,2,0);      
      }
   if(szl==4)
   {
      disNum(dri/10,3,0);
       if(s>50) disNum(10,4,0);
       elsedisNum(dri%10,4,0);      
      }
   if(szl==5)
   {
      disNum(dxiaos/10,1,0);
       if(s>50) disNum(10,2,0);
       elsedisNum(dxiaos%10,2,0);         
      }
   if(szl==6)
   {
      disNum(dfenz/10,3,0);
       if(s>50) disNum(10,4,0);
       elsedisNum(dfenz%10,4,0);      
      }
   if(szl==7)
   {
      disNum(dmiaoz/10,5,0);
       if(s>50) disNum(10,6,0);
       elsedisNum(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 ;//定义数组,显示年月日时分秒
//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 =11;
   elsedNum =clock.month/10;
    dNum =clock.month%10;
    if(clock.dayOfMonth/10==0) dNum =11;
   elsedNum =clock.dayOfMonth/10 ;
    dNum =clock.dayOfMonth%10;
   disNum(dNum, 1,0);
      disNum(dNum, 2,0);
       disNum(dNum, 3,0);
      disNum(dNum, 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 =11;
   elsedNum =clock.hour/10;
    dNum =clock.hour%10;
   dNum =clock.minute/10;
      dNum =clock.minute%10;
       dNum =clock.second/10;   
      dNum =clock.second%10;
    dNum =11;
   // int t=dNum;
    disNum(dNum, 1,0);
   disNum(dNum, 2,x);
      disNum(dNum, 3,0);
       disNum(dNum, 4,0);
       disNum(dNum, 5,0);
      disNum(dNum, 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();
    }
   
   }


humhumhum 发表于 2017-9-27 10:12:28

這個得好好學習學習~~給樓主個讚

huangshan78 发表于 2017-9-28 14:36:00

占个位,收藏学习

by64214 发表于 2017-9-29 10:29:52

谢谢分享   学习一下没有完整程序
页: [1]
查看完整版本: 数码管显示的多功能时钟