不用时钟芯片的 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 <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);
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,881评论 4 368
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,052评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,598评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,407评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,823评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,872评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,037评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,778评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,505评论 1 247
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,745评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,233评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,568评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,231评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,141评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,939评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,954评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,784评论 2 275

推荐阅读更多精彩内容