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

정확한 시간 유지: 아두이노 나노에서 GPS로 DS3231 RTC 동기화하기

부품 및 소모품

부품수량비고
아두이노 나노 R31
DS3231 클록 모듈1
NEO 6M GPS 모듈1
양방향 레벨 시프터1GPS 3.3V ↔ 아두이노 5V 변환용
LCD 16x2 디스플레이1
I2C LCD 백팩1
15핀 0.1인치 소켓2
6핀 0.1인치 소켓2
4핀 0.1인치 소켓1
5핀 0.1인치 소켓1
4핀 0.1인치 핀 스트립1
스트립보드 24스트립 x 37컬럼1
4.7kΩ 저항2I2C 풀업용
푸시버튼 (단극 모멘터리 6mm)1시간 설정용

프로젝트 소개

제 DS3231 RTC가 시간이 틀어지는 현상이 있었습니다. 평소처럼 컴파일 시 시스템 시간으로 업데이트하려 했지만, 컴퓨터의 다른 프로세스 때문에 컴파일/업로드가 중단되어 부정확했습니다.

GPS가 정확한 UTC 시간과 날짜를 제공한다는 것을 알고 이를 이용해 DS3231을 설정하기로 했습니다.

회로 연결

LCD 백팩 → 아두이노

DS3231 클록 모듈 → 아두이노

레벨 시프터 → 아두이노

NEO 6M GPS → 레벨 시프터

스위치 접점

전원

USB 케이블로 회로에 전원을 공급합니다.

소프트웨어

소프트웨어의 99%는 Adafruit GPS 라이브러리의 parsing.ino 예제입니다. 여기에 GPS에서 추출한 날짜/시간을 DS3231에 전달하는 코드와 DS3231의 시간을 LCD에 표시하는 코드를 약간 추가했습니다.

사용 라이브러리

작동 방법

  1. 장치 전원 켜기
  2. LCD에 DS3231 레지스터에 저장된 현재 날짜/시간 표시
  3. GPS가 락(Lock)될 때까지 대기 (실내에서는 10분 이상 걸릴 수 있음)
  4. 버튼을 눌러 GPS 신호로 시간 설정
  5. LCD에 새로운 시간 표시

작동 시 주의사항

GPS 모듈 특이사항

구입한 보드는 단순히 "NEO 6M GPS"라고만 표기되어 있었고 핀 기능만 표시되어 있었습니다. 데이터시트를 보니 장치는 약 3V에서 동작한다고 하여 레벨 시프터를 사용했습니다. 그러나 자세히 보니 보드에 4A2D 칩이 납땜되어 있었는데, 인터넷 검색 결과 전압 레귤레이터로 보이나 통신 라인까지 레벨 시프팅되는지는 보장할 수 없습니다(회로도 미제공).

또한 GPS 모듈마다 실내 수신 능력이 다르다는 글을 보고 LCD를 추가해 야외에서도 테스트할 수 있게 했습니다.

LCD 특이사항

사용한 I2C LCD의 주소가 0x3F입니다(대부분은 0x27). 화면에 아무것도 안 나오면 주소를 먼저 바꿔보세요.

라이브러리 특이사항

RTCLib(Adafruit v1.2.0)은 DS3231의 요일(Day) 레지스터를 설정하지 않고 날짜/시간 레지스터만 설정합니다. 요일은 날짜 레지스터 값을 이용해 공식으로 실시간 계산합니다. 처음에는 이상하게 여겼지만, 윤년 처리를 코드에서 따로 하지 않아도 되므로 합리적입니다.

UTC와 로컬 타임

UTC 검색 결과 제 로컬 타임은 변경이 필요 없었습니다. 필요하면 직접 코드를 추가하세요.

참고 자료

[1] https://www.u-blox.com/sites/default/files/products/documents/NEO-6_DataSheet_(GPS.G6-HW-09005).pdf (2018/12 검색)

코드

DS3231 설정 코드 (아두이노)

// DS3231 RTC와 I2C 연결, Wire 라이브러리 사용한 날짜/시간 기능
#include <Wire.h>
#include "RTClib.h" // Adafruit v1.2.0
RTC_DS3231 RTC;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const int days_string_length = 12;

// LCD 디스플레이용
#include <LiquidCrystal_I2C.h>
// 주소 0x3F (대부분 0x27, 안 나오면 변경)
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// 버튼
#define button 9

// Adafruit GPS 라이브러리 테스트 코드 (MTK3329/MTK3339 드라이버)
// 인터럽트 방식으로 GPS 데이터 수신하여 파싱
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

// 소프트웨어 시리얼 사용 시: GPS TX -> D3, GPS RX -> D2
SoftwareSerial mySerial(3, 2);
// 하드웨어 시리얼 사용 시(메가 등): 위 줄 주석 처리하고 아래 활성화
// HardwareSerial mySerial = Serial1;

Adafruit_GPS GPS(&mySerial);
#define GPSECHO false // 디버그용 GPS 데이터 에코 끄기
boolean usingInterrupt = false;
void useInterrupt(boolean);

void setup() {
  Serial.begin(115200);
  Serial.println("Adafruit GPS library basic test!");
  GPS.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // RMC+GGA 출력
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);    // 1Hz 업데이트
  GPS.sendCommand(PGCMD_ANTENNA);               // 안테나 상태 요청
  useInterrupt(true);                           // 타이머0 인터럽트 사용
  delay(1000);
  mySerial.println(PMTK_Q_RELEASE);             // 펌웨어 버전 요청

  lcd.begin(16, 2);
  lcd.backlight();
  lcd.clear();
  pinMode(button, INPUT_PULLUP);
}

// 타이머0 인터럽트 (1ms마다 호출)
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  #ifdef UDR0
  if (GPSECHO && c) UDR0 = c;
  #endif
}

void useInterrupt(boolean v) {
  if (v) {
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

uint32_t timer = millis();

void loop() {
  if (!usingInterrupt) {
    char c = GPS.read();
    if (GPSECHO && c) Serial.print(c);
  }

  if (GPS.newNMEAreceived()) {
    if (!GPS.parse(GPS.lastNMEA())) return;
  }

  if (timer > millis()) timer = millis();
  static bool second_time_round = false;

  // 버튼 눌리면 GPS 시간으로 RTC 설정 (버튼은 내부 풀업으로 평소 HIGH)
  if (!digitalRead(button)) {
    // RTClib은 DS3231의 요일 레지스터를 명시 설정하지 않음
    // dayOfTheWeek()는 날짜 기반 공식으로 계산 (일요일=0)
    RTC.adjust(DateTime(GPS.year, GPS.month, GPS.day, GPS.hour, GPS.minute, GPS.seconds));
    lcd.clear();
    lcd.setCursor(2, 0);
    lcd.print("Pressed set");
    delay(5000);
    lcd.clear();
  }

  DateTime now = RTC.now();
  lcd.setCursor(4, 0);
  lcd.print(now.year(), DEC); lcd.print('/');
  lcd.print(now.month(), DEC); lcd.print('/');
  lcd.print(now.day(), DEC); lcd.print(' ');
  lcd.setCursor(4, 1);
  lcd.print(now.hour(), DEC); lcd.print(':');
  lcd.print(now.minute(), DEC); lcd.print(':');
  lcd.print(now.second(), DEC); lcd.print(" ");
}

회로도

정확한 시간 유지: 아두이노 나노에서 GPS로 DS3231 RTC 동기화하기
정확한 시간 유지: 아두이노 나노에서 GPS로 DS3231 RTC 동기화하기

제조공정

  1. 셋 스크루(Set Screw) 설명: 설계, 차이점, 응용
  2. 지속 가능한 유산 남기기: 더 나은 미래를 위한 진정성 있는 리더십
  3. SMRP, 유지보수·신뢰성 전문가를 위한 표준화 KPI 세트 발표
  4. Java 10 개발 환경 설정: 빌드, 컴파일, 실행
  5. 세트 스퀘어(Set Square) 완벽 가이드: 목적, 종류, 기술 제도 활용법
  6. 평면 연삭: 정밀도를 위한 전통적 기술
  7. 박스웨이 CNC 선반이 정밀도와 성능을 위한 최적의 선택인 이유
  8. 펀치 세트 완벽 가이드: 종류, 용도, 선택 기준
  9. 리니어 가이드 CNC 선반: 정밀도, 속도, 경량 생산의 최적화
  10. 정비사 공구 세트 선택 완벽 가이드: 필수 도구부터 전문가용 세트까지