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 .