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.