12F1822 には、電極に指が触れると、指とグランド間の寄生容量を検知し、SWがONとなる静電容量式センシングモジュール”Capacitive Sensing (CPS) module"が組み込まれています。 このような非機械式入力装置をMicrochip社では mTouch と呼び、この CPSモジュールは mTouch の代表的な方法です。CPSは、複数の端子を切り替えるMUXと端子の容量により周波数が変化する発振器から構成されています。いろいろな形状の端子に対応できるよう、発振機の基準電圧をソフトウエアで変更できるようなっています。なお、端子の静電容量の変化を検知するため、一般的に端子には薄いフィルムなどで覆い、端子と指が直接接触することはありません。
*注意*
CPS端子に指定するI/Oピンは、以下の設定をします。
CPSRNG <1:0> |
CPSRM = 0 (Low レンジ) 内蔵の参照電圧を使う |
CPSRM = 1 (High レンジ) DAC とFVR を使う |
||
---|---|---|---|---|
オシレータ | 充放電電流 | オシレータ | 充放電電流 | |
00 | OFF | - | ON | 供給されない |
01 | ON | 0.1 μA | ON | 9 μA |
10 | ON | 1.2 μA | ON | 30 μA |
11 | ON | 18 μA | ON | 100 μA |
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|---|
CPSCON0 | CPSON | CPSRM | CPSRNG1 | CPSRNG0 | CPSOUT | T0XCS | ||
CPSCON1 | CPSCH1 | CPSCH0 | ||||||
ANSELA | ANSA4 | ANSA2 | ANSA1 | ANSA0 | ||||
TRISA | TRISC5 | TRISA4 | TRISC3 | TRISA2 | TRISA1 | TRISA0 | ||
WPUA | WPUA5 | WPUA4 | WPUA3 | WPUA2 | WPUA1 | WPUA0 |
レジスタ | BIT | 名 | 内容 | 1 | 0 |
---|---|---|---|---|---|
CPSCON0 | 7 | CPSON | CPS モジュール イネーブル | ON | OFF |
6 | CPSRM | 参照電圧モード | 外部 | 内蔵 | |
3 | CPSRNG1 | 電流レンジ 01:Low 10:Medium 11:High |
|||
2 | CPSRNG0 | ||||
1 | CPSOUT | オシレータ ステータ (Read Only) | 出力 | 入力 | |
0 | T0XCS | Timer0 外部クロック源選択 | CPS | T0CKI | |
CPSCON1 | 4 | CPSCH1 | チャンネル選択 00 = CPS0 01 = CPS1 10 = CPS2 11 = CPS3 |
||
2 | CPSCH0 |
2つのSWパッドを接続し、指が触れると端子に対応したLEDを点灯させるものです。
上記処理を、2つの端子に対して繰り返します。
<回路図>
<PIC内蔵モジュール関係図>
<CPSカウント計測手順>
<プログラム>
/********************************************************************* * 静電容量式センシング * CPS電極に近づくとLEDが点灯 * * 1 VDD 8 VSS * LED 2 RA5 7 RA0 TX * CPS3 3 RA4 6 RA1 LED * 4 MCLR 5 RA2 CPS2 * * PIC12F1822 MPLAB X IDE with XC8 Ver1.32 * Copyright (c) 2014 iwamoto All Rights Reserved * * *******************************************************************/ #define ch_0_IN 2 // CPS index0 Pad 接続 CPS 端子番号 #define ch_1_IN 3 // CPS index1 Pad 接続 CPS 端子番号 #define ch_0_OUT LATA1 // CPS index0 LED 接続 ポート #define ch_1_OUT LATA5 // CPS index1 LED 接続 ポート #define LED_ON 1 #define LED_OFF 0 #include <xc.h> //******************* コンフィグレーション **************************** #pragma config FOSC = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF #pragma config CPD = OFF, BOREN = ON, CLKOUTEN = OFF, IESO = OFF, FCMEN = OFF #pragma config WRT = OFF, PLLEN = OFF, STVREN = ON, BORV = LO, LVP = OFF // //******************* プロトタイプ ************************************ void CPSck(char); unsigned int CPScnt(char); void LEDout(char, char); //******************* 共通変数 **************************************** char ch_IN[] = {ch_0_IN, ch_1_IN}; // CPS 端子番号 unsigned int Avg[2]; // 通常時平均カウント unsigned int swOn[] = {180,180}; // ON 閾値カウント unsigned int swOff[] = { 90, 90}; // OFF 閾値カウント // ******************* main ****************************************** void main() { OSCCON = 0b01101010; // 内部クロック4Mhz PORTA = 0x00; TRISA = 0b11011101; // RA1,5:LED出力 他は入力 ANSELA = 0b00010100; // RA2,4:CPS, 他デジタル WPUA = 0b00001001; // RA0,3 弱プルアップ ON OPTION_REGbits.nWPUEN = 0; // Timer 0 設定 ------------------------------------------------- // 8.2mSでオーバーフローし、CPSカウントのタイムベースとなる // -------------------------------------------------------------- OPTION_REGbits.TMR0CS = 0; // 内部クロックをカウント OPTION_REGbits.PSA = 0; // プリスケラを使用する OPTION_REGbits.PS = 4; // PS_1:32 // Timer 1 設定 ------------------------------------------------- // Gate機能の シングルトグル モードでCPS をカウントする // -------------------------------------------------------------- T1CON = 0b11000001; // CAPOSC, PS 1:1, OSC無効, 同期, ON T1GCON = 0b11110001; // Gate有効,正極性,トグル,シングル,T0入力 // CPS 設定 ------------------------------------------------------ CPSCON0 = 0b10001000; // CPS有効,内蔵参照電圧,Medium レンジ Avg[0] = CPScnt(0); // 通常時平均カウントの初期設定 Avg[1] = CPScnt(1); while(1){ CPSck(0); // CPS index0 の処理 CPSck(1); // CPS index1 の処理 } } /********************************************************************* * 指定 CPS indexチャネルのカウントを計測し、平均カウントと比較 * ON 閾値より小さければ、LED ON * OFF閾値より大きければ、LED OFF さらに平均値を更新 *********************************************************************/ void CPSck(char ch){ unsigned int raw; raw = CPScnt(ch); // チャネルのカウントを計測 if(raw < (Avg[ch] - swOn[ch])){ // ON 閾値より小さければ LEDout(LED_ON, ch); // LED ON }else if(raw > (Avg[ch] - swOff[ch])){ // OFF閾値より大きければ LEDout(LED_OFF, ch); // LED OFF // 平均値を更新 (重み 1/16) Avg[ch] = Avg[ch] + ((long)raw - (long)Avg[ch])/ 16; } } /********************************************************************** * 指定 CPS indexチャネルのカウントを計測する *********************************************************************/ unsigned int CPScnt(char ch){ CPSCON1 = ch_IN[ch]; // CPS indexチャネル指定 TMR0 = 0xFE; // Timer0 始動 TMR1 = 0; // Timer1 クリア T1GGO = 1; // 計測を指示 while(T1GGO); // 計測終了を待つ return TMR1; // Timer1読取 } /********************************************************************** * 指定 CPS indexチャネルのLEDを ON / OFFする *********************************************************************/ void LEDout(char OnOff, char ch){ switch(ch){ case 0: ch_0_OUT = OnOff;break; case 1: ch_1_OUT = OnOff;break; } }
CPS端子は、使用するアプリケーションにより異なるため、指が離れている時の平均カウント値や、指で押さえたときのカウント値を吟味し、ON/OFFを判断する閾値を見つけ出す必要があります。 下図は、評価に必要な関係図を示します。
*注意*
閾値の swOn と swOff は平均値 Avg からの差で表します。
最新のCPSカウント値が
(Avg - swOn) 値より小さければ、LEDを点灯させ、
(Avg - swOff) 値より大きければ、LEDを消灯させます。
Avg は、指が離れている時の最新16サンプルの平均値を使います。
現在のCPSカウント値が、
(Avg - swOn) 値より小さければ、平均値には反映せず、
(Avg - swOff) 値より大ききければ、現在の平均値に反映させます。
最新16サンプルの平均値に反映するる方法は、今までの(旧)Avg を15/16 した値に、最新CPSカウント値を 1/16 した値を加えます。
実際にアプリケーションを設計するときは、設計する装置毎に、端子形状やPICから端子までの距離が異なるので、そのたびごとにON/OFF閾値を適切な値に変更することが求められます。 この目的のため平均カウントと、現在カウント値を外部接続したシリアル表示器に表示するプログラムを上記プログラムに追加しました。
使用したシリアル表示機は、このホームページで作成したものです。
ON/OFF閾値を検証するプログラム CPS_Cnt_Monitor.zip |
<プログラムの使い方>
CPS用PICのpin7(RA0)とシリアル表示器用PICのpin2(RA5)を接続します。ダウンロードしたプログラムは、
CPS index 1 (CPS3) のカウント値をLCDに表示します。
LCD上段が平均カウント、下段が現在のカウントです。
CPS index 0 (CPS2) のカウント値を表示させるには、
プログラム17行目を #define Enable_Dsp 0 とします。(下図赤丸内)
CPS_Cnt_Monitor.c
参照電圧と充放電電流の関連