不用时钟芯片的 Arduino 时钟

我做了一个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 
#include 

#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 时钟)