산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Arduino Nano, DS3231 RTC, LDR 자동 밝기 조절 7-세그먼트 시계 만들기

필요한 부품 및 소모품

Arduino Nano R3 (Arduino Uno 또는 Elegoo Uno와도 호환) 1개
Adafruit 7-세그먼트 백팩 - 1.2" 큰 숫자 1개
Adafruit 1.2" 4자리 7-세그먼트 디스플레이 (I2C 백팩 포함) - 녹색 1개
Adafruit DS3231 RTC 모듈 (DS1307 대체 가능) 1개
저항 100k 옴 1개
포토레지스터 (조도 센서) 1개
브레드보드 1개
점퍼 와이어 (10-14개) 1개
코인 셀 배터리 CR1220 1개

앱 및 온라인 서비스

프로젝트 소개

소개

손목시계나 스마트폰으로 항상 시간을 확인할 수 있는 시대에 Arduino Uno/Nano로 시계를 만드는 건 다소 시시해 보일 수 있습니다. 게다가 NTP 서버와 동기화되어 항상 인터넷에 연결된 기기들도 널려 있으니까요.

배경 이야기

친구 한 명이 개인적인 이유로 침실에 WiFi 연결 기기를 두기 원하지 않아서, 별도의 시계 기능만 하는 Arduino 시계를 만들어주게 되었습니다.

적합한 제품 선택

Adafruit만 해도 전압과 정밀도에 따라 정말 다양한 RTC 모듈을 판매하고 있어 놀랐습니다. 여기서는 저렴한 DS1307과 더 정밀한 DS3231 두 가지를 선택했습니다.

둘 다 이 시계에 사용할 수 있습니다. DS1307을 사용하려면 올바른 핀 할당에 주의하고, 온도 표시 기능은 사용할 수 없습니다(코드 내 displayTemp() 함수 앞에 // 주석 처리).

스케치 수정

다른 회원이 만든 스케치를 찾아 재구성하고 다듬었으며, 원래의 체코어 주석은 유지하고 영어 설명을 추가했습니다.

시간만 크게 표시하면 되므로 7-세그먼트 디스플레이를 선택했습니다.

스케치 검토 중 반가운 발견: DS3231은 온도 측정 기능을 제공하는데, DS1307은 부정확할 뿐 아니라 이 기능이 없습니다.

시계 초기화

CR1220 버튼 배터리가 있다면 Adafruit의 간단한 튜토리얼을 따라 시계를 설정하세요. 요약하자면 인터넷에서 시간을 가져오는 게 아니라 로컬 PC의 시간을 기준으로 업로드 타임스탬프를 타이머에 전송합니다.

기능

이후 LED 매트릭스를 회로에 추가하여 시간과 온도 출력 기능을 구현했습니다. 시간과 온도 표시 전환 주기는 변수로 설정 가능합니다.

개별 깜빡이는 점과 LED 매트릭스의 숫자 제어 방식은 스케치에 잘 설명되어 있습니다. Adafruit 자료를 참고하세요.

스케치에는 서머타임/겨울시간 자동 전환과 주변 조도에 따른 LED 매트릭스 밝기 자동 조절(밤에는 어둡게, 낮에는 밝게) 기능이 포함되어 있습니다.

영상에서 시간과 온도 전환을 보셨을 겁니다. 왼쪽의 점이 초에 따라 위아래로 위치를 바꾸는 것도 확인하셨나요?

피드백 부탁드립니다: 시계 장애 시 LED 매트릭스에 "ERR"을 표시하는 방법을 아시면 알려주세요. 현재는 "bEEF"가 표시됩니다:


// oh no, no data!
Serial.println("DS3231 Sensor Error - cant read temperature");
matrix.print(0xBEEF, HEX); // inform the user with BEEF
matrix.writeDisplay();
delay(5000);

확장 아이디어

업데이트 (2019.02.01)

브레드보드에서 기판으로 이전을 완료했습니다. 관심 있으신 분들을 위한 사진들:

코드

MyClock v1.0 (C/C++)
// MyClock v1.0
// Ingo Lohs
// Hardware: tested with Arduino Uno and Arduino Nano (ATmega328P [Old Bootloader]) by using Arduino IDE v1.8.8

#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"

#define DS3231_I2C_ADDRESS 0x68
int ldr_sensor = A0;
int ldr_value = 0;
int brightness_matrix;
int threshold_brightness = 400;
int blinkrate_value = 0;
int delay_matrix_time = 20;
int delay_matrix_temp = 2000;
int blinky_dot = 2;

Adafruit_7segment matrix = Adafruit_7segment();

byte decToBcd(byte val){ return ((val/10*16) + (val%10)); }
byte bcdToDec(byte val){ return ((val/16*10) + (val%16)); }

void setup() {
  Serial.begin(9600);
  Wire.begin();
  matrix.begin(0x70);
}

void loop() {
  lightBrightness();
  matrixBlinkrate();
  displayTime();
  displayTemp();
}

void lightBrightness() {
  ldr_value = analogRead(ldr_sensor);
  Serial.print("LDR: ");
  Serial.println(ldr_value);
  if (ldr_value <= threshold_brightness) {
    brightness_matrix = 0; // 밝은 낮
  } else {
    brightness_matrix = 15; // 어두운 밤
  }
}

void matrixBlinkrate() {
  matrix.blinkRate(blinkrate_value);
}

void displayTime(){
  matrix.setBrightness(brightness_matrix);
  matrix.clear();
  for (uint16_t i = 0; i < delay_matrix_time; i++) {
    byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
    getDateDs3231(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
    byte se = second, mi = minute, ho = hour, we = dayOfWeek, dm = dayOfMonth, mo = month, ye = year;

    // 서머타임 전환 - 3월 마지막 일요일 오전 2시
    if ((dayOfWeek == 1) && (dayOfMonth >= 25) && (month == 3) && (hour == 2)) {
      setDS3231time(se, mi, 3, we, dm, mo, ye); // 3시로 설정
    }
    // 겨울시간 전환
    if ((dayOfWeek == 1) && (dayOfMonth >= 25) && (month == 10) && (hour == 1) && (year != 1)) {
      setDS3231time(se, mi, ho, we, dm, mo, 1); // year를 서머타임 표시용으로 사용
    }
    if ((dayOfWeek == 1) && (dayOfMonth >= 25) && (month == 10) && (hour == 3) && (year == 1)) {
      setDS3231time(se, mi, 2, we, dm, mo, 0); // 2시로 설정, year 플래그 0
    }

    // 위치 2의 비트 매핑:
    // 0x02 - 중앙 콜론 (두 점)
    // 0x04 - 왼쪽 콜론 아래 점
    // 0x08 - 왼쪽 콜론 위 점
    // 0x10 - 소수점

    // 시간 형식: _0:mm
    if (hour > 9) {
      matrix.writeDigitNum(0, (hour / 10), false);
      matrix.writeDigitNum(1, (hour % 10), false);
    } else {
      matrix.writeDigitNum(1, hour, false);
    }

    // 초에 따라 왼쪽 점 깜빡임
    if (se <= 30) {
      blinky_dot = 10; // 아래쪽 점 + 중앙 콜론
    } else if (se > 30) {
      blinky_dot = 6;  // 위쪽 점 + 중앙 콜론
    }
    matrix.writeDigitRaw(2, blinky_dot);
    matrix.writeDigitNum(3, (minute / 10), false);
    matrix.writeDigitNum(4, (minute % 10), false);
    matrix.writeDisplay();

    // 반초마다 콜론 깜빡임
    delay(500);
    matrix.drawColon(false);
    matrix.writeDisplay();
    delay(500);
  }
}

void displayTemp(){
  matrix.setBrightness(brightness_matrix);
  matrix.clear();
  byte temp = get3231Temp();
  int abs_temp = abs(temp);
  matrix.writeDigitNum(1, (abs_temp % 10), false);
  if (temp < 0) matrix.writeDigitRaw(0, 64); // 마이너스 부호
  if (temp <= -10) matrix.writeDigitRaw(2, 12);
  if (temp >= 10) matrix.writeDigitNum(0, (abs_temp/10), false);
  if (temp <= -10) matrix.writeDigitNum(0, (abs_temp/10), false);
  matrix.writeDigitRaw(3, 99); // "°"
  matrix.writeDigitRaw(4, 57); // "C"
  matrix.writeDisplay();
  Serial.print("Temperatur in C: ");
  Serial.println(get3231Temp());
  delay(delay_matrix_temp);
}

void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year){
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void getDateDs3231(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) {
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

float get3231Temp(){
  byte tMSB, tLSB;
  float temp3231;
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
  if (Wire.available()) {
    tMSB = Wire.read();
    tLSB = Wire.read();
    temp3231 = (tMSB & B01111111);
    temp3231 += ((tLSB >> 6) * 0.25);
    return temp3231;
  } else {
    Serial.println("DS3231 Sensor Error - cant read temperature");
    matrix.print(0xBEEF, HEX);
    matrix.writeDisplay();
    delay(5000);
  }
}
MyClock v1.1 (C/C++) - 서머타임/겨울시간 버그 수정

v1.0에서 v1.1로 변경: displayTime() 함수 내 일요일 판별 조건을 dayOfWeek == 7에서 dayOfWeek == 1로 수정 (DS3231에서 일요일=1)

전체 코드는 v1.0과 동일하며 위 조건만 변경되었습니다.

GitHub

https://github.com/ILohs/MySketches

회로도

LDR 경로 수정됨

제조공정

  1. 아두이노 POV 클락: 퍼시스턴스 오브 비전 LED 디스플레이 제작
  2. 아두이노로 만드는 레트로 누미트론 클락: 심플하고 신뢰성 높으며 에너지 효율적
  3. 아다프루트 60-LED 네오픽셀 링 4개로 스타일리시 벽시계 만들기
  4. 아두이노 실시간 시계로 이슬람 기도 시간 알림 장치 만들기
  5. 아두이노로 만드는 대형 LED 마스터 시계 (알람 기능 포함, 12m 거리에서도 식별 가능)
  6. 아두이노 듀(Due) + 3.2″ TFT로 만드는 실시간 시계 & 온도 모니터
  7. 아두이노 나노와 조이스틱으로 2개 스테퍼 모터 제어하기 – 비주이노(Visuino) 튜토리얼
  8. DIY 아두이노 스마트워치 - 애플 워치 스타일 직접 제작
  9. 아두이노 프로 미니 & DS1302 RTC로 정밀 7세그먼트 시계 만들기
  10. DS1302 RTC와 아두이노 우노로 만드는 신뢰할 수 있는 알람 시계