Saya perlu mengukur frekuensi gelombang persegi yang dapat bervariasi antara 0 dan 1MHz, dan memiliki resolusi 0,25Hz.
Saya belum memutuskan controller yang mana tetapi itu kemungkinan besar akan menjadi salah satu Attiny 20pin.
Biasanya bagaimana saya akan mengukur sinyal frekuensi yang lebih rendah adalah dengan menggunakan dua timer yang dikonfigurasi dalam mode penangkapan waktu untuk menyela mengatakan naiknya tepi sinyal eksternal dan timer lain yang diatur untuk menyela setiap detik oleh karena itu nilai timer counter register pertama setelah 1 detik akan sama dengan frekuensi sinyal.
Namun metode ini jelas tidak akan berfungsi untuk menangkap sinyal yang berkisar antara 0 dan 1MHz dengan resolusi 0,25Hz untuk ini saya akan membutuhkan penghitung 22Bit (AFAIK 8bit micros hanya memiliki penghitung 8/16bit).
Satu ide yang saya miliki adalah untuk membagi sinyal sebelum menerapkannya ke mikro tetapi ini akan tidak rasional karena sinyal harus dibagi dengan 61 oleh karena itu frekuensinya hanya dapat diperbarui setiap 61 detik di mana saya ingin setiap beberapa detik .
Apakah ada metode lain yang akan memungkinkan frekuensi diperbarui katakan setiap 4 detik?
Memperbarui:
Solusi paling sederhana adalah dengan menggunakan interupsi eksternal atau pengatur waktu untuk menginterupsi tepi sinyal yang naik dan isr
menambahkan variabel tipe long int
. Baca variabel setiap 4 detik (untuk memungkinkan frekuensi turun ke 0,25Hz untuk diukur).
Pembaruan 2:
Seperti yang ditunjukkan oleh JustJeff, MCU 8-bit tidak akan mampu mengimbangi sinyal 1MHz sehingga mengesampingkan gangguan pada setiap sisi yang meningkat dan meningkatkan long int
...
Saya telah memilih metode yang disarankan oleh timororr. Setelah saya berkeliling untuk mengimplementasikannya, saya akan mengirim kembali dan membagikan hasilnya. Terima kasih untuk semua saran Anda.
Laporan perkembangan:
Iv'e mulai menguji beberapa ide yang disajikan di sini. Pertama saya mencoba kode vicatcu. Ada masalah nyata dari TCNT1 yang belum dihapus setelah frekuensi dihitung - bukan masalah besar ...
Kemudian saya perhatikan ketika men-debug kode yang setiap 2 sampai 7 kali frekuensi dihitung timer 1's (timer dikonfigurasi untuk menghitung peristiwa eksternal) jumlah overflow akan pendek dua. Saya meletakkan ini ke latensi Timer 0 ISR dan memutuskan untuk memindahkan blok pernyataan if dari ISR ke utama (lihat cuplikan di bawah) dan hanya mengatur bendera di ISR. Beberapa debugging menunjukkan bahwa pengukuran pertama akan baik-baik saja tetapi dengan setiap pembacaan berikutnya, jumlah limpahan Timer 1 akan berakhir pada 2. yang tidak dapat saya jelaskan -Saya harapkan tidak kurang dari ...
int main()
{
while(1)
{
if(global_task_timer_ms > 0 && (T0_overflow == 1))
{
global_task_timer_ms--;
T0_overflow = 0;
}
.....
}
}
Selanjutnya saya memutuskan untuk mencoba menerapkan saran timrorrs. Untuk menghasilkan interval yang diperlukan (sekitar 15ms antara masing-masing interupsi timer_isr), saya harus mengalirkan dua timer 8-bit karena timer 16-bit pada Atmega16 digunakan untuk menangkap peningkatan tepi sinyal eksternal.
Saya pikir solusi ini akan bekerja dan jauh lebih efisien karena sebagian besar overhead dipindahkan ke timer dan hanya satu isr pendek yang tersisa untuk cpu untuk menangani. Namun itu tidak seakurat yang saya harapkan, pengukuran bergeser bolak-balik oleh kira-kira 70Hz yang saya tidak akan keberatan pada frekuensi tinggi tetapi jelas tidak dapat diterima pada frekuensi yang lebih rendah. Saya tidak menghabiskan dua banyak waktu menganalisis masalah tetapi saya menduga pengaturan cascading timer tidak begitu akurat karena saya telah menerapkan pengaturan yang mirip dengan saran timrorrs pada pengontrol 8051 yang jauh lebih lambat yang memiliki 2 timer 16-bit dan hasilnya cukup akurat.
Saya sekarang telah kembali ke saran vicatcu, tetapi saya telah memindahkan perhitungan frekuensi ke Timer 0 isr (lihat cuplikan di bawah ), kode ini telah menghasilkan pengukuran yang konsisten dan cukup akurat. Dengan sedikit kalibrasi, akurasi seharusnya kira-kira +/- 10Hz.
ISR(TIMER0_OVF_vect)
{
TCNT0 = TIMER0_PRELOAD; //Reload timer for 1KHz overflow rate
if(task_timer_ms > 0)
{
task_timer_ms--;
}
else
{
frequency_hz = 1.0 * TCNT1;
TCNT1 = 0;
frequency_hz += global_num_overflows * 65536.0;
global_num_overflows = 0;
frequency_hz /= (TASK_PERIOD_MS / 1000.0);
task_timer_ms = TASK_PERIOD_MS;
}
}
Jika ada yang punya saran lain saya terbuka untuk mereka walaupun tetapi saya lebih suka tidak harus menggunakan rentang ... Saya juga tidak lagi bermaksud mendapatkan resolusi 0,25%, sepertinya tidak ada gunanya dengan tingkat akurasi yang saya miliki saat ini .
Jawaban:
Jika mungkin saya sarankan memilih mikrokontroler yang mendukung operasi penghitung menggunakan input timer; daripada secara manual menambah penghitung di dalam ISR (yang pada frekuensi tinggi dengan cepat berakhir menjenuhkan aktivitas mikrokontroler) Anda mengizinkan perangkat keras untuk menangani penghitungan. Pada titik ini kode Anda hanya menjadi masalah menunggu interupsi berkala Anda kemudian menghitung frekuensi.
Untuk memperluas jangkauan dan membuat penghitung frekuensi lebih digeneralisasi (menghilangkan kebutuhan untuk beberapa rentang dengan mengorbankan sedikit lebih banyak pekerjaan untuk MCU), Anda dapat menggunakan teknik berikut.
Pilih tingkat interupsi berkala yang memungkinkan akurasi pengukuran pada frekuensi input tertinggi; ini harus memperhitungkan ukuran penghitung Anda (Anda perlu memilih periode waktu sehingga penghitung waktu tidak akan meluap pada frekuensi input maksimum). Untuk contoh ini saya akan menganggap bahwa nilai penghitung input dapat dibaca dari variabel "timer_input_ctr".
Sertakan variabel untuk menghitung interupsi berkala (harus diinisialisasi ke 0 pada saat startup); untuk contoh ini saya akan merujuk ke variabel ini sebagai "isr_count". Periode interupsi terkandung dalam konstanta "isr_ period".
Interupsi berkala Anda harus diimplementasikan sebagai (C pseudo-code):
Jelas contoh kasar ini bergantung pada beberapa matematika floating point yang mungkin tidak kompatibel untuk mikrokontroler low-end, ada teknik untuk mengatasi ini tetapi mereka berada di luar ruang lingkup jawaban ini.
sumber
Anda mungkin ingin mempertimbangkan memiliki dua (atau lebih) rentang. Masalah dengan menangkap frekuensi yang sangat rendah agak berbeda dari masalah dengan yang lebih tinggi. Seperti yang telah Anda catat, di ujung rentang Anda, Anda memiliki masalah counter overflow.
Tetapi pertimbangkan pada batas bawah kisaran Anda, akurasi Anda akan menderita karena tidak memiliki jumlah yang cukup dalam register. Tidak yakin apakah Anda benar-benar ingin membedakan antara 0,25Hz dan 0,5Hz, tetapi jika Anda melakukannya, maka Anda benar-benar harus menghitung selama empat detik untuk melakukan itu.
Juga, menentukan resolusi datar 0,25 Hz, diartikan secara ketat, berarti Anda akan dapat membedakan 500.000,00 Hz dari 500.000,25 Hz, yang merupakan tingkat presisi yang agak tinggi.
Karena alasan itu, mendesain untuk rentang yang berbeda dapat mengurangi masalah ukuran penghitung. Menarik angka secara acak demi contoh, untuk low-end, katakan 0 hingga 100Hz, hitung untuk interval 10 detik, dan Anda mendapatkan resolusi 0,1 Hz, dan Anda menghitung hanya perlu naik hingga 1000, bahkan 10 bit. Kemudian dari 100Hz ke 10kHz, hitung untuk interval 1 detik; Anda hanya mendapatkan resolusi 1Hz, tetapi penghitung Anda hanya perlu menjalankan hingga 10.000 masih lebih kecil dari 16 bit. Kisaran atas 10kHz hingga 1MHz bisa dihitung hanya 0,01 detik, dan jumlah maks masih hanya 10.000 dan meskipun resolusi Anda akan 100Hz, ini akan menjadi presisi yang masuk akal.
sumber
Anda dapat mencampur penghitung perangkat keras dan perangkat lunak dengan menghitung luapan penghitung perangkat keras dalam ISR.
Menghitung setiap tepi sinyal dalam ISR akan terlalu lambat untuk sinyal 1 MHz. Saya pikir Anda bisa melakukan hingga 50kHz dengan cara itu.
sumber
Alih-alih melakukan penghitung 1 detik, jadikan penghitung 0,1 detik dan kalikan dengan 10?
Jika itu hanya masalah menyimpan nomor penghitung, tidak bisakah Anda menggunakan kode tambahan untuk melacak kapan penghitung akan meluap dan menulis ke lokasi memori lain untuk menjaga penghitungan?
sumber
Tidak bisakah Anda menggunakan input capture dan limpahan timer 16-bit timer (ditambah variabel) untuk melakukan pengukuran? Inilah cara saya akan melakukannya dengan ATTiny24A dengan AVR-GCC (tentu saja belum diuji dan berpotensi buggy):
... Bagaimanapun, ia mengkompilasi :)
EDIT Saya melihat output file lss dari kode saya, dan kode yang dihasilkan memiliki terlalu banyak instruksi untuk tidak tersandung pada 1MHz dengan jam 8MHz ... bahkan kenaikan sederhana dengan satu baris dalam TIM1_OVF_vect menghasilkan 19 instruksi! Jadi untuk menangani peristiwa 1MHz, Anda pasti perlu mengoptimalkan, mungkin mendaftar mengalokasikan beberapa hal (mungkin num_overflows dan capture_value_ticks), menggunakan inline assembler (mencuri barang-barang penting dari file lss), dan memindahkan pemrosesan dari interupsi dan ke utama lengkung sedapat mungkin.
sumber
Memposting kode ini sebagai alternatif per saran timrorr ke posting saya sebelumnya. Ini mengkompilasi untuk ATTiny24A menggunakan standar bahasa c99, tapi saya belum benar-benar mengujinya dengan cara apa pun selain itu.
Ini adalah sedikit penggunaan yang bagus dari kemampuan perangkat keras dari Timer1 dan membebaskan satu ton siklus pemrosesan dibandingkan dengan posting asli saya.
sumber
Menggunakan prescaler, bahkan pengukuran GHz dapat dicapai. Ini adalah pengukur frekuensi 40MHz sederhana dengan ATMEL AVR AT90S2313: http://www.myplace.nu/avr/countermeasures/index.htm
Berikut adalah beberapa proyek serupa lainnya:
http://www.ikalogic.com/freq_meter_2.php
http://www.saturn.dti.ne.jp/~khr3887/lfcd_e.html
http://www.circuitlake.com/rs232-frequency-meter-and-pulse-generator.html
http://www.ulrichradig.de/home/index.php/avr/frequenzcounter
http://www.triplespark.net/elec/analysis/FreqCnt/
http://www.cappels.org/dproj/30MHzfmeter/30MhzFmtr.html
http://www.qsl.net/pa3ckr/bascom%20and%20avr/rfcounter/index.html
http://www.sump.org/projects/counter
http://digilander.libero.it/alfred73/eprojects.htm#1300%20Mhz%20Frequencymeter%20with%20prescaler
sumber