006回
選択肢


・選択肢

さて、これまでのプログラムで繰り返し動作、LEDのON/OFFを行うことが出来るようになった。
しかし、あくまでも内部的な命令によるものであり、外部からの入力に対しての反応はまだ行えていない。
そこで、外部入力に対応するためにはどういったプログラムを組めば良いかを書きます。
回路部分に関しては省略。


・if文 その1

C言語触ってる人には今更ながらの説明ですが、英語のif〜(もし〜だったら)と同じ感覚で使えます。↓

if(〜〜〜)

この( )内に色々と条件を入れてやればOKです。

考えられる条件としては
「どこかのスイッチが入った」とか「X回この動作を行った」とかです。

取りあえず、前回のプログラムを元に「10回この動作を行ったら終了」を表現するならば、

void main (void)
{

   PORTB=0xFF;      //PORTBを使用するという宣言
   TRISB=0x00;       //PORTBを出力端子として使用するという宣言
   PORTB=0x00;      //PORTBの初期出力が0であるという宣言

   char i;

   i=0;

   while(1)
   {

      if(i==10)break;

      PORTB|=0x20;      //RB5から出力
      Wait(2000);        //2秒間待つ
      PORTB&=0xDF;     //RB5のみ出力を0に
      Wait(2000);        //2秒間待つ

      i=i+1;

   }
}

↑そんな訳で、こんな感じになるはずです。
while使わずに10個同じ文を書けば実現できますが、流石にその方法はスマートじゃないです。
他の方法もあるのですが、また今度。




取りあえずそれぞれ説明しますか、まず

   char i;

これは、C言語の中で数字を扱う際に使われる表記です。
charっていう型の i ってやつを宣言した事になります。
すると、今後プログラムの中で出てくる i って文字は数字として扱う事が出来るわけです。

因みに char の他にも色々と種類があって、以下に記す通り。
Pic使用時に良く使うのはintとcharかな?

char 1byte(8bit)整数
int 2byte(16bit)整数
long 4byte(32bit)整数
float 4byte(32bit)実数 小数の使用可
double 8byte(64bit)実数 小数の使用可

charを使った事によって、8bit(=2~8=256→±127)までの数を数える事が出来ます。
今回は10までしか数えないので十分ですな。

   i=0;

と表記する事によって、 i に0を入れて、初期値を0にするわけです。
最初に何らかの値を入れてあげないと、何が入っているか分からないので注意が必要ですよん。



お次は

      if(i==10)break;

これまた最初にちょっと説明したけど、C言語の「=」は=の右側の値を左側へ与えるといった意味。
「==」は、数学上の「=」と同じ意味。
よって、この文の場合、i が10になったらbreakするという事。
breakとは、今自分がいる中括弧{ }内から抜け出すという事。つまりwhileから抜けるってわけ。

      i=i+1;

数学的にはありえない式。でも、C言語だからOK♪
i(右) に 1 を足してi(左)に代入。って事。
つまり、i の初期値が0だから、0+1をi に入れて、i を1にするわけ。
2週目はi に1が入っているので1+1となりi に2が入る。
こんな感じです。

慣れた人は

      i++;

と書いてる筈。効果は同じです。



ちょっとごちゃごちゃしたかも知れないので、言葉でプログラムの流れを見てみましょうか。
※whileの中だけ

i が10かどうかをチェック → i = 0なので何も無し

2秒光って2秒消える(1回目)

i に1を足す → i = 1になる

i が10かどうかをチェック → i = 1なので何も無し

・・・中略

i が10かどうかをチェック → i = 9なので何も無し

2秒光って2秒消える(10回目)

i に1を足す → i = 10になる

i が10かどうかをチェック → i = 10なのでbreakしてwhile文を抜ける

END

・・・とまぁ、こんな感じです。



・if文 その2

今度は、外部から何らかの入力があった場合に関して。



・スイッチを使おう!

外部からの入力を伝えるものとして、適当だと思われるのがスイッチ類である。
ここで簡単に種類と効果について説明する。

ラッチ系
一度スイッチを押したら手を離してもONになっているスイッチのこと。
マシンの電源とかに使われている。
カタログとかでは「ON-OFF」のように表記されている。

モーメンタリ系
スイッチを押している間だけONになっているスイッチ。
プッシュ、マイクロスイッチがこのタイプ。
タッチセンサとかに使われている。
カタログとかでは「(ON)-OFF」のように、()で括られている。

まぁ、どちらを使うかは用途によりけりである。

今回は電源から5Vを持ってきてそれをプルアップ、プルダウンするなりして回路に接続する。

・初期設定

そんな訳で初期設定。

#__config 0x3F3A
#include <P16F877.h>
#include <Datalib.h>
#include <Delays.h>

void main(void)
{
  PORTB=0xFF; TRISB=0x00; PORTB=0x00;
  PORTC=0xFF; TRISD=0xFF; PORTD=0x00;
 

}

 まぁ、見てもらえば分かると思うけど、001でちょこっと説明したように、TRISDが0xFFになってますね。
って事はPORTDは全て1に設定された訳で、入力ピンとして使用されます。
あと、877↓になったのでconfigワードがちょっと変更されています。

PIC16F877
MCLR/Vpp/THV -| 1 40 |- RB7/PGD
RA0/AN0 -| 2 39 |- RB6/PGC
RA1/AN1 -| 3 38 |- RB5
RA2/AN2/Vref- -| 4 37 |- RB4
RA3/AN3/Vref+ -| 5 36 |- RB3/PGM
RA4/T0CKI -| 6 35 |- RB2
RA5/AN4/SS -| 7 34 |- RB1
RE0/RD/AN5 -| 8 33 |- RB0/INT
RE1/WR/AN6 -| 9 32 |- Vdd
RE2/CS/AN7 -| 10 31 |- Vss
Vdd -| 11 30 |- RD7/PSP7
Vss -| 12 29 |- RD6/PSP6
OSC1/CLKIN -| 13 28 |- RD5/PSP5
OSC2/CLKOUT -| 14 27 |- RD4/PSP4
RC0/T1OSO/T1CKI -| 15 26 |- RC7/RX/DT
RC1/T1OSI/CCP2 -| 16 25 |- RC6/TX/CK
RC2/CCP1 -| 17 24 |- RC5/SDO
RC3/SCK/SCL -| 18 23 |- RC4/SDI/SDA
RD0/PSP0 -| 19 22 |- RD3/PSP3
RD1/PSP1 -| 20 21 |- RD2/PSP2


そんな訳で、RD7番ピンに何らかの入力があった場合↓

#__config 0x3F3A
#include <P16F877.h>
#include <Datalib.h>
#include <Delays.h>

void main(void)
{
  PORTB=0xFF; TRISB=0x00; PORTB=0x00;
  PORTD=0xFF; TRISD=0xFF; PORTD=0x00;
 
  while(1)
  {
   if((PORTD&0x80)==0x80)
   {
    PORTB|=0x20;
    Wait(2000);
    PORTB&=0xDF;
    Wait(2000);
   }
   
  else if((PORTD&0x80)==0x00)
   {
    PORTB|=0x20;
    Wait(1000);
    PORTB&=0xDF;
    Wait(1000);
   }
  }
}



   if((PORTD&0x80)==0x80)
ピン PORTD=0x80
8 0
1 0 0 0 0 0 0 0
RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0
入力 0x80
8 0
1 0 0 0 0 0 0 0

とまぁ、RD7ピン(PORTD&0x80)に電圧がかかっている場合の表記。
取りあえずここにプルアップで電圧をかけておき、通常状態にしておく。
この条件が満たされているのなら、以下に続く{  }内の動作を行う。
つまりこの場合、今までと同じ動作をするわけです。

因みにif( )break;の様にbreakを使う場合は最後に ; が必要だが、
if( )の場合は ; は不用。


お次は

  else if((PORTD&0x80)==0x00)

else ifってのは、同じ{ }内でif文を書く際に2つ目以降のif文に使うモノ。

ピン PORTD=0x80
8 0
1 0 0 0 0 0 0 0
RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0
入力 0x80
0 0
0 0 0 0 0 0 0 0

RD7ピンに電圧の入力がなければこっちのif文に入るわけですな。
入力がないって事でピンを繋がなくてもよさそうですが、ノイズとか乗ると誤動作しなくもないんで、きちんとプルダウンでアースに繋いでおきましょう。



入力信号とかは、直接電源やらアースやらより持ってきてもOKなのですが、きちんと抵抗でプルアップ・ダウンしておいたほうが良いかと思われ。
特に、スイッチで電圧の有無を感知させる場合は、間違って電源とアースが直接接続になってしまったりするので気をつけましょう。

あー、因みにプルアップ・ダウンってそれぞれ抵抗を使って電源、アースに繋ぐ事。

同じようにelse if( )と続けば、いくらでも条件分岐できる訳です。



・複合

さて、これでスイッチによる制御が出来るようになったのですが、まだまだ完全とは言えません。
if文表記には色々と有るわけです。

色々↓

1つの条件対して( )1つです。

== 右と左が同じ時 if(i==10)
< 右より値が下の時 if(i<10)
<= 右の値以下の時 if(i<=10)
> 右より値が大きい時 if(i>10)
>= 右の値以上の時 if(i>=10)
|= 右の値じゃない時 if(i|=10)
&& 右と左を満たした時 if(((PORTD&0x80==0x80)&&(i<=10))
|| 右か左を満たした時 if(((PORTD&0x80)==0x80)||(i<=10))

とまぁこんな感じ。色々と条件を加えていくと( )の位置が複雑になったりするんで、きちんと確認しましょう。



言葉で言ってもちょっとアレなんで、何度か自分で試してみて身につけましょう。


[戻る]