임의의 예측할 수없는 아날로그 비교기 동작


10

진폭과 주파수가 다른 사인파의 주파수를 측정해야하는 비교적 "간단한"프로젝트를 진행하고 있습니다. 일을 단순화하기 위해 지금은 고정 주파수 (27Hz) 사인파 입력 (비교기의 음의 입력) 만 얻었으며 진폭은 전위차계를 사용하여 다양 할 수 있습니다. 비교기의 양의 입력은 Vcc / 2로 설정됩니다. 그런 다음 비교기의 출력은 atmega2560 마이크로 컨트롤러의 입력 캡처 레지스터로 공급되어 주파수를 측정합니다.

문제는 입력 신호의 특정 진폭에서 다음과 같이 출력에서 ​​매우 강렬한 토글 (또는 때로는 불감 대)을 얻는다는 것입니다.

여기에 이미지 설명을 입력하십시오

예상되는 출력이 다음과 같이 보이는 곳 :

여기에 이미지 설명을 입력하십시오

내가 지금까지 시도한 것 :

내부 atmega2560의 내부 비교기를 사용합니다. 외부 비교기 사용. 소프트웨어 및 슈미트 트리거 회로를 사용한 히스테리시스를 소개합니다. 고정 참조 설정 및 데이터 슬라이서 설정을 포함한 다양한 입력 설정을 시도했습니다. 다른 atmega2560을 시도합니다. 다른 클럭 속도를 시도 중입니다.

일부 솔루션은 다른 솔루션보다 안정적이지만 어느 곳도 수용 할 수있는 곳은 없었습니다. 지금까지 가장 안정적인 구성으로 정착했습니다.

여기에 이미지 설명을 입력하십시오

이 설정을 사용하면 특정 사항이 안정성을 개선 / 변경하지만 여전히 완벽한 곳은 없습니다.

히스테리시스를 높이기 위해 R5의 값을 변경합니다. C2를 완전히 제거합니다 (아무 이유가 없습니다). 브레드 보드의 전선을 만지십시오 (몇 개는 서로 옆에 있습니다). 외부에서 USB로 또는 그 반대로 전원 공급 장치 전환

이 시점에서 그것은 사인파를 생성하는 데 사용되는 DAC 인 노이즈이거나 매우 근본적으로 잘못된 일을하고 있습니다. 이 회로는 다른 사람들에게 아무런 문제없이 작동했기 때문에 구성이나 환경에 문제가 있어야합니다.

누구든지 제안 사항이 있으면 시간을 내 주셔서 감사합니다.

여기 내 최소한의 소스가 있습니다 :

#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/

최신 정보:

나는 당신의 모든 제안을 시도했지만 그중 하나도 효과가 없었습니다. ISR 내부 또는 외부에서 인터럽트 플래그를 지우거나 인터럽트를 비활성화해도 실제로 효과가 없었습니다. 칩의 비교기 레지스터가 실제로 어떻게 작동하는지 오해하는 것 같습니다.

처음에 언급했듯이 입력 캡처를 사용하여 사인파에서 파생 된 구형파의 주파수를 측정하려고했습니다. 비교기의 출력은 입력 캡처 핀으로 공급 된 다음 타이머를 사용하여 간단하고주기를 측정합니다.

여기 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는 + 입력>-입력시 설정되고 + 입력 <-입력시 해제됩니다. ACIS0 + ACIS1은 에지 선택 비트입니다.

처음에 내가 한 일은 ISR에서 엣지 유형을 확인하는 것이 었습니다. 대신 ISR을 다음과 같이 변경했습니다.

    ISR(ANALOG_COMP_vect) {

     if (!(ACSR &  (1<<ACO))) { // + < -
         /* Set PIND5 to 0V */
         PORTD &= ~(1 << PIND5);
    }
    else  {
       /* Set PIND5 to 5V */
       PORTD |= (1 << PIND5);
    }
}

그리고 출력은 완벽하게 작동했습니다 (두 번째 그림에서와 같이). 그런 다음 펄스 폭을 측정했지만 결과는 좋지 않았습니다. 신호가 깨끗 해지더라도 LCD 디스플레이에서 강렬한 토글, 숫자가 임의의 값으로 점프하거나 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 페이지 만 있으며 여러 번 다시 읽었으며 내가 뭘 잘못하고 있는지 알 수 없습니다.

제대로 사용하는 방법을 찾고 싶지만 실패하면 백업이 있습니다. 더 이상의 의견이 있으시면 대단히 감사하겠습니다.


4
우선 ... 출력과 + ve 입력 사이에 1M ​​저항을 추가하십시오. 이건 이력을 생성하는 것, 그냥 기준 변경 아닌 R5 ...
JonRB

1
칩 내부에 있고 액세스 할 수없는 비교기에서 출력의 스코프 그림을 어떻게 생성 할 수 있습니까?
Andy 일명

2
ISR에 들어갈 때 추가 인터럽트를 비활성화합니까? 대부분의 ISR이 두 배의 타격을 받고있을 수 있습니다.
Andy 일명

1
히스테리시스 핀을 어떻게 토글하고 현재 값으로 이력을 검증합니까? 인터럽트와 토글 사이의 지연이 문제가 될 수 있습니다.
Trevor_G

1
핀 5와 핀 6 사이의 내부 커패시턴스가 회로도에 표시되어 있지 않습니다. 대신 핀 7의 내부 풀업을 사용하여 히스테리시스를 만들 수 있습니까?
Jasen

답변:


13

사인파 신호를 생성하기 위해 DAC를 사용하고 있음을 읽었습니다. DAC 출력은 출력 상태 변경시 글리치 될 수 있으므로 비교기 회로에 공급하기 전에 DAC 출력에 일부 아날로그 필터링을 적용해야합니다. 이는 발생할 수있는 이중 인터럽트 트리거 중 일부를 방지하는 데 도움이됩니다.

또한 소프트웨어 인터랙션을 사용하지 않고 저항으로 히스테리시스를 적용 할 수 있도록 이러한 유형의 문제에 대해 외부 비교기를 사용하고 싶다고 언급합니다. 또한 비교기의 출력을 직접 모니터링 할 수 있으므로 문제를보다 효과적으로 격리 할 수 ​​있습니다.

마지막 설명은 사용중인 히스테리시스 유형과 관련이 있습니다. 정확히 어떤 체계를 사용하고 있는지 알기는 어렵지만 원하는 것은이 동작을 수행하는 것입니다. 신호가 전환되는 것보다 임계 값 전압을 OPPOSITE 방향으로 당기는 히스테리시스가 필요합니다. 따라서 상승 에지의 경우 임계 값이 영점보다 약간 높아지기를 원하며 상태가 변경되면 임계 값이 더 낮은 레벨로 끌어옵니다.


1
히스테리시스 방향이 작동하는 방법에 대한 추가 설명은 +1입니다. 단락 2는 좋은 조언이지만 내부적으로하는 것도 괜찮습니다 (이 예제에서는 그렇지 않은 것 같습니다).
Trevor_G

@Trevor_G-: ^)
Michael Karas

1
@ Hypomania-ISR에서 단일 타이머를 읽을 수 있다는 것을 알고 있습니다. 그러나 타이머가 이중 버퍼링되어 출력 레지스터가 트리거로부터 카운트를 보유하지 않으면 서 타이머 자체가 카운트를 계속할 수 있으면 타이머를 중지해야합니다. 그러면 타이머를 읽고 다시 읽은 후에 다시 활성화 할 수 있습니다 . 많은 MCU 타이머는 이와 같이 이중 버퍼링되지 않으므로 타이머가 다시 활성화 될 때 ISR로 들어가는 처리 시간이 다음 반주기 동안주기 시간 측정시 손실됩니다. 그것은 타이머가 얼마나 빨리 클럭되고 있는지에 달려 있습니다 (계속)
Michael Karas

1
(위에서 계속) 그러나 카운트를 변경하기 위해 시계가 동시에 올 수있을 때 카운트 값을 읽는 상황에 있지 않으려는 경우는 없습니다. 트리거 캡처 이벤트에서 타이머가 이중 버퍼인지 여부를 확인하기 위해 사용중인 특정 MCU를 연구하지 않았습니다.
Michael Karas

1
@ Hypomania-변덕스럽게도 연결된 AVR MCU 데이터 시트를보고 타이머 입력 캡처 기능이 이중 버퍼링 된 것을 보았습니다! 실제로 이러한 부분의 타이머는 매우 견고합니다. AVR 부품을 사용한 지 거의 15 년이 지났습니다.
Michael Karas

6

이 시나리오의 문제는 비교기 스위칭과 "히스테리시스"핀을 전환하는 지점까지 처리되는 인터럽트 사이에 시간 지연이 있다는 것입니다.

히스테리시스 대역은 사용중인 신호를 고려하여 해당 신호 레벨에 비해 다소 작습니다. 특히 스코프의 구형파에 얼마나 많은 노이즈가 있는지 알 수 있습니다.

이 두 가지 요소를 모두 고려하면 특정 입력 레벨에서 첫 번째 것을 처리하기 전에 비교기에서 여러 에지를 얻을 가능성이 높습니다. 인터럽트 핸들러 동안 비교기 상태가 어떤지 확인하면 어느 상태에 있든 도움이되지 않습니다.

불행히도 처리기 작동 방식에 대한 질문에 대해서는 자세히 설명하지 않았습니다.

그러나 처리기는 이와 같이 작동해야합니다.

  1. 높은 임계 값 상태에서 히스테리시스 값이 발생하면 음의 에지 인터럽트를 기다려야합니다.

  2. 상기 네거티브 에지 인터럽트가 도달하면 히스테리시스를 낮은 값으로 토글하고 몇 사이클을 기다린 다음 보류중인 인터럽트를 지우고 포지티브 에지 인터럽트를 기다리기 시작하십시오.

  3. 상기 포지티브 에지 인터럽트가 도달하면 히스테리시스 핀을 다시 높은 값으로 토글하고 몇 사이클을 기다린 후 보류중인 인터럽트를 지우고 네거티브 에지 인터럽트를 다시 대기하십시오.

  4. 1 단계부터 반복하십시오.

BTW 비교 기준을 신호의 바이어스로 사용하는 방식에 너무 열중하지 않습니다. 그 결과 신호에서 기준으로, 히스테리시스에서 신호로, 특히 저주파수 신호에서 약간의 누화가 발생합니다. 그 값은 효과가 작아야하지만 순도의 경우 신호에 대한 별도의 바이어스가 더 좋습니다.

편집 : 코드를 다시 작성하십시오.

else 문에서 히스테리시스를 설정하기 전에 인터럽트 에지를 변경하십시오.

두 경우 모두 리턴하기 전에 보류중인 인터럽트를 일시 정지하고 지우지 마십시오. (인터럽트 제어 레지스터를 변경하면 자체적으로 인터럽트를 생성 할 수 있습니다.)

Atmega가 인터럽트를 재진입하는지, 즉 후속 에지가 이전 에지에서 여전히 실행중인 핸들러를 인터럽트하는지 여부를 알 수 없습니다. 그렇다면 동시성을 적절히 처리해야합니다.

PORTC 부품이 무엇인지 확실하지 않지만 적격 부품으로 옮겨야 할 수도 있습니다.


대단히 감사합니다. 내일 귀하의 제안을 시도하고 업데이트 해 드리겠습니다. 내 ISR의 경우 대기를 제외하고 설명한 정확한 시나리오에 대한 if-else if 문이 있습니다.
Shibalicious

1
@ Hypomania 당신은 당신의 질문을 편집하고 인터럽트 처리기 코드를 게시해야 사람들이 어딘가에 엉망인지 볼 수 있습니다. 스코프 트레이스에는 50mV 이상의 노이즈가있는 것처럼 보입니다. 여전히 노이즈가 발생하면 전환시 가끔씩 추가 펄스가 발생하기 때문에 자체적으로 교정해야합니다.
Trevor_G

그것은 내가 기대했던 것입니다. 가능한 빨리하겠습니다.
Shibalicious

1
@Hypomania 참조 편집
Trevor_G

1
@Hypomania 두 명령 사이에 또 ​​다른 인터럽트가 생길 수 있기 때문입니다. 나는 또한 편집을 편집했습니다 ...
Trevor_G

3

이 효과는 접촉 바운스와 유사하며 푸시 버튼에 사용하는 것과 동일한 디 바운스 기법으로 완화 할 수 있습니다.

  • 디 바운스 시간 결정 Td
  • 마지막 에지 인터럽트의 타임 스탬프를 변수에 유지
  • 현재 인터럽트와 마지막 인터럽트 사이의 시간이보다 짧은 경우 Td현재 인터럽트를 무시하십시오.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.