工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduinoを使用するだけの正確な時計

コンポーネントと消耗品

>
Arduino Nano R3
Nanoを使用しましたが、どのArduinoでも動作するはずです
× 1
英数字LCD、16 x 2
どのディスプレイでも機能するはずです。私はこれを使用しましたhttps://www.amazon.co.uk/ gp / product / B00N8K2BYM / ref =ppx_yo_dt_b_asin_title_o02_s00?ie =UTF8&psc =1
× 1
触覚スイッチ、上部作動
× 3
トリマポテンショメータ、10キロオーム
10kトリマーならどれでも可能です
× 1
ジャンパー線
× 1

このプロジェクトについて

私はこれを学術的な演習として始めましたが、非常に正確な時計になりました。 5日間実行した後、それはいつでも失ったり、増えたりしていませんでした。

Arduinoだけを使用する場合の主な問題は、内部クロック速度が100%正確ではないことです。したがって、これだけに頼ると、経過したミリ秒のカウントがわずかな割合でなくなり、作成している時計が緩むか、時間が増えます。私のアプローチは、使用していたArduinoの精度をテストし、1時間あたりのミリ秒数の損失または増加を判断することでした。次に必要だったのは、速度調整をプログラムして、1時間ごとに内部で追跡されるミリ秒からこの差を追加または差し引くことだけでした。

私の他の懸念は、Arduinoの時計が一貫して不正確であるかどうかでしたが、示されているように、私がプログラムした時計は5日間にわたって非常に正確な時刻を維持しているため、不正確さは一貫しているようです。

2番目の問題は、内部のmillis()関数が約50日ごとにリセットされ、ミリ秒カウントを操作できないことです。したがって、答えは、私が操作でき、真夜中からのミリ秒をカウントするカウンターを使用して、millis()割り込みを置き換えることでした。毎日リセットして、実行時間の制限を取り除きます。

不正確さの評価

不正確さを評価するために、私は自分のコンピュータークロック、つまり処理中のmillis()が正確であると仮定しました。したがって、Arduinoがハンドシェイクから経過したミリ秒数を2秒に1回Processingに送信するプログラムと、Processingがこれを読み取り、経過したミリ秒と比較してリアルタイムの結果と1時間後の差を表示するスクリプトを作成しました。経過。これにより、1時間に失われた、または得られたミリ秒数が得られたため、時計プログラムの速度調整に使用する値が得られました。

Arduinoプログラムのコードと処理スクリプトを以下に示します。

Processingをインストールしていない場合は、https://processing.orgにアクセスして、ダウンロードして学習してください。

時計コード

クロックコードで重要な主な領域は、割り込みの設定、これがどのように使用されるか、および日付が保持および操作される方法です。

割り込み

次のコードは、ミリ秒ごとにトリガーされる割り込みを設定します。これにより、millis()を維持するために使用される割り込みが迂回されるため、millis()とdelay()は機能しなくなります。

  //時間割り込みを設定します-millis()は50日後にロールオーバーするため、//毎日の終わりにリセットできる独自のミリ秒カウンターを使用しています// CTCモードを設定します比較時間とトリガー割り込みTCCR0A =(1 < 

これは毎秒呼び出されるコードです:

  //これは、比較時間に達したときに呼び出される割り込みです//したがって、// OCR0Aレジスタ設定に基づいて1ミリ秒に1回呼び出されます。ISR(TIMER0_COMPA_vect){if(currentMode!=SET_TIME) currentTime ++;経過++;}  

currentTimeと経過はunsignedlong変数です。メインコードの変数も操作しているため、これらは定義時に揮発性として修飾されることに注意してください。これにより、システムは変数が使用されるたびに変数を読み取り、キャッシュされた値は使用しなくなります。

currentTimeは、真夜中からのミリ秒数を格納します。これをHH:MM:SSに変換し、時刻を設定するとリセットするルーチンがあります。

24時間が経過すると、システムは時刻から1日のミリ秒数を差し引き、日付を1日増やします。したがって、millis()とは異なり、クロックは変数が格納できる最大値の影響を受けません。

  // 1日の終わりにリセット時刻を設定し、日付を増やすif((currentMode ==SHOW_TIME)&&(currentTime> mmolsInADay)){//翌日//リセット時刻中に割り込みを停止noInterrupts(); currentTime- =mmolsInADay;割り込み(); currentDate ++; }  

currentTime変数を操作している間は割り込みを無効にすることに注意してください。そうしないと、計算の途中で割り込み呼び出しがトリガーされ、計算が破損しているmsilliamsInADayが差し引かれる可能性があります。

1時間ごとに、システムは先に計算した速度調整によって経過したミリ秒数を調整し、現在の時刻を調整して、高速または低速の内部時計を補正します。

  //各時間の終わりに、// Arduinoクロックの不正確さの経過時間を調整しますif(elapsed> =millisInHour){noInterrupts(); //低速/高速で動作するArduinoクロックの時間を調整しますcurrentTime + =speedCorrection; //リセットして次の経過時間をカウントします=0;割り込み(); }  

日付の保存と計算

日付は、紀元前4713年1月1日月曜日から経過した日数であるユリウス日として保持されます。ユリウス日を計算し、それをグレゴリオ暦に戻すためのルーチンが含まれています。

  float JulianDate(int iday、int imonth、int iyear){//ユリウス日を計算します(20、000年までテスト済み)unsigned long d =iday; unsigned long m =imonth; unsigned long y =iyear; if(m <3){m =m + 12; y =y-1; } unsigned long t1 =(153 * m --457)/ 5; unsigned long t2 =365 * y +(y / 4)-(y / 100)+(y / 400); return 1721118.5 + d + t1 + t2;} void GregorianDate(float jd、int&iday、int&imonth、int&iyear){//注2100は次のスキップされたうるう年です-スキップされたうるう年を補正しますunsigned long f =jd + 68569.5; unsigned long e =(4.0 * f)/ 146097; unsigned long g =f-(146097 * e + 3)/ 4; unsigned long h =4000ul *(g + 1)/ 1461001; unsigned long t =g-(1461 * h / 4)+ 31; unsigned long u =(80ul * t)/ 2447; unsigned long v =u / 11; iyear =100 *(e-49)+ h + v; imonth =u + 2-12 * v; iday =t-2447 * u / 80;}  

調整ボタン

[モード]ボタンは、現在のモードを[時刻の表示]から[時刻の設定]、[年の設定]、[日付の設定]、[速度調整の設定]に進め、[時刻の表示]に戻ります。これらはそれぞれ自明であり、他の2つのボタンを使用して現在の設定を調整します。

時計が作動しているときに、時刻が増減している場合は、速度調整の設定モードにアクセスし、上下ボタンを使用してこれを一度に5秒ずつ増減することにより、速度調整を変更できます。

>

コード

  • 時計プログラム
  • Arduinoタイマープログラム
  • タイマーテストスクリプトの処理
時計プログラム Arduino
Arduinoを使用しただけの日付の正確な時計
 // Paul Brace- 2021年2月// Arduinoを使用して作成された日付のシンプルな時計-RTCモジュールなし//プログラムには、内部//クロック速度を補正するための時間補正調整が組み込まれています100%正確ではありません。//正しい速度調整を設定すると、時計は驚くほど正確になります。//私のテストでは、5日間にわたって時間の増減はありませんでした。//16x2LCDディスプレイに時間を表示します//ボタン時刻を設定するには//モードボタン(ピン2)で時刻の設定、日付と実行の設定を切り替えます//ボタン1(ピン3)分と月をインクリメントし、年/速度の調整を減らします//ボタン2(ピン4)時と日をインクリメントし、年を増やします。/speedadj//24時間表示//表示用のライブラリドライバを含めます:#include  // LiquidCrystal lcd(RS、EN、D4、D5、D6、D7)LiquidCrystal lcd(12、13 、6、7、8、9); // lcdオブジェクトを作成し、ピンを割り当てます//ボタンとブザー接続を定義します#defineMODE_BUTTON 2#define HOUR_BUTTON 3 //同じボタンで異なる定義を#defineUP_BUTTON 3 //コードを理解しやすくします#defineDAY_BUTTON 3#define MINUTE_BUTTON 4 //同じボタンの異なる定義to#define DOWN_BUTTON 4 //コードを理解しやすくする#defineMONTH_BUTTON 4 //現在のモード設定#defineSHOW_TIME 1 // 1 =実行中-showtime#define SET_TIME 2 // 2 =時間設定#define SET_YEAR 3 // 3 =年セット#defineSET_DATE 4 // 4 =日/月セット#defineSET_SPEED_ADJ 5 // 5 =speedCorrection変数を修正intspeedCorrection =3545; //ナノクロックが1時間あたりに低速で動作するミリ秒数//高速で動作している場合はここで負の数// Arduinoに一致するように変更//割り込みで変更された揮発性変数および//システムに読み取りを強制する必要がある実際の変数//割り込みの外部で使用され、キャッシュされたversionvolatile unsigned longcurrentTimeを使用しない場合。 //真夜中からのミリ秒単位の期間unsignedlong lastTime =-1000; // ShowTimeが呼び出されたlastTimeは-1000に初期化されているため、すぐに揮発性のunsigned longlapsedが表示されます。 //遅延と時間カウントに使用されるタイマーunsignedlong mmolsInADay; // 24時間でミリ秒unsignedlong mmolsInHour; // 1時間でミリ秒intcurrentMode; // 1 =実行中-表示時間// 2 =時間設定// 3 =年設定// 4 =日/月setfloatcurrentDate; // Julian datefloat lastDate =0.0; // ShowDateが呼び出された最後の日付intcurrentDay; int currentMonth; int currentYear; char * dayArray [] ={"Tue。"、//コンパイラの警告を表示しますが、正常に動作します "Wed。"、 "Thur。"、 "Fri 。 "、" Sat. "、" Sun. "、" Mon. "}; void setup(){//時間割り込みを設定します-millis()は50日後にロールオーバーするため、//独自のミリ秒カウンターを使用しています。 //毎日の終わりにリセットできますTCCR0A =(1 < mmolsInADay)){//次へday //リセット時間中に割り込みを停止しますnoInterrupts(); currentTime- =mmolsInADay;割り込み(); currentDate ++; } //各時間の終わりに、// Arduinoクロックの不正確さの経過時間を調整しますif(elapsed> =millisInHour){noInterrupts(); //低速/高速で動作するArduinoクロックの時間を調整しますcurrentTime + =speedCorrection; //リセットして次の経過時間をカウントします=0;割り込み(); } //ボタンが押されているかどうかを確認しますCheckButtons(); //現在のモードスイッチに基づいて表示を表示します(currentMode){case SHOW_TIME://現在の時刻と日付を表示しますShowTime(currentTime); ShowDate(currentDate);壊す; case SET_TIME://時刻を設定するための画面を表示ShowTimeSet(currentTime);壊す; case SET_YEAR://年を設定するための画面を表示ShowYearSet(currentDate);壊す; case SET_DATE://日と月を設定するための画面を表示ShowDDMMSet(currentDate);壊す; case SET_SPEED_ADJ://速度補正を調整するための表示画面ShowSpeedSet();壊す; } Wait(150);} //これは、比較時間に達したときに呼び出される割り込みです//したがって、// OCR0Aレジスタ設定に基づいて1ミリ秒に1回呼び出されます。ISR(TIMER0_COMPA_vect){if(currentMode!=SET_TIME )currentTime ++;経過++;} float JulianDate(int iday、int imonth、int iyear){//ユリウス日を計算します(20、000年までテスト済み)unsigned long d =iday; unsigned long m =imonth; unsigned long y =iyear; if(m <3){m =m + 12; y =y-1; } unsigned long t1 =(153 * m --457)/ 5; unsigned long t2 =365 * y +(y / 4)-(y / 100)+(y / 400); return 1721118.5 + d + t1 + t2;} void GregorianDate(float jd、int&iday、int&imonth、int&iyear){//注2100は次のスキップされたうるう年です-スキップされたうるう年を補正しますunsigned long f =jd + 68569.5; unsigned long e =(4.0 * f)/ 146097; unsigned long g =f-(146097 * e + 3)/ 4; unsigned long h =4000ul *(g + 1)/ 1461001; unsigned long t =g-(1461 * h / 4)+ 31; unsigned long u =(80ul * t)/ 2447; unsigned long v =u / 11; iyear =100 *(e-49)+ h + v; imonth =u + 2-12 * v; iday =t-2447 * u / 80;} void SplitTime(unsigned long curr、unsigned long&ulHour、unsigned long&ulMin、unsigned long&ulSec){//ミリ秒カウントからHH:MM:SSを計算ulSec =curr / 1000; ulMin =ulSec / 60; ulHour =ulMin / 60; ulMin- =ulHour * 60; ulSec =ulSec --ulMin * 60 --ulHour * 3600;} unsigned long SetTime(unsigned long ulHour、unsigned long ulMin、unsigned long ulSec){//午前0時から現在の時刻までのミリ秒数を設定しますreturn(ulHour * 60 * 60 * 1000)+(ulMin * 60 * 1000)+(ulSec * 1000);} void Wait(unsigned long value){//独自のdealy関数を作成します// TCCR0Aに独自の割り込みを設定しました//したがって、millis()とdelay()はunsigned long startTime =経過として機能しなくなります。 while((elapsed --startTime) 12){iMonth =1; } //現在の設定に基づいて保存日を設定currentDate =JulianDate(iDay、iMonth、iYear); } if(digitalRead(DAY_BUTTON)==LOW){// Advance Day int iDay; int iMonth; int iYear; GregorianDate(currentDate、iDay、iMonth、iYear); iDay ++; if(iDay> 31){iDay =1; } if(((iMonth ==4)||(iMonth ==6)||(iMonth ==9)||(iMonth ==11))&&(iDay> 30)){iDay =1; } if((iMonth ==2)&&(iDay> 29)){iDay =1; } if((iMonth ==2)&&((iYear%4)!=0)&&(iDay> 28)){iDay =1; } //現在の設定に基づいて保存日を設定します//その後、日が無効になるように月を調整すると、//表示は次の有効な日付に進みますcurrentDate =JulianDate(iDay、iMonth、iYear); } 壊す; case SET_SPEED_ADJ:// correctonを5ミリ秒増減するif(digitalRead(UP_BUTTON)==LOW){speedCorrection + =5; } if(digitalRead(DOWN_BUTTON)==LOW){speedCorrection- =5; } 壊す; }}} String FormatNumber(int value){//必要に応じて先行0を追加するif(value <10){return "0" + String(value); } else {return String(value); }} void ShowTime(unsigned long value){// 1秒に1回、または深夜にロールオーバーしたときに表示を更新if((value> lastTime + 1000)||(value  
Arduinoタイマープログラム Arduino
このプログラムは、経過ミリ秒数をシリアルポートevert2秒に送信します。コンピューターを使用するclockintinByte =0; unsigned long firstReading =100000; // sendvoid setup(){Serial.begin(9600);を最初に読み取るときのmillis() // helloバイトをProcessingに送信しますsayHello();} void loop(){//バイトがシリアルポートで受信された場合//次にそれを読み取って破棄し、//現在のmillis()の値を送信しますif(Serial。 available()> 0){//着信バイトを取得inByte =Serial.read(); //最初の読み取り処理から経過した時間を送信Serial.print(millis()-firstReading); Serial.print( 'E'); // 2秒ごとに繰り返すdelay(2000); }} void sayHello(){//シリアルポートが使用可能になるまで待機します//次にhelloバイトを送信してハンドシェイクを開始しますwhile(Serial.available()<=0){Serial.print( 'Z'); // Zを処理に送信して、Hello delay(200);と言います。 } firstReading =millis();}
タイマーテストスクリプトの処理処理
これは、Arduinoから送信されたミリ秒を読み取り、処理の経過ミリ秒と比較する処理用のスクリプトです。
 // Paul Brace 2021年2月// Arduinoからmillis()を受け入れて比較するスクリプト内部millis()to // Arduinoクロックの不正確さを評価します//コンピュータのクロックが正確であると仮定します//-ve =Arduinoの動作が遅いので、クロックプログラムに+ ve調整として入力します// + ve =Arduino is高速で実行されているため、-ve調整として入力して、クロックを遅くします。importprocessing.serial。*; Serial theSerialPort; //シリアルポートを作成しますobjectint [] serialBytesArray =new int [15]; //着信バイトを格納する配列intbytesCount =0; //現在受信したバイト数booleaninit =false; //文字ZintfillColor =255を受信して​​ハンドシェイクが完了するまでfalse。 //初期塗りつぶしカラーロングミルを定義=0; //最後の読み取りreceivedlongfirst =0; //最初に受け取ったミルの時間。1時間の差を計算できるようになりました。 //最初のミルがlongfirstReading =100000を受け取ってから経過したミリ秒数; // Arduinolongから受信した最初のメッセージの処理中のmillis()DiffPerHour =0; //最初の1時間が経過した後の差intinByte; //最後のバイトreadvoidsetup(){//キャンバスと描画パラメータを定義しますsize(500、500);背景(70); noStroke(); //すべてのシリアルデバイスのリストを印刷して、Arduinoに設定するデバイスがわかるようにします//プログラムを実行し、正しいポートがprintArray(Serial.list());の下に設定されていない場合は編集する必要があります。 //シリアル通信文字列をインスタンス化しますthePortName =Serial.list()[1]; theSerialPort =new Serial(this、thePortName、9600);} void draw(){//時間設定を表示background(70); fill(fillColor); textSize(25); text(hour()+ ":" + minutes()+ ":" + second()、50、50); // Arduinoによって送信された最後の読み取りミリ秒text( "着信経過:" + mills、50、100); //処理テキスト( "ローカル経過:" +(現在-firstReading)、50、150);で最初に読み取られてからの現在の経過//現在の差分を表示しますtext( "Diff:" +(mills-(now --firstReading))、50、200); // 1時間が経過したかどうかを確認し、最初の1時間が差を保存するかどうかif(((now --firstReading)> =3600000)&&(DiffPerHour ==0)){DiffPerHour =mills-(now --firstReading); } //最初の差と最初の1時間後の差を表示しますtext( "Diff after 1 hour:" + DiffPerHour、50、300);} void serialEvent(Serial myPort){//シリアルポートからバイトを読み取りますinByte =myPort.read(); if(init ==false){//まだハンドシェイクされていない場合はハンドシェイクバイトを確認if(inByte =='Z'){//読み取られたバイトがZの場合myPort.clear(); //シリアルポートバッファをクリアしますinit =true; //最初のhellomyPort.write( 'Z');があったという事実を保存します// Arduinoにさらに送信するように指示しますif(first ==0){first =millis(); }}} else {//最初のhelloがすでに存在する場合//シリアルポートから配列に最新のバイトを追加するif(inByte!=69){//メッセージ文字Eの終わりをチェックしないif(bytesCount <14) {serialBytesArray [bytesCount] =inByte; bytesCount ++; }} if(inByte ==69){//メッセージの終わり//現在経過した現地時間を保存=millis(); //入ってくるmillis()ミルを計算します=0; for(int i =1; i <=bytesCount; i ++){mills + =(serialBytesArray [i --1] --48)* pow(10、(bytesCount --i)); } //次のメッセージを受け入れる準備ができていると言う//これが最初の読み取りである場合、最初の差を設定するif(firstReading ==100000){firstReading =now; } myPort.write( 'Z'); // bytesCountをリセットします:bytesCount =0; }}} 

回路図


製造プロセス

  1. Arduinoハメ撮りビジョンクロック
  2. Arduinoのみを使用するDTMFデコーダー
  3. Arduinoを使用してモニターをAmbilightにする
  4. Adafruit 1/460リングネオピクセルを使用したシンプルな掛け時計
  5. Simple Word Clock(Arduino)
  6. イスラムの祈りの時間とArduino時計
  7. マスタークロック
  8. Arduinoとスマートフォンを使用したDIY電圧計
  9. IoTを使用した心拍数モニター
  10. Arduino UnoWiFiを使用したWebServerBlink
  11. 7セグメントアレイクロック