質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.93%

ESP32でボタンの同時押しが検知できない件

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,586

 前提・実現したいこと

ESP32-DevKitCと74HC138(デコーダ、デマルチプレクサ)と8個のボタンを使い、
次のような回路を組みました。
![イメージ説明](e048eeedad126a19a23cebaadaf30b98.jpeg)

 発生している問題・エラーメッセージ

Arduinoで同様の回路を組んだ時は、正常にボタンの同時押しが検知できたと思うのですが、
ESP32ではうまく検知できていません。
8本の信号線がバッティングしないようダイオードを噛ませております。
任意のボタンAを押したままにしておいて、別のボタンBを押すと、
ボタンAを押しているにも関わらず離された時の処理が走ってしまい、Bの押下も検知されません。

 該当のソースコード

//Mux control pins
int s0 = 12;
int s1 = 13;
int s2 = 14;
int controlPin[] = {s0, s1, s2};

int muxChannel[8][3] = {
  {0, 0, 0}, //channel 0
  {1, 0, 0}, //channel 1
  {0, 1, 0}, //channel 2
  {1, 1, 0}, //channel 3
  {0, 0, 1}, //channel 4
  {1, 0, 1}, //channel 5
  {0, 1, 1}, //channel 6
  {1, 1, 1}, //channel 7
};

int loop_0_7 = 0;

void setup() {

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);

  pinMode(27, INPUT_PULLUP);

  Serial.begin(115200);

}

void loop() {
  //74HC138の0ピン~7ピンに順次Lowを出力していきます。
  for (int i = 0; i < 3; i ++) {
    if(muxChannel[loop_0_7][i]) {
      if(i==0) GPIO.out_w1ts = ((uint32_t)1 << 12);
      else if(i==1) GPIO.out_w1ts = ((uint32_t)1 << 13);
      else if(i==2) GPIO.out_w1ts = ((uint32_t)1 << 14);
    }else{
      if(i==0) GPIO.out_w1tc = ((uint32_t)1 << 12);
      else if(i==1) GPIO.out_w1tc = ((uint32_t)1 << 13);
      else if(i==2) GPIO.out_w1tc = ((uint32_t)1 << 14);
    }
  }
  //ボタンが押されたかどうかをESP32の27ピンで検知しています。
 //内部抵抗でプルアップしているため、ボタンが押されていないときはHIGH(1)、
 //押されたときはLOW(0)となります。
 byte res1 = (GPIO.in >> 27) & 0x1;
  //ボタンが押された時は、その時のloop_0_7の値を読み取ります。
 //これがボタン番号となります。
  if(!res1){Serial.println(loop_0_7);delay(100);}
 //↑ボタンが押されたときは、res1が0となり、その時のloop_0_7の値を画面出力します。
 //押されている間は100msごとに出力し続けます。
 //離される(res1が1に戻る)と画面への出力がストップします。

  if(loop_0_7==7) loop_0_7=0;
  else loop_0_7++;

}


この原因がお分かりになる方いらっしゃいますでしょうか。

【2018年10月17日追記】
2つのボタンを同時に押したときの不具合は、キーの組み合わせによって異なることが分かりました。
以下、キーの組み合わせと不具合の対応を記載します。
回路図中の8個のボタンを左から0番、1番、2番、3番、4番、5番、6番、7番ボタンとしますと、
■ 0番ボタンを押しながら
1番~7番ボタンを押しても、画面に0を出力し続ける(他のボタンの入力を受け付けない)。
■ 1番ボタンを押しながら
0番ボタンを押すと、画面に0を出力し続ける(1番ボタンは離されたと判断されてしまう)。
2番~7番ボタンを押すと、画面に何も出力されなくなる(すべてのボタンが押されてないと判断されてしまう)。
■ 2番ボタンを押しながら
0番ボタンを押すと、画面に0を出力し続ける(2番ボタンは離されたと判断されてしまう)。
1番、3番、5番ボタンを押すと、画面に何も出力されなくなる(すべてのボタンが押されてないと判断されてしまう)。
4番、6番、7番ボタンを押しても、画面に2を出力し続ける(他のボタンの入力を受け付けない)。
■ 3番ボタンを押しながら
0番~7番ボタンを押すと、画面に何も出力されなくなる(すべてのボタンが押されてないと判断されてしまう)。
■ 4番ボタンを押しながら
0番ボタンを押すと、画面に0を出力し続ける(4番ボタンは離されたと判断されてしまう)。
1番、3番、5番ボタンを押すと、画面に何も出力されなくなる(すべてのボタンが押されてないと判断されてしまう)。
2番ボタンを押すと、画面に2を出力し続ける(4番ボタンは離されたと判断されてしまう)。
6番ボタン、7番ボタンを押しても、画面に4を出力し続ける(他のボタンの入力を受け付けない)。
■ 5番ボタンを押しながら
0番ボタンを押すと、画面に0を出力し続ける(5番ボタンは離されたと判断されてしまう)。
1番~7番ボタンを押すと、画面に何も出力されなくなる(すべてのボタンが押されてないと判断されてしまう)。
■ 6番ボタンを押しながら
0番ボタンを押すと、画面に0を出力し続ける(6番ボタンは離されたと判断されてしまう)。
1番~7番ボタンを押すと、画面に何も出力されなくなる(すべてのボタンが押されてないと判断されてしまう)。
■ 7番ボタンを押しながら
0番ボタンを押すと、画面に0を出力し続ける(7番ボタンは離されたと判断されてしまう)。
1番~6番ボタンを押すと、画面に何も出力されなくなる(すべてのボタンが押されてないと判断されてしまう)。

といった具合です。

ちなみに、下の画像のように、もう1列足して、左から8番~15番ボタンとし、
上の列のボタン1個を押しながら、下の列のボタン1個を押すと期待した通りの出力をしてくれます。
例えば、上の列の0番ボタンと下の列の8番ボタンを同時に押すと、
0
8
0
8
0
8
と交互に出力してくれます。
イメージ説明
本当は同じ列の2個のボタンでも同じように交互に出力して欲しかったのですが、
上記のとおり、予期しない出力をしてしまっています。

【2018年10月18日追記】

同時押しが出来ない問題の前に、
もともとボタンの入力とボタン番号の画面出力が異なる謎の現象が起きていました。
0番ボタンを押すと「4」を画面に出力、4番ボタンを押すと「0」を画面に出力。
この現象がどうにも解消されないため、苦肉の策で配線を入れ替えることにしました。
0番ボタンと74HC138のY4ピンを、4番ボタンを74HC138のY0ピンに接続。
最初の回路図の配線がごちゃごちゃとしているのはそのためです。
このようにすると、左のボタンから0 1 2 3 4 5 6 7と期待通りの値を出力してくれるため、
謎は残るものの、まぁ良いかと思って、同時押しができない問題に取り掛かりました。
そして、以前同じようにArduinoと74HC138とボタンとダイオードを使って同様の回路を組んだときは
期待通りの動きをしてくれていたため、昨夜もう一度それらを組んで、当時のコードを実行しました。
そこで思い出したのは、ボタンの入力とボタン番号の画面出力が異なる現象はArduinoでも
発生していたこと。この現象はプリスケーラの設定を変えることで正常にできたこと。
あと、同時押しを可能にするダイオードの繋ぎ方でした(下図)。
左はダメ。右はおk。
同時押しを可能にするダイオードの繋ぎ方
そして、ESP32に戻って、ダイオードを正確に繋いで試してみようとしたところ、
1つのボタンの入力さえブレブレになってしまいました。
0番ボタンを押すと、0、5、6を出力。
1番ボタンを押すと、1、2を出力。
2番ボタンを押すと、2、3、4を出力。
3番ボタンを押すと、3、4を出力。
4番ボタンを押すと、1、2、4を出力。
5番ボタンを押すと、5、6を出力。
6番ボタンを押すと、0、6、7を出力。
7番ボタンを押すと、0、7を出力。
ちょっと僕の手に負える感じじゃないなと感じています。
別のICを使うなど、ほかの方法を考え始めています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tmp

    2018/10/15 17:56

    ソースに押されたと判断する部分と、離されたと判断する部分の記載おねがいします。

    キャンセル

  • tmp

    2018/10/16 17:51

    現象として、押されてるキーが1つならどのキーも押された状態になるが2つ以上のキーを押すとどのキーも押されていない状態になるという認識でよろしいでしょうか?ハード的な信号の確認はできるのでしょうか?(例えば入力信号の確認など)

    キャンセル

  • morleyrobertson

    2018/10/17 14:06

    tmpさん、質問頂きましてありがとうございます。入力信号の確認につきましては、オシロスコープやロジックアナライザなどを所持していないため、Arduino IDEのシリアルプロッタで確認するぐらいのことしかできていません。また2つ以上のキーが押された時の現象は、キーの組み合わせによって変化しますので、後ほど投稿内容に詳細情報を追記いたします。お手数おかけ致しますが、そちらをご覧いただければと存じます。

    キャンセル

  • tmp

    2018/10/18 12:44 編集

    すいません、最初こちらに書いてしまいましたが、回答の方に書きました。

    キャンセル

回答 2

checkベストアンサー

0

2列の写真ですが、見るとダイオードが意味のない状態になってるように見えますが、大丈夫でしょうか?

追記10/18 19:00
ダイオードがブレッドボードの同じ番号のAとDに刺さってるように見えて、このブレッドボードはAとDは、つながってるのではないでしょうか?
その場合は、ダイオードが付いていない状態と同じになると思います。
そして、2列の写真で判断しましたが、1列の時も同じように接続していないでしょうか?
そうすると症状として1つのボタン押しの時は、正常で2つ以上の場合は、出力がぶつかり出力不定になるのではと思います。

追記10/19
回路図で入れ替えててるのは、気が付いてましたが、何かの使いまわしでそうなってるものだと思っていました。
ボタン0と4が入れ替わるのは、74HC138の出力がESP32の出力から読み取りまですぐの為に間に合わないからと思われます。ESP32の3つの出力を順に出力していきますが、最終の14PIN出力直後に即読むため、その14PINの出力後74HC138の出力変化前の状態の結果を読み取ってしまうからと思われます。
14PINが変化するのは、ボタン7から0 , 3から4 で 14PInが前の状態だとすると 0のとき4の状態に、4の時は、0の状態になり、症状にあいます。
GPIOの出力後、GPIOの入力までにほんの少し待ちをいれるか、もう少し速い138に変えれば、正常に読み取れたと思います。
プリスケーラと書いていますが、なんのプリスケーラを変えたのかわかりませんが、おそらく処理を遅くしたことで74HC138が間に合うようになったのでしょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/18 17:54

    ダイオードの質問、ありがとうございます。
    昨夜、新たな現象が出てきてしまい、ダイオードどころの話ではなくなってしまいました。
    長文になりそうですので、今から追記いたします。
    お手数ですが、そちらをご覧下さい。

    キャンセル

  • 2018/10/18 19:31

    ■追記への返答
    そうなんですよ。ダイオードの繋ぎ方を昨夜思い出しました。その辺りも追記いたします。
    ありがとうございます。

    キャンセル

  • 2018/10/21 21:06

    tmpさん、アドバイスの通り今試してみたところ、全ての問題が解決いたしました!本当に、本当にありがとうございます!たった1マイクロ秒のdelayを入れるだけで、あらゆる不具合が解消しました。
    このページをご覧になった皆様へ 
    同じESP32でも、スイッチサイエンス社製のESPr Deveroper32では同じ回路、同じコードを実行しても、やはり不具合は出たままとなっています。74HC138に限らずロジックICを使う場合は、ESPr Deveroper32は不向きだと感じています。ご参考までに。

    キャンセル

0

画像を拡大しても、マルチプレクサの型番が確認できませんでしたが、ふつう、このテのICにはプルアップ/プルダウン抵抗が必要です。

また、どうも回路的におかしいようですが、もうちょっと鮮明な拡大された回路図を提示してください


ああ、HC138なんですね。
それだと、マルチプレクサのアドレス選択のコード出力が間違ってます。

GPIO.out_w1ts = (GPIO.out_w1ts & ~(0x7<<12))|((loop0_7&0x7) << 12);

だけでいいでしょ

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/15 19:33

    y_waiwaiさん

    ご回答ありがとうございます。
    コードの中の
    for (int i = 0; i < 3; i ++) {
    if(muxChannel[loop_0_7][i]) {
    if(i==0) GPIO.out_w1ts = ((uint32_t)1 << 12);
    else if(i==1) GPIO.out_w1ts = ((uint32_t)1 << 13);
    else if(i==2) GPIO.out_w1ts = ((uint32_t)1 << 14);
    }else{
    if(i==0) GPIO.out_w1tc = ((uint32_t)1 << 12);
    else if(i==1) GPIO.out_w1tc = ((uint32_t)1 << 13);
    else if(i==2) GPIO.out_w1tc = ((uint32_t)1 << 14);
    }
    }
    の箇所が
    GPIO.out_w1ts = (GPIO.out_w1ts & ~(0x7<<12))|((loop0_7&0x7) << 12);
    に置き換え可能ということでしょうか。

    キャンセル

  • 2018/10/15 19:34

    そゆことだけど、きちんと理解して使いましょうねっ

    キャンセル

  • 2018/10/15 20:04

    y_waiwaiさん

    返信ありがとうございます。
    111を12ビット左にシフトする。
    loop_0_7と111のビットを比較する。
    共に「1」の場合だけ「1」にして、12ビット左にシフトする。
    と理解しました。
    今、実機で試したのですが、動作が前より意図しない感じになってしまいましたので、考えてみます。
    ありがとうございました。

    キャンセル

  • 2018/10/16 18:01

    GPIO.out_w1tsは、現在の出力ポートの状態ではありません、ライトオンリーでセットしたいところの対応ビットを1にするものです。リードするとどのような値が読み取れるか特に書いていませんし、また、セットしかできませんのでGPIO.out_w1tcのクリアする方も必要です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る