gombeのブログ

マイコンの電子工作系PIC32/KiCad/C/C++/3D/

時計の完成(ハード側)

時計が完成しました。ソフトはまだ調節中です。(時刻調節未実装)

img_2489

左の6は輝度を示します。CdSで自動的に輝度を変更します。時刻カウントについてはほぼ完璧でした。まあずれても困るしね(w。

アクリル板もレーザーカットしました。裏のパネルに彫刻も入れたりとか。

img_2503

まずはTouchSensingで調節してみるか。

それではタッチセンシングのやり方についてまとめておきます。TouchSensingについては多数のやり方が存在します。本マイコン(PIC16F1938)にはタッチセンサーが8つくらいついてた気がします。それらは浮遊容量の変化としてマイコンはタッチを検出します。なんか空いているIOを触るとグラグラしますよね?それと原理は同じです。以下の画像はアプリケーションノートからの転用の転用です。img_2491

センサーの反応値はアナログ的に出力されます。一定期間内に反応した回数であるためです。そのためノイズに対しては非常に弱くなります。何らかの形で様々なノイズ対策が求められます。今回はメーカーの指定通りのPCBパターンで作りました。センシングは容量の変化による充放電の時間変化をもち入ります。そのため元から容量成分が大きいとうまく検出しにくいのであらかじめパターンの周辺のベタグランドを両面とも抜いておきます。また、センシングまでの経路は極力最短で配線し、ノイズの影響を減らします。ガードパターンを敷いてクロスストークを極力減らしますが、センサーの裏にはベタパターンは敷かずに禁止ゾーンとして抜いておきます。これは浮遊容量を極力減らすためです。本来はtmr1を用いて計測します。これは成分における感度、振れ幅を大きくするためであり、比較的ラフに組んでも平気ですが、Tmr1はすでに時刻計測に用いています。だからパターンの設計時から考慮を重ねておく必要があるとの判断です。

タッチセンサーでは機械式でないためチャタリング等の誤作動が起きないものの、値はノイズなどで上下するためアナログ的なもなのでヒステリシスを設ける必要があります。ヒステリシスについての説明をします。

img_2494

上記の図は閾値を赤の線でとったときの反応図です。HLそれぞれ繰り返していて不安定です。これは得られるデータの中に不安定なデータが混入してしまった場合の例です。以下の図はヒステリシスを設けたときの反応です。

img_2495

一回の変化で一回のみ反応するようになります。これはHのときの閾値とLのときの閾値の差によるものでこれがあるおかげで大幅にシステムを安定化されることができます。このヒステリシス幅はソフトウェアで実施する際は通常かなり小さいです。例えばボタン式スイッチでは押すまでに必要な力とそれを維持する力は異なりますよね。それをSoftwareで実装するということです。

これは量産する際にも非常に重要です。例えば今回は何台か作りますがその状態によってはアナログ値が少々上下するかもしれません。これを吸収と言ったら大げさでしょうか?をすることもできます。反応するところとしないところまで指を近づけたときの動作を確定させるということになります。

ボタンを増やす際はさらに多くの課題を解決する必要があります。今回は1つだけですが、ボタンが複数あるということは同時にセンシングできるのが一つだけという制約上切り替えての使用になります。今回は使わないですが例えば4Portだけ持ちいれば最大10個のセンサーを実装することができます。同時押しなどは非対応になりますが。。。詳しくはApplicationNoteを見てください。それにしても素晴らしい機能ですよね。

さらに今回は移動平均を考えていきます。移動平均は移動する平均つまり直近n回のデータの平均を取る作業を示します。この移動平均を取ることで瞬間的なノイズに対して強くなりますがレスポンスが遅れるのが欠点です。ここでは10msごとのサンプリングを4回の移動平均をとってそのヒステリシスを設けたアルゴリズムになります。

入力したいポートはアナログ入力に設定しておきます。ADみたいに同時にサンプリングができずに複数ポートでは一つずつサンプリングします。サンプリング時間という明確なものはなく、実際に実装するときはオーバーフローしない範囲で適当に定めます。Tmr0の時に最低感度ならば10msが妥当でしょうか?200ほど触れます。触ると100ほどまで下がります。

では実際に実装することを考えてコードを書きます。

[c] タッチセンシング値読み出し後再スタート uint8_t _getTouchValue(void){ uint8_t data;

CPSON=0; data=TMR0; TMR0=0; CPSON=1;

return data; } 押下確認で10msごとに呼び出す。 int8_t getTouch(void){ static uint8_t data[4]; static uint8_t idat; uint8_t sum; static uint8_t result;

data[idat++] = _getTouchValue(); idat&=3;

sum=0; for(i=0;i<4;i++){ sum+=data[i]; }

if(!result&&sum<Border-Hysteresis){ result=1; } else if(!result){ result=0; } else if(sum<Border+Hysteresis){ result=1; } else{ result=0; } [/c]