MCR - Micom Car Rally
大会情報 マイコンカーラリーとは? 今から始めるマイコンカーラリー 技術情報 大会記録 MCRファン倶楽部 お問い合せ
マイコンカーラリートップへ マイコンカーラリートップへ
技術情報 >> R8C/M12A 技術情報
技術情報
各種資料
YouTube情報
R8C/M12A 技術情報
上位入賞マイコンカー
よくある質問(FAQ)
ダウンロード
R8C/M12A 技術情報
LEDの点灯(I/Oポートの出力)

内容
LED 8個を点灯させます。マイコン制御の基礎中の基礎です。

ワークスペース
開発環境を整える」ページからダウンロードしてください。

回路
回路を下図に示します。

回路図

ブレッドボード実装図
ブレッドボードの実装を下図に示します。
ブレッドボード実装図

実習中のブレッドボード
実習中のブレッドボード

プログラムを開く
ワークスペース「r8cm12a_breadboard」のプロジェクト「01led」をアクティブ(有効)にします。「01led」が太字になっていない場合は、右画面のように、「アクティブプロジェクトに設定」してください。   プロジェクトを切り替える
プロジェクト「01led」を有効にする

「led.c」をダブルクリックして、プログラムリストを開きます。

「ビルド→ビルド」して、MOTファイルを作成、「ツール→R8C Writer」でプログラムを書き込んで、実行してください。
  プログラムリストを開く

実行中の動画


プログラムの説明
ポートの入出力設定

R8C/M12Aには、17個の入出力端子があります(ただし、PA_0端子はリセット端子と兼用なので、電源立ち上げ時はリセット端子である必要があります)。R8C/M12Aのピン名を、下記に示します。
R8C/M12A pin

Px_yは、『ポートxのbity』という意味です。R8C/M12Aには、ポート1,3,4,Aがあります。
プログラムの初めに、これらの端子を入力用として使用するか、出力用として使用するかを設定します。リセット後は、入力端子になっています。
考え方は、次のとおりです。
@ディップスイッチなど、外部からの信号をマイコンへ入力する場合、端子を「入力」にします。
ALEDなど、マイコンから外部へ信号を出力する場合、端子を「出力」にします。
※PA_0端子は、リセット後はリセット端子です。通常のポートにするには、プログラムで切り替える必要があります。

入出力方向の設定は、「ポートP○方向レジスタ」で行い、レジスタ名は「PD○」となります。○にはポート番号である、1、3、4、Aが入ります。
ポートP○方向レジスタの設定内容を下記に示します。

■ポートP1方向レジスタ(PD1)の設定
bit 7 6 5 4 3 2 1 0
端子 P1_7 P1_6 P1_5 P1_4 P1_3 P1_2 P1_1 P1_0
設定
内容
1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
1端子
で設定
するとき
の名称
pd1_7 pd1_6 pd1_5 pd1_4 pd1_3 pd1_2 pd1_1 pd1_0

設定内容は、表のとおり、
@出力にしたい端子のbitには"1"を設定します。
A入力にしたい端子のbitには"0"を設定します。
また、未接続や端子が無い場合は、
B未接続の端子は、出力にしておきます。
C端子が無い場合は、"1"にしておきます。

プログラム例を、下記に示します。
    // P1_7を入力、その他を出力にしたい場合(0111 1111を設定)
    pd1 = 0x7f;  // 0x○○で、16進数
※プログラムでは、レジスタ名を小文字にします。大文字だとエラーになります。

R8Cのコンパイラは、「0b○○○○○○○○」とすると、2進数で指定することもできます(C言語の正式な表記ではありません)。
    // P1_3〜P1_0を入力、その他を出力にしたい場合(1111 0000を設定)
    pd1 = 0b11110000;  // 0b○○○○○○で、2進数

■ポートP3方向レジスタ(PD3)の設定
bit 7 6 5 4 3 2 1 0
端子 P3_7 - P3_5 P3_4 P3_3 - - -
設定
内容
1:出力
0:入力
- 1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
- - -
1端子
で設定
するとき
の名称
pd3_7 - pd3_5 pd3_4 pd3_3 - - -

■ポートP4方向レジスタ(PD4)の設定
bit 7 6 5 4 3 2 1 0
端子 P4_7 P4_6 P4_5 - - P4_2 - -
設定
内容
1:出力
0:入力
1:出力
0:入力
1:出力
0:入力
- - 1:出力
0:入力
- -
1端子
で設定
するとき
の名称
pd4_7 pd4_6 pd4_5 - - pd4_2 - -

■ポートPA方向レジスタ(PDA)の設定
bit 7 6 5 4 3 2 1 0
端子 - - - - - - - PA_0
設定
内容
- - - - - - - 1:出力
0:入力
1端子
で設定
するとき
の名称
- - - - - - - pda_0

ポートの入出力設定は、init関数(initialize(初期化)の略)で設定しています。今回の入出力設定を下記に示します。
  48 :  void init( void )
  49 :  {
  50 :      /* ポートの入出力設定 */
  51 :      pd1 = 0xff;           /* ポート1の入出力設定  */
  52 :      pd3 = 0xff;           /* ポート3の入出力設定  */
  53 :      pd4 = 0xff;           /* ポート4の入出力設定  */
  54 :      pda = 0xff;           /* ポートAの入出力設定  */
  55 :  }

■1端子毎に入出力設定する
ポートごとの設定では、複数の端子をいっしょに設定する必要があります。1端子毎に入出力設定することもできます。この場合、「pdx_y=0(入力) or 1(出力) (x=ポート、y=端子)」と指定すると、1端子毎に設定することが出来ます。
    // P1_3端子を入力に設定
    pd1_3 = 0;

出力端子から"0"(0V)または"1"(5V)を出力

電圧の出力は、「ポートP○レジスタ」で行い、レジスタ名は「P○」となります。○にはポート番号である、1、3、4、Aが入ります。
ポートP○レジスタの設定内容を下記に示します。
@端子から"1"(5V)を出力したい場合は、"1"を設定します。
A端子から"0"(0V)を出力したい場合は、"0"を設定します。
B入力端子は、"0"、"1"のどちらを設定しても構いません。
C端子が無い場合は、"0"を設定します。

■ポートP1レジスタ(P1)の詳細
bit 7 6 5 4 3 2 1 0
端子 P1_7 P1_6 P1_5 P1_4 P1_3 P1_2 P1_1 P1_0
設定
内容
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1端子
で設定
するとき
の名称
p1_7 p1_6 p1_5 p1_4 p1_3 p1_2 p1_1 p1_0

例えば、P1から次の電圧を出力することとします(PD1=0xffの状態とします)。
bit P1_7 P1_6 P1_5 P1_4 P1_3 P1_2 P1_1 P1_0
出力値 1 0 1 0 0 1 0 1

このとき、下記のプログラムを実行します。
    p1 = 0xa5;  // P1に0xa5(0b10100101)を出力する

■ポートP3レジスタ(P3)の詳細
bit 7 6 5 4 3 2 1 0
端子 P3_7 - P3_5 P3_4 P3_3 - - -
設定
内容
1:5V出力
0:0V出力
- 1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
- - -
1端子
で設定
するとき
の名称
p3_7 - p3_5 p3_4 p3_3 - - -

■ポートP4レジスタ(P4)の詳細
bit 7 6 5 4 3 2 1 0
端子 P4_7 P4_6 P4_5 - - P4_2 - -
設定
内容
1:5V出力
0:0V出力
1:5V出力
0:0V出力
1:5V出力
0:0V出力
- - 1:5V出力
0:0V出力
- -
1端子
で設定
するとき
の名称
p4_7 p4_6 p4_5 - - p4_2 - -

■ポートPAレジスタ(PA)の詳細
bit 7 6 5 4 3 2 1 0
端子 - - - - - - - PA_0
設定
内容
- - - - - - - 1:5V出力
0:0V出力
1端子
で設定
するとき
の名称
- - - - - - - pa_0

■1端子毎に電圧を出力する
1端子毎に電圧を出力することもできます。この場合、「px_y=1(5V出力) or 0(0V出力) (x=ポート、y=端子)」と指定すると、1端子毎に状態を出力することができます。
    p3_7 = 1;   // P3_7端子から5Vを出力

入力端子の入力電圧(0Vか5Vか)を確認する

ポートの入出力設定で入力に設定した端子の電圧(0Vが入力されているのか、5Vが入力されているのか)を確認するには、、「ポートP○レジスタ」で行い、レジスタ名は「P○」となります。○にはポート番号である、1、3、4、Aが入ります(出力と同様です)。
ポートP○レジスタから読み出される値を下記に示します。
@端子に5Vが入力されているなら、"1"が読み込まれます。
A端子に0Vが入力されているなら、"0"が読み込まれます。
B出力端子を読み込むと、現在出力している状態が読み込まれます。
C端子が無い場合は、不定("0"か"1"か分からない状態)が読み込まれます。

例えば、P1には次の電圧が入力されているとします(PD1=0x0fの状態とします)。
bit P1_7 P1_6 P1_5 P1_4 P1_3 P1_2 P1_1 P1_0
入出力 5Vが
入力
5Vが
入力
0Vが
入力
0Vが
入力
0Vを
出力
0Vを
出力
5Vを
出力
5Vを
出力
読み込んだときの値 1 1 0 0 0 0 1 1

このとき、下記のプログラムを実行したとします。
    unsigned char c;
中略
    // P1の状態を読み込み
    c = p1;   // cには0xc3(0b11000011)が代入される
※プログラムでは、レジスタ名を小文字にします。大文字だとエラーになります。

■端子毎に状態を入力する
端子毎に入力状態を確認することもできます。この場合、「px_y (x=ポート、y=端子)」と指定すると、端子毎に設定することが出来ます。
    // P4_3端子の状態を確認
    c = p4_3;   // 0Vが入力されていたら、c=0
                // 5Vが入力されていたら、c=1

タイマ

下記のプログラムを実行したとします。
    while( 1 ) {
        p1 = 0xff;  // ←実行時間:数us
        p1 = 0x00;  // ←実行時間:数us
    }

0xff(P1のbit7〜0のLED点灯)と、0x00(P1のbit7〜0のLED消灯)を繰り返すはず・・・ ですが、ずっとLEDが点灯しているように見えます。実際には、点灯、消灯を繰り返しているのですが、1行の実行時間は数μsなので、人間には速すぎて見えないのです。よって、「p1 = 0xff;」を実行した後と、「p1 = 0x00;」を実行した後に、実行を一時停止するタイマを入れます(ここでは例として1秒で説明します)。プログラムの考え方を下記に示します。
    while( 1 ) {
        p1 = 0xff;  // ←実行時間:数us
        1秒間、この行で停止
        p1 = 0x00;  // ←実行時間:数us
        1秒間、この行で停止
    }

この、「○秒間、この行で停止」を実現するのがtimer関数です。timer関数を下記に示します。
  61 :  void timer( unsigned long timer_set )
  62 :  {
  63 :      int i;
  64 :
  65 :      do {
  66 :          for( i=0; i<871; i++ ); ←これで1ms間の時間稼ぎ
  67 :      } while( timer_set-- );  ←66行をtimer_set回、繰り返す
  68 :  }

timer関数は、何もしないことを繰り返して、時間稼ぎをします。使い方は「timer( 時間 );」で、時間はミリ秒単位で指定します。1秒なら、「timer( 1000 );」とします。

メインプログラム

led.cのmain関数のプログラムを、下記に示します。
  31 :  void main( void )
  32 :  {
  33 :      init();                 /* 初期化 */
  34 :
  35 :      while( 1 ) {
  36 :          p1 = 0b00001111; ←LEDに出力
  37 :          timer( 1000 );   ←1000msの時間稼ぎ
  38 :          p1 = 0b11110000; ←LEDに出力
  39 :          timer( 1000 );   ←1000msの時間稼ぎ
  40 :          p1 = 0b00000000; ←LED 全消灯
  41 :          timer( 1000 );   ←1000msの時間稼ぎ
  42 :      }
  43 :  }

ポート1に接続されているLED 8個を1秒間「0000 1111」で点灯、1秒間「1111 0000」で点灯、1秒間全消灯」、これを無限ループで繰り返します。

課題
1.次のパターンで点灯するプログラムを書きなさい。(1…点灯 0…消灯)

@ 「1000 0001」を0.5秒点灯
A 「1100 0011」を0.5秒点灯
B 「1110 0111」を0.5秒点灯
C 「1111 1111」を0.5秒点灯
D 「0000 0000」を1秒点灯
E @に戻って繰り返す

2.次のパターンで点灯するプログラムを書きなさい。(1…点灯 0…消灯)

@ 「0000 0001」を0.2秒点灯
A 「0000 0010」を0.2秒点灯
B 「0000 0100」を0.2秒点灯
      :
G 「1000 0000」を0.2秒点灯
H @に戻って繰り返す

3.for文を使って、0〜255をカウントするループを作り、カウント値をLEDに出力するプログラムを作りなさい。出力する間隔は、0.2秒とする。また、255の次は0に戻って、出力し続けるものとする。

4.for文を使って、2番目の課題と同じ動作をするようにプログラムを作りなさい。
 ヒント:10進数にすると点灯する値は、1、2、4、8・・・ となる

課題の回答例
1.の回答例
led_answer_1.c

2.の回答例
led_answer_2.c

3.の回答例
led_answer_3.c

4.の回答例
led_answer_4.c

BACK