2017年5月7日 星期日

Arduino 數字鬧鐘及溫濕度顯示器







材料大部份由淘寶網購入,列表如下:




外殼在日本城購買:
  1. 亞加力膠箱 1 個     HK$12
  2. 木紋色貼紙       HK$5


全部材料費大約為港幣 $90



接駁圖:


實驗短片:







程式碼:

#include <EEPROM.h>
#include "DS3231_Simple.h"
#include "TM1637Display.h"
#include "DHT.h"

// DHT22 connection pins and type
#define DHTPIN 12
#define DHTTYPE DHT22

// 74HC595N connection pins (Digital Pins)
#define DS 4
#define ST 5
#define SH 6

// TM1637 connection pins (Digital Pins)
#define CLK 2
#define DIO 3

DS3231_Simple Clock;
TM1637Display display(CLK, DIO);
DHT dht(DHTPIN, DHTTYPE);

boolean colon = false;
boolean enableAlarm = true;
boolean fireAlarm = false;

int alarm;
struct HM {
  int h;
  int m;
};

#define LED 13
#define BUZZER 7
#define BTN_SET 10
#define BTN_ADD 8
#define BTN_SUB 9
#define BTN_MODE 11
#define BRIGHTNESS 3
#define DELAY_MILLIS 6
unsigned long preMillis = 0;
int btnState;
int lastBtnState = LOW;
unsigned long lastDebounceTime = 0;
float temp, humi;
unsigned long preReadTemp = 0;
byte mode = 1;

const int D[] = {A3,A2,A1,A0};
// Setup 7 segment display (common cathode)
int seg[12][7] = {{1,1,1,1,1,1,0},    // 0
                  {0,1,1,0,0,0,0},    // 1
                  {1,1,0,1,1,0,1},    // 2
                  {1,1,1,1,0,0,1},    // 3
                  {0,1,1,0,0,1,1},    // 4
                  {1,0,1,1,0,1,1},    // 5
                  {1,0,1,1,1,1,1},    // 6
                  {1,1,1,0,0,0,0},    // 7
                  {1,1,1,1,1,1,1},    // 8
                  {1,1,1,1,0,1,1},    // 9
                  {1,0,0,0,0,1,1},    // c
                  {1,1,0,0,1,1,1}     // P
                 };

void setup() {
  Clock.begin();
  dht.begin();
  temp = dht.readTemperature();
  humi = dht.readHumidity();
  alarm = readAlarm();
  pinMode(BTN_SET, INPUT_PULLUP);
  pinMode(BTN_ADD, INPUT_PULLUP);
  pinMode(BTN_SUB, INPUT_PULLUP);
  pinMode(BTN_MODE, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);
  pinMode(LED, OUTPUT);
  pinMode(DS, OUTPUT);
  pinMode(ST, OUTPUT);
  pinMode(SH, OUTPUT);
  for (int i = 0; i < 4; i++) {
    pinMode(D[i], OUTPUT);
  }
}

void loop() {
  uint8_t segto;
  int btn0, btn1, btn2, btn3;
  DateTime now;          // Create a variable to hold the data 
  now = Clock.read();    // Ask the clock for the data.
  display.setBrightness(BRIGHTNESS);
  
  int t = now.Hour * 100 + now.Minute;
  display.showNumberDec(t, true);   // Display four digits t with leading zeroes

  /*/ Blink the colon each second
  if (millis() - preMillis >= 500) {
    preMillis = millis();
    colon = !colon; 
  }
  if (colon) {
    segto = 0x80 | display.encodeDigit((t / 100) % 10);
    display.setSegments(&segto, 1, 1);
  }
  segto = 0x80 | display.encodeDigit((t / 100) % 10);
  display.setSegments(&segto, 1, 1);
  */
  // Turn ON or OFF alarm light
  if (enableAlarm) digitalWrite(LED, HIGH); else digitalWrite(LED, LOW);
  
  btn0 = digitalRead(BTN_MODE);
  btn1 = digitalRead(BTN_SET);
  btn2 = digitalRead(BTN_ADD);
  btn3 = digitalRead(BTN_SUB);
  // Set + Add button triggering set alarm
  if (btn1 == LOW && btn2 == LOW) setAlarm();
  
  // Set + Sub button triggering set clock
  if (btn1 == LOW && btn3 == LOW) setClock(now);

  // Mode + Add button triggering set date
  if (btn0 == LOW && btn2 == LOW) setDate(now);

  // Add + Sub button enable or disable alarm
  if (btn2 == LOW && btn3 == LOW) enableAlarm = !enableAlarm;
  
  // Monitor the Mode Button
  int reading = digitalRead(BTN_MODE);
  if (reading != lastBtnState) lastDebounceTime = millis();
  if ((millis() - lastDebounceTime) > 50) {
    if (reading != btnState) {
      btnState = reading;
      if (btnState == LOW) {
        mode++;
        if (mode > 3) mode = 1;
      }
    }
  }
  lastBtnState = reading;
  
  // Check Alarm
  if (t == alarm && enableAlarm) fireAlarm = true;
  if (fireAlarm) handleFireAlarm();

  if (millis() - preReadTemp > 60000) {
    preReadTemp = millis();
    temp = dht.readTemperature();
    humi = dht.readHumidity();
    //Serial.print("Temp: "); Serial.println(temp);
    //Serial.print("Humi: "); Serial.println(dht.readHumidity());
  }
  displayInfo(now);
}
// ***********************************
// ***       End of Main loop      ***
// ***********************************


void setClock(DateTime rtc) {
  int h = rtc.Hour * 100;
  int m = rtc.Minute;
  struct HM hm = adjustTime(h, m);
  if (hm.h == -1) return;       // Cancel operation if Mode button is pressed
  DateTime t;
  t.Hour = hm.h / 100;
  t.Minute = hm.m;
  t.Second = 0;
  t.Day = rtc.Day;
  t.Month = rtc.Month;
  t.Year = rtc.Year;
  Clock.write(t);
}

void setDate(DateTime rtc) {
  delay(1000);
  DateTime t;
  int day = rtc.Day;
  int month = rtc.Month;
  int year = rtc.Year;
  day = adjustDMY(day, 'd');
  month = adjustDMY(month, 'm');
  year = adjustDMY(year, 'y');
  t.Day = day;
  t.Month = month;
  t.Year = year;
  t.Hour = rtc.Hour;
  t.Minute = rtc.Minute;
  t.Second = rtc.Second;
  Clock.write(t);
}

int adjustDMY(int n, char dmy) {
  while (true) {
    outputNumbers(n, 'd');
    int add = digitalRead(BTN_ADD);
    int sub = digitalRead(BTN_SUB);
    int set = digitalRead(BTN_SET);
    delay(120);
    if (add == LOW) {
      n++;
      if (dmy == 'd' && n > 31) n = 1;
      if (dmy == 'm' && n > 12) n = 1;
      if (dmy == 'y' && n > 99) n = 0;
    }
    if (sub == LOW) {
      n--;
      if (dmy == 'd' && n < 1) n = 31;
      if (dmy == 'm' && n < 1) n = 12;
      if (dmy == 'y' && n < 0) n = 99;
    }
    if (set == LOW) break;
  }
  return n;
}

int readAlarm() {
  int eepromAddr = 0;
  int h = EEPROM.read(eepromAddr) * 100;
  eepromAddr++;
  int m = EEPROM.read(eepromAddr);
  return (h + m);
}

void setAlarm() {
  int t = readAlarm();
  struct HM hm = adjustTime((t / 100) * 100, (t % 100));
  if (hm.h == -1) return;       // Cancel operation if Mode button is pressed
  int eepromAddr = 0;
  EEPROM.write(eepromAddr, hm.h/100);
  eepromAddr++;
  EEPROM.write(eepromAddr, hm.m);
  alarm = readAlarm();
  enableAlarm = true;
}

void handleFireAlarm() {
  tone(BUZZER, 1000);
  delay(50);
  tone(BUZZER, 500);
  delay(10);
  int b1 = digitalRead(BTN_ADD);
  int b2 = digitalRead(BTN_SUB);
  delay(40);
  if (b1 == LOW && b2 == LOW) {
    enableAlarm = false;
    fireAlarm = false;
    noTone(BUZZER);
  }
}

struct HM adjustTime(int h, int m) {
  int t = h;
  byte flag = 1;
  struct HM hourMin;
  delay(300);           // Make a delay to avoid memory of last buttons state
  while (true) {
    display.setBrightness(0);
    display.showNumberDec(t, true);
    delay(70);
    DateTime now = Clock.read();   // Ask the clock for the data.
    displayInfo(now);
    display.setBrightness(BRIGHTNESS);
    display.showNumberDec(t, true);
    delay(70);
    int buttonRead = digitalRead(BTN_SET);
    int btnCancel = digitalRead(BTN_MODE);
    if (btnCancel == LOW) {
      delay(100);       // Make a delay to avoid memory of last buttons state
      hourMin.h = -1;
      hourMin.m = -1;
      return hourMin;
    }
    if (buttonRead == LOW) {
      if (flag == 2) {
        hourMin.h = h;
        hourMin.m = m;
        return hourMin;
        break;
      }
      else {
        flag++;
        t = m;
      }
    }
    int add = digitalRead(BTN_ADD);
    int sub = digitalRead(BTN_SUB);
    if (add == LOW) {
      if (flag == 1) {
        t += 100;
        if (t > 2300) t = 0;
        h = t;
      }
      else {
        t++;
        if (t > 59) t = 0;
        m = t;
      }
    }
    if (sub == LOW) {
      if (flag == 1) {
        t -= 100;
        if (t < 0) t = 2300;
        h = t;
      }
      else {
        t--;
        if (t < 0) t = 59;
        m = t;
      }
    }
  }
}

void outputNumbers(float num, char type) {
  int digit[] = {0,0,0,0};
  digit[0] = (int) num / 10;
  digit[1] = (int) num % 10;
  digit[2] = (int) (num * 10) % 10;
  int x = (num >= 10) ? 0 : 1;
  for (int i = x; i < 3; i++) {
    if (i == 1){
      displayOneDigit(i, digit[i], true);
    }
    else {
      displayOneDigit(i, digit[i], false);
    }
    delay(DELAY_MILLIS);
  }
  // Output Celsius or % sign
  if (type == 't') {
    displayOneDigit(3, 10, false);
  }
  else if (type == 'h') displayOneDigit(3, 11, false);
}

void displayOneDigit(int digit, int number, boolean dot) {
  // Turn off all digits
  for (int i = 0; i < 4; i++) {
    digitalWrite(D[i], HIGH);
  }
  fire_595_CLK();
  fire_595_LATCH();
  for (int b = 0; b < 7; b++) {
    digitalWrite(DS, seg[number][b]);
    fire_595_LATCH();
  }
  digitalWrite(DS, dot);
  fire_595_LATCH();
  fire_595_CLK();
  // Turn on the appropriate digit on the display
  digitalWrite(D[digit], LOW);
}

// Send clock rising signal
void fire_595_CLK() {
  digitalWrite(ST, HIGH);
  digitalWrite(ST, LOW);
}

// Send latach rising signal
void fire_595_LATCH() {
  digitalWrite(SH, HIGH);
  digitalWrite(SH, LOW);
}

void displayInfo(DateTime rtc) {
  switch (mode) {
    case 1:
      outputNumbers(temp, 't');
      break;
    case 2:
      outputNumbers(humi, 'h');
      break;
    case 3:
      int day = rtc.Day;
      int month = rtc.Month;
      if (month > 9) {
        displayOneDigit(0, (month/10), false);
        delay(DELAY_MILLIS);
        displayOneDigit(1, (month%10), true);
        delay(DELAY_MILLIS);
      }
      else {
        displayOneDigit(0, (month), true);
        delay(DELAY_MILLIS);
      }
      displayOneDigit(2, (day/10), false);
      delay(DELAY_MILLIS);
      displayOneDigit(3, (day%10), false);
  }
}



5 則留言:

  1. 請問一下#include "DS3231_Simple.h"在做測試的時候會跑出錯誤請問如何修正求解
    測試時顯示
    Arduino:1.8.6 (Windows 10), 開發板:"Arduino/Genuino Uno"

    sketch_oct20a:2:27: error: DS3231_Simple.h: No such file or directory

    compilation terminated.

    exit status 1
    DS3231_Simple.h: No such file or directory

    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.

    回覆刪除
    回覆
    1. 因為你的 Arduino IDE沒有安裝適當的Libraries。

      你可以撳 [Sketch]->[Include Library]->[Manage libraries]
      然後續個搜尋 (DS3231, TM1637, DHT) 並安裝即可

      刪除
  2. 請問我程式都INCLUED但是還是會出現EXIT SATUS1 開發板 Arduino/Genuino Uno 編譯錯誤。
    請問是為何?

    回覆刪除
    回覆
    1. 因為你的 Arduino IDE沒有安裝適當的Libraries。

      你可以撳 [Sketch]->[Include Library]->[Manage libraries]
      然後續個搜尋 (DS3231, TM1637, DHT) 並安裝即可

      刪除
  3. 請問鬧鐘跟溫度顯示的功能是分開的嗎?謝謝

    回覆刪除