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

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

新規登録して質問してみよう
ただいま回答率
85.49%
Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

3回答

4208閲覧

ESP-IDF での GPIO について

sola

総合スコア12

Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2018/08/05 16:29

編集2018/08/05 16:30

WiFiBoy32 と呼ばれる、 ESP-WROOM-32 (ESP32) 搭載の Arduino 互換チップボード上での ESP-IDF の話です。
GPIO にて、プッシュボタン押下(IO)を検知し、Blutooth 経由で HID によるキーボード操作を考えています。
実現したい挙動は以下のとおりです。

①プッシュボタンを1度押下
②プッシュボタンに対応したキーボードキーを1度送信

サンプルを参考にコードを作成しましたが上手くいきません。
実際の挙動は

①プッシュボタンを1度押下(直後に指を離して押下前の状態に戻す)
②プッシュボタンに対応したキーボードキーが連続して送信(別のキーの送信に至るまで止まらない)

となります。また、キー定義は

C

1#define GPIO_INPUT_IO_UP 33 2#define GPIO_INPUT_IO_DOWN 27 3#define GPIO_INPUT_IO_LEFT 17 4#define GPIO_INPUT_IO_RIGHT 32 5#define GPIO_INPUT_IO_B 34 6#define GPIO_INPUT_IO_A 35 7#define GPIO_INPUT_IO_START 39 8#define GPIO_INPUT_IO_SELECT 23

としていますが、そのうち LEFT, DOWN, START のみ反応しており、他のキーは反応しません。
実際のコードは以下のとおりです。(文字数制限のため、関係ないと思われる箇所は変数や関数含め割愛しております。)
実現したい挙動に近づけるべくアドバイスいただけると助かります。

esp/ble_hid_device_demo/main/ble_hidd_demo_main.c

C

1#define GPIO_OUTPUT_IO_0 18 2#define GPIO_OUTPUT_IO_1 19 3#define GPIO_OUTPUT_PIN_SEL ((1<<GPIO_OUTPUT_IO_0) | (1<<GPIO_OUTPUT_IO_1)) 4#define GPIO_INPUT_IO_UP 33 5#define GPIO_INPUT_IO_DOWN 27 6#define GPIO_INPUT_IO_LEFT 17 7#define GPIO_INPUT_IO_RIGHT 32 8#define GPIO_INPUT_IO_B 34 9#define GPIO_INPUT_IO_A 35 10#define GPIO_INPUT_IO_START 39 11#define GPIO_INPUT_IO_SELECT 23 12#define GPIO_INPUT_PIN_SEL ((1<<GPIO_INPUT_IO_UP) | (1<<GPIO_INPUT_IO_DOWN) | (1<<GPIO_INPUT_IO_LEFT) | (1<<GPIO_INPUT_IO_RIGHT) | (1<<GPIO_INPUT_IO_B) | (1<<GPIO_INPUT_IO_A) | (1<<GPIO_INPUT_IO_START) | (1<<GPIO_INPUT_IO_SELECT)) 13#define ESP_INTR_FLAG_DEFAULT 0 14 15static xQueueHandle gpio_evt_queue = NULL; 16static uint16_t hid_conn_id = 0; 17 18void IRAM_ATTR gpio_isr_handler(void* arg) 19{ 20 uint32_t gpio_num = (uint32_t) arg; 21 xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); 22} 23 24void gpio_task_example(void* arg) 25{ 26 static uint8_t i = 0; 27 uint32_t io_num; 28 for(;;) { 29 if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { 30 uint32_t value = gpio_get_level(io_num); 31 ESP_LOGI(HID_DEMO_TAG, "GPIO[%d] intr, val: %d\n", io_num, value); 32 if(io_num == GPIO_INPUT_IO_LEFT){ 33 uint8_t key_vaule_a = {HID_KEY_A}; 34 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_a, 1); 35 } 36 if(io_num == GPIO_INPUT_IO_UP){ 37 uint8_t key_vaule_w = {HID_KEY_W}; 38 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_w, 1); 39 } 40 if(io_num == GPIO_INPUT_IO_RIGHT){ 41 uint8_t key_vaule_d = {HID_KEY_D}; 42 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_d, 1); 43 } 44 if(io_num == GPIO_INPUT_IO_DOWN){ 45 uint8_t key_vaule_s = {HID_KEY_S}; 46 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_s, 1); 47 } 48 if(io_num == GPIO_INPUT_IO_B){ 49 uint8_t key_vaule_k = {HID_KEY_K}; 50 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_k, 1); 51 } 52 if(io_num == GPIO_INPUT_IO_A){ 53 uint8_t key_vaule_l = {HID_KEY_L}; 54 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_l, 1); 55 } 56 if(io_num == GPIO_INPUT_IO_SELECT){ 57 uint8_t key_vaule_h = {HID_KEY_H}; 58 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_h, 1); 59 } 60 if(io_num == GPIO_INPUT_IO_START){ 61 uint8_t key_vaule_j = {HID_KEY_J}; 62 esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_j, 1); 63 } 64 } 65 } 66} 67 68static void gpio_demo_init(void) 69{ 70 gpio_config_t io_conf; 71 //disable interrupt 72 io_conf.intr_type = GPIO_PIN_INTR_DISABLE; 73 //set as output mode 74 io_conf.mode = GPIO_MODE_OUTPUT; 75 //bit mask of the pins that you want to set,e.g.GPIO18/19 76 io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; 77 //disable pull-down mode 78 io_conf.pull_down_en = 0; 79 //disable pull-up mode 80 io_conf.pull_up_en = 0; 81 //configure GPIO with the given settings 82 gpio_config(&io_conf); 83 84 //interrupt of rising edge 85 io_conf.intr_type = GPIO_PIN_INTR_POSEDGE; 86 //bit mask of the pins, use GPIO4/5 here 87 io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; 88 //set as input mode 89 io_conf.mode = GPIO_MODE_INPUT; 90 //enable pull-up mode 91 io_conf.pull_up_en = 0; 92 gpio_config(&io_conf); 93 94 gpio_set_intr_type(GPIO_INPUT_IO_UP, GPIO_INTR_ANYEDGE); 95 gpio_set_intr_type(GPIO_INPUT_IO_DOWN, GPIO_INTR_ANYEDGE); 96 gpio_set_intr_type(GPIO_INPUT_IO_LEFT, GPIO_INTR_ANYEDGE); 97 gpio_set_intr_type(GPIO_INPUT_IO_RIGHT, GPIO_INTR_ANYEDGE); 98 gpio_set_intr_type(GPIO_INPUT_IO_START, GPIO_INTR_ANYEDGE); 99 gpio_set_intr_type(GPIO_INPUT_IO_SELECT, GPIO_INTR_ANYEDGE); 100 gpio_set_intr_type(GPIO_INPUT_IO_A, GPIO_INTR_ANYEDGE); 101 gpio_set_intr_type(GPIO_INPUT_IO_B, GPIO_INTR_ANYEDGE); 102 103 gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); 104 xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL); 105 106 gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); 107 108 gpio_isr_handler_add(GPIO_INPUT_IO_UP, gpio_isr_handler, (void*) GPIO_INPUT_IO_UP); 109 gpio_isr_handler_add(GPIO_INPUT_IO_DOWN, gpio_isr_handler, (void*) GPIO_INPUT_IO_DOWN); 110 gpio_isr_handler_add(GPIO_INPUT_IO_LEFT, gpio_isr_handler, (void*) GPIO_INPUT_IO_LEFT); 111 gpio_isr_handler_add(GPIO_INPUT_IO_RIGHT, gpio_isr_handler, (void*) GPIO_INPUT_IO_RIGHT); 112 gpio_isr_handler_add(GPIO_INPUT_IO_START, gpio_isr_handler, (void*) GPIO_INPUT_IO_START); 113 gpio_isr_handler_add(GPIO_INPUT_IO_SELECT, gpio_isr_handler, (void*) GPIO_INPUT_IO_SELECT); 114 gpio_isr_handler_add(GPIO_INPUT_IO_B, gpio_isr_handler, (void*) GPIO_INPUT_IO_B); 115 gpio_isr_handler_add(GPIO_INPUT_IO_A, gpio_isr_handler, (void*) GPIO_INPUT_IO_A); 116 117} 118 119 120void app_main() 121{ 122 /* コード中略 */ 123 gpio_demo_init(); 124 xTaskCreate(&hid_demo_task, "hid_task", 2048, NULL, 5, NULL); 125 126}

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

キーが離されたという信号を送らないから
受信側がキー長押しの反応をしてるのではありませんか?

esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_a, 1); //KEYDOWN //Aを押した esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_a, 0); //KEYUP //Aを離した

4個目の引数が0だとKEYUPになるようです。
連続で送るか、
離されたときに送るかしましょう。

投稿2018/08/31 04:45

編集2018/08/31 05:05
hillacken

総合スコア359

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sola

2018/09/02 10:16

ありがとうございます。連打される状況は改善致しました。 ただし、 ・数回に1度のみ反応するようになった ・引き続き記載の一部のキーのみ対応 という状態です。
hillacken

2018/09/02 13:43 編集

数回に一度しか反応しない、一部のキー以外は反応しない この、「反応しない」というのは スイッチを押したけど割り込みgpio_isr_handlerが発生しないのか gpio_isr_handlerは発動するがif文まで到達しないのか if文に到達しているがesp_hidd_send_keyboard_valueが正常終了しないのか esp_hidd_send_keyboard_valueで送信しているが相手が反応しないのか どこでコケているのか調べる必要があります
sola

2018/09/04 18:32

ありがとうございます! 確認したいと思いますが、具体的にどういった方法で確認すべきでしょうか? アドバイス頂けると嬉しいです。
hillacken

2018/09/04 23:19

printfデバッグと呼んだりしますが、 まずはESP_LOGIをそれぞれの関数の先頭とそれぞれのif文の先頭で実行して プログラムがどこまで進んでいて どこでルートから外れているか確認するのがいいのではないでしょうか
hillacken

2018/09/04 23:22

ブレークポイントを使える開発環境であれば ブレークポイントを使ってどこまで進んでいるか確認でもよいでしょう
guest

0

これってRTOS環境ですよね。
じっくり読んでいるのですが、一部のルーチンの使い方の問題?
一番簡単なのは各ボタンの処理で’io_num’の値を初期化(どれでも無い値)をセットして挙動を見る(続けざまに送信する件)が先にすべき対応ですね。

恐らくAWSのRTOSなので実環境を用意するのに時間が掛かるのでご了承ください。
また全て割り込み定義されているので出来ればハードの定数(抵抗値とか、使っているタクトスイッチの型番とか)が分かると近道です。

投稿2018/08/06 10:46

MasahikoHirata

総合スコア3747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sola

2018/08/06 11:05

コメントありがとうございます。 > これってRTOS環境ですよね。 私も詳しくないですが、キューの仕組みに FreeRTOS のものが用いられているとの事なので、おそらくそうなのではと思います。 キューの挙動が理解出来ておらず、そこを抑えるともう少しまともなコードになる気はしております。 > 一番簡単なのは各ボタンの処理で’io_num’の値を初期化(どれでも無い値)をセットして挙動を見る(続けざまに送信する件)が先にすべき対応ですね。 続けざまに送信するとは、 ①どれでも無い値 ② xQueueReceive で受け取った値 これを連続で、という事でしょうか? > ハードの定数(抵抗値とか、使っているタクトスイッチの型番とか)が分かると近道です。 申し訳ないですが、明示された情報がなく、以下の写真から読み取れる事しか分かりません。 http://wifiboy.org/img/wifiboy32a.png (裏側を見たところ、抵抗のような部品が見つかりましたが、小さすぎて私には見分けがつきませんでした。)
MasahikoHirata

2018/08/06 13:17

ホビーユースならば良いのですが、実際に回路設計をする場合、他の回答者様も指摘されているような’チャタリング’の対策は重要です。これはオシロで見た程度では無く、論理的に間違いない状態での結論が必要です。またRTOSであるかないかは回答に重要な点です。
sola

2018/08/06 13:59

> ホビーユースならば良いのですが、実際に回路設計をする場合、他の回答者様も指摘されているような’チャタリング’の対策は重要です。 今回はホビーユースですので、一旦動くことを目標にできればと考えています。 > これはオシロで見た程度では無く、論理的に間違いない状態での結論が必要です。 「論理的に間違いない状態での結論」とは、プログラムロジックで分かる部分の話ということでしょうか? > またRTOSであるかないかは回答に重要な点です。 私が明確に把握しているのは投稿に記載の内容のみです。明確にそうであるか否か回答できる状態にはありません。申し訳ありません。 RTOSであるか否か判断するためには、私の方で何をすべきでしょうか?
MasahikoHirata

2018/08/13 13:52

お盆休みの時間を使って実機で確認中です。少し時間をください。
sola

2018/08/13 13:54

本当にありがとうございます!急いでないですので、無理はせずに。 助かりますm(_ _)m
guest

0

ざっとしかソースを見てませんが。
スイッチの入力を処理しようとする場合、チャタリングというものを考慮する必要があります
#「チャタリング」でぐぐってみてください
提示されたコードでは、スイッチ入力を割り込みで処理しようとしてますが、これはまずいです
チャタリングのために、一回の押下で複数の割り込みがかかってしまう恐れがあります

このチャタリングを除去するためには、約5msごとにスイッチの状態を読み出し、直前の状態と同ーであれば、その値をスイッチの状態と判定することです
そして、スイッチの状態が、OFFからONになったときだけ、送信をするようにしましょう
スイッチの状態がONのときに送信、としたら、押している間、送信が続くことになってしまいます

投稿2018/08/05 22:40

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sola

2018/08/06 01:12 編集

コメントありがとうございます。 > 押している間、送信が続くことになってしまいます 前提として、押している間以降も送信が続いている状態です。 また、アドバイスを参考に以下のように変更しましたが、無限に連続して送信される状態は変わりませんでした。 追加でアドバイスいただけると助かります。 (複数のキーのうち、一部しか反応しない問題についても教えて頂けると嬉しいです。) ```C void gpio_task_example(void* arg) { static uint8_t i = 0; uint32_t io_num; uint32_t more_before_value = 2; uint32_t before_value = 2; for(;;) { vTaskDelay(5 * portTICK_PERIOD_MS); if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { uint32_t value = gpio_get_level(io_num); ESP_LOGI(HID_DEMO_TAG, "GPIO[%d] intr, val: %d\n", io_num, value); if(io_num == GPIO_INPUT_IO_LEFT){ if(value == before_value && value == 0 && more_before_value == 1){ uint8_t key_vaule_a = {HID_KEY_A}; esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_a, 1); } more_before_value = before_value; before_value = value; } /* 中略 */ if(io_num == GPIO_INPUT_IO_START){ if(value == before_value && value == 0 && more_before_value == 1){ uint8_t key_vaule_j = {HID_KEY_J}; esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule_j, 1); } more_before_value = before_value; before_value = value; } } } } ```
y_waiwai

2018/08/06 01:23

私がするなら、スイッチ入力の関数を作り、その返り値でスイッチの状態を見れるようにしますな スイッチ1はビット0、スイッチ2はビット1、、とすれば、32個までのスイッチの状態が見れます。 そんな関数をまずしっかり作って、次の機能の実装にかかればどうでしょうか
sola

2018/08/06 10:52

リファクタリングを行い、ソースを見やすくするべきという話でしょうか? > スイッチ1はビット0、スイッチ2はビット1、、とすれば、32個までのスイッチの状態が見れます。 私の知識不足で、ご説明がよく分かりませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問