Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Manufacturing Technology >> Proses manufaktur

Jam Akurat Hanya Menggunakan Arduino

Komponen dan persediaan

Arduino Nano R3
Saya menggunakan Nano tetapi harus bekerja dengan Arduino apa pun
× 1
LCD alfanumerik, 16 x 2
Tampilan apa pun akan berfungsi, saya menggunakan yang ini https://www.amazon.co.uk/ gp/product/B00N8K2BYM/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1
× 1
Saklar Taktil, Digerakkan Atas
× 3
Potensiometer Pemangkas, 10 kohm
Pemangkas 10rb apa pun bisa digunakan
× 1
Kabel jumper
× 1

Tentang proyek ini

Saya memulai ini sebagai latihan akademis, tetapi berakhir dengan jam yang sangat akurat. Setelah berjalan selama 5 hari, itu tidak hilang atau bertambah setiap saat.

Masalah utama dengan hanya menggunakan Arduino adalah kecepatan clock internalnya tidak 100% akurat. Oleh karena itu jika Anda hanya mengandalkan ini maka hitungan milidetik yang berlalu akan keluar dengan persentase kecil dan jam yang Anda buat akan kehilangan atau menambah waktu. Pendekatan saya adalah menguji keakuratan Arduino yang saya gunakan dan menentukan berapa milidetik yang hilang atau diperoleh per jam. Yang kemudian diperlukan hanyalah memprogram penyesuaian kecepatan untuk menambah atau mengurangi perbedaan ini dari milidetik yang dilacak secara internal setiap jam.

Kekhawatiran saya yang lain adalah apakah jam Arduino secara konsisten tidak akurat, tetapi seperti yang ditunjukkan, jam yang saya programkan telah mempertahankan waktu yang sangat akurat selama 5 hari sehingga tampaknya ketidakakuratan itu konsisten.

Masalah kedua adalah bahwa fungsi internal millis() me-reset sendiri setiap 50 hari atau lebih dan Anda tidak dapat memanipulasi hitungan milidetik. Oleh karena itu, jawabannya adalah mengganti interupsi milis() menggunakan penghitung yang dapat saya manipulasi dan yang akan menghitung milidetik dari tengah malam, menyetel ulang setiap hari dengan menghapus batasan waktu proses.

Menilai ketidakakuratan

Untuk menilai ketidakakuratan, saya membuat asumsi bahwa jam komputer saya, dan karenanya milis() dalam Pemrosesan adalah akurat. Oleh karena itu saya membuat program untuk Arduino untuk mengirim jumlah milidetik yang telah berlalu sejak berjabat tangan dengan Pemrosesan setiap 2 detik dan skrip untuk Pemrosesan untuk membaca ini dan membandingkannya dengan milidetik yang telah berlalu yang menampilkan hasil waktu nyata dan perbedaannya setelah satu jam berlalu. Ini memberikan jumlah milidetik yang telah hilang atau diperoleh dalam satu jam dan oleh karena itu nilai yang digunakan untuk penyesuaian kecepatan dalam program jam.

Kode untuk program Arduino dan skrip Pemrosesan disediakan di bawah ini.

Jika Anda belum menginstal Processing, kunjungi https://processing.org di mana Anda dapat mengunduh dan mempelajarinya.

Kode jam

Area utama yang menarik dalam kode jam adalah pengaturan interupsi, bagaimana ini digunakan dan cara tanggal disimpan dan dimanipulasi.

Interupsi

Kode berikut akan mengatur interupsi yang akan memicu setiap milidetik. Ini mengalihkan interupsi yang digunakan untuk mempertahankan milis() sehingga milis() dan delay() tidak akan berfungsi lagi.

 // Mengatur interupsi waktu - milis() berguling setelah 50 hari jadi // kita menggunakan penghitung milidetik kita sendiri yang dapat kita atur ulang pada // akhir setiap hari //Menyetel mode CTC Bandingkan waktu dan pemicu interupsi TCCR0A =(1 < 

Ini adalah kode yang akan dipanggil setiap detik:

// Ini interupsi dipanggil ketika waktu pembandingan telah tercapai// maka akan dipanggil sekali dalam satu milidetik berdasarkan pengaturan register // OCR0A.ISR(TIMER0_COMPA_vect) { if (currentMode !=SET_TIME) saat iniWaktu++; berlalu++;}  

currentTime dan elapsed adalah variabel panjang yang tidak ditandatangani. Perhatikan bahwa ini memenuhi syarat sebagai volatil ketika didefinisikan karena kami juga memanipulasi variabel dalam kode utama. Ini memaksa sistem untuk membaca variabel setiap kali digunakan dan tidak menggunakan nilai yang di-cache.

currentTime menyimpan jumlah milidetik sejak tengah malam dan ada rutinitas untuk mengubahnya menjadi HH:MM:SS dan menyetel ulang saat Anda menyetel waktu.

Ketika 24 jam telah berlalu, sistem mengurangi jumlah milidetik dalam sehari dari waktu dan menambah tanggal 1 hari. Oleh karena itu, jam tidak terpengaruh oleh nilai maksimum yang dapat disimpan variabel, tidak seperti milis().

 // Jika pada akhir hari mengatur ulang waktu dan menambah tanggal if ((Mode saat ini ==SHOW_TIME) &&(Waktu saat ini> milidetikInADay)) { //Hari berikutnya // Menghentikan interupsi saat mengatur ulang waktu noInterrupts(); currentTime -=milidetikInADay; interupsi(); tanggal saat ini++; } 

Perhatikan bahwa kami menonaktifkan interupsi saat memanipulasi variabel currentTime jika tidak, panggilan interupsi dapat dipicu di tengah penghitungan untuk mengurangi milidetikInADay yang merusak penghitungan.

Setelah setiap jam berlalu, sistem menyesuaikan jumlah milidetik yang berlalu dengan penyesuaian kecepatan yang kami hitung sebelumnya, menyesuaikan waktu saat ini untuk mengimbangi jam internal yang cepat atau lambat.

 // Pada akhir setiap jam sesuaikan waktu yang telah berlalu untuk // ketidakakuratan pada jam Arduino if (berlalu>=milidetikInHour) { noInterrupts(); // Sesuaikan waktu untuk berjalan lambat/cepat jam Arduino saat iniWaktu +=kecepatan Koreksi; // Atur ulang untuk menghitung jam berikutnya yang telah berlalu =0; interupsi(); } 

Penyimpanan dan penghitungan tanggal

Tanggal tersebut ditetapkan sebagai tanggal Julian, yaitu jumlah hari yang telah berlalu sejak Senin, 1 Januari 4713 SM. Rutinitas disertakan untuk menghitung tanggal Julian dan mengubahnya kembali ke kalender Gregorian.

float JulianDate(int iday, int imonth, int iyear) { // Hitung tanggal julian (diuji hingga tahun 20.000) unsigned long d =iday; unsigned panjang m =ibulan; unsigned long y =iyear; jika (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) { // Catatan 2100 adalah tahun kabisat yang dilewati berikutnya - mengkompensasi tahun kabisat yang dilewati unsigned long f =jd + 68569.5; unsigned panjang e =(4.0 * f) / 146097; panjang tanpa tanda 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; panjang tanpa tanda v =u / 11; iyear =100 * (e - 49) + h + v; ibulan =u + 2 - 12 * v; iday =t - 2447 * u / 80;} 

Tombol penyesuaian

Tombol Mode memajukan mode saat ini dari Show Time, ke Set Time, Set Year, Set Date, Set Speed ​​Adjustment dan kembali ke Show Time. Masing-masing sudah cukup jelas dan gunakan 2 tombol lainnya untuk menyesuaikan pengaturan saat ini.

Setelah jam berjalan, jika waktu bertambah atau berkurang, Anda dapat mengubah penyesuaian kecepatan, dengan mengakses mode Setel Penyesuaian Kecepatan dan menggunakan tombol atas dan bawah untuk menambah atau menguranginya sebanyak 5 detik setiap kali.

Kode

  • Program jam
  • Program pengatur waktu Arduino
  • Memproses skrip pengujian pengatur waktu
Program jamArduino
Jam akurat dengan tanggal hanya menggunakan dan Arduino
// Paul Brace - Feb 2021// Jam Sederhana dengan Tanggal dibuat hanya menggunakan Arduino - tidak ada modul RTC// Program menggabungkan penyesuaian koreksi waktu untuk mengkompensasi kecepatan internal// jam tidak 100% akurat.// Setelah penyetelan kecepatan yang benar, jam ternyata sangat akurat.// Dalam pengujian saya, jam tidak kehilangan atau bertambah selama periode 5 hari.// Menampilkan waktu pada layar LCD 16x2// Tombol untuk menyetel waktu// Tombol Mode (pin 2) matikan set waktu, setel tanggal dan jalankan// Tombol 1 (pin 3) Penambahan Menit dan Bulan dan penurunan Tahun/kecepatan penyesuaian// Tombol 2 (pin 4) Penambahan Jam dan Hari dan meningkat Tahun./penyesuaian kecepatan// Tampilan 24 Jam// Sertakan driver perpustakaan untuk tampilan:#include // LiquidCrystal lcd( RS, EN, D4, D5, D6, D7)LiquidCrystal lcd(12, 13 , 6, 7, 8, 9); // membuat objek lcd dan menetapkan pin// Menentukan tombol dan koneksi buzzer#menentukan MODE_BUTTON 2#menentukan JAM_BUTTON 3 // Tombol yang sama dengan definisi yang berbeda#menentukan UP_BUTTON 3 // membuat kode lebih mudah dipahami #menentukan DAY_BUTTON 3#menentukan MENIT_BUTTON 4 // Tombol yang sama definisi berbeda untuk#menentukan DOWN_BUTTON 4 // membuat kode lebih mudah dipahami #menentukan MONTH_BUTTON 4// Pengaturan mode saat ini#menentukan SHOW_TIME 1 // 1 =running - show time#define SET_TIME 2 // 2 =set waktu #define SET_YEAR 3 // 3 =set tahun#define SET_DATE 4 // 4 =set hari/bulan #define SET_SPEED_ADJ 5 // 5 =mengubah variabel speedCorrectionint speedCorrection =3545; // Jumlah milidetik jam Nano saya berjalan lambat per jam// angka negatif di sini jika berjalan cepat // ubah agar sesuai dengan Arduino Anda// Variabel volatil seperti yang diubah dalam interupsi dan kami// perlu memaksa sistem untuk membaca variabel aktual// ketika digunakan di luar interupsi dan tidak menggunakan versi yang di-cache, volatil, unsigned long currentTime; // Durasi dalam milidetik dari tengah malamunsigned long lastTime =-1000; // lastTime yang disebut ShowTime diinisialisasi ke -1000 sehingga menunjukkan segera volatil unsigned lama berlalu; // Timer yang digunakan untuk penundaan dan hitungan jam yang tidak ditandatangani milidetikInADay; // Milidetik dalam 24 jamunsigned long milidetikInHour; // Milidetik dalam 1 jamint currentMode; // 1 =berjalan - waktu tayang// 2 =set waktu// 3 =set tahun// 4 =hari/bulan setfloat currentDate; // Julian datefloat lastDate =0.0; // tanggal terakhir yang disebut ShowDateint currentDay;int currentMonth;int currentYear;char *dayArray[] ={ "Sel. ", // Akan menampilkan peringatan compiler tetapi berfungsi dengan baik "Rabu.", "Kamis ", "Jumat . ", "Sab. ", "Sun. ", "Mon. " };void setup() { // Atur interupsi waktu - milis() berguling setelah 50 hari jadi // kita menggunakan penghitung milidetik kita sendiri yang kita bisa reset di // akhir setiap hari TCCR0A =(1 < millisecondsInADay)) { //Next hari // Hentikan interupsi saat mengatur ulang waktu noInterrupts(); currentTime -=milidetikInADay; interupsi(); tanggal saat ini++; } // Pada akhir setiap jam, sesuaikan waktu yang telah berlalu untuk // ketidakakuratan pada jam Arduino if (berlalu>=milidetikInHour) { noInterrupts(); // Sesuaikan waktu untuk berjalan lambat/cepat jam Arduino saat iniWaktu +=kecepatan Koreksi; // Atur ulang untuk menghitung jam berikutnya yang telah berlalu =0; interupsi(); } // Periksa apakah ada tombol yang ditekan CheckButtons(); // Menampilkan tampilan berdasarkan sakelar mode saat ini (Mode saat ini) { case SHOW_TIME:// Menampilkan waktu dan tanggal saat ini ShowTime(currentTime); ShowDate (tanggal saat ini); merusak; case SET_TIME:// Tampilan layar untuk mengatur waktu ShowTimeSet(currentTime); merusak; case SET_YEAR:// Tampilan layar untuk mengatur tahun ShowYearSet(currentDate); merusak; case SET_DATE:// Tampilan layar untuk mengatur hari dan bulan ShowDDMMSet(currentDate); merusak; case SET_SPEED_ADJ:// Tampilan layar untuk menyesuaikan koreksi kecepatan ShowSpeedSet(); merusak; } Wait(150);}// Ini interupsi dipanggil ketika waktu pembandingan telah tercapai// maka akan dipanggil sekali dalam satu milidetik berdasarkan pengaturan register// OCR0A.ISR(TIMER0_COMPA_vect) { if (currentMode !=SET_TIME ) saat iniWaktu++; elapsed++;}float JulianDate(int iday, int imonth, int iyear) { // Hitung tanggal julian (diuji hingga tahun 20.000) unsigned long d =iday; unsigned panjang m =ibulan; unsigned long y =iyear; jika (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) { // Catatan 2100 adalah tahun kabisat yang dilewati berikutnya - mengkompensasi tahun kabisat yang dilewati unsigned long f =jd + 68569.5; unsigned panjang e =(4.0 * f) / 146097; panjang tanpa tanda 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; panjang tanpa tanda v =u / 11; iyear =100 * (e - 49) + h + v; ibulan =u + 2 - 12 * v; iday =t - 2447 * u / 80;}void SplitTime(unsigned long curr, unsigned long &ulHour, unsigned long &ulMin, unsigned long &ulSec) { // Hitung HH:MM:SS dari hitungan milidetik ulSec =curr / 1000; ulMin =ulSec / 60; ulJam =ulMin / 60; ulMin -=ulJam * 60; ulSec =ulSec - ulMin * 60 - ulHour * 3600;}unsigned long SetTime(unsigned long ulHour, unsigned long ulMin, unsigned long ulSec) { // Menyetel jumlah milidetik dari tengah malam ke waktu saat ini kembali (ulHour * 60 * 60 * 1000) + (ulMin * 60 * 1000) + (ulSec * 1000);}void Wait(unsigned long value) { // Buat fungsi dealy kita sendiri // Kita telah menyetel interupsi kita sendiri pada TCCR0A // maka millis() dan delay() tidak akan lagi bekerja unsigned long startTime =elapsed; while ((elapsed - startTime)  12) { iBulan =1; } // Tetapkan tanggal tersimpan berdasarkan pengaturan saat ini currentDate =JulianDate(iDay, iMonth, iYear); } if (digitalRead(DAY_BUTTON) ==LOW) { // Advance day int iDay; int iBulan; int iTahun; GregorianDate (tanggal saat ini, iDay, iMonth, iYear); iDay++; if (iDay> 31) { iDay =1; } if (((iMonth ==4) || (iMonth ==6) || (iMonth ==9) || (iMonth ==11)) &&(iDay> 30)) { iDay =1; } if ((iBulan ==2) &&(iDay> 29)) { iDay =1; } if ((iMonth ==2) &&((iYear % 4) !=0) &&(iDay> 28)) { iDay =1; } // Tetapkan tanggal tersimpan berdasarkan pengaturan saat ini // Jika kemudian sesuaikan bulan sehingga hari tidak valid // maka tampilan akan maju ke tanggal valid berikutnya currentDate =JulianDate(iDay, iMonth, iYear); } merusak; case SET_SPEED_ADJ:// menambah atau mengurangi koreksi sebesar 5 milidetik if (digitalRead(UP_BUTTON) ==LOW) { speedCorrection +=5; } if (digitalRead(DOWN_BUTTON) ==RENDAH) { speedCorrection -=5; } merusak; } }}String FormatNumber(int value) { // Untuk menambahkan 0 di depan jika diperlukan if (value <10) { return "0" + String(value); } else { kembalikan String(nilai); }}void ShowTime(unsigned long value) { // Perbarui tampilan sekali per detik // atau saat berguling di tengah malam if ((value> lastTime + 1000) || (value  
Program pengatur waktu ArduinoArduino
Program ini mengirimkan jumlah milidetik yang telah berlalu ke port serial selama 2 detik.
// Paul Brace Feb 2021// Untuk digunakan dengan skrip Pemrosesan yang sesuai// untuk membandingkan milis() dari sini ke milis() di // Pemrosesan menggunakan jam komputer inByte =0;unsigned long firstReading =100000; // milis() saat pertama kali membaca pengaturan sentvoid() { Serial.begin(9600); // Kirim byte hello ke Processing sayHello();}void loop() { // jika byte diterima pada port serial // lalu baca dan buang dan kirim // nilai milis() saat ini jika (Serial. tersedia()> 0){ // dapatkan byte masuk inByte =Serial.read(); // kirim waktu yang telah berlalu sejak pemrosesan pembacaan pertama Serial.print(millis() - firstReading); Serial.print('E'); // ulangi setiap penundaan 2 detik(2000); }}void sayHello(){ // Tunggu sampai port serial tersedia // lalu kirim hello byte untuk memulai handshake while (Serial.available() <=0){ Serial.print('Z'); // Kirim Z ke pemrosesan untuk mengatakan Halo delay(200); } firstReading =milis();}
Memproses skrip pengujian pengatur waktuMemproses
Ini adalah skrip untuk Processing yang akan membaca milidetik yang dikirim dari Arduino dan membandingkannya dengan milidetik yang telah berlalu dalam pemrosesan.
// Paul Brace Feb 2021// Skrip untuk menerima milis() dari Arduino// dan membandingkannya dengan internal milis() untuk// menilai ketidakakuratan jam Arduino.// Mengasumsikan bahwa jam komputer akurat// -ve =Arduino berjalan lambat jadi masukkan sebagai penyesuaian +ve dalam program jam// +ve =Arduino adalah berjalan cepat jadi masukkan sebagai penyesuaian -ve untuk memperlambat jam impor processing.serial.*;Serial theSerialPort; // buat port serial objectint[] serialBytesArray =new int[15]; // larik untuk menyimpan byte yang masuk byteCount =0; // jumlah byte saat ini yang diterimaboolean init =false; // false sampai handshake selesai dengan menerima karakter Zint fillColor =255; // menentukan pengisian awal colorlong mills =0; // bacaan terakhir diterima panjang pertama =0; // waktu penggilingan pertama diterima sehingga kita dapat menghitung selisih lebih dari satu jam sekarang; // jumlah mili yang berlalu sejak gilingan pertama diterimalong firstReading =100000; // milis() dalam memproses pesan pertama yang diterima dari Arduinolong DiffPerHour =0; // perbedaan setelah satu jam pertama berlalu int inByte; // setup readvoid byte terakhir() { // tentukan beberapa kanvas dan ukuran parameter gambar(500, 500); latar belakang (70); tidak ada Stroke(); // cetak daftar semua perangkat serial sehingga Anda tahu mana yang harus disetel untuk Arduino // perlu menjalankan program dan mengedit jika port yang benar tidak disetel di bawah printArray(Serial.list()); // instantate String Komunikasi Serial thePortName =Serial.list()[1]; theSerialPort =Serial baru(this,thePortName, 9600);}void draw() { // Menampilkan latar belakang pengaturan waktu (70); isi(warna isi); ukuran teks(25); teks(jam() + ":" + menit() + ":" + detik(), 50, 50); // mili yang dibaca terakhir dikirim oleh Arduino text("Incoming elapsed:" + mills, 50, 100); // saat ini berlalu sejak pertama kali dibaca di Processing text("Local elapsed:" + (now - firstReading), 50, 150); // menampilkan perbedaan saat ini teks("Diff:" + (mills - (now - firstReading)), 50, 200); // Periksa apakah 1 jam telah berlalu dan apakah jam pertama menyimpan perbedaan if (((now - firstReading)>=3600000) &&(DiffPerHour ==0)){ DiffPerHour =mills - (now - firstReading); } // Menampilkan perbedaan pertama dan perbedaan setelah jam pertama text("Diff after 1 hour:" + DiffPerHour, 50, 300);}void serialEvent(Serial myPort) { // membaca satu byte dari port serial inByte =myPort.read(); if (init ==false) { // jika belum berjabat tangan lihat apakah byte handshake if (inByte =='Z') { // jika byte yang dibaca adalah Z myPort.clear(); // hapus buffer port serial init =true; // simpan fakta bahwa kita memiliki hello myPort.write('Z'); // beri tahu Arduino untuk mengirim lebih banyak jika (pertama ==0){ pertama =milis(); } } } else { // jika sudah ada hello pertama // Tambahkan byte terbaru dari port serial ke array if (inByte !=69) { // Centang bukan akhir dari karakter pesan E if (bytesCount <14) { serialBytesArray[bytesCount] =inByte; byte Hitung++; } } if (inByte ==69) { // Akhir pesan // simpan waktu lokal yang telah berlalu sekarang =milis(); // menghitung milis masuk() gilingan =0; for (int i =1; i <=bytesCount; i++) { mills +=(serialBytesArray[i - 1] - 48) * pow(10, (bytesCount - i)); } // Katakan kita siap menerima pesan berikutnya // jika ini adalah bacaan pertama maka atur perbedaan pertama if (firstReading ==100000) { firstReading =now; } myPort.write('Z'); // Setel ulang byteCount:byteCount =0; } }}

Skema


Proses manufaktur

  1. Arduino pov vision clock
  2. Decoder DTMF Hanya Menggunakan Arduino
  3. Membuat Monitor Ambilight Menggunakan Arduino
  4. Jam dinding sederhana menggunakan Adafruit 1/4 60 Ring Neopixel
  5. Jam Kata Sederhana (Arduino)
  6. Jam Arduino dengan waktu sholat Islam
  7. Jam Master
  8. Voltmeter DIY Menggunakan Arduino dan Smartphone
  9. Pemantau Detak Jantung Menggunakan IoT
  10. WebServerBlink Menggunakan Arduino Uno WiFi