チャタリング防止

PICやarduinoで,タクトスイッチ等の安物を使うと,話題に上るのがチャタリングです。チャタリングのこと
を考えないと思った動作をしなくなります。
通常は,シュミットトリガー回路に代表されるハードを使って取り除く方法や,ソフトで取り除くこと等が必
要のようです。ソフトでは,間をあけて何回か測定して判別する方法等があるようですが,あるHPで,ビット
シフトを使った方法がでていました。

#define MAXPIN 13

int checkbutton(int i){
   static byte val[MAXPIN];
   static byte state[MAXPIN];

   if(digitalRead(PIN[i]) == 1){
      val[i] = val[i]<<1;
      val[i] += digitalRead(PIN[i]);
   }else{
      val[i] = 0;
   }

   if(val[i] == B01111111){
      state[i] = 1 - state[i];
   }

   return state[i];
}

やはり,先達はすごい。い くつか変数を用意しておいて,古いデータと比べるということは考えつきますが,
ビットシフトを使うとは,すごいなと思いました。ただ,このプログラム,IDEでコンパイルすると

 B01111111→→0b01111111

と怒られます。ちょっとした勘違いなんでしょうね。「弘法も筆の誤り」ですね。

追記
 あと,シフトビットのいいところは,オーバーフローを気にしなくていいことでしょうか。シフトで
はみでた部分は,破棄されるようですので。ここを,int等の変数で足し算すると,オーバーフローの処置をいれないとPGが暴走しますので。

併せて,変数のスコープ等について,調べていたら,大きな勘違いをしていることに気がつきました。IDE
では,Loopの中にmainのプログラムを書きますが,一回だけ実施したい処理を次のように書きました。


loop(){
   int flag;
   if(flag==0){
      syori;//動作させたい処理
      flag=1;
   }
}

みたいな記述をしていましたが,思った動作はしませんでした。それもそのはず,loopの中で,
最後の「 }」の前で,変数が初期化されてしまうとのこと。これでは,思った動作をしませんね。
保持するには,

  int flag;→→static int flag;

のように,静的変数の宣言をしないとだめということが分かりました。これ,IDEの癖みたいなものでしょう
か。知らないとこまりますね。今まで,loopのなかの冒頭で,変数の宣言をしていましたが,これ,何回も
宣言することになって,なんだろうと,疑問にも思っていたところなので,この疑問も解決ですね。

PWM信号発生器のシリアル通信

 過日,いろいろ試すのに◯mazonkから,PWM信号発生器を購入し,
 便利に使ってました。

 

 商品の説明にもシリアル通信ができると記述があり,基盤の裏
 にも TXD RXD の記述があるので,外部からコントロール
 できるのかなと思ってました。
 手持ちのシリアル通信のアダプターに接続し,PCから,あれこれ
 やってみました。
 最初「テラターム」でやりましたが, FAIL の文字が帰ってくる
 だけで,通信はできているようでしたが,うまくいかないようでした。
 「シリアル通信ソフト」というソフト名のプログラムをベクターから
 DLして,試してみると,あっけなく通信ができました。
 (起動にあたっては,管理者権限で起動しないとだめでした。)
 難しいプロトコルが必要かとおもいましたが,簡単なコマンドで,
 制御できるようです。

 

 写真は, ”read” のコマンドで,設定の状態を読んでいます。

   F055 → 周波数
   D090 → DUTY%

 と,表示されている数値を読み取ることができました。
 ちなみに,設定するには,

  周波数 001→999     F*** (ex F090 →90Hz)
  周波数 1.00→9.99   F*.**(ex F1.45 →1.45KHz)
  周波数 10.00→99.9  F**.*(ex F10.45 →10.45KHz)
  周波数 1.0.0→1.5.0 F*.*.*(ex F1.4.6 →146KHz)
  DUTY  1→100       D***(ex D090 →90%)
  read    設定データの読み取り

 でした。まだ,やっていませんが,PICからもコントロールでき
 そうなので,これを使った方が,手軽にPWMの信号のコントロール
 できるかもですね。

自作デジポット(デジタルポテンショメーター)---(3)

ーーーグレイコード(3)ーーー
 A相とB相の信号を使えば,回転方向を検出できることは,
 理解できました。
 これをプログラムで実現するには,いくつか方法がある
 ようです。
 自作のMPG関連では,B相の立ち上がりを検出し,それを
 DFFのICにいれて,回転方向を検出してました。
 今回は,別な方法でやってみようかなと思います。
 基本的な考え方は,◯月の取説にあったように,前回と
 今回の2回のサンプリングをして,その組み合わせの全部
 から回転方向を決める方法です。
 エンコーダーから,出力されるグレイコードをバイナリ変換
 して,前回と今回の2回のサンプリングの差を取って,+1
 の場合は時計方向,-1の場合は逆時計方向としてもいい
 のですが,バイナリ変換するのにビット操作が必要なので,
 私にはちょっと苦手かなと思います。
 それで,組み合わせを全部拾い出し,それをインデックスに
 して,回転方向を決めるのが私には分かり易いかなと思い
 ました。
 前回グレイコード(2)記事の表から,前回と今回の
 サンプリングの可能性を考えて見ます。
 可能性は,次のようになります。
  
  時計回転
  前回→今回
  00 →00 動かない(0)
  00 →01 時計回転(+1)
  00 →11 一つ先に移動(エラー)
  01 →01 動かない(0)
  01 →11 時計回転(+1)
  01 →10 一つ先に移動(エラー)
  11 →11 動かない(0)
  11 →10 時計回転(+1)
  11 →00 一つ先に移動(エラー)
  10 →10 動かない(0)
  10 →00 時計回転(+1)
  10 →01 一つ先に移動(エラー)
  逆時計回転
  前回→今回
  00 →00 動かない(0)
  00 →10 逆時計回転(-1)
  00 →11 一つ先に移動(エラー)
 
  10 →10 動かない(0)
  10 →11 逆時計回転(-1)
  10 →01 一つ先に移動(エラー)
  11 →11 動かない(0)
  11 →01 逆時計回転(-1)
  11 →00 一つ先に移動(エラー)
  01 →01 動かない(0)
  01 →00 逆時計回転(-1)
  01 →10 一つ先に移動(エラー)
 全部で16通りありますので,前回を2ビットシフトして,
 今回と合計すると,その数値がインデックスの数値として
 使えることになります。エラーを100とすると,
  m[(前回<<2)+今回]=数値
  m[0000]=0
  m[0001]=1
  m[0011]=100
  m[0101]=0
  m[0111]=1
  m[0110]=100
  m[1111]=0
  m[1110]=1
  m[1100]=100
  m[1010]=0
  m[1000]=1
  m[1001]=100
  m[0010]=-1
  m[1011]=-1
  m[1101]=-1
  m[0100]=-1
 のようになり,[ ]内を16進数に直すと,
  m[0]=0
  m[1]=1
  m[3]=100
  m[5]=0
  m[7]=1
  m[6]=100
  m[F]=0
  m[E]=1
  m[C]=100
  m[A]=0
  m[8]=1
  m[9]=100
  m[2]=-1
  m[B]=-1
  m[D]=-1
  m[4]=-1
 のようにすることができます。この配列を使えば,
 回転方向の検出ができることになります。

自作デジポット(デジタルポテンショメーター)---(2)

ーーーグレイコード(2)ーーー
 グレイコードをWikipediaでは,
 グレイコード(英: Gray code、交番二進符号
 (こうばんにしんふごう、英:Reflected Binary Codeなどとも)
 とは、数値の符号化法のひとつで、前後に隣接する符号間
 のハミング距離が必ず1であるという特性を持つ
 よような事が書いてあります。なんの事やらと思いましたが,
 どうやら,連続する2進数の符号の変化が,一つだけする
 表記の仕方のようでした。
 ですから,通常の表記とは,違ってるようです。下記がその
 対比表です。

 

 通常の2進数では,
   3→4の変化で 0011→0100
 のように3箇所変化してますが,
 グレイコードでは,
   3→4の変化で 0010→0110
 のように,1カ所しか変化していません。
 この性質が,エンコード等のデータの変化を取り出すのに
 エラーが少なくなるとのような記載もありました。
 エンコーダーの出力をみてみると,その出力は,まさに,
 グレイコードでした。

 

 エンコーダーの出力を Hightを 1 Lowを 0 として,
 B相を1ビット目,A相を0ビット目とした,2進数の出力と
 見てみると,見事にグレイコードの出力になってました。
 なぜ,回転の出力をA相,B相の出力に分けてあるのか,
 なんとなく理解できました。

自作デジポット(デジタルポテンショメーター)---(1)

 ーーーグレイコード(1)---
 縁あって,X9C,AD5220というデジタルポテンショメーター
 を弄る機会に恵まれました。
 存在は,たまに見かけて知っていましたが,スピンドルの
 DCモーターのコントロールもなんとかできました。
 そこで,同じような原理で,自作してみようかなと思いたち
 ました。
 構想として,ロータリーエンコーダーや,タクトスイッチ等で
 アップ・ダウンができること。
 7セグLEDかLCDでモニターできること等,できればいいなと
 思ってます。
 そこで,いろいろ調べ始めました。手始めに,
 ロータリーエンコーターをあたりました。
 以前,自作のMPGを作成した時に,ちょっと,調べたのですが
 調べるといくつか分からないことがでてきました。
 まず目にとまったのが◯月の,
  http://akizukidenshi.com/catalog/g/gK-00083/
 の取説の記事で,
  現在の値をf(t1),一つ前の値をf(t0)とし,記号”<”を
  左ビットシフト,”+”を ex-or をそれぞれ表すものとし
  て,
    D=f(t0<1)+f(t1)
  という回転判別式を定義します。
  (1)時計回りの場合
     入力系列が 00,01,11,10・・・・・・であるので,
    D0=(00<1)+01=01     D1=(01<1)+11=01     D2=(11<1)+10=00     D3=(10<1)+00=00  の記述があり,演算結果の2ビットめを見ると,回転方向  を判別できると記載がありました。  ここで,なぜ,シフトするのか,なぜ,ex-orをするのか,  釈然としませんでした。  いろいろHPをあさりましたが,どうやら,グレイコードに  関係がありそうだということが諸兄のHPで分かりました。   ロータリー・エンコーダの使い方
  ロータリーエンコーダの使い方
  
 等を見て,シフトやex-or グレイコードに関係する
 ということがなんとなく分かりました。
 グレイコードについて,調べて見ます。

---番外編---

 PICをあれこれいじってます。
 ところが,昨日,突然,PICへの書き込みができなくなりました。
 思いつくこと全てやりましたが,だめでした。
 それで,PICKITが故障かなと思い,安いの早速ポチりました。
 夜,また試してみようと,あれこれやると,
 原因が判明しました。PICと基盤接続の自作のコードの一本が
 コネクターの部分で,断線してました。
      あーあ,あーあ,
      ジェジェジェジェッ 
 でした・・・・・。

おもちゃの作成(5)---I2C LCD ACM1602

 制作のついてでに,手元にあるI2CインターフェースのLCD
 をケースに入れて動作を確認しました。
 PICのプログラムを組んでももかったのですが,デバック等
 多少手こずりそうだったので,諸兄のHPにあったaruduino
 をパクりで,動作を確認しました。

 

 諸兄の作られたaruduinoのACM1602用のライブラリーも
 そのまま使わせていただきました。あっけなく完動いたしまし
 た。
 諸兄の配線図では,ACM1602とaruduinoを直接つないで
 いるようでしたが,念のため,間にレベル変換の基板をいれ
 て,接続しました。これ必要ないのかもですね。

 

 諸兄の配線図では,A4とA5を3.3Vにプルアップして,LCD
 に直接つないでいるようでした。このへんの詳細がちょっと
 分かりません。
 とりあえず動きましたので,これから,ボチボチPICの方も,
 プログラム見ていきたいと思います。

 
 
 
 
 

おもちゃの作成(4)---おもちゃの正体

 おもちゃの作成を初めて何日か過ぎました。
 やっと,だいたい完成です。
 おもちゃは,なんのことはない,ポケモンgoプラス
 という,ポケモンをボタン一つで捕獲できる器具を,自動で,
 動作できるようにしたものです。

 

 このポケモンgoプラスの中身を,諸兄のHPを参考に,
 スイッチと振動モーターの結線を引き出し,フォットセンサー
 で読み取った光に応じて,フォットカプラーにて,引き出し
 た線を短絡させるという動作を,自動で行うようにしたものです。

 

 諸兄のHPのように短絡させただけで,自動化できるのですが,
 ちょっと,面白みがないので,手に入った光センサーと組み合わ
 せて作りました。
 ちょっと,大きいのですが,プラスチックの箱にいれて,遊んで
 みる予定です。

 

おもちゃの作成(3)---プロトタイプ?完成

 備忘録で,回路図の掲載です。

 

 冗長なプログラムですが,掲載します。

   main.txt

 あっちこっち,ゴミが残ってますし,一貫した表記では,
 ないですね。その時の気分で,細かい部分が変わってしまいまし
 た。
 そうそう,回路図書いていて,フォットカプラーとタクトスイッチ
 が逆になってること気がつきました。
 回路図が間違いですね。面倒なので,そのままです。
 
 LCDの接続には,全部で8本の結線が必要です。
 I2C方式だと,半分の4本で済みます。
 手元にI2C用のLCDもあるので,LCDのライブラリー
 も諸兄のページを参考に作っておこうかと思います。
 ついでにケースにいれときますかね。

おもちゃの作成(2)---プロトタイプ?完成

 このところ取り組んでいたおもちゃのプロトタイプがほぼ完成
 しました。
 完成の前に,いくつかはまりました。今日は,AD変換の配線
 にはまりました。
 電気の基礎ができてる方は,こんなことはないのでしょうが,
 AD変換がうまくいかなく,もがきました。
 原因は,なんのことはない,AD変換のボリュームは,分圧して
 ることを忘れていました。つまり,-側の配線をしていません
 でした。こんな知識もないのか,とちょっとがっかりしました。
 それと,センシングが微妙で,光源にセンサーが近すぎると
 緑成分と青成分の両方に感応してしまいます。センシングの
 時間を短くすると感度が悪くなるしで,ちょっと,いたちごっご
 でした。
 ただ,それぞれの色を感知するときは,その色の数値が
 他の色の数値より多くなるので,プログラムで処理しまし
 た。
 備忘録のために,回路図,プログラム等,順次掲載しようと
 思います。
 作ったおもちゃはなんのことはない,青と緑のLEDの光を感知
 して,感知した色を点灯させて,外部スイッチ(フォットカプラー)
 をONにするという単純なものです。

 

 外部スイッチをONにする時間と点灯LEDの時間,をどうするか
 迷いましたが,外部スイッチをONにする時間とLEDをONに
 する時間は,0.1秒程度にしました。
 それと,長い時間その色を感知すると,0.1秒点灯の繰り返し
 になりますので,一度,点灯させたら,1秒程度やすませる
 というようなプログラムにしました。
 単純に delay を使ってもよかったのですが,その間,センシング
 も止まるので,割り込みを使って,約1秒の待ち時間をつくって
 みました。