Saya sedang mengerjakan proyek yang relatif "sederhana" di mana saya perlu mengukur frekuensi gelombang sinus yang bervariasi dalam amplitudo dan frekuensi. Untuk menyederhanakan hal-hal, untuk saat ini, saya hanya mendapatkan input gelombang sinus frekuensi tetap (27Hz) (input negatif dari komparator) yang hanya dapat bervariasi dalam amplitudo (menggunakan potensiometer). Input positif komparator diatur ke Vcc / 2. Output dari komparator kemudian dimasukkan ke dalam register pengambilan input dari mikrokontroler atmega2560 untuk mengukur frekuensi.
Masalahnya adalah bahwa pada amplitudo tertentu dari sinyal input saya mendapatkan matikan yang cukup intens (atau kadang-kadang band mati) pada output yang terlihat seperti ini:
Sedangkan output yang diharapkan akan terlihat seperti ini:
Hal-hal yang saya coba sejauh ini:
Menggunakan komparator internal internal atmega2560. Menggunakan pembanding eksternal. Memperkenalkan histeresis menggunakan perangkat lunak dan sirkuit pemicu Schmitt. Mencoba berbagai pengaturan input, termasuk pengaturan referensi tetap dan pengaturan slicer data. Mencoba atmega2560 yang berbeda. Mencoba kecepatan jam yang berbeda.
Beberapa solusi lebih stabil daripada yang lain, tetapi tidak ada yang mendekati diterima. Saya telah menyelesaikan konfigurasi yang paling stabil sejauh ini:
Dengan pengaturan ini, hal-hal tertentu meningkatkan / mengubah stabilitas, namun masih belum sempurna:
Mengubah nilai R5 untuk meningkatkan histeresis. Menghapus C2 sepenuhnya (tidak tahu kenapa). Menyentuh kabel di papan tempat memotong roti (beberapa dari mereka bersebelahan). Mengalihkan catu daya dari eksternal ke USB dan sebaliknya.
Pada titik ini, entah itu kebisingan, DAC saya yang dengannya saya menghasilkan gelombang sinus atau saya melakukan sesuatu yang sangat mendasar secara tidak benar. Sirkuit ini telah berfungsi untuk orang lain tanpa masalah, jadi pasti ada yang salah dengan konfigurasi atau lingkungan saya.
Jika ada yang punya saran, saya akan sangat menghargai waktu Anda.
Inilah sumber minimal saya:
#include <avr/io.h>
void init(void);
void init(void) {
/* Setup comparator */
ACSR = (1 << ACIE) | (1 << ACIS1);
/* Initialize PORTD for PIND5 */
DDRD = 0x00;
PORTD = 0x00;
/* Enable global interrupts */
sei();
}
int main(void) {
init();
while (1) {}
}
ISR(ANALOG_COMP_vect) {
if (!(ACSR & (1<<ACIS0))) { //comparator falling edge
/* Set PIND5 to 0V */
PORTD &= ~(1 << PIND5);
ACSR |= (1<<ACIS0); //set next comparator detection on rising edge
}
else {
ACSR &= ~(1<<ACIS0); //set next comparator detection on falling edge
/* Set PIND5 to 5V */
PORTD |= (1 << PIND5);
}
}
Juga, inilah tautan ke diagram sirkuit dan perpustakaan itu sendiri:
http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/
MEMPERBARUI:
Saya sudah mencoba semua saran Anda, tidak ada yang berhasil kecuali satu. Menghapus bendera interupsi atau menonaktifkan interupsi di dalam atau di luar ISR tidak benar-benar berpengaruh. Saya sepertinya salah paham bagaimana register komparator chip sebenarnya bekerja.
Seperti yang saya sebutkan pada awalnya, saya akan menggunakan input capture untuk mengukur frekuensi gelombang persegi yang berasal dari gelombang sinus. Output dari komparator dimasukkan ke dalam input capture pin, kemudian gunakan timer untuk mengukur periode, sederhana.
Berikut diagram komparator analog atmega2560 http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf , halaman 265:
Seperti yang Anda lihat, komparator memiliki dua output, ACO dan ACIS0 + ACIS1. ACO diatur ketika + input> - input, dihapus ketika + input <- input. ACIS0 + ACIS1 adalah bit pilih tepi.
Yang saya lakukan pada awalnya adalah memeriksa tipe edge di ISR saya. Saya mengubah ISR untuk ini sebagai gantinya:
ISR(ANALOG_COMP_vect) {
if (!(ACSR & (1<<ACO))) { // + < -
/* Set PIND5 to 0V */
PORTD &= ~(1 << PIND5);
}
else {
/* Set PIND5 to 5V */
PORTD |= (1 << PIND5);
}
}
Dan output berperilaku sempurna (seperti pada gambar kedua). Kemudian saya melanjutkan untuk mengukur lebar pulsa tetapi hasilnya tidak bagus. Beralih intens pada layar LCD saya, angka-angka melompat ke nilai acak atau tetap pada 0, meskipun memiliki sinyal bersih. Saya menulis ulang kode saya berkali-kali menggunakan kondisi yang berbeda, satu-satunya solusi semi-stabil yang saya dapatkan sejauh ini adalah ini:
#include <avr/io.h>
#include <util/delay.h>
#include "UART.h"
void init(void);
volatile uint16_t y = 0;
volatile uint16_t x = 0;
volatile uint16_t current_value = 0;
volatile uint16_t previous_value = 0;
volatile uint16_t total = 0;
void init(void) {
/* Normal mode, 64 prescaler, Rising Edge trigger, Input Capture */
TCCR1A = 0;
TCCR1B = (1 << CS10) | (1 << CS11) | (1 << ICES1);
TIMSK1 = (1 << ICIE1);
ACSR = (1 << ACIC);
ADCSRB = 0x00;
/* This port is used for simulating comparator's output */
DDRC = 0xFF;
PORTC = 0xFF;
DDRD = 0x00;
PORTD = 0x00;
USART_Init(UBRR_VALUE);
sei();
}
int main(void) {
init();
while (1) {
if (TCNT1 == 60000) {
/* Display the values on the LCD */
USART_Transmit(0xFE);
USART_Transmit(0x01);
USART_Transmit_Double(x+y);
}
}
}
ISR(TIMER1_CAPT_vect) {
//ACSR &= ~(1<<ACIC);
if (!(ACSR & (1 << ACO))) {
if (!(TCCR1B & (1 << ICES1))) { // check for falling edge
PORTD |= (1 << PIND5);
PORTC &= ~(1 << PINC1);
TCCR1B |= (1 << ICES1);
current_value = ICR1;
x = current_value - previous_value;
previous_value = current_value;
}
}
else {
if (TCCR1B & (1 << ICES1)) { // check for rising edge
PORTD &= ~(1 << PIND5);
PORTC |= (1 << PINC1);
TCCR1B &= ~(1 << ICES1);
current_value = ICR1;
y = current_value - previous_value;
previous_value = current_value;
}
}
//ACSR |= (1<<ACIC);
}
Maksud saya semi-stabil, saya mendapatkan nilai yang benar 1/3 kali. Kali lain 2/3 dari waktu itu adalah setengah dari nilai yang benar atau nilai acak. Saya mencoba menggunakan bit register timer untuk pernyataan kondisional serta bit register pembanding di ISR saya, ini adalah satu-satunya konfigurasi yang berfungsi.
Apa yang saya lakukan di kemudian hari adalah menggunakan pembanding eksternal sebagai gantinya dengan pengaturan dan sumber yang identik (tidak termasuk semua baris yang terkait dengan pembanding). Keluarannya dimasukkan ke dalam input capture pin dan berfungsi sebagaimana mestinya (bahkan tidak perlu histeresis).
Pada titik ini saya dapat mengatakan saya menyelesaikannya dengan menggunakan komparator eksternal tetapi saya tidak tahu mengapa internal tidak berperilaku sendiri. Saya telah membaca banyak posting dan panduan tentang ini, membaca berbagai perpustakaan, mencoba meniru mereka tanpa hasil yang dapat diterima. Datasheet hanya memiliki 5 halaman di seluruh unit pembanding, saya membacanya berulang kali dan saya tidak melihat apa yang saya lakukan salah.
Saya ingin mencari tahu cara menggunakannya dengan benar tetapi jika itu gagal saya punya cadangan. Jika Anda memiliki masukan lebih lanjut, itu sangat dihargai.
sumber
Jawaban:
Saya membaca bahwa Anda menggunakan DAC untuk menghasilkan sinyal gelombang sinus. Keluaran DAC dapat menyebabkan perubahan status keluaran sehingga Anda harus menerapkan beberapa penyaringan analog ke output DAC sebelum memasukkannya ke dalam rangkaian komparator Anda. Ini dapat membantu mencegah beberapa pemicu interupsi ganda yang mungkin terjadi.
Saya juga berkomentar bahwa Anda benar-benar ingin menggunakan komparator eksternal untuk jenis masalah ini sehingga Anda dapat menerapkan histeresis dengan resistor tanpa menggunakan interaksi perangkat lunak. Ini juga akan memungkinkan isolasi masalah yang lebih baik karena Anda dapat langsung memantau output komparator.
Komentar terakhir berkaitan dengan jenis histeresis yang Anda gunakan. Agak sulit untuk melihat skema apa yang Anda gunakan, tetapi perhatikan bahwa yang Anda inginkan adalah perilaku yang melakukan ini: Anda menginginkan histeresis yang menarik tegangan ambang pada arah OPPOSITE daripada sinyal yang ditransisikan. Jadi untuk sisi naik Anda ingin ambang sedikit lebih tinggi dari titik nol dan kemudian ketika negara berubah ambang akan ditarik ke tingkat yang lebih rendah.
sumber
Masalah dengan skenario ini adalah ada penundaan waktu antara switching komparator dan interupsi yang ditangani ke titik di mana Anda mengganti pin "histeresis".
Pita histeresis Anda juga agak kecil untuk level sinyal tersebut mengingat untuk apa Anda menggunakannya. Terutama ketika saya melihat berapa banyak noise pada gelombang persegi pada lingkup Anda.
Dengan mempertimbangkan kedua faktor tersebut, ada kemungkinan besar bahwa pada level input tertentu Anda akan mendapatkan banyak sisi dari komparator sebelum Anda dapat menangani yang pertama. Memeriksa untuk melihat apa status pembanding selama penangan interupsi tidak akan banyak membantu karena bisa dalam keadaan apa pun.
Sayangnya Anda belum merinci dalam pertanyaan bagaimana pawang bekerja.
Namun pawang Anda harus melakukan sesuatu seperti ini.
Ketika nilai histeresis dalam keadaan ambang tinggi Anda harus menunggu tepi negatif menyela.
Ketika interupsi tepi negatif tersebut tiba, alihkan histeresis ke nilai rendah, tunggu beberapa siklus, lalu hapus interupsi tertunda dan mulailah menunggu interupsi tepi positif.
Ketika interupsi tepi positif tersebut tiba, alihkan pin histeresis kembali ke nilai tinggi, tunggu beberapa siklus, hapus interupsi tertunda dan mulailah menunggu tepi negatif menyela lagi.
Ulangi dari langkah 1.
BTW Saya tidak terlalu tertarik pada cara Anda menggunakan referensi pembanding sebagai bias untuk sinyal. Yang menghasilkan sedikit pembicaraan silang baik dari sinyal ke referensi dan dari histeresis ke sinyal, terutama dengan sinyal frekuensi rendah. Memang dengan nilai-nilai yang berpengaruh harus kecil, tetapi untuk kemurnian, bias terpisah pada sinyal akan lebih baik.
EDIT: Re kode Anda.
Dalam pernyataan lain, Anda mengubah tepi interupsi sebelum Anda mengatur histeresis.
Dalam kedua kasus Anda tidak berhenti dan menghapus interupsi tertunda sebelum kembali. (Catatan, mengubah register kontrol interupsi dapat membuat interupsi sendiri.)
Saya tidak tahu apakah Atmega melakukan interupsi peserta, yaitu, jika tepi berikutnya akan mengganggu pengendali yang masih berjalan dari tepi sebelumnya. Jika demikian, Anda perlu menangani konkurensi dengan tepat.
Tidak yakin untuk apa bagian PORTC, tetapi mungkin perlu pindah ke bagian yang memenuhi syarat.
sumber
Efek ini mirip dengan bouncing kontak, dan dapat dikurangi dengan teknik debounce yang sama yang Anda gunakan untuk tombol.
Td
Td
, abaikan interupsi saat inisumber