0

RC 受信機から ATMega 2560 に複数の PWM 信号を読み込もうとしています。ICRn ピンが 3 つの比較レジスタすべてに使用されているように見えるため、ICRn ピンがどのように機能するか理解できません。

RC PWM 信号の周期は 20ms で、2ms の HIGH パルスが有効な上限値で、1ms が有効な下限値です。したがって、値は 1000us から 2000us にスイープします。期間は、パルスの立ち上がりエッジで開始する必要があります。

16MHz クロックを 8 でプリスケールして 2MHz タイマーを持たせたので、0.5us の精度で信号を測定できるはずです。これは私の要件には十分です。

私は PWM 出力に問題がなく、この質問は特に PWM 入力に関するものであることに注意してください。

これまでの私のコードは以下に添付されています。PWM 値を測定するために ICR3 と ISR を使用する必要があることはわかっていますが、これを行うための最適な手順についてはわかりません。また、測定値が PE3、PE4、PE5 のいずれであるかを確認する方法もわかりません。このコードは正しいですか?探している値を取得するにはどうすればよいですか?

どんな助けでも大歓迎です。

// Set pins as inputs
DDRE |= ( 0 << PE3 ) | ( 0 << PE4 ) | ( 0 << PE5 );

// Configure Timers for CTC mode
TCCR3A |=   ( 1 << WGM31 ) | ( 1 << WGM30 ); // Set on compare match
TCCR3B |=   ( 1 << WGM33 ) | ( 1 << WGM32 ) | ( 1 << CS31); // Set on compare match, prescale_clk/8

TCCR3B |=   ( 1 << ICES5 ) // Use rising edge as trigger

// 16 bit register - set TOP value
OCR3A = 40000 - 1;
OCR3B = 40000 - 1;
OCR3C = 40000 - 1;

TIMSK3 |= ( 1 << ICIE3 );
4

2 に答える 2

1

数か月前にソリューションを投稿するのを忘れていたので、ここに...

最後に PPM レシーバーを使用したので、このコードを簡単に編集して単純な PWM を読み取ることができます。

ヘッダー ファイルで、プロジェクトに使用していた 6 チャネル レシーバーの構造を作成しました。これは、多かれ少なかれチャンネルを持つ受信機の必要に応じて変更できます。

#ifndef _PPM_H_
#define _PPM_H_

// Libraries included
#include <stdint.h>
#include <avr/interrupt.h>

struct orangeRX_ppm {
    uint16_t ch[6];
    };
volatile unsigned char ch_index;
struct orangeRX_ppm ppm;

/* Functions */
void ppm_input_init(void); // Initialise the PPM Input to CTC mode
ISR( TIMER5_CAPT_vect ); // Use ISR to handle CTC interrupt and decode PPM

#endif /* _PPM_H_ */

次に、.cファイルに次のものがありました。

// Libraries included
#include <avr/io.h>
#include <stdint.h>
#include "ppm.h"

/*      PPM INPUT
 *      ---
 *      ICP5    Pin48 on Arduino Mega
 */
void ppm_input_init(void)
{
    DDRL |= ( 0 << PL1 ); // set ICP5 as an input

    TCCR5A = 0x00; // none
    TCCR5B = ( 1 << ICES5 ) | ( 1 << CS51); // use rising edge as trigger, prescale_clk/8
    TIMSK5 = ( 1 << ICIE5 ); // allow input capture interrupts

    // Clear timer 5
    TCNT5H = 0x00;
    TCNT5L = 0x00;
}

// Interrupt service routine for reading PPM values from the radio receiver.
ISR( TIMER5_CAPT_vect )
{
    // Count duration of the high pulse
    uint16_t high_cnt; 
    high_cnt = (unsigned int)ICR5L;
    high_cnt += (unsigned int)ICR5H * 256;

    /* If the duration is greater than 5000 counts then this is the end of the PPM signal 
     * and the next signal being addressed will be Ch0
     */
    if ( high_cnt < 5000 )
    {
        // Added for security of the array
        if ( ch_index > 5 )
        {
            ch_index = 5;
        }

        ppm.ch[ch_index] = high_cnt; // Write channel value to array

        ch_index++; // increment channel index
    }
    else
    {
        ch_index = 0; // reset channel index
    }

    // Reset counter
    TCNT5H = 0;
    TCNT5L = 0;

    TIFR5 = ( 1 << ICF5 ); // clear input capture flag
}

このコードは、ICP5 が Low から High になるたびに ISR のトリガーを使用します。この ISR では、16 ビットの ICR5 レジスタ "ICR5H<<8|ICR5L" が、ローからハイへの最後の変化から経過したプリスケールされたクロック パルスの数を保持します。通常、このカウントは 2000 us 未満です。カウントが 2500us (5000 カウント) を超える場合、入力は無効であり、次の入力は ppm.ch[0] になるはずです。

オシロスコープで見た PPM の画像を添付しました。

6チャンネルPPMのイメージ

PPM を読み取るこの方法は、論理レベルをチェックするためにピンをポーリングし続ける必要がないため、非常に効率的です。

sei() コマンドを使用して割り込みを有効にすることを忘れないでください。そうしないと、ISR は実行されません。

于 2016-03-04T23:58:06.867 に答える
0

次のことをしたいとしましょう (これで PWM 信号を正確に測定できると言っているわけではありませんが、レジスタの設定方法の例として役立つかもしれません)。

3 つのタイマーが実行され、20 ミリ秒ごとにリセットされます。これは、OCRnA の CTC モードに設定することで実行できます: wgm3..0 = 0b0100。

//timer 1
TCCR4A = 0;
TCCR1B = (1<<CS11) | (1<<WGM12);
OCR1A = 40000 - 1;
//timer 3 (there's no ICP2)
TCCR3A = 0;
TCCR3B = (1<<CS31) | (1<<WGM32);
OCR3A = 40000 - 1;
//timer 4
TCCR4A = 0;
TCCR4B = (1<<CS41) | (1<<WGM42);
OCR4A = 40000 - 1;

次に、3 つの pwm 信号をそれぞれ独自の ICPn ピン (n = タイマー) に接続します。データシートでさまざまな ICPn ピンの位置を確認してください (PE3、4、5 ではないことは確かです)。

pwm 信号が t=0 でハイになり始め、残りの期間はハイタイムの後にローになると仮定します。ハイタイムを測定したいので、ICPn ピンで立ち下がりエッジが発生するたびに割り込みをトリガーします。

TCCRnB レジスタのビット ICESn を 0 に設定すると、立ち下がりエッジが選択されます (これは前のコード ブロックで既に行われています)。

割り込みをトリガーするには、対応する割り込みイネーブル ビットを設定します。

TIMSK1 |= (1<<ICIE1);
TIMSK3 |= (1<<ICIE3);
TIMSK4 |= (1<<ICIE4);
sei();

これで、ICn の割り込みがトリガーされるたびに、ICRn レジスタを取得して、立ち下がりエッジが発生した時刻 (クロック周期/8) を確認できます。

于 2015-08-06T12:22:34.340 に答える