--/--/--  --:--    スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
先日記述しました、AVRでビット指定する話
あれでは自分で読んでもわかりずらかったので、もうすこしまとめてみます。
最初は先日の内容と一緒なので飛ばしてもらっても構いません。

AVRでは基本的に、PORTやPINなどのレジスタで、1バイトでデータを扱うことができますが、
1ビットでのデータは扱うことができません。
なので、AVRではビット演算を利用して1ビットのデータを扱ってきました。
例)PORT|=_BV(BIT)
  PORT&=~_BV(BIT)
  bit_is_set(sfr,bit)
これをdefineして、
例)#define sbi(PORT,BIT) PORT|=_BV(BIT)
  #define cbi(PORT,BIT) PORT&=~_BV(BIT)
  #define ibi(sfr, bit) (bit_is_set(sfr,bit)?1:0)
sbi(PORTB,PB0)やcbi(PORTD,PD7)のように関数的に1ビットを書き換えていました。
しかし、この場合は0にするにも1にするにも別の関数を使用するため、
もしポートAのビット0にプルアップされたSWが接続されていて、ポートBのビット0のLEDを接続し、
SWが押されていたらLEDを点灯、押されていなかったらLEDを消灯するには以下のようなプログラムになります。
例)
  if(ibi(PINA,PA0)==0){
    sbi(PORTB,PB0);
  }
  else{
    cbi(PORTB,PB0);
  }

これではわざわざif文を使用しなくてはならず、行数も増えてしまいます。
ではもっと簡単に上記の動作をするプログラムを書くにはどうすればいいのかといいますと、
レジスタ自体のビットに直接アクセスし、そこを1か0に書き換えればいいわけです。
ここで、参考にしたのはH8マイコンのヘッダファイルです。
H8マイコンでは構造体と共用体とポインタを使用し、ビットに直接アクセスしています。
例)P1.DR.BIT.B0 = 1;
これでポート1のビット0に1を書き込んでいます。
ヘッダファイルはどうなっているかといいますと、

struct st_p1 {
  unsigned char DDR;
  char wk;
  union {
    unsigned char BYTE;
    struct {
      unsigned char B7:1;
      unsigned char B6:1;
      unsigned char B5:1;
      unsigned char B4:1;
      unsigned char B3:1;
      unsigned char B2:1;
      unsigned char B1:1;
      unsigned char B0:1;
    } BIT;
  } DR;
};
#define P1  (*(volatile struct st_p1  *)0xFFFFC0)

となっています。
説明するのはここでは面倒なので省略します。
構造体と共用体とポインタを使用していることを覚えておいてください。
ではこの方法でAVRでもビットごとにアクセスはできないだろうか?という話です。
というわけで、ヘッダファイルを書いて見ました。

struct st_pa {
  union {
    unsigned char BYTE;
    struct {
      unsigned char B0:1;
      unsigned char B1:1;
      unsigned char B2:1;
      unsigned char B3:1;
      unsigned char B4:1;
      unsigned char B5:1;
      unsigned char B6:1;
      unsigned char B7:1;
    } BIT;
  } PIN;
  unsigned char DDR;
  union {
    unsigned char BYTE;
    struct {
      unsigned char B0:1;
      unsigned char B1:1;
      unsigned char B2:1;
      unsigned char B3:1;
      unsigned char B4:1;
      unsigned char B5:1;
      unsigned char B6:1;
      unsigned char B7:1;
    } BIT;
  } PORT;
};
#define PA  (*(volatile struct st_pa  *)0x39) // PA Address

といった感じで書けばH8のようにビットに直接アクセスできます。
使い方は、下記のとおりです。
例)
  PA.DDR = 0xF0;
  PA.PORT.BYTE = 0x33;
  PA.PORT.BIT.B7 = 1;
  a = PA.PIN.BIT.B0;

DDRは今まで通り、16進数でしか記述できません。
PORT、PINに関してはバイトでもビットでも記述することができます。
以上の書き方で、先ほどのプログラムを書くと、
例)  PB.PORT.BIT.B0 = ~PA.PIN.BIT.B0;
といったように一行で書けてしまいます。
これで便利にプログラムを書くことができますね。

先ほどのAVR用のヘッダファイルの例についてすこし説明したいと思います。
最初に構造体でポートAのレジスタのかたまりをつくります。
struct st_pa{
のところです。
次に、各レジスタの記述をします。
上からみていけば、PINが次にかかれています。
バイトでもビットでもデータを扱いたいので、共用体を使用します。
union{
のところです。
BYTEと書けば普通に1バイトでそのレジスタを扱うことができますが、
BITと書けばビットで扱うようにしたいので、
また共用体の中で構造体を使用します。
しかし、普通に構造体をしようしては、ビットごとにアクセスはできないので、
ビットフィールドを使用します。
ビットフィールドは、例えば通常charで宣言すれば1バイトの領域を使用しますが、
ビットフィールドで記述することにより、必要なビット数だけ使用できるようになります。
例) 
struct{
  unsigned char abc:1;
}ABC;
これでchar型でありながら、1ビットだけ扱うことになります。
詳しくはビットフィールドでググってみてください。
ここで説明すると説明に相当かかなければいけないので。
ここでは、1バイト(8ビット)のレジスタを扱うので、
構造体の中で、ビットフィールドを使用した8つのchar型があります。
これで、そのcharを指定することによって指定したビットだけにアクセスすることができるのです。

ここで、気づいた方もいるかもしれませんが、
H8のヘッダファイルではB7からB0へ降りていくのに対して、
AVRのヘッダファイルではB0からB7へ上昇していきます。
これは、処理する処理系によって、ビットオーダーが違うためです。
H8はビッグエンディアンであるのに対して、
AVRではリトルエンディアンなのです。
なのでもしH8のようにビッグエンディアンで記述してしまうと、自分の思ったビットでは無いビットを間違えて指定してしまいます。
もし自分でこのようなビットフィールドを使用する場合、処理系の特徴にあわせて記述することが必要です。
もし別の処理系から移植する場合は気をつける必要がありますね。

以上のように構造体・共用体・ビットフィールドを使用して、ビットにアクセスしています。
そしてヘッダファイルの最後で、defineを使用し、レジスタのアドレスをポインタで指定しています。


長々書いてしまいましたが、とりあえずもしこの1ビットでデータを扱いたい場合は、
前の記事のヘッダファイルをincludeすれば可能です。
まだATMEGA8515のヘッダファイルしか作ってませんが、
ほかのヘッダファイルもつくっていきたいと思います。
Secret

TrackBackURL
→http://amenotiyukizora.blog76.fc2.com/tb.php/153-d3ca41b0
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。