第24回 スイッチ制御のプログラムを追加する

今回はスイッチ押すと点滅を開始するようにプログラムを作成して動作確認してみます。

本シリーズ記事の内容を改訂して、基礎編、応用編、実践編として以下のリンクに公開しています。以下のシリーズはさらにいろいろなPICマイコンの機能をご紹介しています!
PICマイコン電子工作入門 〜基礎編〜
PICマイコン電子工作入門 〜応用編〜
PICマイコン電子工作入門 〜実践編〜

目次

今回の説明

発光ダイオード点滅回路を完成させるために以下の順序で説明しています。このエントリの説明は(5)「ベース回路にスイッチを追加」の部分になります。

  1. 発光ダイオード(LED)を電池と抵抗のみで光らせる回路を組む
    PICマイコンの回路を組む前に、まずは電池、抵抗、発光ダイオードのみを使って、ブレッドポード上に回路を組んで発光ダイオードを光らせてみます。ここでは電池、抵抗、発光ダイオードの回路記号、回路図と、回路図からブレッドボードに組む方法を説明します。
  2. PICマイコンのベース回路を組む
    はじめの一歩の回路は、発光ダイオードを1秒に1回光らせるだけの回路です。この回路を組みます。
  3. プログラムを作る
    発光ダイオードを1秒に1回光らせるプログラムを作成します。
  4. PICマイコンに書き込んで動作させる
    作成したプログラムをPICマイコンに書き込んで動作させてみます。
  5. ベース回路にスイッチを追加
    発光ダイオードの点滅をスイッチで開始させるために、ベース回路にスイッチを追加します。これまでは発光ダイオードを光らせる、という出力制御をしましたが、PICマイコンで外部から信号を入力する方法を確認します。
  6. ベース回路にブザーを追加
    スイッチ付きの1秒に1回光らせる回路を作りましたので、ブザーを追加してタイマーを作ってみます。

ベースプログラム変更概要

発光ダイオードの点滅制御プログラムの構成をもう一度確認してみます。

Prog structure

このような構成でしたよね。これからスイッチの処理を追加しますが、何をどう直して何をどこに追加すればいいのでしょうか。

まずはじめのコメント部分ですが、これからベースのプログラムを編集していきますので、どのような機能を入れたかメモしておくことにします。

次にヘッダファイルインクルード部分ですが、スイッチの状態検知などPIC12F683の基本的な制御については xc.h のインクルードだけで問題ありませんので特に変更は必要ありません。

PICマイコンコンフィグレーション設定ですが、こちらも特にPICマイコンの振る舞いを変えませんので、特に変更は必要ありません。例えば、内部クロックから外部クロックに変更するとか、MCLRピン(4番ピン)に外部リセットスイッチを付けるなどという場合はこのコンフィグレーション設定をその変更に合わせて編集する必要があります。

その他設定部分についても特に追加はありません。

ということで、スイッチ制御するにはほぼメイン関数内のプログラム変更となります。それでは次にメイン関数をどのように修正すればよいかざっと把握しておきましょう。

Main block

内部クロックは特に変更しませんのでこのままです。

ピンの設定ですが、ベースのプログラムはすべてのピンを「デジタル」で「出力」に設定しました(MCLRピン/4番ピンは入力固定です)。今回はGP4ピン(3番ピン)を「入力」にしたいので、この部分は変更が必要になりますよね。具体的には「GP4ピンを入力」に変更します。

残りの「ピンの初期設定」と「動作処理」はいろいろと変える必要がありそうですよね。この動作処理の変更については以下、順を追って詳しく説明します。

ということで、このあと、以下の内容を詳しく説明します。

  • 動作仕様の決定
  • ピンの設定部分変更
  • ピンの初期設定部分変更
  • 動作処理部分変更

動作仕様の決定

ベース回路は電源を供給するとすぐに点滅を開始させていました。今回はスイッチをつけて、スイッチが押されたら点滅を開始する、というように変更します。動作仕様は何通りか考えられますが、点滅を開始するまえは、発光ダイオードは点灯しておきたいと思います。電源を供給しても、発光ダイオードが消灯したままですと、動いているのかよくわからないですよね。ということで点滅を開始するまでは「ちゃんと電源がきていて、プログラムも動いていますよ」ということを示すために、発光ダイオードの初期状態は点灯状態にしておこうと思います。その状態でスイッチが押されたら点滅を開始する、という動作仕様にします。

これを図にまとめると以下のようになります。

Control sequence

ピンの設定部分変更

それではメイン関数を編集していきましょう。まずピンの設定部分ですが、ベースプログラムでは、内部クロックの設定(OSCCON)、アナログ/デジタル設定(ANSEL)、入出力設定(TRISIO)の設定をしています。内部クロックはそのまま1MHz、アナログ/デジタル設定もすでに全ピンデジタル設定にしてありますので変更なしです。今回、GP4ピン(3番ピン)を入力に変更します。TRISIOは現在以下のように設定しています。

Trisio current

出力ピンにしたいときはそのピンのビットを0、入力ピンにしたいときは1にすればよいので、GP4のビットを1にします。具体的には以下のような設定になります。

Trisio gp4

ビット表現では、0b00010000になりますので、16進数では0x10となります。ということで、TRISIOは

TRISIO = 0x00;

から

TRISIO = 0x10;

に変更すればOKです。これでGP4ピン(3番ピン)は入力ピンに設定できました。

ピンの初期設定部分変更

次にピンの初期設定部分です。今回はスイッチが押されるまで、発光ダイオードを点灯しておく動作仕様としました。現在は電源投入直後は発光ダイオードを消灯しておくようにしています(GP5=0;)。これを点灯するように変更します。現在の

GP5 = 0;

から

GP5 = 1;

に変更すればOKです。

動作処理部分変更

このままですと、次の点滅処理が始まってしまいます。スイッチが押されてから点滅処理を開始するように変更すればよいので、今の点滅処理の前に、スイッチが押されるまで、何もしないでずっと待ち続けれる処理を追加すればいいですよね。

まず、スイッチの状態はGP4という変数(レジスタ)に格納されます。GP4ピンが0Vのときは0、5V(電源電圧)のときは1がリアルタイムに格納されます。スイッチが押されるまで何もしない、ということは、変数GP4が0の間は次に進まないでずっと待ち続ける、というプログラムを書けばよいことになります。これは以下のようなプログラムを追加すればOKです。

while(GP4 == 0) {
}

またスイッチが押されたら点滅を開始しますが、発光ダイオードは消灯の状態から始まります。そのため、スイッチが押された後は発光ダイオードを消灯する必要があります。そのため、上のwhile文の後にGP = 0;を追加します。

完成したプログラム

これで一通り変更できましたので、コメントに現在のプログラム内容をメモして完成です。以下は完成したプログラムです。コメントを入れましたので、処理の流れをよく確認してみてくだい。

理解したらこのプログラムをビルドして書き込み、動作確認してみましょう。一発で動かないこともあるかもしれません。その場合は諦めずに、ひとつひとつ問題がないか確認していきます。どうしてもわからない場合はコメント欄かCONTACTページからご連絡いただければ、一緒に考えてみたいと思います。

/*
 * File:   main.c
 * Author: Tool Labs
 * プログラム内容:
 *   電源投入後はスイッチ(GP4)が押されるまで
 *   発光ダイオード(GP5)を点灯、スイッチが押されたら
 *   点滅を開始する。
 */


// インクルードファイル
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// PIC12F683コンフィグレーションビット設定
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)

// クロック周波数指定
// (__delay_ms()関数が必要としているため)
#define _XTAL_FREQ  1000000

/*
 * main()関数
 */
int main(int argc, char** argv) {

    // PICマイコン初期化
    OSCCON = 0x40;  //クロック周波数を1MHzに設定
    ANSEL  = 0x00;  //すべてのピンをデジタルモードに設定
    TRISIO = 0x10;  //GP4を入力ピン、それ以外を出力ピンに設定。ただしGP3ピンはもともと入力固定

    // LEDのピン(GP5)を1にして、LEDを点灯させる
    GP5 = 1;

    // スイッチ(GP4)がOFFの間、何もしないで待ち続ける
    while(GP4 == 0){
    }

    // スイッチが押されたら、上のwhileループを抜けるので、LEDの点滅を開始する
    // まずはじめにLEDのピン(GP5)を0にして、LEDを消灯する
    GP5 = 0;

    // 点滅を永遠繰り返す
    while(1){
        // まず、消灯状態のまま950ミリ秒待つ
        __delay_ms(950);
        // 950ミリ秒経過したら、LEDのピンを1にして、LEDを点灯する
        GP5 = 1;
        // LED点灯状態で50ミリ秒待つ
        __delay_ms(50);
        // 50ミリ秒経ったら、LEDのピンを0にして、LEDを消灯する
        GP5 = 0;
    }

    // ここには到達しない
    return (EXIT_SUCCESS);
}

このあとの説明

スイッチの処理、思ったより簡単でしたよね。ねっ。スイッチに接続したピンに対応する変数(この場合はGP4)には現在のスイッチ状態に応じた値が入っていますので、それをみて必要な処理をすればいいだけです。

と、大半の方が感じると思うのですが、実は、スイッチには根深い問題があります。この根深い問題については後で詳しく説明します。おそらくげんなりすると思います。でもスイッチのことを嫌いにならないでくださいね。

更新履歴

日付 内容
2015.9.22 新規投稿
2018.12.3 新シリーズ記事紹介追加
通知の設定
通知タイミング
guest
10 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
aaa
aaa
2 年 前

お世話になります
例文を弄って点滅の個所にこのようなコードを入れて
点滅のON/OFFを切り替えたりしたのですが、4,5回に一回位しか反応しません
原因は何なのでしょうか?
何か他に方法有れば教えてください

if(GP4==1 && c==0){
    c=1;   
}
else if(GP4==1 && c==1){
    c=0;   
}
if(c==0){
    __delay_ms(1000);
}
最終更新日 2 年 前 ( 管理者 )
aaa
aaa
返信  管理者
2 年 前

返信ありがとうございます
待ち関数が動いている時に作動しないので
950m秒以上押し続けてOFFの機能が限界の様な気がしました
ONは50m秒待ちなので押し続けなくても失敗しないです
半導体の方は殆ど意味が分からないんですが(特に電流の流れなど複雑で)
プログラムで何となく理解した様な気持ちになれますね

while(1){
    if(GP4==1&&c==0){c=1;__delay_ms(1000);}
    if(GP4==1&&c==1){c=0;__delay_ms(1000);}
    if(c==0){
    // まず、消灯状態のまま950ミリ秒待つ
    __delay_ms(950);
    // 950ミリ秒経過したら、LEDのピンを1にして、LEDを点灯する
    GP5 = 1;
    }

aaa
aaa
返信  aaa
2 年 前

追記で、
GP4のスイッチのON/OFFの制御は電流が流れたかどうかの有無で
GP4ピンに戻って判定しているという理解で良いんでしょうか?

aaa
aaa
返信  管理者
2 年 前

数値の電流じゃなくて電子の流れです
電子の流れが視覚化できればそこまで難しい事を
してないと思うんですよね

aaa
aaa
返信  管理者
2 年 前

待機時間を更に細分化とは思いつきませんでした
これならどのタイミングでもON/OFF出来そうです

目次