桜のはなびらブログロゴ

Sakura87のPCと電子工作と写真のブログ @16周年

Raspberry Pi 2 でスイッチオン・オフを感知

この記事は5年ほど前に投稿されました。内容が古くなっている可能性がありますので更新日時にご注意ください。


IMG_4661_20150614

今まで主にGPIOを出力として使用してきましたが、今回は入力として使ってみたいと思います。

必要なもの

  • 適当なスイッチ
  • GPIOポート保護用抵抗(1kΩ程度)
  • プルダウン用の抵抗(20k~50kΩ程度)

つなぎ方

Raspberry Piにスイッチを接続する場合、接続方法としては2パターンあります。
1つは他のマイコンなどと同じく、プルダウン・プルアップ抵抗をつけて接続する方法。これが一番基本形であり他のマイコンに移植する際にも回路変更が少なくて済みます。
sw1

回路としてはこんなかんじになります。Raspberry Piの3.3V出力とGNDの間にスイッチと抵抗を入れ
スイッチ⇔プルダウン抵抗間に回路保護用の抵抗を入れてGPIOピンに接続します。
プルダウン抵抗は色々な解説サイトを見ていると20k~50kΩの抵抗と書かれているところが多いようですが、基本的に1k~100kΩの中で選択すればいいようです。最悪何かしらの抵抗があればいいという記事もありますが。基本的には以下のとおりみたいです。

  • 10kΩがいいらしい→上の推奨値なら20k
  • 省消費電力優先なら抵抗値の高い抵抗
  • 耐ノイズ性・応答性を優先するなら抵抗値の低い抵抗

今回は実験なので基本的に「入っていればいい」ということですが。実際にどの抵抗値の抵抗を採用するかは端子やスイッチのの許容電力などを考慮して決める必要があるそうです。
(まぁ、ホビーユースならとりあえず推奨値のうちで持ってる抵抗をつけておけばいいでしょう)

そしてもう一つは上記の回路に「プルダウン抵抗を省いた」接続方法です。

sw2

上で長々と説明しましたが、実はRaspberry PiのGPIOには「プルダウン・アップ抵抗」が内蔵されているので、コマンドで有効にしてあげれば無くても使えます。部品点数が少なくなるので通常はこちらを使っても大丈夫でしょう。ただし保護用の抵抗は入れておくべきだと思います。(最悪なくても人間は死にませんがパイが焼けます。)

配線

この回路図を参考に、適当なスイッチを適当に配線してください。
IMG_4665_20150614
プルダウン抵抗外付け時の例
なお、複数のスイッチを連続させる場合、プルダウン抵抗は抵抗アレイを使ってもいいかもしれない。

IMG_4667_20150614
Raspberry Pi内蔵プルダウン抵抗を使用する場合

コーディング

基本的には今までと同じでWiringPiを初期化してポート指定を行い、ポートの値を読み取るだけです。

ポート設定はこうなります。(#define BTN1 でポート番号を設定すること)

    pinMode(BTN1,INPUT);
    pullUpDnControl(BTN1,PUD_DOWN); // 内蔵プルダウン抵抗を使用する場合のみ

ピンの入出力モードを入力にして、Raspberry Pi内蔵のプルダウン抵抗を使用する場合のみプルアップ・ダウンコントロールを指定します。(心配なら使わない時もPUD_OFFを指定すると安心です。)

そしてボタンの状態の検出はこう

digitalRead(BTN1)

こいつを何らかの変数に代入するなり直接命令にいれこむなりして使う。例えばBTN_STATという変数に代入する場合は

BTN_STAT=digitalRead(BTN1);

となる。
これでBTN_STATに

ON=1
OFF=0

が代入される。

実行結果

これを前回の液晶表示のプログラムと組み合わせてON/OFF状態と押した回数を表示してみた。

IMG_4667_20150614
ボタンオフの状態(内蔵プルダウン抵抗使用のときの写真)

IMG_4668_20150614
ボタンを押したら反応する。

以下に上の液晶表示のソースコードを貼り付けておく。

#include <stdio.h>
#include <wiringPi.h>
#include <string.h>

//LCDのピンを指定
// 4bit Mode
#define LCD_D7 13 // ここから
#define LCD_D6 12
#define LCD_D5 3
#define LCD_D4 2 // ここまでがデータ用
#define LCD_EN 0 // リード/ライト イネーブル信号
#define LCD_RW 7 // リード/ライト 選択信号
#define LCD_RS 9 // レジスタ選択信号
#define LCD_BK 8 // LCDのバックライト電源オンオフ用
#define LCD_ON 25 // LCDの電源オンオフ用

#define BTN1 15


int main(void){
    
    // WiringPi初期化
    wiringPiSetup();

    // GPIOポートの設定
    pinMode(LCD_D7,OUTPUT);
    pinMode(LCD_D6,OUTPUT);
    pinMode(LCD_D5,OUTPUT);
    pinMode(LCD_D4,OUTPUT);
    pinMode(LCD_EN,OUTPUT);
    pinMode(LCD_RS,OUTPUT);
    pinMode(LCD_RW,OUTPUT);
    pinMode(LCD_ON,OUTPUT);
    pinMode(LCD_BK,OUTPUT);
    pinMode(BTN1,INPUT);
    pullUpDnControl(BTN1,PUD_DOWN);

    // 液晶リセット
    LCD_RES();
        int BTN_STAT,BTN_STATO,btn_cnt;
        char btn_st[2][3]={"ON ","OFF"},str[16];
    LCD_SET(0,0,0,0,0,0,0,0,0,1);
                LCD_TEX(1,"ボタンヲ オシテ クダサイ...");
                LCD_TEX(2,"Press Button.");
    for(;;){
        BTN_STATO=BTN_STAT;
        BTN_STAT=digitalRead(BTN1);
        
    if(BTN_STAT!=BTN_STATO){
        if(BTN_STAT)sprintf(str,"ボタン ON カイスウ:%03dカイ",btn_cnt);
        if(!BTN_STAT)sprintf(str,"ボタン OFFカイスウ:%03dカイ",btn_cnt);
            LCD_TEX(1,str);
            LCD_TEX(2," ");

        if(BTN_STAT)btn_cnt++;}
    delay(1);
    }
    
    
    }
    
    
int LCD_RES(void){
        
    digitalWrite(LCD_ON,0); // LCD電源オフ
    digitalWrite(LCD_BK,0); // LCDバックライトオフ
    delay(1);
    digitalWrite(LCD_ON,1); // LCD電源オン
    digitalWrite(LCD_BK,1); // LCDバックライトオン
    delay(40);

    LCD_SET(0,0,0,0,1,1); // 8bitモードに設定
    delay(4.1);
    LCD_SET(0,0,0,0,1,1); // 8bitモードに設定
    usleep(100);
    LCD_SET(0,0,0,0,1,1); // 8bitモードに設定
    LCD_SET(0,0,0,0,1,0); // 4bitモードに設定

    LCD_SET(0,0,0,0,1,0,1,0,0,0); // 2行 普通フォントに設定
    LCD_SET(0,0,0,0,0,0,1,0,0,0); // 液晶表示OFF
    LCD_SET(0,0,0,0,0,0,0,0,0,1); // データクリア
    LCD_SET(0,0,0,0,0,0,0,1,1,0); // カーソル右移動 左シフトに設定        
    LCD_SET(0,0,0,0,0,0,1,1,0,0); // 液晶表示ON
        
}

int LCD_SET(int rs,int rw,int db7,int db6,int db5,int db4,int db3,int db2,int db1,int db0){
    
    // 一旦全ポートに0を書き込む
    digitalWrite(LCD_RW,0);
    digitalWrite(LCD_RS,0);
    digitalWrite(LCD_EN,0);
    nanosleep(60);
    digitalWrite(LCD_D7,0);
    digitalWrite(LCD_D6,0);
    digitalWrite(LCD_D5,0);
    digitalWrite(LCD_D4,0);
    usleep(40);
    
    // データ転送
    digitalWrite(LCD_RW,rw);
    digitalWrite(LCD_RS,rs);
    nanosleep(60);
    digitalWrite(LCD_EN,1);
    nanosleep(60);
    digitalWrite(LCD_D7,db7);
    digitalWrite(LCD_D6,db6);
    digitalWrite(LCD_D5,db5);
    digitalWrite(LCD_D4,db4);
    digitalWrite(LCD_EN,0);
    nanosleep(1000);
    digitalWrite(LCD_EN,1);
    nanosleep(60);
    digitalWrite(LCD_D7,db3);
    digitalWrite(LCD_D6,db2);
    digitalWrite(LCD_D5,db1);
    digitalWrite(LCD_D4,db0);
    digitalWrite(LCD_EN,0);
    
    // 表示クリア、初期位置復帰命令の実行時間が
    // 1.52msと長いので、RSとR/Wの数値が0の命令は
    // 待ち時間を長く設定する。
    if((rw+rs)==0)usleep(1520);
    if((rw+rs)!=0)usleep(40);

}

int LCD_TEX(int line,char SendText[40]){
    
    int i,n,bin[8];char dec;
    

    //書き込みアドレス指定
    if(line==1){LCD_SET(0,0,1,0,0,0,0,0,0,0);}
    if(line==2){LCD_SET(0,0,1,1,0,0,0,0,0,0);}
    
    // 読み取ったデータを1文字ずつ液晶に転送
    for(n=0;n<strlen(SendText);n++){ 
        dec=SendText[n];
        
        // Char型を2進数に変換して配列に格納
        bin[0]=(dec%2);dec/=2;
        bin[1]=(dec%2);dec/=2;
        bin[2]=(dec%2);dec/=2;
        bin[3]=(dec%2);dec/=2;
        bin[4]=(dec%2);dec/=2;
        bin[5]=(dec%2);dec/=2;
        bin[6]=(dec%2);dec/=2;
        bin[7]=(dec%2);dec/=2;
        
        //データを液晶に送る
        LCD_SET(1,0,bin[7],bin[6],bin[5],bin[4],bin[3],bin[2],bin[1],bin[0]);
    }
    
    // 残った文字を空白でうめる
    for(n=n;n<40;n++){LCD_SET(1,0,0,0,1,0,0,0,0,0);}

    
    }

 


コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事