2016-11-16 6 views
0

Atmel ATMega32U4のArduinoのピン番号に類似したものを実装したいと思います。私はArduinoのdigitalWriteコマンドとそれに関連するソースファイルを見てきましたが、これは少し複雑ですので、より基本的なバージョンを実装したいと思っています。Arduinoに似たAVRマイクロコントローラのピン番号の実装

アイデアは、AVRチップ上の各I/Oピンを表す整数1からnを持つことです。私は、インデックスは、ピンを表すことになりDDR/PORTレジスタのアドレスへのポインタの配列で開始:

volatile uint8_t *pin_port_dir_regs[] = { 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    &DDRE,   // PIN_7 
    &DDRB,   // PIN_8 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    0,    // NOT USED 
    &DDRB,   // PIN_15 
    &DDRB    // PIN_16 
}; 

volatile uint8_t *pin_port_out_regs[] = { 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    &PORTE,   // PIN_7 
    &PORTB,   // PIN_8 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    0,     // NOT USED 
    &PORTB,   // PIN_15 
    &PORTB    // PIN_16 
}; 

私もDDRX/PORTxレジスタの各ビットの番号を知っておく必要がありますので、私は別の配列を作成しました:

const uint8_t pin_bits[] = { 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(6), // PIN_7 
    _BV(4), // PIN_8 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // NOT USED 
    _BV(0), // PIN_14 
    _BV(1), // PIN_15 
    _BV(3) // PIN_16 
}; 

ピン・モードを設定すると、私は次の関数を作成し、ピンに書き込むには:

void pin_mode(uint8_t pin, uint8_t direction) { 
    // defeference the pointer to the direction register 
    uint8_t port_dir_register = *(pin_port_dir_regs[pin]); 

    // get pin mask 
    uint8_t mask = pin_bits[pin]; 

    // set its mode 
    if (direction == INPUT) { 
     port_dir_register &= ~mask; 
    } else { 
     port_dir_register |= mask; 
    } 
} 

void pin_write(uint8_t pin, uint8_t level) { 
    // defeference the pointer to the output register 
    uint8_t port_out_register = *(pin_port_out_regs[pin]); 

    // get pin mask 
    uint8_t mask = pin_bits[pin]; 

    // set output 
    if (level == LOW) { 
     port_out_register &= ~mask; 
    } else { 
     port_out_register |= mask; 
    } 
} 

起こることになっているものは、あなたが例えばを呼ぶだろうということですpin_mode(7, OUTPUT)を使用してピン7を出力に設定し、次にpin_write(7, HIGH)を使用して出力を1に設定します(OUTPUTおよびHIGHは事前定義されたマクロです)。コードはコンパイルされ、AVRに正常にアップロードされますが、出力をテストすると応答しません。私はメモリの場所に書き込む必要がありますが、目的のレジスタに対応するものではないと思います。誰かが私がこれをやろうとしている方法で問題を参照してくださいか?

uint8_t port_out_register = *(pin_port_out_regs[pin]); 

あなたが特定のアドレスに配置されたハードウェアレジスタへの書き込みをしたい:

+0

なぜgccで提供されているavrの標準ファイルを使用しないのですか?さらに、pin_writeメソッドのようなものでピンの初期化を書くと、progの開始フェーズでのみ多くのコードが無駄になります。これらのすべては、各ピンだけで動作するのではなく、コンパイル時にテンプレートコードによって実行できます。同じジョブに対してddrとportレジスタを一度8回設定しないでください。 – Klaus

+0

@Klaus、どのような標準ファイルを参照していますか?私は自分がしたいことをする既存のコードを認識していませんでした。 また、この段階ではスタートアップの最適化には関心がありませんが、アドバイスをいただきありがとうございます。 – Sean

+0

貴重なRAMとROMのスペースが私にとってかなり浪費しているようです。あなたの質問はここで話題になっていません。私たちはノーディスカッションサイトであり、あまりにも議論の余地があります。編集:申し訳ありませんが、私は最後のsentencを念頭に置いていました。何が間違っているか詳細をご記入ください。 See [ask]。 – Olaf

答えて

1

あなたのコードが動作しない理由理由は、このステップです。これを行うには、次のようにする必要があります。

*(pin_port_out_regs[pin]) = some_value; 

これ以外の場合は、スタックメモリを変更しないでください。

が、この代わりに変更してください:

void pin_write(uint8_t pin, uint8_t level) 
{ 
    uint8_t *port_out_register = pin_port_out_regs[pin]; 
    uint8_t mask = pin_bits[pin]; 

    if (level == LOW) { 
     *port_out_register &= ~mask; 
    } else { 
     *port_out_register |= mask; 
    } 
} 
+0

ありがとうございました! – Sean

2

コメントへの答えとして、私が与えた:

あなたが標準どのようなファイルを参照してくださいか?

avrlibcがインストールされているavr-gccは、使用可能な各コントローラの標準ファイルセットです。

あなたのコードのようなものである場合:

#include <avr/io.h> // automatic include correct io from device like 
        // <avr/iom32u4.h> in your case. That file defines 
        // all registers and pin descriptions and also irq 
        // vectors! 

// So you can write: 
int main() 
{ 
    DDRA= 1 << PA4; // enable output Pin 4 on Port A 
    PORTA= 1 << PA4; // set output Pin4 on Port A high 

    // and normally on startup all needed output pins will be 
    // set with only one instruction like: 
    // To set Pin 2..4 as output 
    DDRA= (1 << PA4) | (1 << PA3) | (1 << PA2); 
} 

関数呼び出しにシンプルPORTA= 1 << PA4を行い、廃棄物がたくさんあります。独自のレジスタ名とピン名を定義することは無意味です。すべてのピンはすでに定義されています。

魔法の定義されたポートのどこかにある論理ポート番号しか持たないという考えは私にはあまり自然ではありません。回路とソフトウェアを設計する場合は、データシートに記載されているようにピンを処理する必要があります。 「論理ピン番号」はありません。

さらに、どのピンにも複数の機能があることを覚えておく必要があります。たとえば、uartsやその他のハードウェアのような複数の機能があります。したがって、別のデバイスに移動すると、ピン/ポートの使用状況についてのレビューが常に必要になります。論理ポート番号は、ハードウェアと本来のソフトウェアの間の複雑な層でもあります。

関連する問題