Hành vi so sánh tương tự ngẫu nhiên và không thể đoán trước


10

Tôi đang làm việc trong một dự án tương đối "đơn giản" trong đó tôi cần đo tần số của sóng hình sin thay đổi về biên độ và tần số. Để đơn giản hóa mọi thứ, hiện tại, tôi chỉ có một đầu vào sóng hình sin tần số cố định (27Hz) (đầu vào âm của bộ so sánh) chỉ có thể thay đổi về biên độ (sử dụng chiết áp). Đầu vào tích cực của bộ so sánh được đặt thành Vcc / 2. Đầu ra của bộ so sánh sau đó được đưa vào thanh ghi bắt đầu vào của vi điều khiển atmega2560 để đo tần số.

Vấn đề là ở các biên độ nhất định của tín hiệu đầu vào, tôi có thể chuyển đổi khá mạnh (hoặc đôi khi là các dải chết) trên đầu ra trông như thế này:

nhập mô tả hình ảnh ở đây

Trường hợp như đầu ra dự kiến ​​sẽ trông giống như thế này:

nhập mô tả hình ảnh ở đây

Những điều tôi đã cố gắng cho đến nay:

Sử dụng bộ so sánh nội bộ của atmega2560. Sử dụng một bộ so sánh bên ngoài. Giới thiệu độ trễ bằng phần mềm và mạch kích hoạt Schmitt. Đã thử các thiết lập đầu vào khác nhau, bao gồm thiết lập tham chiếu cố định và thiết lập bộ cắt dữ liệu. Đang thử khác nhau của atmega2560. Thử tốc độ đồng hồ khác nhau.

Một số giải pháp ổn định hơn các giải pháp khác, nhưng không có giải pháp nào ở bất kỳ đâu gần chấp nhận được. Tôi đã giải quyết với cấu hình ổn định nhất cho đến nay:

nhập mô tả hình ảnh ở đây

Với thiết lập này, một số thứ nhất định cải thiện / thay đổi độ ổn định, tuy nhiên vẫn chưa có gì hoàn hảo:

Thay đổi giá trị của R5 để tăng độ trễ. Loại bỏ hoàn toàn C2 (không biết tại sao). Chạm dây trên bảng điều khiển (khá nhiều trong số chúng nằm cạnh nhau). Chuyển đổi nguồn điện từ bên ngoài sang USB và ngược lại.

Tại thời điểm này, đó là tiếng ồn, bộ xử lý tín hiệu mà tôi đang tạo ra sóng hình sin hoặc tôi đang làm một cái gì đó rất cơ bản không chính xác. Mạch này đã làm việc cho những người khác mà không có bất kỳ vấn đề nào, vì vậy có gì đó không ổn với cấu hình hoặc môi trường của tôi.

Nếu bất cứ ai có bất kỳ đề nghị, tôi sẽ đánh giá rất cao thời gian của bạn.

Đây là nguồn tối thiểu của tôi:

#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);
    }
}

Ngoài ra, đây là liên kết đến sơ đồ mạch và chính thư viện:

http://interface.khm.de/index.php/lab/interfaces-advified/frequency-measousing-l Library /

CẬP NHẬT:

Tôi đã thử tất cả các đề xuất của bạn, không ai trong số họ làm việc mà chỉ có một. Xóa các cờ ngắt hoặc vô hiệu hóa các ngắt trong hoặc ngoài ISR ​​thực sự không có tác dụng gì. Tôi dường như hiểu sai cách đăng ký so sánh của chip thực sự hoạt động.

Như tôi đã đề cập ban đầu, tôi sẽ sử dụng chụp đầu vào để đo tần số của sóng vuông bắt nguồn từ sóng hình sin. Đầu ra của bộ so sánh được đưa vào pin chụp đầu vào, sau đó sử dụng bộ định thời để đo thời gian, đơn giản.

Đây là sơ đồ so sánh tương tự của atmega2560 http://ww1.microchip.com/doads/en/DeviceDoc/Atmel-2549-8-bit-AVR-Microcontler-ATmega640-1280-1281-2560-2561_datasheet.pdf , trang 265:

nhập mô tả hình ảnh ở đây

Như bạn có thể thấy, bộ so sánh có hai đầu ra, ACO và ACIS0 + ACIS1. ACO được đặt khi + đầu vào> - đầu vào, bị xóa khi + đầu vào <- đầu vào. ACIS0 + ACIS1 là các bit chọn cạnh.

Tôi những gì tôi đã làm ban đầu là kiểm tra loại cạnh trong ISR của tôi. Tôi đã thay đổi ISR ​​thành cái này thay vào đó:

    ISR(ANALOG_COMP_vect) {

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

Và đầu ra tự hành xử hoàn hảo (giống như trong hình thứ hai). Sau đó, tôi đã tiến hành đo độ rộng của các xung nhưng kết quả không tốt. Chuyển đổi mạnh mẽ trên màn hình LCD của tôi, các số nhảy đến giá trị ngẫu nhiên hoặc giữ ở mức 0, mặc dù có tín hiệu rõ ràng. Tôi đã viết lại mã của mình nhiều lần bằng các điều kiện khác nhau, giải pháp bán ổn định duy nhất tôi có được cho đến nay là:

#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);
}

Ý tôi là bán ổn định, tôi nhận được giá trị đúng 1/3 số lần. Lần khác 2/3 số lần đó là một nửa giá trị đúng hoặc giá trị ngẫu nhiên. Tôi đã thử sử dụng các bit đăng ký của bộ đếm thời gian cho các câu lệnh có điều kiện cũng như các bit đăng ký của bộ so sánh trong ISR của tôi, đây là cấu hình duy nhất sắp xếp công việc.

Những gì tôi đã làm sau đó trong ngày là sử dụng một bộ so sánh bên ngoài thay vì thiết lập và nguồn giống hệt nhau (không bao gồm tất cả các dòng liên quan đến bộ so sánh). Đầu ra của nó được đưa vào pin chụp đầu vào và nó hoạt động như dự định (thậm chí không cần bất kỳ độ trễ nào).

Tại thời điểm này tôi có thể nói rằng tôi đã giải quyết nó bằng cách sử dụng một bộ so sánh bên ngoài tuy nhiên tôi không biết tại sao cái bên trong không tự hành xử. Tôi đã đọc nhiều bài viết và hướng dẫn về điều này, đọc các thư viện khác nhau, cố gắng bắt chước chúng mà không có kết quả chấp nhận được. Bảng dữ liệu chỉ có 5 trang trên toàn bộ đơn vị so sánh, tôi đọc lại nhiều lần và tôi không thấy mình đang làm gì sai.

Tôi muốn tìm hiểu làm thế nào để sử dụng nó đúng cách nhưng nếu thất bại tôi đã có một bản sao lưu. Nếu bạn có bất kỳ đầu vào nào nữa, nó được đánh giá rất cao.


4
để bắt đầu ... thêm một điện trở 1M giữa đầu ra và đầu vào + ve. ĐÂY là thứ tạo ra độ trễ, không phải R5 của bạn ... mà chỉ thay đổi tham chiếu
JonRB

1
Làm thế nào bạn có thể tạo ra hình ảnh phạm vi của đầu ra từ một bộ so sánh bên trong chip và không thể truy cập được?
Andy aka

2
Bạn có vô hiệu hóa các ngắt tiếp theo khi bạn nhập ISR không? Bạn có thể cần phải - có thể là hầu hết các ISR đang nhận được hai lần truy cập.
Andy aka

1
Làm thế nào bạn chuyển đổi pin trễ và bạn có đủ điều kiện theo giá trị hiện tại. Độ trễ giữa ngắt và chuyển đổi có thể làm bạn khó chịu.
Trevor_G

1
không được hiển thị trong sơ đồ của bạn là điện dung bên trong giữa pin5 và pin6, bạn có thể sử dụng tính năng kéo bên trong trên pin7 để tạo ra độ trễ thay thế không?
Jasen

Câu trả lời:


13

Tôi đọc được rằng bạn đang sử dụng một bộ định tuyến để tạo tín hiệu sóng hình sin. Đầu ra của DAC có thể bị trục trặc khi thay đổi trạng thái đầu ra, do đó bạn chắc chắn nên áp dụng một số bộ lọc tương tự cho đầu ra của bộ xử lý trước khi đưa nó vào mạch so sánh của bạn. Điều này có thể giúp ngăn chặn một số tác nhân gây gián đoạn kép có khả năng xảy ra.

Tôi cũng sẽ nhận xét rằng bạn thực sự muốn sử dụng một bộ so sánh bên ngoài cho loại vấn đề này để bạn có thể áp dụng độ trễ với điện trở mà không cần sử dụng tương tác phần mềm. Điều này cũng sẽ cho phép cách ly vấn đề tốt hơn vì bạn có thể theo dõi trực tiếp đầu ra của bộ so sánh.

Nhận xét cuối cùng liên quan đến loại độ trễ bạn đang sử dụng. Thật khó để thấy chính xác sơ đồ bạn đang sử dụng nhưng lưu ý rằng những gì bạn muốn là hành vi thực hiện điều này: Bạn muốn độ trễ kéo điện áp ngưỡng theo hướng OPPOSITE so với tín hiệu đang chuyển. Vì vậy, đối với cạnh tăng, bạn muốn ngưỡng cao hơn một chút so với điểm 0 và sau đó khi trạng thái thay đổi, ngưỡng sẽ được kéo xuống mức thấp hơn.


1
+1 cho mô tả thêm về cách hoạt động của hướng trễ. Đoạn 2 là lời khuyên tốt nhưng thực hiện nó trong nội bộ cũng được, miễn là nó được thực hiện đúng, trong ví dụ này, dường như không phải là trường hợp.
Trevor_G

@Trevor_G -: ^)
Michael Karas

1
@Hypomania - Tôi biết bạn có thể đọc bộ đếm thời gian duy nhất trong ISR. Nhưng trừ khi bộ định thời được đệm đôi để thanh ghi đầu ra giữ số đếm từ bộ kích hoạt trong khi bộ định thời có thể tiếp tục đếm thì cần phải dừng bộ hẹn giờ để bạn có thể đọc và sau đó bật lại sau khi đã đọc . Nhiều bộ định thời MCU không được đệm đôi như vậy và do đó thời gian xử lý để vào ISR khi bộ định thời được bật lại bị mất thời gian khi đo thời gian trong nửa chu kỳ tiếp theo. Nó phụ thuộc vào một mức độ nào đó về tốc độ của bộ đếm thời gian đang được bấm giờ (tiếp theo)
Michael Karas

1
(tiếp tục từ phía trên) nhưng bạn không bao giờ muốn ở trong tình huống bạn đang đọc giá trị đếm khi đồng hồ có thể đến cùng lúc để thay đổi số đếm. Tôi chưa nghiên cứu MCU cụ thể mà bạn đang sử dụng để xem liệu bộ đếm thời gian của bạn có được đệm đôi trong một sự kiện chụp kích hoạt hay không.
Michael Karas

1
@Hypomania - Trong một ý thích bất chợt, tôi đã xem bảng dữ liệu AVR MCU được liên kết của bạn và thấy rằng chức năng chụp đầu vào bộ đếm thời gian được đệm đôi !! Trên thực tế, bộ đếm thời gian trong các bộ phận này trông khá mạnh mẽ. Đã gần 15 năm kể từ khi tôi sử dụng bất kỳ bộ phận AVR nào.
Michael Karas

6

Các vấn đề với kịch bản này là có một độ trễ về thời gian giữa việc chuyển đổi bộ so sánh và ngắt được xử lý đến điểm mà bạn chuyển đổi pin "trễ".

Dải trễ của bạn cũng khá nhỏ đối với mức tín hiệu đó khi xem xét bạn đang sử dụng nó để làm gì. Đặc biệt là khi tôi thấy có bao nhiêu nhiễu trên sóng vuông trên phạm vi của bạn.

Với cả hai yếu tố đó, có khả năng cao là ở các mức đầu vào nhất định, bạn sẽ nhận được nhiều cạnh từ bộ so sánh trước khi bạn có thể xử lý cái đầu tiên. Kiểm tra để xem trạng thái của bộ so sánh là gì trong trình xử lý ngắt đó sẽ không giúp ích nhiều vì nó có thể ở trạng thái này.

Thật không may, bạn đã không chi tiết trong câu hỏi làm thế nào xử lý làm việc.

Xử lý của bạn nên tuy nhiên, làm việc như thế này.

  1. Khi giá trị trễ trong trạng thái ngưỡng cao, bạn nên chờ một ngắt cạnh âm.

  2. Khi nói ngắt cạnh âm đến, chuyển độ trễ về giá trị thấp, đợi một vài chu kỳ, sau đó xóa bất kỳ ngắt đang chờ xử lý nào và bắt đầu chờ ngắt cạnh dương.

  3. Khi nói đến ngắt cạnh dương, chuyển đổi độ trễ trở lại giá trị cao, đợi một vài chu kỳ, xóa bất kỳ ngắt đang chờ xử lý nào và bắt đầu chờ ngắt cạnh âm một lần nữa.

  4. Lặp lại từ bước 1.

BTW Tôi không quá quan tâm đến cách bạn đang sử dụng tham chiếu so sánh làm độ lệch cho tín hiệu. Điều đó dẫn đến một cuộc nói chuyện chéo nhỏ cả từ tín hiệu đến tham chiếu và từ độ trễ đến tín hiệu, đặc biệt là với tín hiệu tần số thấp. Cấp với các giá trị đó có hiệu lực nên nhỏ, nhưng đối với độ tinh khiết, độ lệch riêng biệt trên tín hiệu sẽ tốt hơn.

EDIT: Re mã của bạn.

Trong câu lệnh khác, bạn thay đổi cạnh ngắt trước khi bạn đặt độ trễ.

Trong cả hai trường hợp, bạn tạm dừng và xóa bất kỳ ngắt đang chờ xử lý trước khi quay trở lại. (Lưu ý, việc thay đổi thanh ghi điều khiển ngắt có thể tự tạo các ngắt.)

Tôi không biết liệu Atmega có thực hiện lại các ngắt hay không, nghĩa là, nếu một cạnh tiếp theo sẽ làm gián đoạn trình xử lý vẫn đang chạy từ cạnh trước đó. Nếu vậy bạn cần xử lý đồng thời một cách thích hợp.

Không chắc phần PORTC dùng để làm gì, nhưng có lẽ nó cần chuyển sang phần đủ điều kiện.


Cảm ơn bạn rất nhiều, tôi sẽ thử đề xuất của bạn vào ngày mai và cung cấp cho bạn một bản cập nhật. Đối với ISR ​​của tôi, tôi có câu lệnh if-if if cho kịch bản chính xác mà bạn đã mô tả, ngoại trừ việc chờ đợi.
Bộ lạc

1
@Hypomania bạn nên chỉnh sửa câu hỏi của mình và đăng mã xử lý ngắt để mọi người có thể biết nếu bạn đang làm phiền ở đâu đó. Nó có thể chỉ là tiếng ồn mặc dù, dấu vết phạm vi của bạn trông giống như có hơn 50mV tiếng ồn trên đó. Vẫn với tiếng ồn, tôi hy vọng nó sẽ tự sửa, tất cả đều là xung với các xung bổ sung thỉnh thoảng tại các chuyển tiếp.
Trevor_G

Đó là những gì tôi mong đợi quá. Sẽ làm điều đó càng sớm càng tốt.
Bộ lạc

1
@Hypomania xem chỉnh sửa
Trevor_G

1
@Hypomania Bởi vì bạn có thể nhận được một ngắt khác giữa hai lệnh đó. Tôi cũng đã chỉnh sửa bản chỉnh sửa ...
Trevor_G

3

Hiệu ứng này tương tự như phản hồi tiếp xúc và có thể được giảm thiểu bằng các kỹ thuật gỡ lỗi tương tự mà bạn sử dụng cho nút bấm.

  • Quyết định thời gian ra mắt Td
  • giữ dấu thời gian của cạnh cuối cùng trong một biến
  • nếu thời gian giữa ngắt hiện tại và lần cuối nhỏ hơn Td, hãy bỏ qua ngắt hiện tại
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.