Я працюю над відносно "простим" проектом, де мені потрібно виміряти частоту синусоїди, яка змінюється за амплітудою та частотою. Для спрощення речей, на даний момент у мене є лише синусоїдальний вхід фіксованої частоти (27 ГГц) (негативний вхід компаратора), який можна змінювати лише за амплітудою (використовуючи потенціометр). Позитивний вхід компаратора встановлений на Vcc / 2. Потім вихід компаратора подається в регістр захоплення входу мікроконтролера atmega2560 для вимірювання частоти.
Проблема полягає в тому, що при певних амплітудах вхідного сигналу я отримую досить інтенсивне переміщення (або іноді мертвих смуг) на виході, який виглядає приблизно так:
Де очікуваний результат повинен виглядати приблизно так:
Що я спробував досі:
Використання внутрішнього компаратора atmega2560. Використання зовнішнього компаратора. Представляємо гістерезис за допомогою програмного забезпечення та тригерної схеми Шмітта. Випробували різні параметри введення, включаючи фіксовану довідкову настройку та налаштування зрізу даних. Спробуйте різні atmega2560's. Спробуйте різні тактові швидкості.
Деякі рішення були більш стійкими, ніж інші, але жодне з них не було десь прийнятним. Я вирішив найбільш стабільну конфігурацію до цих пір:
За допомогою цього налаштування деякі речі покращують / змінюють стабільність, однак все ще ніде не ідеально:
Зміна значення R5 для збільшення гістерезису. Видалення С2 повністю (навіть не знаю чому). Торкання проводів на дошці (їх досить багато поруч). Перемикання джерел живлення із зовнішнього на USB та навпаки.
На даний момент це або шум, мій ЦАП, з яким я генерую синусоїду, або роблю щось дуже фундаментальне неправильно. Ця схема працює для інших людей без будь-яких проблем, тому щось не має бути в моїй конфігурації чи оточенні.
Якщо у когось є якісь пропозиції, я дуже вдячний за ваш час.
Ось мій мінімальний джерело:
#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);
}
}
Також ось посилання на схему і саму бібліотеку:
http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/
ОНОВЛЕННЯ:
Я спробував усі ваші пропозиції, жодна з них не працювала, окрім однієї. Видалення прапорів переривання або відключення перерв всередині або поза МСУ насправді не мало жодного ефекту. Мені здається, неправильно розумію, як насправді працює реєстр компараторів мікросхем.
Як я вже згадував спочатку, я збирався використовувати вхідне захоплення для вимірювання частоти квадратної хвилі, отриманої від синусоїди. Вихід компаратора подається на вхідний штифт захоплення, потім використовуються таймери для вимірювання періоду, прості.
Ось аналогова схема порівняння atmega2560 http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf , сторінка 265:
Як бачимо, компаратор має два виходи, ACO та ACIS0 + ACIS1. ACO встановлюється, коли + input> - вхід, очищається, коли + input <- input. ACIS0 + ACIS1 - це біт вибору краю.
Я те, що я робив спочатку, перевіряв тип ребра в моєму рейтингу. Натомість я змінив ISR на це:
ISR(ANALOG_COMP_vect) {
if (!(ACSR & (1<<ACO))) { // + < -
/* Set PIND5 to 0V */
PORTD &= ~(1 << PIND5);
}
else {
/* Set PIND5 to 5V */
PORTD |= (1 << PIND5);
}
}
І вихід поводив себе бездоганно (як і на другій картині). Потім я приступив до вимірювання ширини імпульсів, але результати були не великі. Інтенсивне перемикання на моєму РК-дисплеї, цифри переходять до випадкових значень або залишаються на 0, незважаючи на чистий сигнал. Я переписував свій код багато разів, використовуючи різні умови. Єдине напівстабільне рішення, яке я отримав, це:
#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);
}
Під напівстабільним я маю на увазі, я отримую правильне значення в 1/3 разів. Інший раз 2/3 разів це або половина від правильного значення, або випадкове значення. Я спробував використовувати біти реєстру таймера для умовних операторів, а також біт реєстру компаратора в моєму ISR, це єдина конфігурація, яка працює.
Що я зробив пізніше цього дня, це застосувати зовнішній компаратор замість однакових налаштувань та джерела (виключаючи всі рядки, пов'язані з компаратором). Його вихід подавали у вхідний штифт, і він працював за призначенням (навіть не потребував гістерезису).
На даний момент я можу сказати, що це я вирішив за допомогою зовнішнього компаратора, але я не маю поняття, чому внутрішній не веде себе. Я прочитав багато публікацій і посібників з цього приводу, читав різні бібліотеки, намагався наслідувати їх без прийнятного результату. Лист даних містить лише 5 сторінок у всьому блоці порівняння, я перечитував його багато разів, і я не бачу, що я роблю неправильно.
Я хотів би дізнатися, як правильно його використовувати, але якщо це не вдається, у мене є резервна копія. Якщо у вас є додаткові дані, це дуже вдячно.