GPIO IN, OUT (ESP-IDF 環境 + C 言語)

プログラムの書き方

LED やスイッチを使う上でよく使われる関数については, ESP-IDF Programming GuideAPI ReferenceGPIO & RTC GPIO を参照して欲しい.

GPIO (IN) : L チカ

電子工作における hello world と言える L チカを実行する. まずはサンプルファイルをコピーし, 実行してみる.

$ cd ~/esp

$ cp -r esp-idf/examples/get-started/blink .

$ cd blink

サンプルでは, config menu で点灯させる LED の GPIO を指定するようになっている. その設定は, main/Kconfig.projbuild に書かれており, デフォルトで GPIO 5 が設定されている.

$ lv main/Kconfig.projbuild

  menu "Example Configuration"    
      config BLINK_GPIO
          int "Blink GPIO number"
          range 0 34
          default 5
          help
              GPIO number (IOxx) to blink on and off.
              Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.
              GPIOs 35-39 are input-only so cannot be used as outputs.
  endmenu

main プログラムでは congig menu で設定された LED GPIO が CONFIG_BLINK_GPIO に 代入され, それがマクロで BLINK_GPIO に置き換えられている. プログラム中では BLINK_GPIO のレベルを 0, 1 に変化させることで LED の点灯を実現している.

$ lv main/blink.c

  ...(中略)....
  #define BLINK_GPIO CONFIG_BLINK_GPIO

  ...(中略)....    
  printf("Turning off the LED\n");
  gpio_set_level(BLINK_GPIO, 0);

  ...(後略)....    

ビルド

make コマンドを実行する. プロジェクトのディレクトリで最初に make コマンドを実行した時には 以下の例のように config menu が表示される.

  • Serial flasher config を選択し, Default serial port にデバイス名 (ここでは /dev/ttyUSB0) を入力する.

  • Example Configuration を選択し, Blink GPIO number に LED の GPIO の番号 (ここでは 13) を入力する.

マイコンへの書き込み

マイコンに書き込むのは make flash コマンド, 標準出力を表示するのは make monitor コマンドである. まとめて make flash monitor としても良い.

$ make flash monitor

  Turning off the LED
  Turning on the LED
  Turning off the LED
  Turning on the LED
  Turning off the LED
  ....

上記のように標準出力に LED の点灯・消灯のメッセージが表示され, さらに実際に実習ボードの LED の 1 つが点灯することが確認できるであろう.

プログラムの修正と実行

デフォルトの blink.c は make menuconfig で設定された GPIO の LED を点灯させるもの となっている. それを修正して 1 つ目の LED (GPIO 13) を点灯させるプログラムに修正する.

$ cp main/blink.c main/blink.c.bk

$ vi main/blink.c

エディタを使って以下のように書く.

1  #include <stdio.h>
2  #include "freertos/FreeRTOS.h"
3  #include "freertos/task.h"
4  #include "driver/gpio.h"
5 
6  #define BLINK_GPIO 13
7 
8  void app_main(void)
9  {
10   /* ESP32 の各ピンは様々な役割がとれる. GPIO モードに切り替える*/
11   gpio_pad_select_gpio(BLINK_GPIO);
12 
13   /* GPIO を出力モードに切り替える (OUTPUT と INPUT の 2 つから選ぶ)*/
14   gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
15 
16   while(1) {
17     /* Blink off (output low) */
18     printf("Turning off the LED\n");
19     gpio_set_level(BLINK_GPIO, 0);
20     vTaskDelay(1000 / portTICK_PERIOD_MS);
21 
22     /* Blink on (output high) */
23     printf("Turning on the LED\n");
24     gpio_set_level(BLINK_GPIO, 1);
25     vTaskDelay(1000 / portTICK_PERIOD_MS);
26   }
27 }
  • 4 行目: GPIO を利用する場合に driver/gpio.h を include する必要がある.
  • 6 行目: LED の接続される GPIO を指定
  • 11 行目: ピンの役割を GPIO モードに変更
  • 14 行目: LED の接続されているピンを出力に設定.
  • 19, 24 行目: LED の点灯・消灯. gpio_set_level の第二引数が 0 なら電圧を 0V に (= 消灯)
  • 20, 25 行目: 1 秒 = 1000 ミリ秒だけ動作を止める. ESP-IDF 環境では, 待ち時間 (単位 ミリ秒) を portTICK_PERIOD_MS (FreeRTOS の割込み周期)で割り算した結果を vTaskDelay の引数に与える必要がある.

編集したのち, コンパイルとマイコンへの書き込みを行う. make flash すると LED の点滅が確認できるはずである.

$ make 

$ make flash   

全ての LED を点灯させる.

LED を 1 つしか点灯できない. 実習ボードの全ての LED を点灯させてみよう. 実習基板には 8 つの LED があるが, それらの GPIO は 32,33,25,26,27,14,12,13 である.

1  #include <stdio.h>
2  #include "freertos/FreeRTOS.h"
3  #include "freertos/task.h"
4  #include "driver/gpio.h"
5 
6  #define NUM 8
7 
8  void app_main(void)
9  {
10   int BLINK_GPIO[NUM] = {32,33,25,26,27,14,12,13};
11   int i;
12 
13   /* 初期化 */
14   for (i = 0; i < NUM; i++){
15     /* ESP32 の各ピンは様々な役割がとれる. GPIO モードに切り替える*/
16     gpio_pad_select_gpio(BLINK_GPIO[i]);
17 
18     /* GPIO を出力モードに切り替える (OUTPUT と INPUT の 2 つから選ぶ)*/
19     gpio_set_direction(BLINK_GPIO[i], GPIO_MODE_OUTPUT);
20   }
21   
22   while(1) {
23     for (i = 0; i < NUM; i++){
24       /* Blink off (output low) */
25       gpio_set_level(BLINK_GPIO[i], 0);
26       vTaskDelay(1000 / portTICK_PERIOD_MS);
27 
28       /* Blink on (output high) */
29       gpio_set_level(BLINK_GPIO[i], 1);
30       vTaskDelay(1000 / portTICK_PERIOD_MS);
31     }
32   }
33 }

編集したのち, コンパイルとマイコンへの書き込みを行う.

$ make 

$ make flash   

上記の操作で全ての LED が点灯することが確認できたと思う. 念のために, gpio_pad_select_gpio が必要であることを確認してみる. gpio_pad_select_gpio をコメントアウトして実行するとどうなるであろうか?

1  #include <stdio.h>
2  #include "freertos/FreeRTOS.h"
3  #include "freertos/task.h"
4  #include "driver/gpio.h"
5 
6  #define NUM 8
7 
8  void app_main(void)
9  {
10   int BLINK_GPIO[NUM] = {32,33,25,26,27,14,12,13};
11   int i;
12 
13   /* 初期化 */
14   for (i = 0; i < NUM; i++){
15     /* ESP32 の各ピンは様々な役割がとれる. GPIO モードに切り替える*/
16//     gpio_pad_select_gpio(BLINK_GPIO[i]);
17 
18     /* GPIO を出力モードに切り替える (OUTPUT と INPUT の 2 つから選ぶ)*/
19     gpio_set_direction(BLINK_GPIO[i], GPIO_MODE_OUTPUT);
20   }
21   
22   while(1) {
23     for (i = 0; i < NUM; i++){
24       /* Blink off (output low) */
25       gpio_set_level(BLINK_GPIO[i], 0);
26       vTaskDelay(1000 / portTICK_PERIOD_MS);
27 
28       /* Blink on (output high) */
29       gpio_set_level(BLINK_GPIO[i], 1);
30       vTaskDelay(1000 / portTICK_PERIOD_MS);
31     }
32   }
33 }

改めてコンパイルとマイコンへの書き込みを行う.

$ make 

$ make flash   

そうすると, LED が 5 個しか点灯しないことが確認できるはずである. ESP32 の Pin Description (データシート の 2.2 節を参照) を見ると, 各ピンに様々な役割があることがわかる. 上記のように, 初期化プロセスで各ピンを GPIO モードに切り替えることを忘れる, 思った通りの動作をさせられないことになる.

GPIO (OUT) : スイッチ

スイッチと LED を連動させたプログラムを書く. 以下のようなプログラムを書くと, SW4 を ON/OFF した時に LED1 が点灯/消灯する.

1  #include <stdio.h>
2  #include "freertos/FreeRTOS.h"
3  #include "freertos/task.h"
4  #include "driver/gpio.h"
5 
6  #define buttonPin 19
7  #define ledPin    13
8 
9  void app_main(void)
10 {
11   /* LED の初期化 */
12   gpio_pad_select_gpio(ledPin);
13   gpio_set_direction(ledPin, GPIO_MODE_OUTPUT);
14 
15   /* スイッチの初期化*/
16   gpio_pad_select_gpio(buttonPin);
17   gpio_set_direction(buttonPin, GPIO_MODE_INPUT);
18   gpio_set_pull_mode(buttonPin, GPIO_PULLUP_ONLY);  //PULLUP が必要  
19   
20   while(1) {
21     int buttonState = gpio_get_level(buttonPin);
22     
23     if (buttonState == 1) {
24       gpio_set_level(ledPin, 1); // turn LED on:
25     } else {
26       gpio_set_level(ledPin, 0); // turn LED off:
27     }        
28   }
29 }
  • 6 行目: スイッチの接続される GPIO を指定.
  • 16~18 行目: スイッチの接続されているピンを入力に設定
    • GPIO をインプットモードにする. PULLUP しないといけない.
  • 21 行目: スイッチの入力値を取得
  • 23-24 行目: スイッチが入っていたら LED を ON に.
  • 25~26 行目: スイッチが入ってなければ LED を OFF に.