hiro yamamoto works

マイコンハード、ソフトを作ったりしています。
お家や現場のお困りごと解決に!
内容利用は自己責任でお願いします。

NTPで取得した時刻をRTCへセットする(ESP編2)

2020-08-24 08:58:00 | マイコンハードウェア
「NTPで取得した時刻をRTCへセットする」の続編2です。

こちらもどうぞ
NTPで取得した時刻をRTCへセットする(ESP32)

NTPとRTCを組み合わせる方法を考えてみました。
NTPから時刻を取得し、取得出来た時のみRTCを
合わせます。
(スケッチ例や作例を公開している方々に感謝します。)

今回は
ESPr One(ESP-WROOM-02)とDS3231 I2C RTCモジュール
を使って、スケッチ例NTPCilentを改変してやって
みました。
NTPで取得した時刻をRTCへセットするESP編

スケッチを紹介します。
※変更のないところは省略していますので、オリジナルの
スケッチ例からコピペして下さい。わかりやすくするため、
変更がなくても表示している所もあります。
include行は < から < へ修正して下さい。

#include <ESP8266WiFi.h>//< を < に直して下さい
#include <WiFiUdp.h>
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include "RTClib.h"
#define UTC_TOKYO +9

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif

const char * ssid = STASSID; // your network SSID (name)
const char * pass = STAPSK; // your network password

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

/* Don't hardwire the IP address or we won't get the benefits of the pool.
Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";

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

unsigned long unixtime;//
char date_ymdhms[21]; // yyyy/mm/dd,hh:mm:ssn0
unsigned long previousMillis = 0;//
const long interval = 60000;//600000 :10分 3600000 :1h
int ntpAccsCount = 0;//NTP accsess count
int accsInterval = 60;//NTP accsess interval

// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;
RTC_DS3231 rtc;

void setup() {
//変更のないところ中略
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, lets set the time!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
}

void loop() {
//get a random server from the pool
WiFi.hostByName(ntpServerName, timeServerIP);

/* 起動初期はRTC時刻は合っていない。rtc.lostPower()の時はコンパイル時刻が設定されている。起動初期だけ早くNTP時刻を取得して、RTC時刻を合わせたい。通常動作時のNTPアクセス頻度は1日あたり3回(RTCの日差を補正できる妥当な回数を設定)
intervalを1分ぐらいにしておいて、繰返し回数をカウント、指定回数になったらNTPアクセス。起動時ntpAccsCountは0でNTPアクセス、アクセス後Udp.parsePacket()の戻り値がなかったら繰返し カウントを指定回数まで進めて、NTPアクセス頻度を上げる。*/
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (ntpAccsCount == 0) {

sendNTPpacket(timeServerIP); // send an NTP packet to a time server
// wait to see if a reply is available
delay(1000);

int cb = udp.parsePacket();
if ( cb ) {
//変更がないところ中略
// print Unix time:
//Serial.println(epoch);
unixtime = epoch;//追加箇所
//変更がないところ中略
time_t t = unixtime + (UTC_TOKYO * 60 * 60);//日本時間へ調整
// wait ten seconds before asking for the time again
//delay(10000);
//adjust RTC time
rtc.adjust(DateTime(year(t), month(t), day(t), hour(t), minute(t), second(t)));
Serial.println("adjust RTC time");
} else {
Serial.println("no packet yet");
ntpAccsCount = accsInterval;/*NTPアクセスできなかった時はカウント値を変えて
アクセスタイミングを早める。*/
}
}
ntpAccsCount++;//NTP accsess count
if (ntpAccsCount >= accsInterval) {//accsess interval
ntpAccsCount = 0;
}
}
delay(1000);
DateTime now = rtc.now();//RTCの現在時刻を読む
sprintf(date_ymdhms, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());//
Serial.println(date_ymdhms);//
}

//以降変更がないので省略

無保証自己責任でよろしくおねがいします。
ESPr-One、I2C RTC DS3231 NTP to RTC

NTPで取得した時刻をRTCへセットする(Arduino編)

2020-08-23 06:23:00 | マイコンハードウェア
「NTPで取得した時刻をRTCへセットする」の続編です。

こちらもどうぞ
NTPで取得した時刻をRTCへセットする(ESP32)

NTPとRTCを組み合わせる方法を考えてみました。
NTPから時刻を取得し、取得出来た時のみRTCを
合わせます。
(スケッチ例や作例を公開している方々に感謝します。)

続編の記事を投稿しました。
ESPr One(ESP-WROOM-02)とDS3231 I2C RTCモジュール
を使って、スケッチ例NTPCilentを改変してやって
みました。
NTPで取得した時刻を・・・(ESP編2)

今回は
Arduion UNOとEthernet shield、DS3231 I2C RTCモジュール
を使って、スケッチ例Ethernet2 UdpNtpCilentを改変して
やってみました。
NTPで取得した時刻をRTCへセットするArduino編

スケッチを紹介します。
※変更のないところは省略していますので、オリジナルの
スケッチ例からコピペして下さい。わかりやすくするため、
変更がなくても表示している所もあります。
include行は < から < へ修正して下さい。

/* Arduino UNO ,Ethernet shield ,ds3231 I2C RTC
* スケッチ例Ethernet2 Udp NTP Clientにds3231 RTCを追加して、RTCを
* adjustする機能を追加して取得できた時はNTP時刻でRTCをadjustする。
* 取得できなかった時は取得できるまでアクセス間隔を短く変更する。
* 日本時間に直して、シリアルモニタへ表示する。
* 改変 hiro yamamoto works 2020.08.21*/

#include <SPI.h>//include行のすべての「<」を「<」へ修正して下さい。
#include <Ethernet2.h>
#include <EthernetUdp2.h>
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include "RTClib.h"
#define UTC_TOKYO +9
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
unsigned int localPort = 8888; // local port to listen for UDP packets
char timeServer[] = "time.nist.gov"; // 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
unsigned long unixtime;//
char date_ymdhms[21]; // yyyy/mm/dd,hh:mm:ssn0
unsigned long previousMillis = 0;//
const long interval = 60000;//60000 :1分 3600000 :1h
int ntpAccsCount = 0;//NTP accsess count
int accsInterval = 60;//NTP accsess interval 1分を60回なので60分
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
RTC_DS3231 rtc;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
/*while (!Serial) {//Leonardoなら/**/取ってcodeを有効にして下さい。
; // wait for serial port to connect. Needed for Leonardo only
}*/
// start Ethernet and UDP
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore:
for (;;)
;
}
//Serial.println(Ethernet.localIP());
Udp.begin(localPort);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, lets set the time!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
}
void loop() {
/* 起動初期はRTC時刻は合っていない。rtc.lostPower()の時は
コンパイル時刻が設定されている。
起動初期だけ早くNTP時刻を取得して、RTC時刻を合わせたい。
通常動作時のNTPアクセス頻度は1日あたり数回(RTCの日差を補正できる
妥当な回数を設定)intervalを1分ぐらいにしておいて、繰返し回数を
カウント、指定回数になったらNTPアクセス。起動時ntpAccsCountは
0でNTPアクセス、アクセス後Udp.parsePacket()の戻り値がなかったら
繰返しカウントを指定回数まで進めて、NTPアクセス頻度を上げる。*/
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (ntpAccsCount == 0) {
//変更がないところ中略

time_t t = unixtime + (UTC_TOKYO * 60 * 60);//日本時間へ調整
// wait ten seconds before asking for the time again
//delay(10000);
//adjust RTC time
rtc.adjust(DateTime(year(t), month(t), day(t), hour(t), minute(t), second(t)));
Serial.println("adjust RTC time");
} else {
Serial.println("no packet yet");
ntpAccsCount = accsInterval;/*NTPアクセスできなかった時はカウント値を変えて
アクセスタイミングを早める。*/
}
}
ntpAccsCount++;//NTP accsess count
if (ntpAccsCount >= accsInterval) {//accsess interval
ntpAccsCount = 0;
}
}
delay(1000);
DateTime now = rtc.now();//RTCの現在時刻を読む
sprintf(date_ymdhms, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());//
Serial.println(date_ymdhms);//

}
//以降変更がないので省略


無保証自己責任でよろしくおねがいします。

Arduinoで簡単なWebserverやってみた

2020-08-17 06:05:00 | マイコンハードウェア
プログラム学習と実験をしてみました。

SDWebServerスケッチの機能を目標に挑戦しましたが、
達成ならず、データ保存をあきらめ、web表示だけとしました。

概要
スケッチ例WebserverとUdpNTPClientを組み合わせる。
timeライブラリ追加、日本時間表示

機能
SDからIP Address設定を読み込んで固定IP Addressで
ネットワーク接続する。
webアクセスがあるとNTP時刻を取得し、アナログ入力
0~5を読み込みと電圧値(mV表示)変換、時刻と一緒に
webページに表示する。

Arduino用のブレッドボードは秋月電子さんで入手できます。
ArduinoUNO,EthernetShiled,ブレッドボード

Arduino UNOをセット
ブレッドボードにArduinoUNOをセット

Etherenet Shiledをセット
ArduinoUNOにEthernetShiledを挿す

USB、LANケーブルを接続、SDをセット
USB,LANケーブル,SDをセット

Webページの表示
ブラウザで表示されたArduinoWebServerのページ
表示される時刻とアナログ入力測定タイミングは数秒(?)
ずれます。(測定タイミングが遅い)

スケッチは改変部分を公開します。
サンプルスケッチUdpNTPClientをベースに編集します。
codeの変更点を投稿しておきますので参考にして下さい。
誤記はご容赦願います。サンプルスケッチの公開者に感謝します。

int ip[4];
#include <SPI.h>
#include <SD.h>
#include <Ethernet2.h>
#include <EthernetUdp2.h>
#include <Time.h>
#include <TimeLib.h>
#define UTC_TOKYO +9

中略
EthernetUDP Udp;の次行から
unsigned long unixtime;
const int chipSelect = 4;
char date_ymdhms[21]; // yyyy/mm/dd,hh:mm:ssn0
EthernetServer server(80);

中略
// start Ethernet and UDPの前に挿入
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
File dataFile = SD.open("setup/setup.txt", FILE_READ);
if (dataFile) {
while (dataFile.available()) {//dataFileを1行づつ評価していく
String line = dataFile.readStringUntil('\n');//終端文字'\n'が検出されるまで読んで文字列全体をlineへ入れる
//Serial.println(line);
line = line.substring(0, line.indexOf('#'));//インデックス0(行頭)から(#までのインデックス数)の文字列取得
if (line.substring(0, 2) == "ip") {
String ip0 = line.substring(3, 6);
String ip1 = line.substring(7, 10);
String ip2 = line.substring(11, 14);
String ip3 = line.substring(15, 18);
ip[0] = ip0.toInt(); ip[1] = ip1.toInt(); ip[2] = ip2.toInt(); ip[3] = ip3.toInt();
}
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening setup.txt");
}

中略
// start Ethernet and UDPの次行に追加
byte ip_ad[4] = {ip[0], ip[1], ip[2], ip[3]};
Ethernet.begin(mac, ip_ad); //
server.begin();
次行から6行は/*と*/でコメント行に変更、もしくは削除
/*if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore:
for (;;)
;
}*/
Serial.println(Ethernet.localIP());

中略
void loop() { の次行に挿入
// listen for incoming clients (WebServer sketch)着信クライアントをリッスンします
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line HTTPリクエストが空白行で終了する
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line(received a newline character)and the line is blank,the http request has ended,so you can send a reply
//行の終わりに達し(改行文字を受信)その行が空白の場合httpリクエストは終了しているため返信を送信できます
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header標準のhttp応答ヘッダーを送信する
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
//応答の完了後に接続が閉じられます
//client.println("Refresh: 20"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
中略
// wait to see if a reply is available
delay(3000);//デフォルト1000を3000(3秒)に変更してみる

中略
unsigned long secsSince1900 = highWord << 16 | lowWord;の次行に2行入れる
client.println("this is NTP time");
client.println("<br />");

中略
Serial.println(epoch);//の次行に2行入れる
unixtime = epoch;
time_t t = unixtime + (UTC_TOKYO * 60 * 60);

中略
Serial.print("The UTC time is ");// UTC is the time at Greenwich Meridian (GMT)の次行に+9を追加
Serial.print((epoch % 86400L) / 3600 + 9); // print the hour (86400 equals secs per day)

中略
Serial.println(epoch % 60); // print the secondの次行に挿入
sprintf(date_ymdhms, "%04d/%02d/%02d,%02d:%02d:%02d", year(t), month(t), day(t),hour(t), minute(t), second(t));
Serial.println(date_ymdhms);
client.print(date_ymdhms);
client.println("<br />");
}
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = map(analogRead(analogChannel), 0, 1023, 0, 5000);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.print(" mV");
client.println("<br />");
}
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
//delay(10000);//この行はコメント化します。</code>
SDに保存するファイル名はsetupフォルダ内のsetup.txtです。

setup.txtのサンプルです。
#setup.txt#以降はコメントとして扱われます。
# ip address
ip 172, 16, 40,115 #ip address
#
#end