第25回 スイッチ制御プログラム

今回はスイッチを制御するプログラムを作成します。

目次

今回の説明

PICマイコン電子工作入門の基礎編は、次のステップで説明しています。

この記事の説明は「❺ ベース回路にスイッチを追加」のうち、「スイッチ制御のプログラム作成」を説明します。

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

動作仕様検討

スイッチを制御するプログラムを作成する前に、動作仕様を検討します。

スイッチの役割

今までのプログラムでは。電源をONにするとすぐに点滅を開始していました。

タイマーとして動作させたいため、動作仕様としては「スイッチを押したらLEDの点滅を開始する」ようにしたいと思います。

LEDの役割

「スイッチを押したらLEDの点滅を開始する」という動作は問題ないと思いますが、スイッチを押すまでLEDをどうするかも考えておきたいと思います。

電源をONにしてもLEDが消えた状態のままですと、プログラムが動いているのかよくわからないですよね。

そこで、スイッチを押すまでは「ちゃんと電源がきていて、プログラムも動いていますよ」ということを示すために、LEDの初期状態は点灯状態にしておこうと思います。

その状態でスイッチが押されたら点滅を開始する、という動作仕様にします。

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

Pic basic 25 time chart

念のため補足しておきます。

スイッチはプルアップ抵抗を接続しましたので、スイッチがOFFの場合はRA3ピンは5V、スイッチをONにすると0Vになります

プルアップ抵抗の場合は普通のイメージと逆になりますので注意します。

プログラム変更概要

最初に、LEDの点滅制御プログラムの構成をもう一度確認しておきます。

このような構成でしたよね。

これからスイッチの処理を追加しますが、どこをどう変更するか最初に概要を検討しておきます。

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

「❷ ヘッダファイルインクルード」、「❸ PICマイコンコンフィグレーション設定」、「❹ その他設定」は変更ありません。

「❺ メイン処理」は、「スイッチを押したら点滅を開始する」という処理がありませんので、この処理の追加が必要です。

このメイン処理をどのように修正すればよいかざっと把握しておきましょう。

動作仕様の検討では、「LEDの初期状態をON」、「スイッチを押したらLEDの点滅を開始」することにしました。

これから、この2つの動作のプログラムを作成していきます。

スイッチ制御プログラム作成

LEDの初期状態をON

現在のプログラムは、LEDの初期状態を次のようにOFFにしています。

// LEDを消灯する
LATA5 = 0;

初期状態をONにしますので、この部分は次のように変更します。

// LEDを点灯する
LATA5 = 1;

スイッチを押したらLEDの点滅を開始

「スイッチを押してからLEDの点滅処理を開始」するように変更すればよいので、点滅処理の前に、「スイッチが押されるまで待ち続ける」という処理を追加すれば実現できます。

スイッチの状態はRA3という変数に格納されています。

RA3ピンが0VのときRA3が0に、5Vのときは1になります。

スイッチはプルアップ抵抗で5Vに接続されていますので、スイッチがOFFのとき、RA3ピンは5Vですので変数RA3は1になります。

またスイッチがONのとき、RA3ピンは0Vですので変数RA3は0になります。


スイッチが押されるまで何もしない、ということは、変数RA3が1の間は次に進まないでずっと待ち続ける、というプログラムを書けばよいことになります。

これは以下のようなプログラムになります。

while(RA3 == 1) {
}

このコードはもう少し簡略化できます。

プログラムでは、「1」は「true」を意味しますので、次のように書くこともできます。

while( RA3 ) {
}

最初のコードより少しわかりづらい気もしますが、PICマイコンのプログラムではこのように書く方もいますので、どちらの書き方に慣れていただければと思います。

このコードはLEDの点滅処理の前に追加すればOKです。

完成したプログラム

プログラムは次のように完成させてみました。

プログラムを書き込んだら、PICkitを外して、電池ボックスを接続して動作確認してみてください。

スイッチをONにするとLEDが点灯状態になり、スイッチを押すと点滅が始まれば成功です!

/*
 * File:   main.c
 * 変更履歴
 *   2025.4.14: スイッチ制御追加
 */

#include <xc.h>

// PIC12F1822 Configuration Bit Settings
// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)


// クロック周波数指定
// __delay_ms()関数が使用する
#define _XTAL_FREQ 1000000

void main(void) {

    // PICマイコン設定
    OSCCON = 0b01011000;  // 内部クロック周波数を1MHzに設定
    ANSELA = 0b00000000;  // すべてのピンをデジタルモードに設定
    TRISA  = 0b00001000;  // すべてのピンを出力モードに設定(ただしRA3ピンは常に入力モード)

    // LEDを点灯する
    LATA5 = 1;

    // スイッチが押されるまで待つ
    while( RA3 ) {
    }
    
    // LED点滅処理(永久に繰り返す)
    while(1){
        // LEDを950ms消灯する
        LATA5 = 0;
        __delay_ms(950);            
        // LEDを50ms点灯する
        LATA5 = 1;
        __delay_ms(50);
    }

    // 以下の命令は実行されない
    return;

}

スイッチの扱い

スイッチ制御のプログラムって思ったより簡単でしたよね。

PICマイコンのピンをデジタル入力にすると、ピンに対応する変数に電圧の状態に応じた値がわかります。

また、スイッチを接続する場合、プルダウン抵抗かプルアップ抵抗を接続する必要があることも確認しました。

とはいっても、物理的なスイッチは、実は根深い問題を抱えているんです。

この問題については応用編で詳しく説明します。おそらくげんなりすると思いますが、頑張って一緒に理解していきましょう。

疑問

今回までに、PICマイコンのピンを「デジタル出力」に設定した場合、ピンに対応する変数、例えばLATA5に値を代入するとピンの出力電圧を制御することを確認しました。

また、ピンを「デジタル入力」に設定した場合、ピンに対応する変数、例えばRA3の値を確認すると現在のピンの状態がわかりました。

この変数、ちょっと疑問があります。例えば、2番ピンのRA5で考えて見ます。2番ピンを「デジタル出力」に設定した場合、出力電圧を制御するには変数「LATA5」に値を代入することになります。同じ2番ピンを「デジタル入力」に設定した場合、ピンの状態を読み取るには変数「RA5」の値を確認することになります。

出力制御するときは「LATA」という名前で、入力の場合は「RA」という名前を使用していますが、これって統一できないんですかね。例えば、デジタル出力する場合は変数「RA5」に値を代入して、デジタル入力の場合は同じく変数「RA5」を読み取る、という感じです。

実は、今回作成したプログラムは全て「RA」変数を使用しても動作します。例えば、電源投入時に次のようにLEDを制御しました。

LATA5 = 1;

この部分を次のように変更しても動作します。

RA5 = 1;

PICマイコンに関する書籍やサイトのプログラムを見ると、入力も出力も変数「RA」を使っているものがあります。特に問題が発生しない場合はこれで全く問題ありません。

ただ、例えばLEDを複数制御する場合などは、出力制御する場合「RA」を使用すると問題が発生するケースもあります。

最初は、出力制御する場合は変数「LATA」、入力読み取りの場合は変数「RA」を使用する、と覚えておいていただければと思います。

更新履歴

日付内容
2016.11.20新規投稿
2018.11.24プログラムテンプレートをMPLABX IDE v5.10に変更
2025.4.14説明順序変更
通知の設定
通知タイミング
guest
13 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
Narushima
Narushima
2 年 前

ツール・ラボ様

はじめまして。
ツール・ラボ様のサイトからマイコンを始めました初心者です。

サイトの通りに回路をつくりプログラムもコピペしたのですが、
スイッチを押す前にLEDの点滅が始まってしまいました。

試しにスイッチを外し、
while(1){
    LATA5 = RA3;
}
としてみたところ、RA3はどこにも繋がっていないにもかかわらず
LEDは不安定に点灯と消灯し始めました。

LEDが消灯している状態で指を近づけると点灯するなど反応がありました。
スイッチを付けて通電させると何故かLEDは高い確率で消灯になります。
他のPICシリーズのマイコンでも試しましたが同様の現象が発生します。

対処法をご教示頂ければ幸いです。

Narushima
Narushima
返信  管理者
2 年 前

ツール・ラボ様

ありがとうございます。

while(1) {
}
に変更したところ、LEDは全く点灯しなくなりました。

添付の画像の状態で行っているのですが、
間違っている部分がありましたらご指摘いただけると幸いです。

Narushima
Narushima
返信  管理者
2 年 前

ツール・ラボ様

プルアップ抵抗をつけることで解決できました。
理解不足、確認不足で質問してしまい申し訳ありません。
お忙しい中、本当にありがとうございました。

toshio kumagai
toshio kumagai
4 年 前

> なお、1はtrueを意味しますので
というのは正確ではないと思います。
trueは0以外の場合を指すわけですから、”1 はbool ではtrueなので”
というのが正解なのでは?

三浦秀信
三浦秀信
4 年 前

お忙しい中すいません。
大阪に住むPIC初心者です。
SWによるLED点灯スタートのプログラムをコピペして動かしたのですがSWを押す前に点灯が始まってしまいます。
while(RA3){
}
が実行されていないようなのですが対処法を教えていただければ幸いです。
三浦秀信

Shinya Saito
Shinya Saito
返信  三浦秀信
2 年 前

三浦様

もう解決されたのかもしれませんが、
私も同じ現象となり悩みましたが、以下のようにして解決しました。
(原因)
おそらくPIC起動直後は、3番ピンの電圧が不安定なのだと思われます。

つまりまだ3番ピンにpull-upの5Vが出きらないうちに、whileの条件式が実行されて
しまい、ボタンが押されたと誤認識されたものだと思います。

(対応)
私はwhileに入る直前にdelayを入れることでうまく動作するようになりました。

__delay_ms(20); // 20msのdelayを追加し電圧の安定を待つ。
while(RA3) {
}

なお、原因は推測で、実際に3番ピンの電圧を測定したわけではありません。
万が一誤りやもっといい方法がある等あれば、どなたかご指摘いただければ幸いです。

Shinya Saito
Shinya Saito
返信  Shinya Saito
2 年 前

その後、追試をしました。
Pickit(当方Pickit 4を使用)を外し、外部電源から直接5Vを給電した場合については20msのdelayは不要でした。従い、Pickit給電の場合に限りプログラム動作に5V給電が追いつかないケースがあるということと思われます。いずれ時間があれば実際に電源波形の計測も試みて見ようと思います。

小林春樹
小林春樹
5 年 前

ツールラボ様
解決しました。MCLRとRA3ピンは共有していますが、インプットとしてのRA3の機能をとりあえず物理的に外してPICKIT4でプログラムを書き込むとうまくいきました。考えてみればPICKIT4の機能はプログラム書き込みにあるのですから、インプット機能はそのあと配線しても問題ないですね。つまらないことお聞きして申し訳ありませんでした。

管理者
管理者
返信  小林春樹
5 年 前

反応が遅く申し訳ございませんでした。

書き込みに問題がある場合、RA3ピンの機能を物理的に外す、というのが一番の解ですね。ただ、あとから配線する場合、ちょっと手間ですよね。自分も問題が発生した場合は同じ方法をとっていますが、他にもうちょっと楽な方法があるといいのですが…

目次