본문 바로가기

개발자/Arduino

Arduino Nano 33 IoT 개발 가이드 4 - 내부 RTC와 Sleep Mode

반응형

 

Arduino Nano 33 IoT 개발 가이드 4 - 내부 RTC와 Sleep Mode(6장)

 

여기에서는 Arduino 33 IoT의 내부 RTC 모듈에 대해 실습하기로 한다. IoT 보드는 스케치 프로그램에서 RTC 라이브러리를 사용해 접근할 수 있도록 내장 RTC 모듈을 제공한다. RTC 모듈 레퍼런스 링크를 참고하기 바란다. 

 

전체 강의자료와 소스코드는 아래를 참고하십시요. 소스코드의 출처는 위의 책 마지막 페이지에 소개되어 있습니다.

 

Arduino Nano 33 IoT 개발 가이드 1 - 개발환경

Arduino Nano 33 IoT 개발 가이드 2 - 기본적인 예제 살펴보기

Arduino Nano 33 IoT 개발 가이드 3 - WiFi Network 실습

Arduino Nano 33 IoT 개발 가이드 4 - 내부 RTC와 Sleep Mode

Arduino Nano 33 IoT 개발 가이드 5 - Arduino Cloud

Arduino Nano 33 IoT 개발 가이드 6 - Accelerator and Gyroscope

Arduino Nano 33 IoT 개발 가이드 7 - Bluetooth Low Energy (BLE)

실습에 필요한 전체 소스코드 다운

 

우선 RTC 라이브러리를 포함하기 위해 메뉴에서 -> 스케치 -> 아리브러리 포함하기 ->라이브러리 관리를 실행한다. 아래 이미지를 참고한다.

 

메뉴에서 -> 스케치 -> 아리브러리 포함하기 ->라이브러리 관리

라이브러리 관리 화면에서 검색창에 rtc로 검색한다. 맨위에 RTCZero 라이브러리가 보이는데 설치한다. 아래 화면에 rtc 검색후 RTCZero 라이브러리가 보인다.

 

 

RTCZero 라이브러리에서 setTime()과 setDate 함수를 사용해서 시간을 설정할 수 있고, 아래의 함수를 이용해서 시간 정보를 가져올 수 있다. 아래 데모 소스코드를 입력한다. 

- getYear()
- getMonth()
- getDay()
- getHours()
- getMinutes()
- getSeconds()

 

RTCdemo.ino 로 파일을 저장하고 툴 -> 보드 설정에서 "Arduino NANO 33 IoT" 로 선택하고, 포트를 연결된 포트 설정 COM63 등으로 선택하고 컴파일 업로드 한다.

 

#include <RTCZero.h>

RTCZero rtc;

void setup() 
{
	while (!Serial);
	Serial.begin(9600);
	rtc.begin(); // initialize RTC
	Serial.println("RTC set time");
	// set the current time 8 August 2019 7:23 AM
	rtc.setDate(10, 8, 19);
	rtc.setTime(7, 23, 00);
	delay(1000);
	Serial.println("RTC Read time");
	Serial.println("-------------------");
}

void loop() 
{
	Serial.print("RTC, Time = ");
	print2digits(rtc.getMinutes());
	Serial.write(':');
	print2digits(rtc.getHours());
	Serial.write(':');
	print2digits(rtc.getSeconds());
	Serial.print(", Date (D/M/Y) = ");
	Serial.print(rtc.getDay());
	Serial.write('/');
	Serial.print(rtc.getMonth());
	Serial.write('/');
	Serial.print(rtc.getYear());
	Serial.println();
	delay(1000);
}

void print2digits(int number) 
{
	if (number >= 0 && number < 10) 
    {
		Serial.write('0');
	}
	Serial.print(number);
}

 

시리얼 모니터를 실행하여 시간 데이터 출력을 확인한다. setup() 함수를 보면 시간 설정을 다음과 같은 코드로 한다. 데이터를 정확히 포맷에 맞춰 입력한다.

 

// set the current time 8 August 2019 7:23 AM
rtc.setDate(10, 8, 19);  ---> 5, 7, 20 
rtc.setTime(7, 23, 00);  ---> 11, 48, 00 으로 현재 시간을 바꾸어 설정하여 실습하기 바란다.

 

RTCdemo 실행화면

 

Connecting to Network Time Protocol (NTP) Server

 

아주 중요한 실습이므로 꼭 알아두어야 한다. 특정 시스템의 시간을 바로 현재 시간으로 동기화 할 필요가 있다. 이러한 경우에 NTP 프로토콜을 사용한다.

 

"Network Time Protocol의 약자로 Network 상에 연결된 장비와 장비 간에 시간 정보를 동기화하기 위한 프로토콜을 말합니다. NTP는 계층적인 구조를 가지는데 각각의 계층은 상위 계층으로부터 시간을 동기화합니다. 한국에서 운영되고 있는 NTP 서버에서 정보를 동기화하여 다른 장비들에게 서비스할 수 있습니다. NTP Client세팅으로 상위 계층에서 시간 정보를 받아 동기화할 수 있고, NTP Server세팅을 통해 다른 장비들에게 정보를 보내줄 수 있습니다." 상세 내용은 위키백과 네크워크 타임 프로토콜을 참조.

 

여기서 NTP를 통해 time.nist.gov의 시간을 가져온다. 아두이노 프로그램 예제를 이용한다. 아래 이미지를 참고해 예제를 연다. 메뉴에서 파일 -> 예제 -> WiFiNINA -> WifiUdpNtpClient 예제를 불러온다.

 

여기서 중요한 점은 arduino_secrets.h 파일에 있는 네트워크의 SSID 와 패스워드를 바꿔주는 일이다. 불러온 예제 파일, 즉 WifiUdpNtpClient 예제를 "다른 이름으로 저장" 을 선택하여 폴더를 지정하여 저장해 주면 그 폴더 아래에 arduino_secrets.h 파일이 생성된다. 이 파일을 열어 보면 아래와 같다. 참고로 WiFiUdpNtpClient.ino 소스코드를 올려둔다.

 

/*

 Udp NTP Client

 Get the time from a Network Time Protocol (NTP) time server
 Demonstrates use of UDP sendPacket and ReceivePacket
 For more on NTP time servers and the messages needed to communicate with them,
 see http://en.wikipedia.org/wiki/Network_Time_Protocol

 created 4 Sep 2010
 by Michael Margolis
 modified 9 Apr 2012
 by Tom Igoe

 This code is in the public domain.

 */

#include <SPI.h>
#include <WiFiNINA.h>
#include <WiFiUdp.h>

int status = WL_IDLE_STATUS;
#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

unsigned int localPort = 2390;      // local port to listen for UDP packets

IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < "1.0.0") {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  Udp.begin(localPort);
}

void loop() {
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  // wait to see if a reply is available
  delay(1000);
  if (Udp.parsePacket()) {
    Serial.println("packet received");
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = ");
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    Serial.println(epoch);


    // print the hour, minute and second:
    Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
    Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)
    Serial.print(':');
    if (((epoch % 3600) / 60) < 10) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':');
    if ((epoch % 60) < 10) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch % 60); // print the second
  }
  // wait ten seconds before asking for the time again
  delay(10000);
}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) {
  //Serial.println("1");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  //Serial.println("2");
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  //Serial.println("3");

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  //Serial.println("4");
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  //Serial.println("5");
  Udp.endPacket();
  //Serial.println("6");
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

 

arduino_secrets.h 파일을 열어 "" 안에 무선 WiFi의 SSID와 password를 알맞게 넣어준다.

 

#define SECRET_SSID ""
#define SECRET_PASS ""

 

실행하면 결과는 아래 화면과 같다. 각 메시지와 시간을 확인한다. 시간이 3:42:33초 이렇게 나오는데 이것은 그리니치 천문대 세계 표준 시간이므로 해당하는 나라의 지역 시간으로 바꾸어야 한다. 한국은 9시간을 더하면 12:43분으로 정확하게 맞는다. 확인했다. 와우! 참고로 리눅스 타임은 시작될 때부터 1초씩 시간을 잰 횟수를 말한다. 그래서 정확히 표준시로 이용하게 되었다. 

 

NTP 서버 시간 동기화 결과 화면

 

우리는 Arduino Nano 33 IoT 를 RTCZero 라이브러리의 함수 stanbyMode()를 사용해서 sleep mode 로 설정할 수 있다. 보드를 깨우기 위해 setAlarmTime() 을 설정한다. callback function and enableAlarm() 함수를 이용해 실행을 하도록 한다.

 

실습을 위해 setup() 함수에서 sleep mode로 실행하는 간단한 프로그램을 만든다. 보드가 깨어나면 loop() 를 실행한다. 아래 코드를 입력한다.

 

RTCAlarm.ino 파일

 

#include <RTCZero.h>
int led = 13;
RTCZero rtc;
void setup() {
while (!Serial);
Serial.begin(9600);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
rtc.begin(); // initialize RTC
Serial.println("RTC set time");
// set the current time 11 August 2019 7:23 AM
// 2020년 5월 7일 12시 53분이니까
rtc.setDate(7, 5, 20);
rtc.setTime(12, 54, 00);
delay(1000);
Serial.println("RTC Read time");
Serial.println("-------------------");
Serial.println("set standby");
rtc.setAlarmTime(12, 55, 00);
rtc.enableAlarm(rtc.MATCH_HHMMSS);
rtc.attachInterrupt(wakeup);
rtc.standbyMode();
}
void loop() 
{
// this program will be executed
// after program wakes up
Serial.println(">> do something");
delay(800);
}
void wakeup()
{
Serial.println("Wake up...");
digitalWrite(led, HIGH);
}

아래는 결과 화면이다. 설정은 잘 되고 1분 후에 정확히 13번 핀의 내장 LED 가 불이 켜지며 실행하는 것으로 확인은 되지만 loop 함수를 실행하는 메세지가 표시가 안되었다. 통신 모드가 sleep 으로 영향을 받는지도 모른다. 여하는 다른 결과를 확인하신 분은 답글 부탁드린다.

 

NTP 알람 실습 결과

 

여기까지 하고 놀러나가야지. ^^

 

초한지 천하대전. 유방은 항우의 여인 우미인이 잃어버린 비파를 찾아준다.

 

 

 

 

반응형

캐어랩 고객 지원

취업, 창업의 막막함, 외주 관리, 제품 부재!

당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약, 아이디어는 있지만 구현할 기술이 없는 막막함.

우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.

이제 고민을 멈추고, 캐어랩을 만나세요!

코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.

제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!

귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.

지난 30년 여정, 캐어랩이 얻은 모든 것을 함께 나누고 싶습니다.

카카오 채널 추가하기

카톡 채팅방에서 무엇이든 물어보세요

당신의 성공을 위해 캐어랩과 함께 하세요.

캐어랩 온라인 채널 바로가기

캐어랩