振幅と周波数が変化する正弦波の周波数を測定する必要がある比較的「単純な」プロジェクトに取り組んでいます。物事を簡単にするために、今のところ、固定周波数(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の2つの出力があります。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);
}
}
そして、出力は(2番目の図のように)完璧に動作しました。その後、パルス幅の測定に進みましたが、結果はあまり良くありませんでした。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ページしかないので、何度も読み直しましたが、何が間違っているのかわかりません。
それを適切に使用する方法を知りたいのですが、それが失敗した場合は、バックアップを取得しています。他にご意見がありましたら、大歓迎です。