Perilaku pembanding analog acak dan tidak dapat diprediksi

10

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:

masukkan deskripsi gambar di sini

Sedangkan output yang diharapkan akan terlihat seperti ini:

masukkan deskripsi gambar di sini

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:

masukkan deskripsi gambar di sini

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:

masukkan deskripsi gambar di sini

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.

Shibalicious
sumber
4
sebagai permulaan ... tambahkan resistor 1M antara output dan input + ve. INI adalah apa yang menciptakan histeresis, bukan R5 Anda ... yang hanya mengubah referensi
JonRB
1
Bagaimana Anda bisa menghasilkan gambar lingkup hasil dari komparator yang ada di dalam chip dan tidak dapat diakses?
Andy alias
2
Apakah Anda menonaktifkan interupsi lebih lanjut ketika Anda memasuki ISR? Anda mungkin perlu - mungkin sebagian besar ISR mendapatkan klik ganda.
Andy alias
1
Bagaimana Anda mengubah pin histeresis dan apakah Anda memenuhi syarat dengan nilai saat ini. Penundaan antara interupsi dan sakelar mungkin mengacaukan Anda.
Trevor_G
1
tidak ditampilkan dalam skema Anda adalah kapasitansi internal antara pin5 dan pin6, dapatkah Anda menggunakan internal pull-up pada pin7 untuk membuat hysterisis Anda?
Jasen

Jawaban:

13

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.

Michael Karas
sumber
1
+1 untuk deskripsi tambahan tentang bagaimana arah histeresis seharusnya bekerja. Paragraf 2 adalah nasihat yang baik tetapi melakukannya secara internal juga ok, asalkan dilakukan dengan benar, yang dalam contoh ini, tampaknya tidak menjadi masalah.
Trevor_G
@Trevor_G -: ^)
Michael Karas
1
@ Hipomania - Saya tahu Anda dapat membaca pengatur waktu tunggal di ISR. Tetapi kecuali jika penghitung waktu berlipat ganda sehingga register keluaran menahan penghitungan dari pemicu sementara penghitung waktu itu sendiri dapat terus menghitung maka penghitung waktu itu perlu untuk dihentikan sehingga Anda dapat membacanya dan kemudian mengaktifkannya kembali setelah pembacaannya selesai. . Banyak timer MCU tidak memiliki buffer ganda seperti itu dan dengan demikian waktu pemrosesan untuk masuk ke ISR ketika timer diaktifkan kembali adalah waktu yang hilang pada pengukuran periode waktu untuk setengah siklus berikutnya. Tergantung pada tingkat tertentu pada seberapa cepat timer sedang diputar (lanjutan)
Michael Karas
1
(lanjutan dari atas) tetapi Anda tidak pernah ingin berada dalam situasi saat Anda membaca nilai hitungan ketika jam bisa datang pada saat yang sama untuk mengubah hitungan. Saya belum meneliti MCU spesifik yang Anda gunakan untuk melihat apakah timer Anda memiliki buffer ganda pada peristiwa pemicu pemicu atau tidak.
Michael Karas
1
@ Hipomania - Saat saya melihat lembar data AVR MCU yang ditautkan dan melihat bahwa fungsi pengambilan input penghitung waktu memiliki buffer ganda !! Sebenarnya timer di bagian ini terlihat cukup kuat. Sudah hampir 15 tahun sejak saya menggunakan bagian AVR.
Michael Karas
6

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.

  1. Ketika nilai histeresis dalam keadaan ambang tinggi Anda harus menunggu tepi negatif menyela.

  2. Ketika interupsi tepi negatif tersebut tiba, alihkan histeresis ke nilai rendah, tunggu beberapa siklus, lalu hapus interupsi tertunda dan mulailah menunggu interupsi tepi positif.

  3. 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.

  4. 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.

Trevor_G
sumber
Terima kasih banyak, saya akan mencoba saran Anda besok dan memberi Anda pembaruan. Adapun ISR saya, saya memiliki pernyataan if-else jika untuk skenario yang tepat yang telah Anda jelaskan tidak termasuk menunggu.
Shibalicious
1
@ Hipomania Anda harus mengedit pertanyaan Anda dan memposting kode penangan interrupt Anda sehingga orang-orang dapat melihat apakah Anda mengacaukan suatu tempat. Mungkin saja noise, jejak lingkup Anda terlihat seperti ada lebih dari 50mV noise di sana. Masih dengan suara saya berharap untuk memperbaiki sendiri, semua itu dengan pulsa ekstra sesekali pada transisi.
Trevor_G
Itu yang saya harapkan juga. Akan melakukannya sesegera mungkin.
Shibalicious
1
@Hypomania lihat edit
Trevor_G
1
@ Hipomania Karena Anda bisa mendapatkan interupsi lain di antara kedua perintah itu. Saya juga mengedit hasil edit ...
Trevor_G
3

Efek ini mirip dengan bouncing kontak, dan dapat dikurangi dengan teknik debounce yang sama yang Anda gunakan untuk tombol.

  • Tentukan waktu debounce Td
  • menjaga stempel waktu dari tepi terakhir mengganggu dalam suatu variabel
  • jika waktu antara interupsi saat ini dan yang terakhir kurang dari Td, abaikan interupsi saat ini
Dmitry Grigoryev
sumber