Genlik ve frekansta değişen bir sinüs dalgasının frekansını ölçmem gereken nispeten "basit" bir proje üzerinde çalışıyorum. Bir şeyleri basitleştirmek için, şimdilik, sadece bir genlik (bir potansiyometre kullanarak) değiştirilebilen sabit bir frekans (27Hz) sinüs dalgası girişi (karşılaştırıcının negatif girişi) var. Karşılaştırıcının pozitif girişi Vcc / 2 olarak ayarlanmıştır. Daha sonra karşılaştırıcının çıkışı, frekansı ölçmek için atmega2560 mikrodenetleyicinin giriş yakalama kaydına beslenir.
Sorun, giriş sinyalinin belirli genliklerinde, çıkışta şu şekilde görünen oldukça yoğun geçiş (veya bazen ölü bantlar) elde etmemdir:
Beklenen çıktı aşağıdaki gibi görünmelidir:
Şimdiye kadar denediğim şeyler:
Dahili atmega2560'ın dahili karşılaştırıcısını kullanma. Harici bir karşılaştırıcı kullanma. Yazılım ve Schmitt tetikleme devresi kullanarak histerezis tanıtımı. Sabit referans kurulumu ve veri dilimleyici kurulumu dahil olmak üzere çeşitli giriş kurulumlarını denedi. Farklı atmega2560 deniyor. Farklı saat hızları deniyor.
Bazı çözümler diğerlerinden daha kararlıydı, ancak hiçbiri kabul edilebilir bir yerde değildi. Şimdiye kadarki en istikrarlı yapılandırmaya yerleştim:
Bu kurulumla, bazı şeyler istikrarı geliştirir / değiştirir, ancak yine de mükemmel bir yere yakın değildir:
Histereziyi arttırmak için R5'in değerinin değiştirilmesi. C2'yi tamamen kaldırmak (neden olduğu hakkında hiçbir fikrim yok). Breadboard'daki tellere dokunmak (oldukça az sayıda yan yana). Güç kaynaklarını hariciten USB'ye veya tersi yönde değiştirme.
Bu noktada, ya gürültü, sinüs dalgası ürettiğim DAC'ım ya da çok temel bir şeyi yanlış yapıyorum. Bu devre diğer insanlar için sorunsuz çalıştı, bu yüzden yapılandırmam veya ortamımla ilgili bir sorun olması gerekiyor.
Herhangi bir öneriniz varsa, zaman ayırdığınız için çok teşekkür ederim.
İşte asgari kaynağım:
#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);
}
}
Ayrıca, devre şemasına ve kütüphanenin kendisine olan bağlantı:
http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/
GÜNCELLEME:
Tüm önerilerinizi denedim, hiçbiri işe yaramadı, biri değil. Kesme bayraklarını temizlemek veya ISR'nin içindeki veya dışındaki kesintileri devre dışı bırakmak gerçekten bir etkiye sahip değildi. Çipin karşılaştırıcı kaydının gerçekten nasıl çalıştığını yanlış anlıyorum.
Başlangıçta bahsettiğim gibi, sinüs dalgasından elde edilen kare dalganın frekansını ölçmek için girdi yakalamayı kullanacaktım. Karşılaştırıcının çıkışı giriş yakalama pimine beslenir, daha sonra süreyi ölçmek için zamanlayıcıları kullanın, basit.
İşte atmega2560'ın analog karşılaştırıcı şeması http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf , sayfa 265:
Gördüğünüz gibi, karşılaştırıcının ACO ve ACIS0 + ACIS1 olmak üzere iki çıkışı vardır. ACO, + input> - input olduğunda ayarlanır, + input <- input olduğunda silinir. ACIS0 + ACIS1 kenar seçme bitleridir.
Başlangıçta yaptığım şey ISR'mdeki kenar tipini kontrol etmekti. Bunun yerine ISR'yi değiştirdim:
ISR(ANALOG_COMP_vect) {
if (!(ACSR & (1<<ACO))) { // + < -
/* Set PIND5 to 0V */
PORTD &= ~(1 << PIND5);
}
else {
/* Set PIND5 to 5V */
PORTD |= (1 << PIND5);
}
}
Ve çıktı kusursuz davrandı (tıpkı ikinci resimde olduğu gibi). Sonra bakliyatların genişliğini ölçmeye devam ettim ama sonuçlar iyi değildi. LCD ekranımda yoğun geçiş, sayılar rastgele bir değere atlıyor veya temiz bir sinyale sahip olmasına rağmen 0'da kalıyor. Kodumu birçok kez farklı koşullar kullanarak yeniden yazdım, şimdiye kadar aldığım tek yarı kararlı çözüm şudur:
#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);
}
Yarı kararlı demek istediğim, doğru değeri 1/3 oranında alıyorum. Diğer zamanların 2 / 3'ü doğru değerin yarısı veya rastgele bir değerdir. Koşullu ifadeler için zamanlayıcı kayıt bitlerini ve karşılaştırıcısının kayıt bitlerini ISR'mde kullanmayı denedim, bu tür işler sadece yapılandırma.
Gün içinde daha sonra yaptığım aynı kurulum ve kaynak yerine harici bir karşılaştırıcı kullanmak oldu (karşılaştırıcı ile ilgili tüm satırlar hariç). Çıkışı giriş yakalama pimine beslendi ve istendiği gibi çalıştı (histerezise bile gerek yoktu).
Bu noktada, harici bir karşılaştırıcı kullanarak çözdüğümü söyleyebilirim, ancak dahili olanın neden davranmadığı hakkında hiçbir fikrim yok. Bu konuda birçok yazı ve rehber okudum, farklı kütüphaneleri okudum, kabul edilebilir bir sonuç olmadan taklit etmeye çalıştım. Veri sayfasında tüm karşılaştırıcı biriminde sadece 5 sayfa var, birçok kez tekrar okuyorum ve ne yaptığımı göremiyorum.
Nasıl düzgün kullanılacağını öğrenmek istiyorum ama bu başarısız olursa bir yedek var. Başka bir girişiniz varsa, büyük beğeni topluyor.