eepoo が 2021年02月21日09時31分06秒 に編集
初版
タイトルの変更
GPSのPPSを利用したRTCの精度測定器
タグの変更
秋葉原2021
GPS
PPS
RTC
本文の変更
DS3231を使ったRTCが安く出回っている。データシートによると2ppmを詠っているので一日0.2秒弱の誤差のはずだが結構当たりはずれがある。最初は選別するために電波時計と目視比較でチェックしていたが、0.2秒程度の解像度(笑)しか期待できない上に、電波時計も校正直後以外は案外ずれていることが分かった。 なんたって精度ならGPSでしょう。ということで手持ちのGPSが流してくれるシリアルデータを解析。特定のタグを毎秒流すのでそれを利用した。ところが短期間は安定しているものの、数時間でごそっとシフトすることが分かった。理由はわからないが、、 次に117の音声信号をマイクで拾ってLow Pass Filterをかけて信号の立ち上がりを比較するようにした。悪くないんだけど、117が案外お金がかかる。 ネット上のJJY的な信号を流しているところや原子時計アプリも使ってみたが、ちゃんとモニターしてみると信号が安定していない。 本家JJYを受信しようとキットも買ったが家の中では電波が弱くて、、 聞けばGPSは一秒ごとのパルスを出してくれるはずというではないか。 いや、私のGPSにはそんな端子がないんですけど、、ん、でもLEDにPPSって書いてあるぞ。 だめもとで高度な半田テクニック(笑)を用いて信号線を引き出した。(画像黄色のリード線) ![キャプションを入力できます](https://camo.elchika.com/cd28580a7810178a897fda33d3375be77541f321/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f66303131363439382d656138642d346438632d613438332d626339653061663262343265/) モニターしてみるときれいなパルスが出ている、、が電圧が低いのでトランジスタでしゃっきりさせてarduino nanoの割込みポートへ。一方のRTCからもSQWという端子からPPSが出ているのでそちらも割込みへ。双方の割込み時の micros() を比較し、差を7セグ表示機(TM1637)に表示。一度に2つチェックできるようにnanoを二つ並べGPS信号は共用した。 ![キャプションを入力できます](https://camo.elchika.com/4c8f429ac74f45910ce038ea2468c2fe2ac54162/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f32626638313437322d303335302d346134652d616232612d613532633461383437376436/) ![キャプションを入力できます](https://camo.elchika.com/63caead513c0eab9283c9d77a06170402e5df4cd/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34383434643937372d666533372d343734362d613535612d6566383862393438646166612f31646435653136622d303938352d346339312d626432662d666335316163643064306331/) これで適当な時間にチェックして表示の差を時間で割れば、一日当たりの精度を求めることができる。 ```GPSとRTCのトリガ差で精度チェック #include <DS3231.h> #include <Wire.h> #include <TM1637Display.h> #define CLK 6 #define DIO 5 TM1637Display display(CLK, DIO); volatile unsigned long cpuClock = 0; //GPSトリガー毎のcpuClock数をバッファする volatile unsigned long lastGPS = 0; //GPSトリガー毎のcpuClock数を算出するため volatile bool sqrInt = false; volatile bool d3Int = false; volatile unsigned long lastDS = 0; volatile unsigned long lastDelta = 0; DS3231 Clock; //DS3231からの一秒ごとの割込み void sqrSecIntHandler() { lastDS = micros(); } //GPSからのPPS D3に繋いだ void d3Out() { d3Int = true; unsigned long curr = micros(); cpuClock = curr - lastGPS; lastGPS = curr; lastDelta = micros() - lastDS; } void setup() { Serial.begin(115200); Wire.begin(); display.setBrightness(0x0f); display.showNumberDec(0, false); pinMode(2, INPUT);//DS3231からのオシレート Clock.enableOscillator(true, true, 0); attachInterrupt(0, sqrSecIntHandler, FALLING); pinMode(3, INPUT_PULLUP); attachInterrupt(1, d3Out, FALLING); } void loop() { //GPSのオシレート if (d3Int) { d3Int = false; //cpuの温度ドリフトによるクロック数変化をキャンセルする float delta = (float)lastDelta * 1000000.0 / (float)cpuClock; lastDelta = delta; display.showNumberDec(lastDelta / 100, false); } } ```