美文网首页Arduino我爱编程
不用时钟芯片的 Arduino 时钟

不用时钟芯片的 Arduino 时钟

作者: redexpress | 来源:发表于2017-12-27 23:15 被阅读43次

    我做了一个Arduino时钟,功能就像普通的电子表。有两个按键。
    按键1可用来显示日期、秒,在显示日期三秒后,自动返回到时间显示。
    按键2可进入调整小时、分钟、月、日状态,在这些状态下,用按键1进行调整数值。

    用到的器件:

    • Arduino UNO
    • 两个按键开关
    • TM1637芯片驱动的四位数码管
    • 导线若干

    我们通常使用1302等时钟芯片做Arduino时钟,其实用系统的millis()函数就可以计时了,可以从这里下载Arduino时间库,有了这个库,写时钟程序很方便了。TM1637芯片的库文件可以从这里找到。

    使用millis()函数有一个限制,进入外部中断的时候,millis()会停止计时️,所以不能用中断来处理事件。不过这也不算啥事,而且像Arduino UNO等只有两个中断引脚,要是有多个按键还不够用。

    不使用中断要提高响应速度,需要减少delay函数的使用,在读取按键的值的时候delay了50毫秒,时钟闪烁采用轮询。previousMillis保存前一个的millis(),和当前millis()比较,如下:

    #define UPDATE_TIME_INTERVAL 500
    unsigned long previousMillis = 0;
    void loop() {
      unsigned long currentMillis = millis();
      if (currentMillis - previousMillis >= UPDATE_TIME_INTERVAL) {
        previousMillis = currentMillis;
        // 更新时间显示
      }
    }
    

    Timelib 库的使用很简单
    本文用的的有:setTime,month,day,hour,minute,second这几个函数,setTime时间时,年份可以省略前两位,表示2000年之后多少年,本文的0就表示2000年,本时钟不是万年历,年份用任意一个闰年就行。

    TM1637库用一个长度为4的数值表示,point表示是否显示分隔符“:”。让某一位不显示,可以给其赋值0x7f,也可以用clear()清空屏幕再给其它位赋值。

    完整程序如下:

    #include <TM1637.h>
    #include <TimeLib.h>
    
    #define CLK 12
    #define DIO 13
    #define SW1 6
    #define SW2 7
    #define UPDATE_TIME_INTERVAL 500
    #define EMPTY 0x7f
    #define AUTO_SWITCH_TO_TIME_INTERVAL 3000
    
    int8_t timeDisp[] = {0, 0, 0, 0};
    TM1637 tm1637(CLK, DIO);
    
    unsigned long previousMillis = 0;
    boolean point = true;
    int8_t sw1oldValue = true;
    int8_t sw2oldValue = true;
    unsigned long enterDateMillis = 0;
    int8_t sw1status = 0;
    int8_t sw2status = 0;
    
    typedef enum {
      Status1Time,
      Status1Date,
      Status1Second,
      Status1AdjustTime
    } Switch1Status;
    
    typedef enum {
      Status2Normal,
      Status2Hour,
      Status2Minute,
      Status2Month,
      Status2Day
    } Switch2Status;
    
    void setup() {
      // switch setup
      pinMode(SW1, INPUT);
      digitalWrite(SW1, HIGH);
      pinMode(SW2, INPUT);
      digitalWrite(SW2, HIGH);
      // TM1637 setup
      tm1637.set();
      tm1637.init();
      tm1637.display(timeDisp);
      // TimeLib setup
      setTime(8, 20, 15, 27, 11, 0); // hour min sec day month year
    }
    
    void loop() {
      readSwitch();
      unsigned long currentMillis = millis();
      if (currentMillis - previousMillis >= UPDATE_TIME_INTERVAL) {
        previousMillis = currentMillis;
        updateTime();
        display();
      }
    }
    
    void readSwitch() {
      int8_t sw1value = digitalRead(SW1);
      if (sw1value != sw1oldValue) {
        if (sw1value == LOW) {
          adjustAction1();
        }
        sw1oldValue = sw1value;
      }
      int8_t sw2value = digitalRead(SW2);
      if (sw2value != sw2oldValue) {
        if (sw2value == LOW) {
          adjustAction2();
        }
        sw2oldValue = sw2value;
      }
      delay(50);
    }
    
    void adjustAction2() {
      sw1status = Status1AdjustTime;
      sw2status++;
      if (sw2status >= 5) {
        sw2status = 0;
        sw1status = Status1Time;
      }
    }
    
    void adjustAction1() {
      if (sw1status != Status1AdjustTime) {
        sw1status++;
        if (sw1status >= 3) {
          sw1status = 0;
        }
        if (sw1status == Status1Date) {
          enterDateMillis = millis();
        }
      } else {
        if (sw2status == Status2Hour) {
          int8_t h = hour();
          h++;
          if (h == 24) {
            h == 0;
          }
          setTime(h, minute(), second(), day(), month(), 0);
        } else if (sw2status == Status2Minute) {
          int8_t m = minute();
          m++;
          if (m == 60) {
            m == 0;
          }
          setTime(hour(), m, second(), day(), month(), 0);
        } else if (sw2status == Status2Month) {
          int8_t m = month();
          m++;
          if (m == 13) {
            m == 1;
          }
          setTime(hour(), minute(), second(), day(), m, 0);
        } else if (sw2status == Status2Day) {
          int8_t d = day();
          d++;
          int8_t days[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
          int8_t m = month();
          if (d > days[m]) {
            d == 1;
          }
          setTime(hour(), minute(), second(), d, month(), 0);
        }
      }
    }
    
    void updateTime() {
      if (sw1status == Status1Time) {
        timeDisp[0] = hour() < 10 ? EMPTY : hour() / 10;
        timeDisp[1] = hour() % 10;
        timeDisp[2] = minute() / 10;
        timeDisp[3] = minute() % 10;
      } else if (sw1status == Status1Second) {
        timeDisp[0] = EMPTY;
        timeDisp[1] = EMPTY;
        timeDisp[2] = second() / 10;
        timeDisp[3] = second() % 10;
      } else if (sw1status == Status1Date) {
        timeDisp[0] = month() < 10 ? EMPTY : month() / 10;
        timeDisp[1] = month() / 10;
        timeDisp[2] = day() / 10;
        timeDisp[3] = day() % 10;
        unsigned long ms = millis();
        if (ms - enterDateMillis > 3000) {
          sw1status = Status1Time;
        }
      } else if (sw1status == Status1AdjustTime) {
        if (sw2status == Status2Hour) {
          timeDisp[0] = hour() < 10 ? EMPTY : hour() / 10;
          timeDisp[1] = hour() % 10;
          timeDisp[2] = EMPTY;
          timeDisp[3] = EMPTY;
        } else if (sw2status == Status2Minute) {
          timeDisp[0] = EMPTY;
          timeDisp[1] = EMPTY;
          timeDisp[2] = minute() / 10;
          timeDisp[3] = minute() % 10;
        } else if (sw2status == Status2Month) {
          timeDisp[0] = month() < 10 ? EMPTY : month() / 10;
          timeDisp[1] = month() % 10;
          timeDisp[2] = EMPTY;
          timeDisp[3] = EMPTY;
        } else if (sw2status == Status2Day) {
          timeDisp[0] = EMPTY;
          timeDisp[1] = EMPTY;
          timeDisp[2] = day() / 10;
          timeDisp[3] = day() % 10;
        }
      }
    }
    
    void display() {
      if (sw1status == Status1Time) {
        point = !point;
        tm1637.point(point);
        tm1637.display(timeDisp);
      } else if (sw1status == Status1Second) {
        tm1637.point(false);
        tm1637.display(timeDisp);
      } else if (sw1status == Status1Date) {
        tm1637.point(false);
        tm1637.display(timeDisp);
      } else if (sw1status == Status1AdjustTime) {
        if (sw2status == Status2Hour || sw2status == Status2Minute) {
          point = !point;
          tm1637.point(point);
          tm1637.display(timeDisp);
        } else if (sw2status == Status2Month || sw2status == Status2Day) {
          tm1637.point(false);
          tm1637.display(timeDisp);
        }
      }
    }
    

    相关文章

      网友评论

        本文标题:不用时钟芯片的 Arduino 时钟

        本文链接:https://www.haomeiwen.com/subject/fxipgxtx.html