充電時間計測ユニット(CTMU)でタッチセンサーを行ってみます

〔PICの動かせ方入門に戻る〕


前回の記事で、PIC12F1822の容量検知モジュール(CPS:Capacitive Sensing)/CSM 機能を使用して
タッチセンサーを実験してみました。
この機能は、センサーパッドに充電と放電を繰り返すと三角波が出来ます、この三角波はセンサーの
静電容量で波形の周波数が変化するので、この周波数をカウントする事により検知させる物です。
(詳しくは前回記事を参照下さい)

PIC18FとPIC24Fの一部に、充電時間計測ユニット(CTMU:Charge Time Measurement Unit) 機能が
搭載されています、このユニットは、定電流源を内蔵していて色々な制御が出来る様になっているので
様々なアプリケーションが開発出来ます。
例えば、静電容量・インダクタンス・抵抗・温度・高分解能時間などの計測や時間遅延生成にPWM出力
などです。(こちらの"AN1375:CTMU の多彩な機能"が参考になるでしょう)

今回はPIC18F25K22のCTMUを利用してタッチセンシングを実験してみようと思います。
尚、"AN1250:CTMU の静電容量式タッチ アプリケーションへの適用"と、
18F25K22のデータシート(321頁から)を参考に実験を進めます。

タッチセンサー概要図

この図はマイクロチップのデータシートからの拝借ですが、静電容量式タッチセンスの基本原理です。
上図の様にパッド(電極)には自然の寄生容量コンデンサー(CSW/CCIR)が存在しています。
で、人にもコンデンサー(Cf)が存在していて絵の様に指で触れると、コンデンサーが並列接続の状態と
なり静電容量が増える事になります、この変化を充電時間計測ユニットで検出しようと言う事です。

どうやって検出するのぉ?

検出の概念図
定電流源から電流を一定時間(t)だけ
センサーパッドに流します。
その後PICのA/D変換器から電圧を読取ります。

電流と充電時間が同じなら静電容量の多い方が
測定電圧(V1)は下がります。
だからぁ、指で触れる前の電圧値と触れた後の
電圧値を比較すれば良いと言う事です。

PICのA/Dコンバータを使用すると言う事は、
PICのアナログピンが全て接続利用可能です。
18F25K22ならAN0-4,AN8/9,AN10-19の17本です

《実験1》

まずは、充電時間計測ユニット(CTMU)の基本的な動作を調べて見ましょう。
ピンの構成図
 左図がPIC18F25K22のピン構成図です。
 PIC18F2xK22も同じです、またPIC18F4xK22は、
 ピン数の違いだけで参考になります。

 今回使用するピン番号は20番(VDD)と8/19番(VSS)を
 電源に配線します。
 電源は5Vを繋いで下さい。

 センサパッド(電極)はAN0〜AN19の端子に接続します。
 実験1ではAN0(2番端子)を使いました。

 28番RB7より別途作成のLCDモニタに接続しています。


実験1の配線図  下記の様な電極を作ってみました。
  自作の電極写真
 青いアクリル板は0.5mmの厚さがあり、これに
 横20mm x 縦20mm x 厚0.3mm の銅板を両面
 テープで貼付けて、長さ22cmのリード線を配線
 しています。
 まぁ、わざわざ作らなくても実験には
 普通のリード線を繋ぐだけでも動作します。


@では、上図の様に配線しましょう。
 (モニター表示は他の方法で行っているならその様に行っても構いません。)
AMPLAB X IDE(V3.40)を起動させます。 *2)

B下記がPIC18F25K22を使ったプログラムソースです、
  MPLAB(R) XC8 C Compiler Version 1.38コンパイラを使用しています。
  プロジェクトを作成して新規ファイルにコピーペーストして貼り付けて下さい。
  プログラムソースをダウンロードしてプロジェクトに取込む事も出来ます。 *2)
---------------------------------------------------------------------
#include <xc.h>
#include <stdlib.h>
#include "skMonitorLCD.h"     // LCDモニター用

#define _XTAL_FREQ 16000000   // delay用に必要(クロック16MHzを指定)

// コンフィギュレーションの設定(ここの記述に無い設定はデフォルト値での動作)
// 外部クロックは使用しない(PRICLKEN_OFF)
// 動作クロックを4倍では動作させない(PLLCFG_OFF):内部クロックを使用する(INTIO67)
#pragma config PRICLKEN=OFF,PLLCFG=OFF,FOSC=INTIO67    // CONFIG1H
// 電源電圧降下常時監視機能ON(BOREN_NOSLP):監視電圧は(2.85V)に設定
// 電源ONから後65.6msにプログラムを開始する(PWRTEN_ON)
#pragma config BOREN=NOSLP,BORV=285,PWRTEN=ON          // CONFIG2L
// ウオッチドッグタイマー無し(WDTEN_OFF)
#pragma config WDTEN=OFF                               // CONFIG2H
// 外部リセット信号は使用せずにデジタル入力(RE3)ピンとする(MCLRE_INTMCLR)
// オシレータが安定するのを待ってシステムクロックを供給する(HFOFST_OFF)
#pragma config MCLRE=INTMCLR,HFOFST=OFF                // CONFIG3H
// 低電圧プログラミング機能使用しない(LVP_OFF)
#pragma config LVP=OFF                                 // CONFIG4L

// 指定した時間(num x 10ms)だけウエイトを行う処理関数
void Wait(unsigned int num)
{
     int i ;

     // numで指定した回数だけ繰り返す
     for (i=0 ; i<num ; i++) {
          __delay_ms(10) ;         // 10msプログラムの一時停止
     }
}
// 電極の電圧値を読み取る処理
int CTM_ReadRobe()
{
     unsigned long temp ;
     unsigned int cap , i ;

     temp = 0 ;
     for (i=0 ; i < 10 ; i++) {
          // ゼロ電位から開始させる為に電荷を放電させる
          CTMUCONHbits.IDISSEN = 1 ;
          __delay_us(125) ;
          CTMUCONHbits.IDISSEN = 0 ;
          // 電極に充電を行う
          CTMUCONLbits.EDG2STAT = 0 ;
          CTMUCONLbits.EDG1STAT = 1 ;
          __delay_us(20) ;
          CTMUCONLbits.EDG1STAT = 0 ;
          // 電極の電圧(AN0)を読み取る
          GO_nDONE = 1 ;           // アナログ値読取り開始指示
          while(GO_nDONE) ;        // 読取り完了まで待つ
          cap = ADRESH ;
          cap = ( cap << 8 ) | ADRESL ;
          temp = temp + cap ;
     }
     return temp/10 ;              // 10回の平均値を返す
}
// メインの処理
void main()
{
     char s[8] ;
     unsigned int cap ;

     OSCCON = 0b01110010 ;    // 内部クロックとする(16MHz)
     ANSELA = 0b00000001 ;    // AN0のみアナログ、他のAN1-4はデジタルI/Oに割当
     ANSELB = 0b00000000 ;    // AN8-13アナログは使用しない、デジタルI/Oに割当
     ANSELC = 0b00000000 ;    // AN14-19アナログは使用しない、デジタルI/Oに割当
     TRISA  = 0b00000001 ;    // RA0のみ入力、他は全て出力に設定、、1で入力 0で出力
     TRISB  = 0b00000000 ;    // RB0-RB7全て出力に設定
     TRISC  = 0b00000000 ;    // RC0-RC7全て出力に設定 
     PORTA  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)
     PORTB  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)
     PORTC  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)
     // アナログ入力の設定
     ADCON1 = 0b00000000 ;    // VDDをリファレンスとする
     ADCON2 = 0b10010101 ;    // 読取値は右寄せ、A/D変換クロックはFOSC/16、4TAD後に変換開始
     ADCON0 = 0b00000001 ;    // アナログ変換情報設定(AN0から読込む)
     __delay_us(8) ;          // アナログ変換情報が設定されるまでとりあえず待つ
     // CTMU(充電時間計測ユニット)の設定
     CTMUICON = 0b00000010 ;  // 電流ソースは5.5uA(調整は無)
     CTMUCONL = 0b00000000 ;  // エッジ制御ロジックは未使用
     CTMUCONH = 0b10000000 ;  // CTMUの開始

     MonitorInit() ;        // LCDモニターに送信出来る様に初期化する

     while(1) {
          // 電極の電圧(AN0)を読み込む
          cap = CTM_ReadRobe() ;
          // 読んだ値をLCDモニターに表示する
          MonitorPutc(0x11) ;      // モニターの表示位置を設定する
          MonitorPuts("      ") ;  // 表示を消す
          MonitorPutc(0x11) ;      // モニターの表示位置を設定する
          utoa(s,cap,10) ;         // カウント値を文字列に変換する
          MonitorPuts(s) ;         // 表示する
          // 500ms後に繰り返す
          Wait(50) ;
     }
}
---------------------------------------------------------------------
 このプログラムにはデバッグモニタープログラム「skMonitorLCD.c」「skMonitorLCD.h」が必要です。
 デバッグLCDモニターについてはこちらを参照して下さい。
 「skMonitorLCD.c」は送信データをTimer2のタイミングで送る様に変更しました、
 その為に上記プログラムを変更しています。
 *1)

 また、LCDモニターの出力はRB7から行っているので「skMonitorLCD.h」を下記の様に変更します。
  #define _XTAL_FREQ 16000000  // 使用するPIC等により動作周波数値を設定する
  #define BAUDRATE 103      // 9600bps(8MHz=51)(4MHz=25)(16MHz=103)
  #define MONITOR_PIN LATB7   // モニタ出力するピンの番号を設定する

CコンパイルPIC書き込みを実行して下さい。 *2)

DPICをブレッドボードに取付けて動作させます。
 電極に触れてみましょう、LCDモニターの数値が変化すると思います。

 電圧値(A/D変換値)を見てみると。(値は接続した電極やその他諸々により変化します)
電極 触れていない時 触れた時 0.5mmの青アクリル裏
から触れた時
リードジャンプワイヤー
(充電時間 20us)
733〜734位 545〜595位
20mm x 20mm x 0.3mm の銅板
(充電時間 20us)
706〜709位 547〜605位 632〜645位
20mm x 20mm x 0.3mm の銅板
(充電時間 10us)
366〜369位 280〜320位 320〜332位

 銅板電極の項で、充電時間の長さを変えて見ました、上は20usで下が10usです。
 電極に触れると静電容量が増えるので電圧値は低くなっていますね。
 電極にずっと長く触れたままでいると値が増えて行きます、で605位になるとまた550位に戻り
 またまた増えて行くを繰り返しています。(長く触れた操作を行う人はこの最大値を見極める必要有)
 また、電極に指が近づくと約1cm位辺りから数値は減って行きます。

調整について

今回のサンプルソースで電圧値を10回読み込んで平均化させていますが、これはデータシートの
サンプルプログラムがそうなっていたので行っています。

充電する為の定電流は、0.55uA/5.5uA/55uA が設定可能です。(±62% 程増減設定可能です)
当然、充電電流が多い方が充電時間は少なくて済みます、今回は 5.5uA で充電時間が 20us です。
上の表を見れば解る様に同じ 5.5uA でも充電時間が異なると得られる電圧値も違っていますよね。
また、電圧値が 1000 を超えている場合は充電時間が長すぎます、短くするか電流値を下げます。

それとぉ、「ゼロ電位から開始させる為に電荷を放電させる」 と言う事で今回 125us で行っていますが、
この時間もデータシートのサンプルプログラムと同じで行って見ました、上で書いた様に指で触れた
ままだと 605位まで電圧値は上がりましたが、試しに 1000us で行ったら 580位までの上昇値でしたが、
この値を上げすぎると電極の検知に時間が掛かりタッチ操作の反応が今一つとなるでしょう。

アナログの設定について

アナログI/Oの設定についてはこちらを参照下さい。


充電時間計測ユニット(CTMU)の設定について

CTMUの設定はCTMUCONHCTMUCONLCTMUICONのレジスターで行います。
CTMUの機能にエッジ制御ロジックが有りますが今回は利用していません、
この機能とコンパレータを使いこなす事が出来れば色んなアプリケーションを開発出来ると思うのですがぁ.....

CTMUCONHレジスタの構成
ビッ ト
機能 CTMUEN   CTMUSIDL TGEN EDGEN
EDGSEQEN IDISSEN CTTRIG

Bit 7 :CTMUEN      CTMUモジュール イネーブル ビット
              1=モジュールの動作を開始させます
              0=モジュールの動作を停止させます
Bit 5 :CTMUSIDL   アイドルモード時の動作を指示する ビット
              1=デバイスがアイドルモードに入ると CTMUは動作を停止
              0=アイドルモードで動作する
Bit 4 :TGEN          CTMUの エッジ遅延生成モード
              1=有効にする
              0=無効にする
Bit 3 :EDGEN        エッジ制 御ロジックの 利用を
              1=有効にする
              0=無効にする
Bit 2 :EDGSEQEN  エッジイベントのシーケンス動作を
              1=有効(エッジ1の後にエッジ2を発生させる)
              0=無効にする
Bit 1 :IDISSEN       ア ナログ電流の制御ビット
              1=アナログ電流の 出力が接地される
              0=アナログ電流の 出力は接地されない
Bit 0 :CTTRIG        CTMU特 殊イベントトリガの制御を
              1=有効にする
              0=無効にする

CTMUCONLレジスタの構成
ビッ ト
機能 EDG2POL EDG2SEL EDG1POL EDG1SEL EDG2STAT EDG1STAT

Bit 7 :EDG2POL     エッジ2の極 性を選択する
              1=立ち上がりで利用する
              0=立ち下がりで利用する
Bit 5-6:EDG2SEL    エッジ2のソースを 選択するビット
              11=CTED1のピンを利用する
              10=CTED2のピンを利用する
              01=ECCP1の特殊イベントトリガを利用する
              00=ECCP2の特殊イベントトリガを利用する
Bit 4 :EDG1POL     エッジ2の極 性を選択する
              1=立ち上がりで利用する
              0=立ち下がりで利用する
Bit 2-3:EDG1SEL    エッジ2のソースを 選択するビット
              11=CTED1のピンを利用する
              10=CTED2のピンを利用する
              01=ECCP1の特殊イベントトリガを利用する
              00=ECCP2の特殊イベントトリガを利用する
Bit 1 :EDG2STAT   エッジ2のス テータスビット
              1=エッジ2のイ ベントが発生した
              0=イベントは発生していない
Bit 0 :EDG1STAT   エッジ1のス テータスビット
              1=エッジ1のイ ベントが発生した
              0=イベントは発生していない

CTMUICONレジスタの構成(電流源の電流を設定するレジスタ)
ビッ ト
機能 ITRIM IRNG

Bit 7-2 :ITRIM     電流値を調整する(±62% 程増減設定可能です)
             "000001"〜"011111"まで設定可能(+2%ステップで電流値を増やす)
             "000000"=IRNGでの設定値のままで使用する
             "111111"〜"100001"まで設定可能(-2%ステップで電流値を減らす)
Bit 1-0 :IRNG     電流ソースの レンジを選択するビット
             11=ベース電流 X 100倍 (55uA)
             10=ベース電流 X 10倍   (5.5uA)
             01=ベース電流       (0.55uA)
             00=ベース電流は未使用

データシートに
 「CTMU 電流源はソフトウェアで有効/ 無効にします。
 CTMU 制御レジスタの2 つの制御ビットEDG1STATEDG2STATが、電流源を有効にするかどうかを
 決定します。これらのビットの排他的論理和を取ります。
 すなわち、EDG1STATEDG2STAT の両方がセットまたはクリアされると電流源がOFF になります。
 いずれかのビットがセットされ、もう一方のビットがクリアされると、電流源が有効化され、回路を
 充電します。」
と書いて有ります。

《実験2》

実験2の配線図
 この左図の電極1に触れればLED1
 が点灯し、電極2に触れればLED2
 が点灯する回路です。

 電極は上写真で紹介の銅板を
 使用し、端子はAN0(2)/AN1(3)に
 接続しています。

 LEDは足の短い方をGND側に接続
 して下さい。
 LED1がRB7(28)端子に接続で、
 LED2がRB6(27)端子に接続です。
 LEDの電流制限抵抗は470Ωです


では、上の様に配線したら下記のサンプルプログラムを動かして見て下さい。
実験2のサンプルプログラムはこちらからダウンロードして下さい。
---------------------------------------------------------------------
#include <xc.h>

#define _XTAL_FREQ    16000000               // delay用に必要(クロック16MHzを指定)
#define ANALOG_NUMBER 20                     // アナログ端子のピン実装個数(AN0-AN19)

                                             // CTMU用データ
unsigned int CTM_data[3][ANALOG_NUMBER] = {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ;


// コンフィギュレーションの設定(ここの記述に無い設定はデフォルト値での動作)
// 外部クロックは使用しない(PRICLKEN_OFF)
// 動作クロックを4倍では動作させない(PLLCFG_OFF):内部クロックを使用する(INTIO67)
#pragma config PRICLKEN=OFF,PLLCFG=OFF,FOSC=INTIO67    // CONFIG1H
// 電源電圧降下常時監視機能ON(BOREN_NOSLP):監視電圧は(2.85V)に設定
// 電源ONから後65.6msにプログラムを開始する(PWRTEN_ON)
#pragma config BOREN=NOSLP,BORV=285,PWRTEN=ON          // CONFIG2L
// ウオッチドッグタイマー無し(WDTEN_OFF)
#pragma config WDTEN=OFF                               // CONFIG2H
// 外部リセット信号は使用せずにデジタル入力(RE3)ピンとする(MCLRE_INTMCLR)
// オシレータが安定するのを待ってシステムクロックを供給する(HFOFST_OFF)
#pragma config MCLRE=INTMCLR,HFOFST=OFF                // CONFIG3H
// 低電圧プログラミング機能使用しない(LVP_OFF)
#pragma config LVP=OFF                                 // CONFIG4L

// 指定した時間(num x 10ms)だけウエイトを行う処理関数
void Wait(unsigned int num)
{
     int i ;

     // numで指定した回数だけ繰り返す
     for (i=0 ; i<num ; i++) {
          __delay_ms(10) ;    // 10msプログラムの一時停止
     }
}
// 電極の電圧値を読み取る処理
int CTM_ReadRobe()
{
     unsigned long temp ;
     unsigned int cap , i ;


     temp = 0 ;
     for (i=0 ; i < 10 ; i++) {
          // ゼロ電位から開始させる為に電荷を放電させる
          CTMUCONHbits.IDISSEN = 1 ;
          __delay_us(500) ;        // 500usの時間だけ放電させる
          CTMUCONHbits.IDISSEN = 0 ;
          // 電極に充電を行う
          CTMUCONLbits.EDG2STAT = 0 ;
          CTMUCONLbits.EDG1STAT = 1 ;
          __delay_us(20) ;         // 20usの時間だけ充電させる
          CTMUCONLbits.EDG1STAT = 0 ;
          // 電極の電圧を読み取る
          GO_nDONE = 1 ;           // アナログ値読取り開始指示
          while(GO_nDONE) ;        // 読取り完了まで待つ
          cap = ADRESH ;
          cap = ( cap << 8 ) | ADRESL ;
          temp = temp + cap ;
     }
     return temp/10 ;              // 10回の平均値を返す
}
// CTMUに接続されている電極の初期値を読み込む処理
void CTM_Init()
{
     int i ;

     // 接続している電極の分だけ繰り返す
     for (i=0 ; i<ANALOG_NUMBER ; i++) {
          if (CTM_data[0][i] == 1) {
               ADCON0bits.CHS = i ;                    // アナログ変換を行うチャンネルの設定
               __delay_us(8) ;                         // アナログ変換情報が設定されるまでとりあえず待つ
               CTM_data[1][i] = CTM_ReadRobe() ;       // 電極の電圧値を読む
          } else CTM_data[1][i] = 0 ;
          CTM_data[2][i] = 0 ;
     }
}
// CTMUに接続されている電極の現在値を読み込む処理
void CTM_ScanRobe()
{
     unsigned int cap ;
     int i ;

     // 接続している電極の分だけ繰り返す
     for (i=0 ; i<ANALOG_NUMBER ; i++) {
          if (CTM_data[0][i] == 1) {
               ADCON0bits.CHS = i ;                    // アナログ変換を行うチャンネルの設定
               __delay_us(8) ;                         // アナログ変換情報が設定されるまでとりあえず待つ
               cap = CTM_ReadRobe() ;                  // 電極の電圧値を読む
               if (cap <= (CTM_data[1][i]*0.92)) {     // 現在値が初期値の92%以内ならONとする
                    CTM_data[2][i] = cap ;             // ONとする
               } else {
                    CTM_data[2][i] = 0 ;               // OFFとする
                    CTM_data[1][i] = cap ;             // 初期値とする
               }
          }
     }
}
// CTMUに接続されている電極の状態を調べる処理
//   num : 調べる電極のアナログ番号を指定する
int CTM_StateRobe(int num)
{
     if (num >= ANALOG_NUMBER)   return( -1 ) ;   // 数値指定エラー
     if (CTM_data[0][num] != 1)  return( -1 ) ;   // 数値指定エラー
     if (CTM_data[2][num] == 0) return( 0 ) ;     // 電極に触れていない
     else                       return( 1 ) ;     // 電極に触れている
}
/*******************************************************************************
*  メインの処理                                                                *
*******************************************************************************/
void main()
{
     OSCCON = 0b01110010 ;    // 内部クロックとする(16MHz)
     ANSELA = 0b00000011 ;    // AN0/1のみアナログ、他のAN2-4はデジタルI/Oに割当
     ANSELB = 0b00000000 ;    // AN8-13アナログは使用しない、デジタルI/Oに割当
     ANSELC = 0b00000000 ;    // AN14-19アナログは使用しない、デジタルI/Oに割当
     TRISA  = 0b00000011 ;    // RA0/1のみ入力、他は全て出力に設定、1で入力 0で出力
     TRISB  = 0b00000000 ;    // RB0-RB7全て出力に設定
     TRISC  = 0b00000000 ;    // RC0-RC7全て出力に設定 
     PORTA  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)
     PORTB  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)
     PORTC  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)
     // アナログ入力の設定
     ADCON1 = 0b00000000 ;    // VDDをリファレンスとする
     ADCON2 = 0b10010101 ;    // 読取値は右寄せ、A/D変換クロックはFOSC/16、4TAD後に変換開始
     ADCON0 = 0b00000001 ;    // アナログ変換情報設定(AN0から読込む)
     __delay_us(8) ;          // アナログ変換情報が設定されるまでとりあえず待つ
     // CTMU(充電時間計測ユニット)の設定
     CTMUICON = 0b00000010 ;  // 電流ソースは5.5uA(調整は無)
     CTMUCONL = 0b00000000 ;  // エッジ制御ロジックは未使用
     CTMUCONH = 0b10000000 ;  // CTMUの開始
 
     // 電極の初期値を読み込む
     CTM_Init() ;

     while(1) {
          // 電極の現在値を読み込む
          CTM_ScanRobe() ;
          // 電極1(AN0)の状態でLED1を点灯させる処理
          if (CTM_StateRobe(0) == 1) LATB7 = 1 ; // LED1を点灯
          else                       LATB7 = 0 ; // LED1を消灯
          // 電極2(AN1)の状態でLED2を点灯させる処理
          if (CTM_StateRobe(1) == 1) LATB6 = 1 ; // LED2を点灯
          else                       LATB6 = 0 ; // LED2を消灯
     }
}
---------------------------------------------------------------------
プログラムについて

電極
 今回は電極をAN0とAN1に2個接続しています、なので下記の様に宣言されています。
  #define ANALOG_NUMBER 20                   // アナログ端子のピン実装個数(AN0-AN19)
                                             // CTMU用データ
  unsigned int CTM_data[3][ANALOG_NUMBER] = {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ;
 ANALOG_NUMBERはAN0-AN19までアナログが有るので20とします。
 (PIC18F4xK22の場合はAN0-AN27までなので28です)

 CTM_data[ ][ ]の {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} は左から右側へAN0〜AN19の並びで、
 使用しているアナログピン番号を1にします。(今回はAN0とAN1だから上の様になります)

 例えば、AN10の一個だに電極を接続していた場合は、
  #define ANALOG_NUMBER 20                   // アナログ端子のピン実装個数(AN0-AN19)
                                             // CTMU用データ
  unsigned int CTM_data[3][ANALOG_NUMBER] = {0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0} ;

 もちろん利用するアナログ端子はANSELx/TRISxで、アナログ端子で入力ピンとしないとダメですよ。

調整値については
 自分で作成した電極や操作方法などにより調整値が変わりますが、実験2では、
 5.5uAの定電流で、20usの時間だけ充電させ、500usの時間だけ放電としています。
 それと、指で触れた時の電圧値が、指で触れていない時の電圧値から92%以下であればタッチした
 と判断させています、この92%を変える場合は、CTM_ScanRobe()関数に
   if (cap <= (CTM_data[0][i]*0.92)) {
 と有るので0.92を変更して下さい、0.92を上げれば感度も良くなります。

CTM_Init( )
  接続している電極の初期電圧値を読込む処理と、CTMUデータ値の初期化を行っています。
  PICの電源ON時に1回だけ実行します、接続している全ての電極の電圧値を読み込みます。

CTM_ScanRobe( )
  CTMUに接続されている全ての電極の現在電圧値を読み込む処理です。
  この処理を実行すると電極の現在電圧値が読み込まれ初期値と比較して、今回値が初期値
  の92%より低かったら電極に触れたと判断します。
  なのでこの関数は常に実行させる必要が有ります。
      while(1) {
           CTM_ScanRobe() ;

      }
  とこんな感じですね。
  または、タイマー0が余っているならタイマー0をインターバル間欠タイマーとして割り込みを発生
  させ割り込み処理の中でこの関数を実行させた方が良いかもね。(未実験)
      void interrupt InterTimer( void )
      {
           if (TMR0IF == 1) {           // タイマー0の割込み発生か?
                TMR0 = ???? ;           // タイマー0の初期化
                CTM_ScanRobe() ;
                TMR0IF = 0 ;            // タイマー0割込フラグをリセット
           }
      }
  とこんな感じですね。

ans = CTM_ReadRobe( )
  実際にこの関数で電極の電圧値が読み込まれます、10回読み込んで平均値を返します。
  読み込む電極のチャンネルは、ADCON0bits.CHS に指定しこの関数を呼びます。
  ans       :読み込んだ電圧値を返す

ans = CTM_StateRobe(int num)
  CTMUに接続されている電極の状態を調べる処理です。
  num      : 調べる電極のアナログ番号(AN0-AN19)を指定する
  ans       : 1=触れている 0=触れていない −1=電極番号の指定エラー

《その他》

実験2の風景
 左写真は実験2の風景です。

 PIC12F/16Fの容量検知モジュール(CPS:CSM)
 方式と今回の充電時間計測ユニット(CTMU)
 方式を比較してみるとCTMUの方が感度も良く
 て1個の電極をスキャンする時間も早いので
 能力は上かなっと感じがします。



こちらに”スライドスイッチ機能付感圧センサ(FSLP)を使ってみる”の記事も有ります。



リンクの見直し(*2) 2017/01/13
"skMonitorLCD.c"変更により"実験1"のプログラム変更(*1) 2014/02/01


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2017 Shigehiro Kimura All Rights Reserved.