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:
Trường hợp như đầu ra dự kiến sẽ trông giống như thế nà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:
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ư 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.