PICマイコンでタッチセンサを使ってみる(mTouch)【PIC16F1938】

Pocket

今回の必要素材

  • PIC16F1938
  • ブレッドボード
  • I2C接続LCD
  • LED
  • ジャンパケーブル
  • 抵抗(100Ω)

必要な前提知識

今回作る工作(動画)

PICのピンに繋がった抵抗の足を指で触れると、LEDが点灯します(タッチスイッチ)。LCDの値が指の触れる前後で変動していることが分かりますね。

タッチセンサ

今回はタッチセンサを扱っていきます。タッチセンサとはその名の通り、タッチされたことを感知するセンサです。このサイトで扱っているPIC16F1938にはもともとタッチセンサ機能が付いています。しかも、拡張パーツなしでこのセンサが利用できます。この技術をMicrochip社はmTouch™と呼んでいます。

mTouch™とは

簡単に言えば、mTouchの機能が割り当てられているピンのコンデンサとしての容量を数値化するという機能です。コンデンサというのは、そのピンと空気中との間に電気が溜まることを指します。この電気が溜まるまでの時間を勝手に測ってくれると思えばOKです。

例えば、このピンに巨大な電極(ただの四角い鉄板でもなんでもいい)がつながっていれば、充電には時間がかかるのでこの数値は変化します。つまり、何かがピンに触れたことを感知出来るのです。人間も導電性がありますから、巨大な電極として働き、この値がかなり大きく変動します。よって、例えば「mTouchの値が100以下ならLEDをオンにする」というプログラムを書けば、人間がそのピンを触った時にLEDをオンにするように動かせるということです。タッチスイッチですね。

もう少し詳しい説明(飛ばしてもOK)

実際のmTouchの動きは若干直感と異なり、指が触れた時に値が小さくなります。この原理に関しては、いつもお世話になっているこちらのサイトの開いてすぐ下に書いてあります。つまり、ある時間(例えば1秒間など)に何回充放電ができたかをカウントして、その値を返すということをしてくれます。当然指を触れた方が電荷が多く溜まって充放電に時間がかかりますから、1秒間にできる充放電の回数は少なくなります。よって、指が触れた方がmTouchの値は小さくなるわけです。

実際にプログラムで使うときは、指が触れたらどのくらいまで値が下がるのかを確かめる必要があります。人によっても値は違うかもしれませんね。

センサの値を表示する

今回使う回路図


では早速mTouchの技術を使ってみましょう。これから各関数を紹介していきますが、内容がある程度理解できればいいので、実際にプログラムを書くときは目次最後の完成プログラムからコピペして、自分のやりたいように関数の中身を変えたりするのが早いかと思います。

PICinit()

ほぼこのサイトの他の記事のコピペですが、一部変わっているところがあります。


    void PICinit(){
            OSCCON = 0b01110000;
            ANSELA = 0b00010000;      //AN4をCPS
            ANSELB = 0b00000000;
            TRISA  = 0b00100000;
            TRISB  = 0b00000000;
            TRISC  = 0b00011000;
            PORTA  = 0b00000000;    //2進数で書いた場合
            PORTB  = 0x00;          //16進数で書いた場合
    }
  

ANSELAのAN4を1にしました。今回mTouchを使えるピンにはCPSという表記がされています。今回私はピン番号7のCPS7を使いたいのですが、この時充放電をするのでアナログ入力にしなければなりません。そのため、ANSELの5bit目はAN4,つまり7番ピンに当たるので1を割り当て、アナログ入力ができるようにしました。

TRISAに関しても同様に7番ピンであるRA5を入力に割り当てています。これで入力する準備はできました。

CPSinit()

今度は容量検知モジュール(CPS)の初期設定をする関数です。


    void CPSinit(){
          CPSCON0 = 0b00001000;     //発振子は中速を利用
          CPSCON1bits.CPSCH = 0b0111;  //CPSチャネルはCPS7(7ピン)を利用
          T1CON = 0b11000001;           //クロックソースは容量検知オシレータ、Timer1ON
          TMR1H = 0;                    //Timer1の値をリセット
          TMR1L = 0;
          PEIE = 1;                     //割り込みを許可
          GIE = 1;                      //グローバル割り込みを許可

          CPSON = 1;                    //容量検知モジュール(mTouch)ON
      }
  

コメントを見ていただければ、そのまま分かるかとは思います。これらのレジスタの意味が分からなくなったら、PIC16F1938のデータシートを開き、ctrl+Fでレジスタ名を入れれば出てきますので参考にしてください。

Timer1はある発振子を基準にカウントします。デフォルトではPICを駆動している内部発振子なのですが、今回はクロックソースを容量検知オシレータ(CPSモジュールのことです)にしました。よって、容量が変わるとクロック周波数も変わり、Timer1の時間の刻みが変化します。

getCap()

実際にこの容量を検知する関数です。


      int getCap(){                     //容量検知関数(充放電回数のカウントを返す)
          int cap;
          TMR1H = 0;                     //Timer1の値を0に
          TMR1L = 0;
          __delay_ms(9);
          CPSON = 0;                     //容量検知モジュールをオフ
          cap = (TMR1H*256) + TMR1L;     //Timer1の値をcapへ
          CPSON = 1;                    //容量検知モジュールをオン
          return cap;                   //capの値(カウント値)を返す
      }
    

CPSinit()関数の後では常にCPS(mTouch)がオンになっています。よって、TMR1の値がどんどん増えて行っているわけです。これでは計算が面倒なので、計測前に0にしています。

その後9ms待っていますね。この間も充放電を繰り返して、その回数がTMR1にカウントされていきます。この秒数は適当に決めて構いません。多ければカウント数が多くなります。

ある程度待ったらCPSONを再度オンにします。そしてTMR1の値をcapに代入し、それをreturnで返しています。

showCap()

getCap()で取得した値をLCDの使い方を参考にLCDに表示します。LCDへの接続関数はこのサイトのままです。


      void showCap(){
          char Cap[16];
          sprintf(Cap,"Cap:%d",getCap());
          LCD_str(Cap);
          writeCommand(0x02);
      }
    

文字列用の配列Capを用意して、sprintfで「Cap:getCap()」をCapに入れます。これをLCD_strでLCDに表示します。

main関数


      int main(void){
        PICinit();      //PICを初期化
        LCD_Init();       //LCDを初期化
        CPSinit();
        writeCommand(0x01); //画面をクリア
        __delay_ms(20);      //LCD処理待ち
        writeCommand(0x02); //ホームへカーソル移動
        __delay_ms(100); // LCD側の処理待ち
        RB7 = 1;
        __delay_ms(1000);
        while(1){
            showCap();

            if(getCap() < 800){
                RB7 = 1;
            }else{
                RB7 = 0;
            }
                __delay_ms(10); //0.01秒おきに更新
        }
        return 0;
      }
    

始めの方にあるinitラッシュはそのまま初期化しているだけです。そこに先程作ったCPSinitがありますね。次にLCDのセットアップ待ちを入れ、RB7をオンにしています。RB7には今回の動画では青色LEDを繋いでいるので、これが点灯します。

while文の中ではまずshowCap()で容量の値をLCDに表示しています。次にif文内でgetCap()が800以下の時にLEDをオンにしています。私の環境ではmTouchのピンに抵抗を繋いでピンを拡張しているようになっていて、通常時は900ぐらいの値を示します。指で触れた時に300程度まで落ち込むので、その判定基準を800にしました。

if文の後の__delay_msですが、別にこの値である必要は全くありません。応答性を良くしたい場合は、これを無くしてもいいかもしれません。

Pocket

関連記事   ESP32でNTPで取得した時間をOLEDディスプレイ「SSD1306」に表示してみた

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です