入出力

とりあえず,一番単純な入出力の説明です. 入力のため,前回の回路にスイッチ(ボタン)を付けてみます.

circuit02.png

ポート

今回使う,ATMEGA88というAVRは,28本の足があって,そのうち22本を プログラムから操作できます(本当はもう1本あるがリセットに使っている). また,ピン8本がセットになった「ポート」というものを1単位として操作します. MEGA88にはB,C,Dの3つのポートがあります.

入出力のために3種類のレジスタ(C言語でいう変数)を使います. 「x」の部分にはポート名が入ります.

  • DDRx 入出力切り替え
  • PORTx ピンに出力する値
  • PINx ピンから入力された値

それぞれのピンは,入力と出力の両方に使えます. ただし,入力と出力は同時にできないので,モードを切り替える必用があります. DDRxというレジスタに数値を書き込むことで設定できます.

DDRxのビットが「0」のピンは入力,「1」のピンは出力になります.

レジスタは8ビットなので,下位から順にポートの0〜7番目のピンに対応します. 例えば,PORTBに書き込むと,ピンPB0〜PB7に反映されます.

出力の方法

PORTxというレジスタに値を書き込むと,0ならばL,1ならばHがピンから出力されます. これも,「x」の部分にはポート名が入ります.

ポート単位で操作するので,書き込む値は8ビットの整数となります.

2進数の表記法

おまけとして,C言語で数字を2進数で表記する方法. ただし,必ず使えるわけでは無いので普段は使わないようにしてください.

数値の前に「0b」を付けると2進数とみなされます.

例: &plain{ a = 0b11111111; &}

「a = 255;」 や 「a = 0xFF」と同じ結果になります.

この機能は,Cの標準ではありません.

入力の方法

PINxというレジスタで,ピンに入力されている電圧がHかLかが分かります. 入力がLだと0,Hだと1が得られます.

ビット演算

マイコンのプログラムでは,1つの変数に複数の情報を持たせることが頻繁にあります. 必用なビットを取り出すためには,ビット演算子の「&」を使います.

  • PC0がHのとき → (PINC&1) = 1
  • PC0がLのとき → (PINC&1) = 0
  • PC1がHのとき → (PINC&2) = 2
  • PC1がLのとき → (PINC&2) = 0

一度に複数のビットを見ることもできます.

  • PC0:H PC1:H → (PINC&3) = 3
  • PC0:L PC1:H → (PINC&3) = 2
  • PC0:H PC1:L → (PINC&3) = 1
  • PC0:L PC1:L → (PINC&3) = 0

内部プルアップ

何も繋がっていないピンの入力の値は何になるでしょうか?

何も繋がっていないので,ピンの電位は不定です. つまり,ポートの内容を読んでも0になるか1になるか分かりません.

これは,スイッチのON/OFFを読み取るときに面倒になります. 切り替えスイッチで,ピンに繋がる回路をGNDとVccとで切り替えることも 可能ですが,非効率的です.

普通は,プルアップ抵抗で入力をプルアップしておきます. そして,スイッチがONになった時に,GNDに落ちるようにしておくのが普通です.

AVRのピンには内部にプルアップ抵抗を持っていて,使う・使わないを選択できます.

DDRxでピンを入力に設定している状態でPORTxのビットに1を書き込むと プルアップ抵抗が有効になります.

サンプルプログラム

入出力をするためには「avr/io.h」をインクルードします. 入出力が無いプログラムは殆どあり得ないので, 何も考えずにこのヘッダファイルはインクルードしておきましょう.

「util/delay.h」は一定時間待つためのループが含まれています. 使うためには,F_CPUマクロでクロック周波数を指定しておく必要があります. _delay_ms()関数は長い時間待てないので,自分でdelay_ms()を定義しています.

   #define F_CPU 8000000
   #include <avr/io.h>
   #include <util/delay.h>
   
   void delay_ms(uint16_t t) {
      while (t--) _delay_ms(1);
   }
   
   int main()
   {
       DDRD = 0b11111111; // PD0〜PD7を出力に
       DDRC = 0b00000000; // PC0〜PC5を入力に
       PORTC= 0b11111111; // 内部プルアップON
   
       DDRD=0x0F;
       for(;;) {
           delay_ms(100); // 少し待つ
           if ( (PINC&1)==0 ) { // SW1が押されている
               PORTD = 0b00000011; // ON
           } else { // 押されていない
               PORTD = 0b00000000; // OFF
           }
       }
   }
total: 8308  / today: 1  / yesterday: 0  / now: 1

添付ファイル: filecircuit02.png 275件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-09-22 (火) 17:26:03 (1307d)